From a412ceb4d920d173542c69f73cd1051b146f554e Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 25 Apr 2018 23:51:13 +0200 Subject: [PATCH] Applied all relevant PCem commits; Extensively cleaned up and changed the CD-ROM code; Removed CD-ROM IOCTTL (it was causing performance and stability issues); Turned a lot of things into device_t's; Added the PS/1 Model 2011 XTA and standalone XTA hard disk controllers, ported from Varcem; Numerous FDC fixes for the PS/1 Model 2121; NVR changes ported from Varcem; The PCap code no longer requires libpcap to be compiled; Numerous fixes to various SCSI controllers; Updated NukedOPL to 1.8; Fixes to OpenAL initialization and closing, should give less Audio issues now; Revorked parts of the common (S)VGA code (also based on code from QEMU); Removed the Removable SCSI hard disks (they were a never finished experiment so there was no need to keep them there); Cleaned up the SCSI hard disk and Iomega ZIP code (but more cleanups of that are coming in the future); In some occasions (IDE hard disks in multiple sector mode and SCSI hard disks) the status bar icon is no longer updated, should improve performance a bit; Redid the way the tertiary and quaternary IDE controllers are configured (and they are now device_t's); Extensively reworked the IDE code and fixed quite a few bugs; Fixes to XT MFM, AT MFM, and AT ESDI code; Some changes to XTIDE and MCA ESDI code; Some fixes to the CD-ROM image handler. --- src/86box.h | 6 +- src/Makefile.local | 3 +- src/cdrom/cdrom.c | 5807 ++++++++--------- src/cdrom/cdrom.h | 286 +- src/cdrom/cdrom_dosbox.cpp | 10 +- src/cdrom/cdrom_image.cc | 2024 +++--- src/cdrom/cdrom_null.c | 38 +- src/cdrom/cdrom_null.h | 8 +- src/config.c | 404 +- src/cpu/808x.c | 14 +- src/cpu/codegen_ops_fpu.h | 9 +- src/cpu/codegen_timing_686.c | 44 +- src/cpu/codegen_timing_pentium.c | 2 +- src/cpu/cpu.c | 38 +- src/cpu/cpu.h | 8 +- src/cpu/x86_ops_amd.h | 4 +- src/cpu/x86_ops_i686.h | 11 +- src/cpu/x86_ops_misc.h | 30 +- src/cpu/x86seg.c | 1 + src/cpu/x87_ops.h | 23 +- src/cpu/x87_ops_misc.h | 2 +- src/device.c | 25 +- src/device.h | 3 +- src/disk/hdc.c | 53 +- src/disk/hdc.h | 12 +- src/disk/hdc_esdi_at.c | 40 +- src/disk/hdc_esdi_mca.c | 221 +- src/disk/hdc_ide.c | 4859 +++++++------- src/disk/hdc_ide.h | 104 +- src/disk/hdc_mfm_at.c | 71 +- src/disk/hdc_mfm_xt.c | 13 +- src/disk/hdc_xta.c | 1200 ++++ src/disk/hdc_xtide.c | 36 +- src/disk/hdd.c | 70 +- src/disk/hdd.h | 65 +- src/disk/hdd_image.c | 753 ++- src/disk/hdd_table.c | 8 +- src/disk/zip.c | 4569 +++++++------ src/disk/zip.h | 165 +- src/dma.c | 1666 ++--- src/dma.h | 74 +- src/floppy/fdc.c | 150 +- src/floppy/fdc.h | 4 +- src/floppy/fdd.c | 4 +- src/floppy/fdd.h | 3 +- src/floppy/fdd_86f.c | 3 +- src/intel_piix.c | 1477 +++-- src/intel_sio.c | 267 +- src/intel_sio.h | 8 +- src/keyboard.h | 5 +- src/keyboard_at.c | 28 +- src/machine/m_amstrad.c | 4 +- src/machine/m_at.c | 2 +- src/machine/m_at_430fx.c | 472 +- src/machine/m_at_430hx.c | 520 +- src/machine/m_at_430lx_nx.c | 348 +- src/machine/m_at_430vx.c | 380 +- src/machine/m_at_440fx.c | 371 +- src/machine/m_at_sis_85c496.c | 291 +- src/machine/m_europc.c | 19 +- src/machine/m_europc_hdc.c | 987 --- src/machine/m_olivetti_m24.c | 4 +- src/machine/m_ps1.c | 115 +- src/machine/m_ps1_hdc.c | 1523 +++++ src/machine/m_ps2_isa.c | 2 +- src/machine/m_ps2_mca.c | 2 +- src/machine/m_xt_t1000.c | 4 +- src/machine/m_xt_xi8088.c | 2 +- src/machine/machine.c | 15 +- src/machine/machine.h | 14 +- src/machine/machine_table.c | 219 +- src/mem.c | 79 +- src/network/net_pcap.c | 80 +- src/nvr.c | 315 +- src/nvr.h | 34 +- src/nvr_at.c | 311 +- src/pc.c | 163 +- src/pci.c | 45 +- src/pci.h | 10 +- src/pci_dummy.c | 1 + src/piix.h | 24 +- src/pit.c | 12 +- src/pit.h | 2 + src/plat.h | 5 +- src/scsi/scsi.c | 92 +- src/scsi/scsi.h | 10 +- src/scsi/scsi_aha154x.c | 4 +- src/scsi/scsi_buslogic.c | 19 +- src/scsi/scsi_device.c | 52 +- src/scsi/scsi_device.h | 3 +- src/scsi/scsi_disk.c | 2262 +++---- src/scsi/scsi_disk.h | 56 +- src/scsi/scsi_ncr5380.c | 4 +- src/scsi/scsi_ncr53c810.c | 26 +- src/scsi/scsi_x54x.c | 74 +- src/scsi/scsi_x54x.h | 3 +- src/sio_fdc37c669.c | 8 +- src/sio_fdc37c66x.c | 8 +- src/sio_fdc37c93x.c | 6 +- src/sio_pc87306.c | 6 +- src/sio_um8669f.c | 2 - src/sio_w83877f.c | 4 +- src/sound/midi_fluidsynth.c | 2 +- src/sound/nukedopl.cpp | 694 +- src/sound/nukedopl.h | 57 +- src/sound/openal.c | 31 +- src/sound/snd_adlibgold.c | 2 +- src/sound/snd_audiopci.c | 2 + src/sound/snd_dbopl.cc | 64 +- src/sound/snd_dbopl.h | 2 +- src/sound/snd_sb.c | 38 +- src/sound/snd_sb_dsp.c | 44 +- src/sound/sound.c | 82 +- src/sound/sound.h | 7 +- src/ui.h | 11 +- src/video/vid_ati18800.c | 23 +- src/video/vid_ati_eeprom.c | 7 +- src/video/vid_ati_mach64.c | 12 +- src/video/vid_cl54xx.c | 394 +- src/video/vid_et4000w32.c | 3 +- src/video/vid_oak_oti.c | 11 +- src/video/vid_paradise.c | 21 +- src/video/vid_s3.c | 594 +- src/video/vid_s3_virge.c | 3 +- src/video/vid_svga.c | 2710 ++++---- src/video/vid_svga.h | 367 +- src/video/vid_table.c | 19 +- src/video/vid_ti_cf62011.c | 11 +- src/video/vid_vga.c | 9 +- src/video/vid_voodoo.c | 32 +- src/video/video.h | 4 +- src/win/86Box.rc | 64 +- src/win/Makefile.mingw | 21 +- src/win/icons/removable_disk.ico | Bin 1150 -> 0 bytes src/win/icons/removable_disk_active.ico | Bin 1150 -> 0 bytes src/win/icons/removable_disk_empty.ico | Bin 1150 -> 0 bytes src/win/icons/removable_disk_empty_active.ico | Bin 1150 -> 0 bytes src/win/resource.h | 15 +- src/win/win.c | 102 +- src/win/win.h | 4 +- src/win/win_about.c | 10 +- src/win/win_cdrom.c | 119 +- src/win/win_cdrom_ioctl.c | 1341 ---- src/win/win_ddraw.cpp | 3 +- src/win/win_devconf.c | 8 +- src/win/win_dialog.c | 44 +- src/win/win_new_floppy.c | 20 +- src/win/win_settings.c | 765 +-- src/win/win_stbar.c | 526 +- src/win/win_thread.c | 9 +- src/win/win_ui.c | 35 +- 151 files changed, 21026 insertions(+), 21058 deletions(-) create mode 100644 src/disk/hdc_xta.c delete mode 100644 src/machine/m_europc_hdc.c create mode 100644 src/machine/m_ps1_hdc.c delete mode 100644 src/win/icons/removable_disk.ico delete mode 100644 src/win/icons/removable_disk_active.ico delete mode 100644 src/win/icons/removable_disk_empty.ico delete mode 100644 src/win/icons/removable_disk_empty_active.ico delete mode 100644 src/win/win_cdrom_ioctl.c diff --git a/src/86box.h b/src/86box.h index 28a46cc0b..c5121da72 100644 --- a/src/86box.h +++ b/src/86box.h @@ -8,7 +8,7 @@ * * Main include file for the application. * - * Version: @(#)86box.h 1.0.21 2018/03/19 + * Version: @(#)86box.h 1.0.22 2018/03/28 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -100,7 +100,7 @@ extern int sound_is_float, /* (C) sound uses FP values */ GUS, /* (C) sound option */ SSI2001, /* (C) sound option */ voodoo_enabled; /* (C) video option */ -extern int mem_size; /* (C) memory size */ +extern uint32_t mem_size; /* (C) memory size */ extern int cpu_manufacturer, /* (C) cpu manufacturer */ cpu, /* (C) cpu type */ cpu_use_dynarec, /* (C) cpu uses/needs Dyna */ @@ -139,7 +139,9 @@ extern void pclog(const char *fmt, ...); extern void fatal(const char *fmt, ...); extern void set_screen_size(int x, int y); extern void set_screen_size_natural(void); +#if 0 extern void pc_reload(wchar_t *fn); +#endif extern int pc_init_modules(void); extern int pc_init(int argc, wchar_t *argv[]); extern void pc_close(void *threadid); diff --git a/src/Makefile.local b/src/Makefile.local index 9b9b7f2a7..f5b4dbed1 100644 --- a/src/Makefile.local +++ b/src/Makefile.local @@ -10,7 +10,7 @@ # settings, so we can avoid changing the main one for all of # our local setups. # -# Version: @(#)Makefile.local 1.0.10 2018/03/20 +# Version: @(#)Makefile.local 1.0.11 2018/03/26 # # Author: Fred N. van Kempen, # @@ -38,6 +38,7 @@ STUFF := # -DENABLE_KEYBOARD_AT_LOG=N sets logging level at N. # -DENABLE_KEYBOARD_LOG=N sets logging level at N. # -DENABLE_PCI_LOG=N sets logging level at N. +# -DENABLE_PIIX_LOG=N sets logging level at N. # -DENABLE_CDROM_LOG=N sets logging level at N. # -DENABLE_CDROM_IMAGE_LOG=N sets logging level at N. # -DENABLE_CDROM_IOCTL_LOG=N sets logging level at N. diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index e88a9606e..7bd85196f 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)cdrom.c 1.0.45 2018/03/21 + * Version: @(#)cdrom.c 1.0.46 2018/03/26 * * Author: Miran Grca, * @@ -33,6 +33,7 @@ #include "../disk/hdc.h" #include "../disk/hdc_ide.h" #include "../plat.h" +#include "../sound/sound.h" #include "../ui.h" #include "cdrom.h" #include "cdrom_image.h" @@ -42,8 +43,8 @@ /* Bits of 'status' */ #define ERR_STAT 0x01 #define DRQ_STAT 0x08 /* Data request */ -#define DSC_STAT 0x10 -#define SERVICE_STAT 0x10 +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 #define READY_STAT 0x40 #define BUSY_STAT 0x80 @@ -51,9 +52,14 @@ #define ABRT_ERR 0x04 /* Command aborted */ #define MCR_ERR 0x08 /* Media change request */ +#define MIN_SEEK 2000 +#define MAX_SEEK 333333 + +#define cdbufferb dev->buffer + + cdrom_t *cdrom[CDROM_NUM]; cdrom_image_t cdrom_image[CDROM_NUM]; -cdrom_ioctl_t cdrom_ioctl[CDROM_NUM]; cdrom_drive_t cdrom_drives[CDROM_NUM]; uint8_t atapi_cdrom_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; uint8_t scsi_cdrom_drives[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, @@ -100,237 +106,249 @@ static struct /* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ const uint8_t cdrom_command_flags[0x100] = { - IMPLEMENTED | CHECK_READY | NONDATA, - IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, - 0, - IMPLEMENTED | ALLOW_UA, - 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, - 0, 0, - IMPLEMENTED | CHECK_READY | NONDATA, - 0, 0, 0, 0, 0, 0, - IMPLEMENTED | ALLOW_UA, - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, - 0, - IMPLEMENTED, - 0, 0, 0, 0, - IMPLEMENTED, - IMPLEMENTED | CHECK_READY, - 0, 0, - IMPLEMENTED | CHECK_READY, - 0, 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, - 0, 0, - IMPLEMENTED | CHECK_READY, - 0, 0, - IMPLEMENTED | CHECK_READY | NONDATA, - 0, 0, 0, - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, - IMPLEMENTED | CHECK_READY, - IMPLEMENTED | CHECK_READY, /* Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS - NOTE: The ATAPI reference says otherwise, but I think this is a question of - interpreting things right - the UNIT ATTENTION condition we have here - is a tradition from not ready to ready, by definition the drive - eventually becomes ready, make the condition go away. */ - IMPLEMENTED | CHECK_READY, - IMPLEMENTED | CHECK_READY, - IMPLEMENTED | ALLOW_UA, - IMPLEMENTED | CHECK_READY, - IMPLEMENTED | CHECK_READY, - 0, - IMPLEMENTED | ALLOW_UA, - IMPLEMENTED | CHECK_READY, - 0, 0, - IMPLEMENTED | CHECK_READY, - 0, 0, - IMPLEMENTED | CHECK_READY, - IMPLEMENTED | CHECK_READY, - 0, 0, - IMPLEMENTED, - 0, 0, 0, 0, - IMPLEMENTED, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, - 0, 0, - IMPLEMENTED | CHECK_READY, - 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, - 0, - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, - 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY | ATAPI_ONLY, - 0, 0, 0, - IMPLEMENTED | CHECK_READY | ATAPI_ONLY, - IMPLEMENTED | CHECK_READY, - IMPLEMENTED | CHECK_READY, - IMPLEMENTED, - IMPLEMENTED | CHECK_READY, - IMPLEMENTED, - IMPLEMENTED | CHECK_READY, - IMPLEMENTED | CHECK_READY, - 0, 0, - IMPLEMENTED | CHECK_READY | SCSI_ONLY, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY | SCSI_ONLY, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - IMPLEMENTED | SCSI_ONLY, - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + IMPLEMENTED | CHECK_READY | NONDATA, + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, + 0, + IMPLEMENTED | ALLOW_UA, + 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY | NONDATA, + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | ALLOW_UA, + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, + 0, + IMPLEMENTED, + 0, 0, 0, 0, + IMPLEMENTED, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY | NONDATA, + 0, 0, 0, + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, /* Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS + NOTE: The ATAPI reference says otherwise, but I think this is a question of + interpreting things right - the UNIT ATTENTION condition we have here + is a tradition from not ready to ready, by definition the drive + eventually becomes ready, make the condition go away. */ + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | ALLOW_UA, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, + 0, + IMPLEMENTED | ALLOW_UA, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED, + 0, 0, 0, 0, + IMPLEMENTED, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY, + 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, + 0, + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, + 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY | ATAPI_ONLY, + 0, 0, 0, + IMPLEMENTED | CHECK_READY | ATAPI_ONLY, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED, + IMPLEMENTED | CHECK_READY, + IMPLEMENTED | CHECK_READY, + 0, 0, + IMPLEMENTED | CHECK_READY | SCSI_ONLY, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY | SCSI_ONLY, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | SCSI_ONLY, + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -uint64_t cdrom_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << GPMODE_CDROM_PAGE) | (1LL << GPMODE_CDROM_AUDIO_PAGE) | (1LL << GPMODE_CAPABILITIES_PAGE) | (1LL << GPMODE_ALL_PAGES); +static uint64_t cdrom_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | + GPMODEP_CDROM_PAGE | + GPMODEP_CDROM_AUDIO_PAGE | + GPMODEP_CAPABILITIES_PAGE | + GPMODEP_ALL_PAGES); static const mode_sense_pages_t cdrom_mode_sense_pages_default = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 1, 0, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } -} }; +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } +} }; static const mode_sense_pages_t cdrom_mode_sense_pages_default_scsi = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { 0x8E, 0xE, 5, 4, 0,0x80,0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 1, 0, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } -} }; +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 5, 4, 0,128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } +} }; static const mode_sense_pages_t cdrom_mode_sense_pages_changeable = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { 0x8E, 0xE, 5, 4, 0,0x80,0, 75, 1, 0xFF, 2, 0xFF, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 0x02, 0xC2, 1, 0, 0, 0, 0x02, 0xC2, 0, 0, 0, 0 } -} }; +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 5, 4, 0,128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } +} }; -static mode_sense_pages_t cdrom_mode_sense_pages_saved[CDROM_NUM]; +uint8_t cdrom_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + +static void cdrom_command_complete(cdrom_t *dev); + +static void cdrom_mode_sense_load(cdrom_t *dev); + +static void cdrom_init(cdrom_t *dev); +void cdrom_phase_callback(cdrom_t *dev); #ifdef ENABLE_CDROM_LOG @@ -342,2997 +360,2848 @@ static void cdrom_log(const char *format, ...) { #ifdef ENABLE_CDROM_LOG - va_list ap; + va_list ap; - if (cdrom_do_log) - { - va_start(ap, format); - pclog_ex(format, ap); - va_end(ap); - } + if (cdrom_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } #endif } -int find_cdrom_for_channel(uint8_t channel) +int +find_cdrom_for_channel(uint8_t channel) { - uint8_t i = 0; + uint8_t i = 0; - for (i = 0; i < CDROM_NUM; i++) { - if (((cdrom_drives[i].bus_type == CDROM_BUS_ATAPI_PIO_ONLY) || (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) && (cdrom_drives[i].ide_channel == channel)) - return i; - } - return 0xff; + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) && (cdrom_drives[i].ide_channel == channel)) + return i; + } + return 0xff; } -void cdrom_init(int id, int cdb_len_setting); -void build_atapi_cdrom_map() +void +build_atapi_cdrom_map() { - uint8_t i = 0; + uint8_t i = 0; - memset(atapi_cdrom_drives, 0xff, 8); + memset(atapi_cdrom_drives, 0xff, 8); - for (i = 0; i < 8; i++) { - atapi_cdrom_drives[i] = find_cdrom_for_channel(i); - if (atapi_cdrom_drives[i] != 0xff) - cdrom_init(atapi_cdrom_drives[i], 12); - } + for (i = 0; i < 8; i++) + atapi_cdrom_drives[i] = find_cdrom_for_channel(i); } -int find_cdrom_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) -{ - uint8_t i = 0; - for (i = 0; i < CDROM_NUM; i++) { - if ((cdrom_drives[i].bus_type == CDROM_BUS_SCSI) && (cdrom_drives[i].scsi_device_id == scsi_id) && (cdrom_drives[i].scsi_device_lun == scsi_lun)) - return i; - } - return 0xff; +int +find_cdrom_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t i = 0; + + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom_drives[i].bus_type == CDROM_BUS_SCSI) && (cdrom_drives[i].scsi_device_id == scsi_id) && (cdrom_drives[i].scsi_device_lun == scsi_lun)) + return i; + } + return 0xff; } -void build_scsi_cdrom_map() + +void +build_scsi_cdrom_map() { - uint8_t i = 0; - uint8_t j = 0; + uint8_t i = 0; + uint8_t j = 0; - for (i = 0; i < 16; i++) - memset(scsi_cdrom_drives[i], 0xff, 8); + for (i = 0; i < 16; i++) + memset(scsi_cdrom_drives[i], 0xff, 8); - for (i = 0; i < 16; i++) { - for (j = 0; j < 8; j++) { - scsi_cdrom_drives[i][j] = find_cdrom_for_scsi_id(i, j); - if (scsi_cdrom_drives[i][j] != 0xff) - cdrom_init(scsi_cdrom_drives[i][j], 12); - } - } + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) + scsi_cdrom_drives[i][j] = find_cdrom_for_scsi_id(i, j); + } } -void cdrom_set_callback(uint8_t id) + +static void +cdrom_set_callback(cdrom_t *dev) { - if (cdrom_drives[id].bus_type != CDROM_BUS_SCSI) - ide_set_callback(cdrom_drives[id].ide_channel, cdrom[id]->callback); + if (dev && dev->drv && (dev->drv->bus_type != CDROM_BUS_SCSI)) + ide_set_callback(dev->drv->ide_channel >> 1, dev->callback); } -void cdrom_set_cdb_len(int id, int cdb_len) + +void +cdrom_set_signature(cdrom_t *dev) { - cdrom[id]->cdb_len = cdb_len; + if (!dev) + return; + dev->phase = 1; + dev->request_length = 0xEB14; } -void cdrom_reset_cdb_len(int id) + +static void +cdrom_init(cdrom_t *dev) { - cdrom[id]->cdb_len = cdrom[id]->cdb_len_setting ? 16 : 12; + if (!dev) + return; + + /* Tell the cdrom_t struct what cdrom_drives element corresponds to it. */ + dev->drv = &(cdrom_drives[dev->id]); + + /* Do a reset (which will also rezero it). */ + cdrom_reset(dev); + + /* Configure the drive. */ + dev->requested_blocks = 1; + + dev->drv->bus_mode = 0; + if (dev->drv->bus_type >= CDROM_BUS_ATAPI) + dev->drv->bus_mode |= 2; + if (dev->drv->bus_type < CDROM_BUS_SCSI) + dev->drv->bus_mode |= 1; + cdrom_log("CD-ROM %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); + dev->cdb_len = 12; + + dev->sense[0] = 0xf0; + dev->sense[7] = 10; + dev->status = READY_STAT | DSC_STAT; + dev->pos = 0; + dev->packet_status = 0xff; + cdrom_sense_key = cdrom_asc = cdrom_ascq = dev->unit_attention = 0; + dev->cur_speed = dev->drv->speed; + cdrom_mode_sense_load(dev); } -void cdrom_set_signature(int id) -{ - cdrom_t *dev = cdrom[id]; - if (id >= CDROM_NUM) - return; - dev->phase = 1; - dev->request_length = 0xEB14; +static int +cdrom_supports_pio(cdrom_t *dev) +{ + return (dev->drv->bus_mode & 1); } -void cdrom_destroy_drives(void) -{ - int i; - for (i = 0; i < CDROM_NUM; i++) { - if (cdrom[i]) { - free(cdrom[i]); - cdrom[i] = NULL; - } - } +static int +cdrom_supports_dma(cdrom_t *dev) +{ + return (dev->drv->bus_mode & 2); } -void cdrom_init(int id, int cdb_len_setting) -{ - cdrom_t *dev; - - uint8_t *trcbuf; - uint32_t tcap; - - if (id >= CDROM_NUM) - return; - dev = cdrom[id]; - tcap = dev->cdrom_capacity; - trcbuf = (uint8_t *) malloc(16); - memcpy(trcbuf, dev->rcbuf, 16); - memset(dev, 0, sizeof(cdrom_t)); - memcpy(dev->rcbuf, trcbuf, 16); - free(trcbuf); - dev->cdrom_capacity = tcap; - dev->requested_blocks = 1; - if (cdb_len_setting <= 1) - dev->cdb_len_setting = cdb_len_setting; - cdrom_reset_cdb_len(id); - dev->cd_status = CD_STATUS_EMPTY; - dev->sense[0] = 0xf0; - dev->sense[7] = 10; - cdrom_drives[id].bus_mode = 0; - if (cdrom_drives[id].bus_type >= CDROM_BUS_ATAPI_PIO_AND_DMA) - cdrom_drives[id].bus_mode |= 2; - if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) - cdrom_drives[id].bus_mode |= 1; - cdrom_log("CD-ROM %i: Bus type %i, bus mode %i\n", id, cdrom_drives[id].bus_type, cdrom_drives[id].bus_mode); - if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) - cdrom_set_signature(id); - dev->status = READY_STAT | DSC_STAT; - dev->pos = 0; - dev->packet_status = 0xff; - cdrom_sense_key = cdrom_asc = cdrom_ascq = dev->unit_attention = 0; - dev->cdb_len_setting = 0; - dev->cdb_len = 12; - dev->cur_speed = cdrom_drives[id].speed; -} - -int cdrom_supports_pio(int id) -{ - return (cdrom_drives[id].bus_mode & 1); -} - -int cdrom_supports_dma(int id) -{ - return (cdrom_drives[id].bus_mode & 2); -} /* Returns: 0 for none, 1 for PIO, 2 for DMA. */ -int cdrom_current_mode(int id) +static int +cdrom_current_mode(cdrom_t *dev) { - cdrom_t *dev = cdrom[id]; - - if (!cdrom_supports_pio(id) && !cdrom_supports_dma(id)) - return 0; - if (cdrom_supports_pio(id) && !cdrom_supports_dma(id)) { - cdrom_log("CD-ROM %i: Drive does not support DMA, setting to PIO\n", id); - return 1; - } - if (!cdrom_supports_pio(id) && cdrom_supports_dma(id)) - return 2; - if (cdrom_supports_pio(id) && cdrom_supports_dma(id)) { - cdrom_log("CD-ROM %i: Drive supports both, setting to %s\n", id, (dev->features & 1) ? "DMA" : "PIO", id); - return (dev->features & 1) ? 2 : 1; - } - + if (!cdrom_supports_pio(dev) && !cdrom_supports_dma(dev)) return 0; + if (cdrom_supports_pio(dev) && !cdrom_supports_dma(dev)) { + cdrom_log("CD-ROM %i: Drive does not support DMA, setting to PIO\n", dev->id); + return 1; + } + if (!cdrom_supports_pio(dev) && cdrom_supports_dma(dev)) + return 2; + if (cdrom_supports_pio(dev) && cdrom_supports_dma(dev)) { + cdrom_log("CD-ROM %i: Drive supports both, setting to %s\n", dev->id, + (dev->features & 1) ? "DMA" : "PIO", + dev->id); + return (dev->features & 1) ? 2 : 1; + } + + return 0; } + /* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int cdrom_CDROM_PHASE_to_scsi(uint8_t id) +int +cdrom_CDROM_PHASE_to_scsi(cdrom_t *dev) { - cdrom_t *dev = cdrom[id]; - - if (dev->status & ERR_STAT) - return SCSI_STATUS_CHECK_CONDITION; - else - return SCSI_STATUS_OK; + if (dev->status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; } + /* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ -int cdrom_atapi_phase_to_scsi(uint8_t id) +int +cdrom_atapi_phase_to_scsi(cdrom_t *dev) { - cdrom_t *dev = cdrom[id]; - - if (dev->status & 8) { - switch (dev->phase & 3) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 1; - case 3: - return 7; - } - } else { - if ((dev->phase & 3) == 3) - return 3; - else - return 4; - } - - return 0; -} - -int cdrom_lba_to_msf_accurate(int lba) -{ - int temp_pos; - int m, s, f; - - temp_pos = lba + 150; - f = temp_pos % 75; - temp_pos -= f; - temp_pos /= 75; - s = temp_pos % 60; - temp_pos -= s; - temp_pos /= 60; - m = temp_pos; - - return ((m << 16) | (s << 8) | f); -} - -uint32_t cdrom_mode_sense_get_channel(uint8_t id, int channel) -{ - return cdrom_mode_sense_pages_saved[id].pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; -} - -uint32_t cdrom_mode_sense_get_volume(uint8_t id, int channel) -{ - return cdrom_mode_sense_pages_saved[id].pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; -} - -void cdrom_mode_sense_load(uint8_t id) -{ - FILE *f; - wchar_t file_name[512]; - int i; - memset(&cdrom_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); - for (i = 0; i < 0x3f; i++) { - if (cdrom_mode_sense_pages_default.pages[i][1] != 0) { - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - memcpy(cdrom_mode_sense_pages_saved[id].pages[i], cdrom_mode_sense_pages_default_scsi.pages[i], cdrom_mode_sense_pages_default_scsi.pages[i][1] + 2); - else - memcpy(cdrom_mode_sense_pages_saved[id].pages[i], cdrom_mode_sense_pages_default.pages[i], cdrom_mode_sense_pages_default.pages[i][1] + 2); - } - } - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", id); - else - swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", id); - f = plat_fopen(nvr_path(file_name), L"rb"); - if (f) { - fread(cdrom_mode_sense_pages_saved[id].pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); - fclose(f); - } -} - -void cdrom_mode_sense_save(uint8_t id) -{ - FILE *f; - wchar_t file_name[512]; - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", id); - else - swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", id); - f = plat_fopen(nvr_path(file_name), L"wb"); - if (f) { - fwrite(cdrom_mode_sense_pages_saved[id].pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); - fclose(f); - } -} - -static void cdrom_command_complete(uint8_t id); - -uint8_t cdrom_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -static int cdrom_pass_through(uint8_t id, uint32_t *len, uint8_t *cdb, uint8_t *buffer); - -int cdrom_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - int ret = 0; - int size = 0; - - if (cdrom_drives[id].handler->pass_through) { - ret = cdrom_pass_through(id, len, cdb, buffer); - if (!ret) + if (dev->status & 8) { + switch (dev->phase & 3) { + case 0: return 0; - if (*len == 65534) - *len = 8; - } else { - size = cdrom_drives[id].handler->size(id) - 1; /* IMPORTANT: What's returned is the last LBA block. */ - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 8; /* 2048 = 0x0800 */ - *len = 8; + case 1: + return 2; + case 2: + return 1; + case 3: + return 7; } - return 1; + } else { + if ((dev->phase & 3) == 3) + return 3; + else + return 4; + } + + return 0; } + +int +cdrom_lba_to_msf_accurate(int lba) +{ + int temp_pos; + int m, s, f; + + temp_pos = lba + 150; + f = temp_pos % 75; + temp_pos -= f; + temp_pos /= 75; + s = temp_pos % 60; + temp_pos -= s; + temp_pos /= 60; + m = temp_pos; + + return ((m << 16) | (s << 8) | f); +} + + +uint32_t +cdrom_mode_sense_get_channel(cdrom_t *dev, int channel) +{ + return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; +} + + +uint32_t +cdrom_mode_sense_get_volume(cdrom_t *dev, int channel) +{ + return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; +} + + +static void +cdrom_mode_sense_load(cdrom_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + int i; + + memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (cdrom_mode_sense_pages_default.pages[i][1] != 0) { + if (dev->drv->bus_type == CDROM_BUS_SCSI) + memcpy(dev->ms_pages_saved.pages[i], + cdrom_mode_sense_pages_default_scsi.pages[i], + cdrom_mode_sense_pages_default_scsi.pages[i][1] + 2); + else + memcpy(dev->ms_pages_saved.pages[i], + cdrom_mode_sense_pages_default.pages[i], + cdrom_mode_sense_pages_default.pages[i][1] + 2); + } + } + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (dev->drv->bus_type == CDROM_BUS_SCSI) + swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) { + fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); + fclose(f); + } +} + + +static void +cdrom_mode_sense_save(cdrom_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (dev->drv->bus_type == CDROM_BUS_SCSI) + swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) { + fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); + fclose(f); + } +} + + +int +cdrom_read_capacity(cdrom_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int size = 0; + + size = dev->handler->size(dev->id) - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 8; /* 2048 = 0x0800 */ + *len = 8; + + return 1; +} + + /*SCSI Mode Sense 6/10*/ -uint8_t cdrom_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) +static uint8_t +cdrom_mode_sense_read(cdrom_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) { - switch (page_control) { - case 0: - case 3: - return cdrom_mode_sense_pages_saved[id].pages[page][pos]; - break; - case 1: - return cdrom_mode_sense_pages_changeable.pages[page][pos]; - break; - case 2: - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - return cdrom_mode_sense_pages_default_scsi.pages[page][pos]; - else - return cdrom_mode_sense_pages_default.pages[page][pos]; - break; - } + switch (page_control) { + case 0: + case 3: + return dev->ms_pages_saved.pages[page][pos]; + break; + case 1: + return cdrom_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + if (dev->drv->bus_type == CDROM_BUS_SCSI) + return cdrom_mode_sense_pages_default_scsi.pages[page][pos]; + else + return cdrom_mode_sense_pages_default.pages[page][pos]; + break; + } - return 0; + return 0; } -uint32_t cdrom_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) + +static uint32_t +cdrom_mode_sense(cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) { - cdrom_t *dev = cdrom[id]; + uint8_t page_control = (type >> 6) & 3; + int i = 0, j = 0; - uint8_t page_control = (type >> 6) & 3; + uint8_t msplen; - int i = 0; - int j = 0; + type &= 0x3f; - uint8_t msplen; + if (block_descriptor_len) { + buf[pos++] = 1; /* Density code. */ + buf[pos++] = 0; /* Number of blocks (0 = all). */ + buf[pos++] = 0; + buf[pos++] = 0; + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x800 = 2048 bytes). */ + buf[pos++] = 8; + buf[pos++] = 0; + } - type &= 0x3f; - - if (block_descriptor_len) { - buf[pos++] = 1; /* Density code. */ - buf[pos++] = 0; /* Number of blocks (0 = all). */ - buf[pos++] = 0; - buf[pos++] = 0; - buf[pos++] = 0; /* Reserved. */ - buf[pos++] = 0; /* Block length (0x800 = 2048 bytes). */ - buf[pos++] = 8; - buf[pos++] = 0; - } - - for (i = 0; i < 0x40; i++) { - if ((type == GPMODE_ALL_PAGES) || (type == i)) { - if (cdrom_mode_sense_page_flags & (1LL << dev->current_page_code)) { - buf[pos++] = cdrom_mode_sense_read(id, page_control, i, 0); - msplen = cdrom_mode_sense_read(id, page_control, i, 1); - buf[pos++] = msplen; - cdrom_log("CD-ROM %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); - for (j = 0; j < msplen; j++) { - if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 6) && (j <= 7)) { - if (j & 1) - buf[pos++] = ((cdrom_drives[id].speed * 176) & 0xff); - else - buf[pos++] = ((cdrom_drives[id].speed * 176) >> 8); - } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 12) && (j <= 13)) { - if (j & 1) - buf[pos++] = ((dev->cur_speed * 176) & 0xff); - else - buf[pos++] = ((dev->cur_speed * 176) >> 8); - } else - buf[pos++] = cdrom_mode_sense_read(id, page_control, i, 2 + j); - } + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (cdrom_mode_sense_page_flags & (1LL << dev->current_page_code)) { + buf[pos++] = cdrom_mode_sense_read(dev, page_control, i, 0); + msplen = cdrom_mode_sense_read(dev, page_control, i, 1); + buf[pos++] = msplen; + cdrom_log("CD-ROM %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); + for (j = 0; j < msplen; j++) { + if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 6) && (j <= 7)) { + if (j & 1) + buf[pos++] = ((dev->drv->speed * 176) & 0xff); + else + buf[pos++] = ((dev->drv->speed * 176) >> 8); + } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 12) && (j <= 13)) { + if (j & 1) + buf[pos++] = ((dev->cur_speed * 176) & 0xff); + else + buf[pos++] = ((dev->cur_speed * 176) >> 8); + } else + buf[pos++] = cdrom_mode_sense_read(dev, page_control, i, 2 + j); } } } + } - return pos; + return pos; } -void cdrom_update_request_length(uint8_t id, int len, int block_len) + +static void +cdrom_update_request_length(cdrom_t *dev, int len, int block_len) { - cdrom_t *dev = cdrom[id]; - uint32_t bt; + int32_t bt, min_len = 0; - uint32_t min_len = 0; + dev->max_transfer_len = dev->request_length; - dev->max_transfer_len = dev->request_length; + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (dev->current_cdb[0]) { + case 0x08: + case 0x28: + case 0xa8: + case 0xb9: + case 0xbe: + /* Make sure total length is not bigger than sum of the lengths of + all the requested blocks. */ + bt = (dev->requested_blocks * block_len); + if (len > bt) + len = bt; - /* For media access commands, make sure the requested DRQ length matches the block length. */ - switch (dev->current_cdb[0]) { + min_len = block_len; + + if (len <= block_len) { + /* Total length is less or equal to block length. */ + if (dev->max_transfer_len < block_len) { + /* Transfer a minimum of (block size) bytes. */ + dev->max_transfer_len = block_len; + dev->packet_len = block_len; + break; + } + } + default: + dev->packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) + dev->max_transfer_len &= 0xfffe; + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (!dev->max_transfer_len) + dev->max_transfer_len = 65534; + + if ((len <= dev->max_transfer_len) && (len >= min_len)) + dev->request_length = dev->max_transfer_len = len; + + return; +} + + +static double +cdrom_get_short_seek(cdrom_t *dev) +{ + switch(dev->cur_speed) { + case 0: + fatal("CD-ROM %i: 0x speed\n", dev->id); + return 0.0; + case 1: + return 240.0; + case 2: + return 160.0; + case 3: + return 150.0; + case 4: case 5: case 6: case 7: case 8: + case 9: case 10: case 11: + return 112.0; + case 12: case 13: case 14: case 15: + return 75.0; + case 16: case 17: case 18: case 19: + return 58.0; + case 20: case 21: case 22: case 23: + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + case 48: + return 50.0; + default: + /* 24-32, 52+ */ + return 45.0; + } +} + + +static double +cdrom_get_long_seek(cdrom_t *dev) +{ + switch(dev->cur_speed) { + case 0: + fatal("CD-ROM %i: 0x speed\n", dev->id); + return 0.0; + case 1: + return 1446.0; + case 2: + return 1000.0; + case 3: + return 900.0; + case 4: case 5: case 6: case 7: case 8: + case 9: case 10: case 11: + return 675.0; + case 12: case 13: case 14: case 15: + return 400.0; + case 16: case 17: case 18: case 19: + return 350.0; + case 20: case 21: case 22: case 23: + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + case 48: + return 300.0; + default: + /* 24-32, 52+ */ + return 270.0; + } +} + + +static double +cdrom_seek_time(cdrom_t *dev) +{ + uint32_t diff = dev->seek_diff; + double sd = (double) (MAX_SEEK - MIN_SEEK); + + if (diff < MIN_SEEK) + return 0.0; + if (diff > MAX_SEEK) + diff = MAX_SEEK; + + diff -= MIN_SEEK; + + return cdrom_get_short_seek(dev) + ((cdrom_get_long_seek(dev) * ((double) diff)) / sd); +} + + +static double +cdrom_bus_speed(cdrom_t *dev) +{ + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + dev->callback = -1LL; /* Speed depends on SCSI controller */ + return 0.0; + } else { + if (cdrom_current_mode(dev) == 2) + return 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ + else + return 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ + } +} + + +static void +cdrom_command_bus(cdrom_t *dev) +{ + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + dev->callback = 1LL * CDROM_TIME; + cdrom_set_callback(dev); +} + + +static void +cdrom_command_common(cdrom_t *dev) +{ + double bytes_per_second, period; + double dusec; + + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + dev->callback = 0LL; + + cdrom_log("CD-ROM %i: Current speed: %ix\n", dev->id, dev->cur_speed); + + if (dev->packet_status == CDROM_PHASE_COMPLETE) { + cdrom_phase_callback(dev); + dev->callback = 0LL; + } else { + switch(dev->current_cdb[0]) { + case GPCMD_REZERO_UNIT: + case 0x0b: + case 0x2b: + /* Seek time is in us. */ + period = cdrom_seek_time(dev); + cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", + dev->id, (int64_t) period); + period = period * ((double) TIMER_USEC); + dev->callback += ((int64_t) period); + cdrom_set_callback(dev); + return; case 0x08: case 0x28: case 0xa8: + /* Seek time is in us. */ + period = cdrom_seek_time(dev); + cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", + dev->id, (int64_t) period); + period = period * ((double) TIMER_USEC); + dev->callback += ((int64_t) period); + case 0x25: + case 0x42: + case 0x43: + case 0x44: + case 0x51: + case 0x52: + case 0xad: + case 0xb8: case 0xb9: case 0xbe: - /* Make sure total length is not bigger than sum of the lengths of - all the requested blocks. */ - bt = (dev->requested_blocks * block_len); - if (len > bt) - len = bt; - - min_len = block_len; - - if (len <= block_len) { - /* Total length is less or equal to block length. */ - if (dev->max_transfer_len < block_len) { - /* Transfer a minimum of (block size) bytes. */ - dev->max_transfer_len = block_len; - dev->packet_len = block_len; - break; - } - } + if (dev->current_cdb[0] == 0x42) + dev->callback += 200LL * CDROM_TIME; + /* Account for seek time. */ + bytes_per_second = 176.0 * 1024.0; + bytes_per_second *= (double) dev->cur_speed; + break; default: - dev->packet_len = len; + bytes_per_second = cdrom_bus_speed(dev); + if (bytes_per_second == 0.0) { + dev->callback = -1LL; /* Speed depends on SCSI controller */ + return; + } break; } - /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ - if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) - dev->max_transfer_len &= 0xfffe; - /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ - if (!dev->max_transfer_len) - dev->max_transfer_len = 65534; - if ((len <= dev->max_transfer_len) && (len >= min_len)) { - dev->request_length = dev->max_transfer_len = len; - } - return; + period = 1000000.0 / bytes_per_second; + cdrom_log("CD-ROM %i: Byte transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); + period = period * (double) (dev->packet_len); + cdrom_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); + dusec = period * ((double) TIMER_USEC); + dev->callback += ((int64_t) dusec); + } + cdrom_set_callback(dev); } -static double cdrom_get_short_seek(uint8_t id) + +static void +cdrom_command_complete(cdrom_t *dev) { - cdrom_t *dev = cdrom[id]; - - switch(dev->cur_speed) { - case 0: - fatal("CD-ROM %i: 0x speed\n", id); - return 0.0; - case 1: - return 240.0; - case 2: - return 160.0; - case 3: - return 150.0; - case 4: case 5: case 6: case 7: case 8: - case 9: case 10: case 11: - return 112.0; - case 12: case 13: case 14: case 15: - return 75.0; - case 16: case 17: case 18: case 19: - return 58.0; - case 20: case 21: case 22: case 23: - case 40: case 41: case 42: case 43: - case 44: case 45: case 46: case 47: - case 48: - return 50.0; - default: - /* 24-32, 52+ */ - return 45.0; - } + dev->packet_status = CDROM_PHASE_COMPLETE; + cdrom_command_common(dev); } -static double cdrom_get_long_seek(uint8_t id) + +static void +cdrom_command_read(cdrom_t *dev) { - cdrom_t *dev = cdrom[id]; - - switch(dev->cur_speed) { - case 0: - fatal("CD-ROM %i: 0x speed\n", id); - return 0.0; - case 1: - return 1446.0; - case 2: - return 1000.0; - case 3: - return 900.0; - case 4: case 5: case 6: case 7: case 8: - case 9: case 10: case 11: - return 675.0; - case 12: case 13: case 14: case 15: - return 400.0; - case 16: case 17: case 18: case 19: - return 350.0; - case 20: case 21: case 22: case 23: - case 40: case 41: case 42: case 43: - case 44: case 45: case 46: case 47: - case 48: - return 300.0; - default: - /* 24-32, 52+ */ - return 270.0; - } + dev->packet_status = CDROM_PHASE_DATA_IN; + cdrom_command_common(dev); + dev->total_read = 0; } -#define MIN_SEEK 2000 -#define MAX_SEEK 333333 -static double cdrom_seek_time(uint8_t id) +static void +cdrom_command_read_dma(cdrom_t *dev) { - cdrom_t *dev = cdrom[id]; - - uint32_t diff = dev->seek_diff; - double sd = (double) (MAX_SEEK - MIN_SEEK); - - if (diff < MIN_SEEK) - return 0.0; - if (diff > MAX_SEEK) - diff = MAX_SEEK; - - diff -= MIN_SEEK; - - return cdrom_get_short_seek(id) + ((cdrom_get_long_seek(id) * ((double) diff)) / sd); + dev->packet_status = CDROM_PHASE_DATA_IN_DMA; + cdrom_command_common(dev); + dev->total_read = 0; } -static double cdrom_bus_speed(uint8_t id) + +static void +cdrom_command_write(cdrom_t *dev) { - cdrom_t *dev = cdrom[id]; - - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - dev->callback = -1LL; /* Speed depends on SCSI controller */ - return 0.0; - } else if (cdrom_drives[id].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA) { - if (cdrom_current_mode(id) == 2) - return 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ - else - return 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ - } else - return 3333333.333333333333333; /* 3.3 MB/s PIO-0 speed */ + dev->packet_status = CDROM_PHASE_DATA_OUT; + cdrom_command_common(dev); } -static void cdrom_command_bus(uint8_t id) + +static void cdrom_command_write_dma(cdrom_t *dev) { - cdrom_t *dev = cdrom[id]; - - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; - dev->callback = 1LL * CDROM_TIME; - cdrom_set_callback(id); + dev->packet_status = CDROM_PHASE_DATA_OUT_DMA; + cdrom_command_common(dev); } -static void cdrom_command_common(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - double bytes_per_second, period; - double dusec; - - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; - dev->callback = 0LL; - - cdrom_log("CD-ROM %i: Current speed: %ix\n", id, dev->cur_speed); - - if (dev->packet_status == CDROM_PHASE_COMPLETE) { - cdrom_phase_callback(id); - dev->callback = 0LL; - } else { - switch(dev->current_cdb[0]) { - case GPCMD_REZERO_UNIT: - case 0x0b: - case 0x2b: - /* Seek time is in us. */ - period = cdrom_seek_time(id) * ((double) TIMER_USEC); - dev->callback += ((int64_t) period); - cdrom_set_callback(id); - cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", id, (int64_t) cdrom_seek_time(id)); - return; - case 0x08: - case 0x28: - case 0xa8: - /* Seek time is in us. */ - period = cdrom_seek_time(id) * ((double) TIMER_USEC); - dev->callback += ((int64_t) period); - cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", id, (int64_t) cdrom_seek_time(id)); - case 0x25: - case 0x42: - case 0x43: - case 0x44: - case 0x51: - case 0x52: - case 0xad: - case 0xb8: - case 0xb9: - case 0xbe: - /* bytes_per_second = 150.0 * 1024.0; */ - /* bytes_per_second = (1000000.0 / 12000.0) * 2048.0; */ /* Account for seek time. */ - bytes_per_second = 176.0 * 1024.0; - bytes_per_second *= (double) dev->cur_speed; - break; - default: - bytes_per_second = cdrom_bus_speed(id); - if (bytes_per_second == 0.0) { - dev->callback = -1LL; /* Speed depends on SCSI controller */ - return; - } - break; - } - - period = 1000000.0 / bytes_per_second; - cdrom_log("CD-ROM %i: Byte transfer period: %" PRIu64 " us\n", id, (int64_t) period); - period = period * (double) (dev->packet_len); - cdrom_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", id, (int64_t) period); - dusec = period * ((double) TIMER_USEC); - dev->callback += ((int64_t) dusec); - } - cdrom_set_callback(id); -} - -static void cdrom_command_complete(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - dev->packet_status = CDROM_PHASE_COMPLETE; - cdrom_command_common(id); -} - -static void cdrom_command_read(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - dev->packet_status = CDROM_PHASE_DATA_IN; - cdrom_command_common(id); - dev->total_read = 0; -} - -static void cdrom_command_read_dma(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - dev->packet_status = CDROM_PHASE_DATA_IN_DMA; - cdrom_command_common(id); - dev->total_read = 0; -} - -static void cdrom_command_write(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - dev->packet_status = CDROM_PHASE_DATA_OUT; - cdrom_command_common(id); -} - -static void cdrom_command_write_dma(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - dev->packet_status = CDROM_PHASE_DATA_OUT_DMA; - cdrom_command_common(id); -} /* id = Current CD-ROM device ID; len = Total transfer length; block_len = Length of a single block (why does it matter?!); alloc_len = Allocated transfer length; direction = Transfer direction (0 = read from host, 1 = write to host). */ -static void cdrom_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +static void cdrom_data_command_finish(cdrom_t *dev, int len, int block_len, int alloc_len, int direction) { - cdrom_t *dev = cdrom[id]; + cdrom_log("CD-ROM %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", + dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); + dev->pos=0; + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if ((len == 0) || (cdrom_current_mode(dev) == 0)) { + if (dev->drv->bus_type != CDROM_BUS_SCSI) + dev->packet_len = 0; - cdrom_log("CD-ROM %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); - dev->pos=0; - if (alloc_len >= 0) { - if (alloc_len < len) { - len = alloc_len; - } + cdrom_command_complete(dev); + } else { + if (cdrom_current_mode(dev) == 2) { + if (dev->drv->bus_type != CDROM_BUS_SCSI) + dev->packet_len = alloc_len; + + if (direction == 0) + cdrom_command_read_dma(dev); + else + cdrom_command_write_dma(dev); + } else { + cdrom_update_request_length(dev, len, block_len); + if (direction == 0) + cdrom_command_read(dev); + else + cdrom_command_write(dev); } - if ((len == 0) || (cdrom_current_mode(id) == 0)) { - if (cdrom_drives[id].bus_type != CDROM_BUS_SCSI) { - dev->packet_len = 0; - } - cdrom_command_complete(id); - } - else { - if (cdrom_current_mode(id) == 2) { - if (cdrom_drives[id].bus_type != CDROM_BUS_SCSI) { - dev->packet_len = alloc_len; - } + } - if (direction == 0) - cdrom_command_read_dma(id); - else - cdrom_command_write_dma(id); - } - else { - cdrom_update_request_length(id, len, block_len); - if (direction == 0) - cdrom_command_read(id); - else - cdrom_command_write(id); - } - } - - cdrom_log("CD-ROM %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); + cdrom_log("CD-ROM %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", + dev->id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); } -static void cdrom_sense_clear(int id, int command) -{ - cdrom_t *dev = cdrom[id]; - dev->previous_command = command; - cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; +static void +cdrom_sense_clear(cdrom_t *dev, int command) +{ + dev->previous_command = command; + cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; } -static void cdrom_set_phase(uint8_t id, uint8_t phase) + +static void +cdrom_set_phase(cdrom_t *dev, uint8_t phase) { - uint8_t scsi_id = cdrom_drives[id].scsi_device_id; - uint8_t scsi_lun = cdrom_drives[id].scsi_device_lun; + uint8_t scsi_id = dev->drv->scsi_device_id; + uint8_t scsi_lun = dev->drv->scsi_device_lun; - if (cdrom_drives[id].bus_type != CDROM_BUS_SCSI) - return; + if (dev->drv->bus_type != CDROM_BUS_SCSI) + return; - SCSIDevices[scsi_id][scsi_lun].Phase = phase; + SCSIDevices[scsi_id][scsi_lun].Phase = phase; } -static void cdrom_cmd_error(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - cdrom_set_phase(id, SCSI_PHASE_STATUS); - dev->error = ((cdrom_sense_key & 0xf) << 4) | ABRT_ERR; - if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; - dev->packet_status = 0x80; - dev->callback = 50LL * CDROM_TIME; - cdrom_set_callback(id); - cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", id, cdrom_sense_key, cdrom_asc, cdrom_ascq); +static void +cdrom_cmd_error(cdrom_t *dev) +{ + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = ((cdrom_sense_key & 0xf) << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * CDROM_TIME; + cdrom_set_callback(dev); + cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", dev->id, cdrom_sense_key, cdrom_asc, cdrom_ascq); } -static void cdrom_unit_attention(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - cdrom_set_phase(id, SCSI_PHASE_STATUS); - dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; - if (dev->unit_attention) - dev->error |= MCR_ERR; - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->pos = 0; - dev->packet_status = 0x80; - dev->callback = 50LL * CDROM_TIME; - cdrom_set_callback(id); - cdrom_log("CD-ROM %i: UNIT ATTENTION\n", id); +static void +cdrom_unit_attention(cdrom_t *dev) +{ + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * CDROM_TIME; + cdrom_set_callback(dev); + cdrom_log("CD-ROM %i: UNIT ATTENTION\n", dev->id); } -static void cdrom_not_ready(uint8_t id) + +static void +cdrom_bus_master_error(cdrom_t *dev) { - cdrom_sense_key = SENSE_NOT_READY; - cdrom_asc = ASC_MEDIUM_NOT_PRESENT; - cdrom_ascq = 0; - cdrom_cmd_error(id); + cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; + cdrom_cmd_error(dev); } -static void cdrom_invalid_lun(uint8_t id) + +static void +cdrom_not_ready(cdrom_t *dev) { - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INV_LUN; - cdrom_ascq = 0; - cdrom_cmd_error(id); + cdrom_sense_key = SENSE_NOT_READY; + cdrom_asc = ASC_MEDIUM_NOT_PRESENT; + cdrom_ascq = 0; + cdrom_cmd_error(dev); } -static void cdrom_illegal_opcode(uint8_t id) + +static void +cdrom_invalid_lun(cdrom_t *dev) { - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_ILLEGAL_OPCODE; - cdrom_ascq = 0; - cdrom_cmd_error(id); + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INV_LUN; + cdrom_ascq = 0; + cdrom_cmd_error(dev); } -static void cdrom_lba_out_of_range(uint8_t id) + +static void +cdrom_illegal_opcode(cdrom_t *dev) { - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_LBA_OUT_OF_RANGE; - cdrom_ascq = 0; - cdrom_cmd_error(id); + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_ILLEGAL_OPCODE; + cdrom_ascq = 0; + cdrom_cmd_error(dev); } -static void cdrom_invalid_field(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET; - cdrom_ascq = 0; - cdrom_cmd_error(id); - dev->status = 0x53; +static void +cdrom_lba_out_of_range(cdrom_t *dev) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_LBA_OUT_OF_RANGE; + cdrom_ascq = 0; + cdrom_cmd_error(dev); } -static void cdrom_invalid_field_pl(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; - cdrom_ascq = 0; - cdrom_cmd_error(id); - dev->status = 0x53; +static void +cdrom_invalid_field(cdrom_t *dev) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET; + cdrom_ascq = 0; + cdrom_cmd_error(dev); + dev->status = 0x53; } -static void cdrom_illegal_mode(uint8_t id) + +static void +cdrom_invalid_field_pl(cdrom_t *dev) { - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; - cdrom_ascq = 0; - cdrom_cmd_error(id); + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + cdrom_ascq = 0; + cdrom_cmd_error(dev); + dev->status = 0x53; } -static void cdrom_incompatible_format(uint8_t id) + +static void +cdrom_illegal_mode(cdrom_t *dev) { - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_INCOMPATIBLE_FORMAT; - cdrom_ascq = 2; - cdrom_cmd_error(id); + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; + cdrom_ascq = 0; + cdrom_cmd_error(dev); } -static void cdrom_data_phase_error(uint8_t id) + +static void +cdrom_incompatible_format(cdrom_t *dev) { - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_DATA_PHASE_ERROR; - cdrom_ascq = 0; - cdrom_cmd_error(id); + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INCOMPATIBLE_FORMAT; + cdrom_ascq = 2; + cdrom_cmd_error(dev); } -static int cdrom_pass_through(uint8_t id, uint32_t *len, uint8_t *cdb, uint8_t *buffer) + +static void +cdrom_data_phase_error(cdrom_t *dev) { - int ret = 0; - uint8_t temp_cdb[16]; + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_DATA_PHASE_ERROR; + cdrom_ascq = 0; + cdrom_cmd_error(dev); +} - memset(temp_cdb, 0, 16); - if (cdb[0] == 8) { - temp_cdb[0] = 0x28; - temp_cdb[8] = cdb[4]; - temp_cdb[3] = cdb[1]; - temp_cdb[4] = cdb[2]; - temp_cdb[5] = cdb[3]; - } else - memcpy(temp_cdb, cdb, 16); +void +cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks) +{ + int temp = 0; - ret = cdrom_drives[id].handler->pass_through(id, temp_cdb, buffer, len); - cdrom_log("CD-ROM %i: Data from pass through: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5], buffer[6], buffer[7]); - cdrom_log("CD-ROM %i: Returned value: %i\n", id, ret); + switch(cdb[0]) { + case GPCMD_READ_6: + cdb[1] = (lba_pos >> 16) & 0xff; + cdb[2] = (lba_pos >> 8) & 0xff; + cdb[3] = lba_pos & 0xff; + break; + + case GPCMD_READ_10: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[7] = (number_of_blocks >> 8) & 0xff; + cdb[8] = number_of_blocks & 0xff; + break; + + case GPCMD_READ_12: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[6] = (number_of_blocks >> 24) & 0xff; + cdb[7] = (number_of_blocks >> 16) & 0xff; + cdb[8] = (number_of_blocks >> 8) & 0xff; + cdb[9] = number_of_blocks & 0xff; + break; + + case GPCMD_READ_CD_MSF: + temp = cdrom_lba_to_msf_accurate(lba_pos); + cdb[3] = (temp >> 16) & 0xff; + cdb[4] = (temp >> 8) & 0xff; + cdb[5] = temp & 0xff; + + temp = cdrom_lba_to_msf_accurate(lba_pos + number_of_blocks - 1); + cdb[6] = (temp >> 16) & 0xff; + cdb[7] = (temp >> 8) & 0xff; + cdb[8] = temp & 0xff; + break; + + case GPCMD_READ_CD: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[6] = (number_of_blocks >> 16) & 0xff; + cdb[7] = (number_of_blocks >> 8) & 0xff; + cdb[8] = number_of_blocks & 0xff; + break; + } +} + + +static int +cdrom_read_data(cdrom_t *dev, int msf, int type, int flags, int32_t *len) +{ + int ret = 0; + uint32_t cdsize = 0; + + int i = 0; + int temp_len = 0; + + cdsize = dev->handler->size(dev->id); + + if (dev->sector_pos >= cdsize) { + cdrom_log("CD-ROM %i: Trying to read from beyond the end of disc (%i >= %i)\n", dev->id, + dev->sector_pos, cdsize); + cdrom_lba_out_of_range(dev); + return 0; + } + + if ((dev->sector_pos + dev->sector_len - 1) >= cdsize) { + cdrom_log("CD-ROM %i: Trying to read to beyond the end of disc (%i >= %i)\n", dev->id, + (dev->sector_pos + dev->sector_len - 1), cdsize); + cdrom_lba_out_of_range(dev); + return 0; + } + + dev->old_len = 0; + *len = 0; + + for (i = 0; i < dev->requested_blocks; i++) { + ret = dev->handler->readsector_raw(dev->id, cdbufferb + dev->data_pos, dev->sector_pos + i, + msf, type, flags, &temp_len); + + dev->data_pos += temp_len; + dev->old_len += temp_len; + + *len += temp_len; if (!ret) { - /* Command failed with OS error code, return illegal opcode. */ - cdrom_log("CD-ROM %i: Command failed with OS error code, return illegal opcode.\n", id); - cdrom_illegal_opcode(id); + cdrom_illegal_mode(dev); return 0; - } else { - if ((cdrom_sense_key != 0) || (cdrom_asc != 0) || (cdrom_ascq != 0)) { - /* Command failed with sense, error with that sense. */ - cdrom_log("CD-ROM %i: Command failed with sense, error with that sense (%02X/%02X/%02X).\n", id, cdrom_sense_key, cdrom_asc, cdrom_ascq); - cdrom_cmd_error(id); - return 0; - } else { - /* Command was performed successfully. */ - cdrom_log("CD-ROM %i: Command was performed successfully.\n", id); - return 1; - } } + } + + return 1; } -void cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks) + +static int +cdrom_read_blocks(cdrom_t *dev, int32_t *len, int first_batch) { - int temp = 0; + int ret = 0, msf = 0; + int type = 0, flags = 0; - switch(cdb[0]) { - case GPCMD_READ_6: - cdb[1] = (lba_pos >> 16) & 0xff; - cdb[2] = (lba_pos >> 8) & 0xff; - cdb[3] = lba_pos & 0xff; - break; + if (dev->current_cdb[0] == 0xb9) + msf = 1; - case GPCMD_READ_10: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[7] = (number_of_blocks >> 8) & 0xff; - cdb[8] = number_of_blocks & 0xff; - break; + if ((dev->current_cdb[0] == 0xb9) || (dev->current_cdb[0] == 0xbe)) { + type = (dev->current_cdb[1] >> 2) & 7; + flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); + } else { + type = 8; + flags = 0x10; + } - case GPCMD_READ_12: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[6] = (number_of_blocks >> 24) & 0xff; - cdb[7] = (number_of_blocks >> 16) & 0xff; - cdb[8] = (number_of_blocks >> 8) & 0xff; - cdb[9] = number_of_blocks & 0xff; - break; + dev->data_pos = 0; - case GPCMD_READ_CD_MSF: - temp = cdrom_lba_to_msf_accurate(lba_pos); - cdb[3] = (temp >> 16) & 0xff; - cdb[4] = (temp >> 8) & 0xff; - cdb[5] = temp & 0xff; + if (!dev->sector_len) { + cdrom_command_complete(dev); + return -1; + } - temp = cdrom_lba_to_msf_accurate(lba_pos + number_of_blocks - 1); - cdb[6] = (temp >> 16) & 0xff; - cdb[7] = (temp >> 8) & 0xff; - cdb[8] = temp & 0xff; - break; + cdrom_log("Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); - case GPCMD_READ_CD: - cdb[2] = (lba_pos >> 24) & 0xff; - cdb[3] = (lba_pos >> 16) & 0xff; - cdb[4] = (lba_pos >> 8) & 0xff; - cdb[5] = lba_pos & 0xff; - cdb[6] = (number_of_blocks >> 16) & 0xff; - cdb[7] = (number_of_blocks >> 8) & 0xff; - cdb[8] = number_of_blocks & 0xff; - break; - } + cdrom_update_cdb(dev->current_cdb, dev->sector_pos, dev->requested_blocks); + + ret = cdrom_read_data(dev, msf, type, flags, len); + + cdrom_log("Read %i bytes of blocks...\n", *len); + + if (!ret || ((dev->old_len != *len) && !first_batch)) { + if ((dev->old_len != *len) && !first_batch) + cdrom_illegal_mode(dev); + + return 0; + } + + dev->sector_pos += dev->requested_blocks; + dev->sector_len -= dev->requested_blocks; + + return 1; } -#define cdbufferb dev->buffer -int cdrom_read_data(uint8_t id, int msf, int type, int flags, uint32_t *len) -{ - cdrom_t *dev = cdrom[id]; - - int ret = 0; - int cdsize = 0; - - int i = 0; - int temp_len = 0; - - int last_valid_data_pos = 0; - - cdsize = cdrom_drives[id].handler->size(id); - - if (dev->sector_pos >= cdsize) { - cdrom_log("CD-ROM %i: Trying to read from beyond the end of disc (%i >= %i)\n", id, dev->sector_pos, cdsize); - cdrom_lba_out_of_range(id); - return 0; - } - - if ((dev->sector_pos + dev->sector_len - 1) >= cdsize) { - cdrom_log("CD-ROM %i: Trying to read to beyond the end of disc (%i >= %i)\n", id, (dev->sector_pos + dev->sector_len - 1), cdsize); - cdrom_lba_out_of_range(id); - return 0; - } - - if (cdrom_drives[id].handler->pass_through) { - ret = cdrom_pass_through(id, len, dev->current_cdb, cdbufferb + dev->data_pos); - dev->data_pos += *len; - - if (!ret) - return 0; - - dev->old_len = *len; - } else { - dev->old_len = 0; - *len = 0; - - for (i = 0; i < dev->requested_blocks; i++) { - ret = cdrom_drives[id].handler->readsector_raw(id, cdbufferb + dev->data_pos, dev->sector_pos + i, msf, type, flags, &temp_len); - - last_valid_data_pos = dev->data_pos; - - dev->data_pos += temp_len; - dev->old_len += temp_len; - - *len += temp_len; - - if (!ret) { - cdrom_illegal_mode(id); - return 0; - } - } - - cdrom_log("CD-ROM %i: Data from raw sector read: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, cdbufferb[last_valid_data_pos + 0], cdbufferb[last_valid_data_pos + 1], cdbufferb[last_valid_data_pos + 2], cdbufferb[last_valid_data_pos + 3], cdbufferb[last_valid_data_pos + 4], cdbufferb[last_valid_data_pos + 5], cdbufferb[last_valid_data_pos + 6], cdbufferb[last_valid_data_pos + 7]); - } - - return 1; -} - -int cdrom_read_blocks(uint8_t id, uint32_t *len, int first_batch) -{ - cdrom_t *dev = cdrom[id]; - - int ret = 0; - - int msf = 0; - - int type = 0; - int flags = 0; - - if (dev->current_cdb[0] == 0xb9) - msf = 1; - - if ((dev->current_cdb[0] == 0xb9) || (dev->current_cdb[0] == 0xbe)) { - type = (dev->current_cdb[1] >> 2) & 7; - flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); - } else { - type = 8; - flags = 0x10; - } - - dev->data_pos = 0; - - if (!dev->sector_len) { - cdrom_command_complete(id); - return -1; - } - - cdrom_log("Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); - - cdrom_update_cdb(dev->current_cdb, dev->sector_pos, dev->requested_blocks); - - ret = cdrom_read_data(id, msf, type, flags, len); - - cdrom_log("Read %i bytes of blocks...\n", *len); - - if (!ret || ((dev->old_len != *len) && !first_batch)) { - if ((dev->old_len != *len) && !first_batch) - cdrom_illegal_mode(id); - - return 0; - } - - dev->sector_pos += dev->requested_blocks; - dev->sector_len -= dev->requested_blocks; - - return 1; -} - -/*SCSI Get Configuration*/ /*SCSI Read DVD Structure*/ -static int cdrom_read_dvd_structure(uint8_t id, int format, const uint8_t *packet, uint8_t *buf) +static int +cdrom_read_dvd_structure(cdrom_t *dev, int format, const uint8_t *packet, uint8_t *buf) { - int layer = packet[6]; - uint64_t total_sectors; + int layer = packet[6]; + uint64_t total_sectors; - switch (format) { - case 0x00: /* Physical format information */ - total_sectors = (uint64_t) cdrom_drives[id].handler->size(id); + switch (format) { + case 0x00: /* Physical format information */ + total_sectors = (uint64_t) dev->handler->size(dev->id); - if (layer != 0) { - cdrom_invalid_field(id); - return 0; - } - - total_sectors >>= 2; - if (total_sectors == 0) { - /* return -ASC_MEDIUM_NOT_PRESENT; */ - cdrom_not_ready(id); - return 0; - } - - buf[4] = 1; /* DVD-ROM, part version 1 */ - buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ - buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ - buf[7] = 0; /* default densities */ - - /* FIXME: 0x30000 per spec? */ - buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ - buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ - buf[13] = (total_sectors >> 16) & 0xff; - buf[14] = (total_sectors >> 8) & 0xff; - buf[15] = total_sectors & 0xff; - - buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ - buf[17] = (total_sectors >> 16) & 0xff; - buf[18] = (total_sectors >> 8) & 0xff; - buf[19] = total_sectors & 0xff; - - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048 +2 ) >> 8) & 0xff; - buf[1] = (2048 + 2) & 0xff; - - /* 2k data + 4 byte header */ - return (2048 + 4); - - case 0x01: /* DVD copyright information */ - buf[4] = 0; /* no copyright data */ - buf[5] = 0; /* no region restrictions */ - - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((4 + 2) >> 8) & 0xff; - buf[1] = (4 + 2) & 0xff; - - /* 4 byte header + 4 byte data */ - return (4 + 4); - - case 0x03: /* BCA information - invalid field for no BCA info */ - cdrom_invalid_field(id); + if (layer != 0) { + cdrom_invalid_field(dev); return 0; + } - case 0x04: /* DVD disc manufacturing information */ - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048 + 2) >> 8) & 0xff; - buf[1] = (2048 + 2) & 0xff; - - /* 2k data + 4 byte header */ - return (2048 + 4); - - case 0xff: - /* - * This lists all the command capabilities above. Add new ones - * in order and update the length and buffer return values. - */ - - buf[4] = 0x00; /* Physical format */ - buf[5] = 0x40; /* Not writable, is readable */ - buf[6] = ((2048 + 4) >> 8) & 0xff; - buf[7] = (2048 + 4) & 0xff; - - buf[8] = 0x01; /* Copyright info */ - buf[9] = 0x40; /* Not writable, is readable */ - buf[10] = ((4 + 4) >> 8) & 0xff; - buf[11] = (4 + 4) & 0xff; - - buf[12] = 0x03; /* BCA info */ - buf[13] = 0x40; /* Not writable, is readable */ - buf[14] = ((188 + 4) >> 8) & 0xff; - buf[15] = (188 + 4) & 0xff; - - buf[16] = 0x04; /* Manufacturing info */ - buf[17] = 0x40; /* Not writable, is readable */ - buf[18] = ((2048 + 4) >> 8) & 0xff; - buf[19] = (2048 + 4) & 0xff; - - /* Size of buffer, not including 2 byte size field */ - buf[6] = ((16 + 2) >> 8) & 0xff; - buf[7] = (16 + 2) & 0xff; - - /* data written + 4 byte header */ - return (16 + 4); - - default: /* TODO: formats beyond DVD-ROM requires */ - cdrom_invalid_field(id); + total_sectors >>= 2; + if (total_sectors == 0) { + /* return -ASC_MEDIUM_NOT_PRESENT; */ + cdrom_not_ready(dev); return 0; - } + } + + buf[4] = 1; /* DVD-ROM, part version 1 */ + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[7] = 0; /* default densities */ + + /* FIXME: 0x30000 per spec? */ + buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ + buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ + buf[13] = (total_sectors >> 16) & 0xff; + buf[14] = (total_sectors >> 8) & 0xff; + buf[15] = total_sectors & 0xff; + + buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ + buf[17] = (total_sectors >> 16) & 0xff; + buf[18] = (total_sectors >> 8) & 0xff; + buf[19] = total_sectors & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048 +2 ) >> 8) & 0xff; + buf[1] = (2048 + 2) & 0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0x01: /* DVD copyright information */ + buf[4] = 0; /* no copyright data */ + buf[5] = 0; /* no region restrictions */ + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((4 + 2) >> 8) & 0xff; + buf[1] = (4 + 2) & 0xff; + + /* 4 byte header + 4 byte data */ + return (4 + 4); + + case 0x03: /* BCA information - invalid field for no BCA info */ + cdrom_invalid_field(dev); + return 0; + + case 0x04: /* DVD disc manufacturing information */ + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048 + 2) >> 8) & 0xff; + buf[1] = (2048 + 2) & 0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buf[4] = 0x00; /* Physical format */ + buf[5] = 0x40; /* Not writable, is readable */ + buf[6] = ((2048 + 4) >> 8) & 0xff; + buf[7] = (2048 + 4) & 0xff; + + buf[8] = 0x01; /* Copyright info */ + buf[9] = 0x40; /* Not writable, is readable */ + buf[10] = ((4 + 4) >> 8) & 0xff; + buf[11] = (4 + 4) & 0xff; + + buf[12] = 0x03; /* BCA info */ + buf[13] = 0x40; /* Not writable, is readable */ + buf[14] = ((188 + 4) >> 8) & 0xff; + buf[15] = (188 + 4) & 0xff; + + buf[16] = 0x04; /* Manufacturing info */ + buf[17] = 0x40; /* Not writable, is readable */ + buf[18] = ((2048 + 4) >> 8) & 0xff; + buf[19] = (2048 + 4) & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[6] = ((16 + 2) >> 8) & 0xff; + buf[7] = (16 + 2) & 0xff; + + /* data written + 4 byte header */ + return (16 + 4); + + default: /* TODO: formats beyond DVD-ROM requires */ + cdrom_invalid_field(dev); + return 0; + } } -void cdrom_insert(uint8_t id) + +void +cdrom_insert(cdrom_t *dev) { - cdrom_t *dev = cdrom[id]; - - dev->unit_attention = 1; - - cdrom_log("CD-ROM %i: Media insert\n", id); + dev->unit_attention = 1; + cdrom_log("CD-ROM %i: Media insert\n", dev->id); } + /*SCSI Sense Initialization*/ -void cdrom_sense_code_ok(uint8_t id) +void +cdrom_sense_code_ok(uint8_t id) { - cdrom_sense_key = SENSE_NONE; - cdrom_asc = 0; - cdrom_ascq = 0; + cdrom_t *dev = cdrom[id]; + + cdrom_sense_key = SENSE_NONE; + cdrom_asc = 0; + cdrom_ascq = 0; } -int cdrom_pre_execution_check(uint8_t id, uint8_t *cdb) + +static int +cdrom_pre_execution_check(cdrom_t *dev, uint8_t *cdb) { - cdrom_t *dev = cdrom[id]; + int ready = 0, status = 0; - int ready = 0; - - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - if (((dev->request_length >> 5) & 7) != cdrom_drives[id].scsi_device_lun) { - cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((dev->request_length >> 5) & 7)); - cdrom_invalid_lun(id); - return 0; - } - } - - if (!(cdrom_command_flags[cdb[0]] & IMPLEMENTED)) { - cdrom_log("CD-ROM %i: Attempting to execute unknown command %02X over %s\n", id, cdb[0], (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) ? "SCSI" : ((cdrom_drives[id].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA) ? "ATAPI PIO/DMA" : "ATAPI PIO")); - - cdrom_illegal_opcode(id); + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (((dev->request_length >> 5) & 7) != dev->drv->scsi_device_lun) { + cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", + dev->id, ((dev->request_length >> 5) & 7)); + cdrom_invalid_lun(dev); return 0; } + } - if ((cdrom_drives[id].bus_type < CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & SCSI_ONLY)) { - cdrom_log("CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI\n", id, cdb[0]); - cdrom_illegal_opcode(id); - return 0; - } + if (!(cdrom_command_flags[cdb[0]] & IMPLEMENTED)) { + cdrom_log("CD-ROM %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], + (dev->drv->bus_type == CDROM_BUS_SCSI) ? "SCSI" : "ATAPI"); - if ((cdrom_drives[id].bus_type == CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) { - cdrom_log("CD-ROM %i: Attempting to execute ATAPI-only command %02X over SCSI\n", id, cdb[0]); - cdrom_illegal_opcode(id); - return 0; - } + cdrom_illegal_opcode(dev); + return 0; + } - if ((cdrom_drives[id].handler->status(id) == CD_STATUS_PLAYING) || (cdrom_drives[id].handler->status(id) == CD_STATUS_PAUSED)) { - ready = 1; - goto skip_ready_check; - } + if ((dev->drv->bus_type < CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & SCSI_ONLY)) { + cdrom_log("CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); + cdrom_illegal_opcode(dev); + return 0; + } - if (cdrom_drives[id].handler->medium_changed(id)) - cdrom_insert(id); + if ((dev->drv->bus_type == CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) { + cdrom_log("CD-ROM %i: Attempting to execute ATAPI-only command %02X over SCSI\n", dev->id, cdb[0]); + cdrom_illegal_opcode(dev); + return 0; + } - ready = cdrom_drives[id].handler->ready(id); + status = dev->handler->status(dev->id); + + if ((status == CD_STATUS_PLAYING) || (status == CD_STATUS_PAUSED)) { + ready = 1; + goto skip_ready_check; + } + + if (dev->handler->medium_changed(dev->id)) + cdrom_insert(dev); + + ready = dev->handler->ready(dev->id); skip_ready_check: - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - if (!ready && dev->unit_attention) - dev->unit_attention = 0; - - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ - if (dev->unit_attention == 1) { - /* Only increment the unit attention phase if the command can not pass through it. */ - if (!(cdrom_command_flags[cdb[0]] & ALLOW_UA)) { - /* cdrom_log("CD-ROM %i: Unit attention now 2\n", id); */ - dev->unit_attention++; - cdrom_log("CD-ROM %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); - cdrom_unit_attention(id); - return 0; - } - } - else if (dev->unit_attention == 2) { - if (cdb[0] != GPCMD_REQUEST_SENSE) { - /* cdrom_log("CD-ROM %i: Unit attention now 0\n", id); */ - dev->unit_attention = 0; - } - } - - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ - if (cdb[0] != GPCMD_REQUEST_SENSE) - cdrom_sense_clear(id, cdb[0]); - - /* Next it's time for NOT READY. */ - if (!ready) - dev->media_status = MEC_MEDIA_REMOVAL; - else - dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; - - if ((cdrom_command_flags[cdb[0]] & CHECK_READY) && !ready) { - cdrom_log("CD-ROM %i: Not ready (%02X)\n", id, cdb[0]); - cdrom_not_ready(id); - return 0; - } - - cdrom_log("CD-ROM %i: Continuing with command %02X\n", id, cdb[0]); - - return 1; -} - -void cdrom_clear_callback(uint8_t channel) -{ - cdrom_t *dev; - - uint8_t id = atapi_cdrom_drives[channel]; - - dev = cdrom[id]; - - if (id < CDROM_NUM) - { - dev->callback = 0LL; - cdrom_set_callback(id); - } -} - -static void cdrom_seek(uint8_t id, uint32_t pos) -{ - cdrom_t *dev = cdrom[id]; - - /* cdrom_log("CD-ROM %i: Seek %08X\n", id, pos); */ - dev->seek_pos = pos; - if (cdrom_drives[id].handler->stop) - cdrom_drives[id].handler->stop(id); -} - -static void cdrom_rezero(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (cdrom_drives[id].handler->stop) - cdrom_drives[id].handler->stop(id); - dev->sector_pos = dev->sector_len = 0; - cdrom_seek(id, 0); -} - -void cdrom_reset(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (!dev) - return; - - cdrom_rezero(id); - dev->status = 0; - dev->callback = 0LL; - cdrom_set_callback(id); - dev->packet_status = 0xff; + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + if (!ready && dev->unit_attention) dev->unit_attention = 0; -} -int cdrom_playing_completed(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - dev->prev_status = dev->cd_status; - dev->cd_status = cdrom_drives[id].handler->status(id); - if (((dev->prev_status == CD_STATUS_PLAYING) || (dev->prev_status == CD_STATUS_PAUSED)) && ((dev->cd_status != CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_PAUSED))) - return 1; - else + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (dev->unit_attention == 1) { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(cdrom_command_flags[cdb[0]] & ALLOW_UA)) { + /* cdrom_log("CD-ROM %i: Unit attention now 2\n", dev->id); */ + dev->unit_attention++; + cdrom_log("CD-ROM %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", + dev->id, cdb[0]); + cdrom_unit_attention(dev); return 0; -} - -void cdrom_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length) -{ - cdrom_t *dev = cdrom[id]; - - /*Will return 18 bytes of 0*/ - if (alloc_length != 0) { - memset(buffer, 0, alloc_length); - memcpy(buffer, dev->sense, alloc_length); } - - buffer[0] = 0x70; - - if ((cdrom_sense_key > 0) && ((dev->cd_status < CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_STOPPED)) && cdrom_playing_completed(id)) { - buffer[2]=SENSE_ILLEGAL_REQUEST; - buffer[12]=ASC_AUDIO_PLAY_OPERATION; - buffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; - } - else if ((cdrom_sense_key == 0) && (dev->cd_status >= CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_STOPPED)) { - buffer[2]=SENSE_ILLEGAL_REQUEST; - buffer[12]=ASC_AUDIO_PLAY_OPERATION; - buffer[13]=(dev->cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; - } - else { - if (dev->unit_attention && (cdrom_sense_key == 0)) { - buffer[2]=SENSE_UNIT_ATTENTION; - buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - buffer[13]=0; - } - } - - cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); - - if (buffer[2] == SENSE_UNIT_ATTENTION) { - /* If the last remaining sense is unit attention, clear - that condition. */ + } else if (dev->unit_attention == 2) { + if (cdb[0] != GPCMD_REQUEST_SENSE) { + /* cdrom_log("CD-ROM %i: Unit attention now 0\n", dev->id); */ dev->unit_attention = 0; } + } - /* Clear the sense stuff as per the spec. */ - cdrom_sense_clear(id, GPCMD_REQUEST_SENSE); + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + cdrom_sense_clear(dev, cdb[0]); + + /* Next it's time for NOT READY. */ + if (!ready) + dev->media_status = MEC_MEDIA_REMOVAL; + else + dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; + + if ((cdrom_command_flags[cdb[0]] & CHECK_READY) && !ready) { + cdrom_log("CD-ROM %i: Not ready (%02X)\n", dev->id, cdb[0]); + cdrom_not_ready(dev); + return 0; + } + + cdrom_log("CD-ROM %i: Continuing with command %02X\n", dev->id, cdb[0]); + + return 1; } -void cdrom_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) + +static void +cdrom_seek(cdrom_t *dev, uint32_t pos) { - cdrom_t *dev = cdrom[id]; - - int ready = 0; - - if (cdrom_drives[id].handler->medium_changed(id)) - cdrom_insert(id); - - ready = cdrom_drives[id].handler->ready(id); - - if (!ready && dev->unit_attention) { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - dev->unit_attention = 0; - } - - /* Do *NOT* advance the unit attention phase. */ - - cdrom_request_sense(id, buffer, alloc_length); + /* cdrom_log("CD-ROM %i: Seek %08X\n", dev->id, pos); */ + dev->seek_pos = pos; + if (dev->handler && dev->handler->stop) + dev->handler->stop(dev->id); } -void cdrom_set_buf_len(uint8_t id, int32_t *BufLen, uint32_t *src_len) + +static void +cdrom_rezero(cdrom_t *dev) { - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - if (*BufLen == -1) - *BufLen = *src_len; - else { - *BufLen = MIN(*src_len, *BufLen); - *src_len = *BufLen; - } - cdrom_log("CD-ROM %i: Actual transfer length: %i\n", id, *BufLen); - } + if (dev->handler && dev->handler->stop) + dev->handler->stop(dev->id); + dev->sector_pos = dev->sector_len = 0; + cdrom_seek(dev, 0); } -void cdrom_buf_alloc(uint8_t id, uint32_t len) -{ - cdrom_t *dev = cdrom[id]; - cdrom_log("CD-ROM %i: Allocated buffer length: %i\n", id, len); - cdbufferb = (uint8_t *) malloc(len); +void +cdrom_reset(cdrom_t *dev) +{ + if (!dev) + return; + + cdrom_rezero(dev); + dev->status = 0; + dev->callback = 0LL; + cdrom_set_callback(dev); + dev->packet_status = 0xff; + dev->unit_attention = 0xff; } -void cdrom_buf_free(uint8_t id) + +static int +cdrom_playing_completed(cdrom_t *dev) { - cdrom_t *dev = cdrom[id]; - - if (cdbufferb) { - cdrom_log("CD-ROM %i: Freeing buffer...\n", id); - free(cdbufferb); - cdbufferb = NULL; - } -} - -void cdrom_command(uint8_t id, uint8_t *cdb) -{ - uint32_t len; - int msf; - int pos=0; - uint32_t max_len; - uint32_t feature; - uint32_t used_len; - unsigned idx = 0; - unsigned size_idx; - unsigned preamble_len; - int toc_format; - uint32_t alloc_length; - int block_desc = 0; - int format = 0; - int ret; - int real_pos; - int track = 0; - char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; - char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; - int32_t blen = 0; - int32_t *BufLen; - uint8_t *b; - uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; - uint32_t i = 0; - - cdrom_t *dev = cdrom[id]; - - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - BufLen = &SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].BufferLength; - dev->status &= ~ERR_STAT; - } else { - BufLen = &blen; - dev->error = 0; - } - - dev->packet_len = 0; - dev->request_pos = 0; - - device_identify[7] = id + 0x30; - - device_identify_ex[7] = id + 0x30; - device_identify_ex[10] = EMU_VERSION[0]; - device_identify_ex[12] = EMU_VERSION[2]; - device_identify_ex[13] = EMU_VERSION[3]; - - dev->data_pos = 0; - - memcpy(dev->current_cdb, cdb, dev->cdb_len); - - dev->cd_status = cdrom_drives[id].handler->status(id); - - if (cdb[0] != 0) { - cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", id, cdb[0], cdrom_sense_key, cdrom_asc, cdrom_ascq, dev->unit_attention); - cdrom_log("CD-ROM %i: Request length: %04X\n", id, dev->request_length); - - cdrom_log("CD-ROM %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", id, - cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], - cdb[8], cdb[9], cdb[10], cdb[11]); - } - - msf = cdb[1] & 2; - dev->sector_len = 0; - - cdrom_set_phase(id, SCSI_PHASE_STATUS); - - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ - if (cdrom_pre_execution_check(id, cdb) == 0) - return; - - switch (cdb[0]) { - case GPCMD_TEST_UNIT_READY: - cdrom_set_phase(id, SCSI_PHASE_STATUS); - cdrom_command_complete(id); - break; - - case GPCMD_REZERO_UNIT: - if (cdrom_drives[id].handler->stop) - cdrom_drives[id].handler->stop(id); - dev->sector_pos = dev->sector_len = 0; - dev->seek_diff = dev->seek_pos; - cdrom_seek(id, 0); - cdrom_set_phase(id, SCSI_PHASE_STATUS); - break; - - case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE - should forget about the not ready, and report unit attention straight away. */ - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - max_len = cdb[4]; - cdrom_buf_alloc(id, 256); - cdrom_set_buf_len(id, BufLen, &max_len); - cdrom_request_sense(id, cdbufferb, max_len); - cdrom_data_command_finish(id, 18, 18, cdb[4], 0); - break; - - case GPCMD_SET_SPEED: - case GPCMD_SET_SPEED_ALT: - dev->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; - if (dev->cur_speed < 1) - dev->cur_speed = 1; - else if (dev->cur_speed > cdrom_drives[id].speed) - dev->cur_speed = cdrom_drives[id].speed; - cdrom_set_phase(id, SCSI_PHASE_STATUS); - cdrom_command_complete(id); - break; - - case GPCMD_MECHANISM_STATUS: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - cdrom_buf_alloc(id, 8); - - cdrom_set_buf_len(id, BufLen, &len); - - memset(cdbufferb, 0, 8); - cdbufferb[5] = 1; - - cdrom_data_command_finish(id, 8, 8, len, 0); - break; - - case GPCMD_READ_TOC_PMA_ATIP: - dev->toctimes++; - - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - - cdrom_buf_alloc(id, 65536); - - if (cdrom_drives[id].handler->pass_through) { - ret = cdrom_pass_through(id, &len, dev->current_cdb, cdbufferb); - if (!ret) { - cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; - goto cdrom_readtoc_fallback; - } - alloc_length = cdbufferb[0]; - alloc_length <<= 8; - alloc_length |= cdbufferb[1]; - alloc_length += 2; - len = MIN(alloc_length, len); - - cdrom_set_buf_len(id, BufLen, &len); - } else { -cdrom_readtoc_fallback: - toc_format = cdb[2] & 0xf; - - if (toc_format == 0) - toc_format = (cdb[9] >> 6) & 3; - - switch (toc_format) { - case 0: /*Normal*/ - len = cdrom_drives[id].handler->readtoc(id, cdbufferb, cdb[6], msf, max_len, 0); - break; - case 1: /*Multi session*/ - len = cdrom_drives[id].handler->readtoc_session(id, cdbufferb, msf, max_len); - cdbufferb[0] = 0; cdbufferb[1] = 0xA; - break; - case 2: /*Raw*/ - len = cdrom_drives[id].handler->readtoc_raw(id, cdbufferb, max_len); - break; - default: - cdrom_invalid_field(id); - cdrom_buf_free(id); - return; - } - } - - if (len > max_len) { - len = max_len; - - cdbufferb[0] = ((len - 2) >> 8) & 0xff; - cdbufferb[1] = (len - 2) & 0xff; - } - - cdrom_set_buf_len(id, BufLen, &len); - - if (len >= 8) { - cdrom_log("CD-ROM %i: TOC: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, - cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], - cdbufferb[4], cdbufferb[5], cdbufferb[6], cdbufferb[7]); - } - - if (len >= 16) { - cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", - cdbufferb[8], cdbufferb[9], cdbufferb[10], cdbufferb[11], - cdbufferb[12], cdbufferb[13], cdbufferb[14], cdbufferb[15]); - } - - if (len >= 24) { - cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", - cdbufferb[16], cdbufferb[17], cdbufferb[18], cdbufferb[19], - cdbufferb[20], cdbufferb[21], cdbufferb[22], cdbufferb[23]); - } - - if (len >= 32) { - cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", - cdbufferb[24], cdbufferb[25], cdbufferb[26], cdbufferb[27], - cdbufferb[28], cdbufferb[29], cdbufferb[30], cdbufferb[31]); - } - - if (len >= 36) { - cdrom_log(" %02X %02X %02X %02X\n", - cdbufferb[32], cdbufferb[33], cdbufferb[34], cdbufferb[35]); - } - - cdrom_data_command_finish(id, len, len, len, 0); - /* cdrom_log("CD-ROM %i: READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", id, toc_format, ide->cylinder, cdbufferb[1]); */ - return; - - case GPCMD_READ_CD_OLD: - dev->current_cdb[0] = 0xbe; /* IMPORTANT: Convert the command to new read CD for pass through purposes. */ - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - case GPCMD_READ_CD: - case GPCMD_READ_CD_MSF: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - alloc_length = 2048; - - switch(cdb[0]) { - case GPCMD_READ_6: - dev->sector_len = cdb[4]; - dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - msf = 0; - break; - case GPCMD_READ_10: - dev->sector_len = (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", id, dev->sector_len, dev->sector_pos); - msf = 0; - break; - case GPCMD_READ_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", id, dev->sector_len, dev->sector_pos); - msf = 0; - break; - case GPCMD_READ_CD_MSF: - /* cdrom_log("CD-ROM %i: Read CD MSF: Start MSF %02X%02X%02X End MSF %02X%02X%02X Flags %02X\n", id, cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]); */ - alloc_length = 2856; - dev->sector_len = MSFtoLBA(cdb[6], cdb[7], cdb[8]); - dev->sector_pos = MSFtoLBA(cdb[3], cdb[4], cdb[5]); - - dev->sector_len -= dev->sector_pos; - dev->sector_len++; - msf = 1; - break; - case GPCMD_READ_CD_OLD: - case GPCMD_READ_CD: - /* cdrom_log("CD-ROM %i: Read CD: Start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n", id, cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]); */ - alloc_length = 2856; - dev->sector_len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - - msf = 0; - break; - } - - dev->seek_diff = ABS((int) (pos - dev->seek_pos)); - dev->seek_pos = dev->sector_pos; - - if (!dev->sector_len) { - cdrom_set_phase(id, SCSI_PHASE_STATUS); - /* cdrom_log("CD-ROM %i: All done - callback set\n", id); */ - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->callback = 20LL * CDROM_TIME; - cdrom_set_callback(id); - break; - } - - max_len = dev->sector_len; - dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ - - dev->packet_len = max_len * alloc_length; - cdrom_buf_alloc(id, dev->packet_len); - - ret = cdrom_read_blocks(id, &alloc_length, 1); - if (ret <= 0) { - cdrom_buf_free(id); - return; - } - - dev->requested_blocks = max_len; - dev->packet_len = alloc_length; - - cdrom_set_buf_len(id, BufLen, &dev->packet_len); - - cdrom_data_command_finish(id, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 0); - - dev->all_blocks_total = dev->block_total; - if (dev->packet_status != CDROM_PHASE_COMPLETE) - ui_sb_update_icon(SB_CDROM | id, 1); - else - ui_sb_update_icon(SB_CDROM | id, 0); - return; - - case GPCMD_READ_HEADER: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - - alloc_length = ((cdb[7] << 8) | cdb[8]); - cdrom_buf_alloc(id, 8); - - if (cdrom_drives[id].handler->pass_through) { - ret = cdrom_pass_through(id, &len, dev->current_cdb, cdbufferb); - if (!ret) { - cdrom_buf_free(id); - return; - } - } else { - dev->sector_len = 1; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4]<<8) | cdb[5]; - if (msf) - real_pos = cdrom_lba_to_msf_accurate(dev->sector_pos); - else - real_pos = dev->sector_pos; - cdbufferb[0] = 1; /*2048 bytes user data*/ - cdbufferb[1] = cdbufferb[2] = cdbufferb[3] = 0; - cdbufferb[4] = (real_pos >> 24); - cdbufferb[5] = ((real_pos >> 16) & 0xff); - cdbufferb[6] = ((real_pos >> 8) & 0xff); - cdbufferb[7] = real_pos & 0xff; - - len = 8; - } - - len = MIN(len, alloc_length); - - cdrom_set_buf_len(id, BufLen, &len); - - cdrom_data_command_finish(id, len, len, len, 0); - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - else - block_desc = 0; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = cdb[4]; - cdrom_buf_alloc(id, 256); - } else { - len = (cdb[8] | (cdb[7] << 8)); - cdrom_buf_alloc(id, 65536); - } - - dev->current_page_code = cdb[2] & 0x3F; - - if (!(cdrom_mode_sense_page_flags & (1LL << dev->current_page_code))) { - cdrom_invalid_field(id); - cdrom_buf_free(id); - return; - } - - memset(cdbufferb, 0, len); - alloc_length = len; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = cdrom_mode_sense(id, cdbufferb, 4, cdb[2], block_desc); - len = MIN(len, alloc_length); - cdbufferb[0] = len - 1; - cdbufferb[1] = cdrom_drives[id].handler->media_type_id(id); - if (block_desc) - cdbufferb[3] = 8; - } else { - len = cdrom_mode_sense(id, cdbufferb, 8, cdb[2], block_desc); - len = MIN(len, alloc_length); - cdbufferb[0]=(len - 2) >> 8; - cdbufferb[1]=(len - 2) & 255; - cdbufferb[2] = cdrom_drives[id].handler->media_type_id(id); - if (block_desc) { - cdbufferb[6] = 0; - cdbufferb[7] = 8; - } - } - - cdrom_set_buf_len(id, BufLen, &len); - - cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", id, cdb[2]); - - cdrom_data_command_finish(id, len, len, alloc_length, 0); - return; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - cdrom_set_phase(id, SCSI_PHASE_DATA_OUT); - - if (cdb[0] == GPCMD_MODE_SELECT_6) { - len = cdb[4]; - cdrom_buf_alloc(id, 256); - } else { - len = (cdb[7] << 8) | cdb[8]; - cdrom_buf_alloc(id, 65536); - } - - cdrom_set_buf_len(id, BufLen, &len); - - dev->total_length = len; - dev->do_page_save = cdb[1] & 1; - - dev->current_page_pos = 0; - - cdrom_data_command_finish(id, len, len, len, 1); - return; - - case GPCMD_GET_CONFIGURATION: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - - /* XXX: could result in alignment problems in some architectures */ - feature = (cdb[2] << 8) | cdb[3]; - max_len = (cdb[7] << 8) | cdb[8]; - - /* only feature 0 is supported */ - if ((cdb[2] != 0) || (cdb[3] > 2)) { - cdrom_invalid_field(id); - cdrom_buf_free(id); - return; - } - - cdrom_buf_alloc(id, 65536); - memset(cdbufferb, 0, max_len); - - alloc_length = 0; - b = cdbufferb; - - /* - * the number of sectors from the media tells us which profile - * to use as current. 0 means there is no media - */ - if (cdrom_drives[id].handler->ready(id)) { - len = cdrom_drives[id].handler->size(id); - if (len > CD_MAX_SECTORS) { - b[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; - b[7] = MMC_PROFILE_DVD_ROM & 0xff; - ret = 1; - } else { - b[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; - b[7] = MMC_PROFILE_CD_ROM & 0xff; - ret = 0; - } - } else - ret = 2; - - alloc_length = 8; - b += 8; - - if ((feature == 0) || ((cdb[1] & 3) < 2)) { - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 8; - - alloc_length += 4; - b += 4; - - for (i = 0; i < 2; i++) { - b[0] = (profiles[i] >> 8) & 0xff; - b[1] = profiles[i] & 0xff; - - if (ret == i) - b[2] |= 1; - - alloc_length += 4; - b += 4; - } - } - if ((feature == 1) || ((cdb[1] & 3) < 2)) { - b[1] = 1; - b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 8; - - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - b[7] = 1; - else - b[7] = 2; - b[8] = 1; - - alloc_length += 12; - b += 12; - } - if ((feature == 2) || ((cdb[1] & 3) < 2)) { - b[1] = 2; - b[2] = (1 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 4; - - b[4] = 2; - - alloc_length += 8; - b += 8; - } - - cdbufferb[0] = ((alloc_length - 4) >> 24) & 0xff; - cdbufferb[1] = ((alloc_length - 4) >> 16) & 0xff; - cdbufferb[2] = ((alloc_length - 4) >> 8) & 0xff; - cdbufferb[3] = (alloc_length - 4) & 0xff; - - alloc_length = MIN(alloc_length, max_len); - - cdrom_set_buf_len(id, BufLen, &alloc_length); - - cdrom_data_command_finish(id, alloc_length, alloc_length, alloc_length, 0); - break; - - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - - cdrom_buf_alloc(id, 8 + sizeof(gesn_event_header)); - - gesn_cdb = (void *) cdb; - gesn_event_header = (void *) cdbufferb; - - /* It is fine by the MMC spec to not support async mode operations. */ - if (!(gesn_cdb->polled & 0x01)) { - /* asynchronous mode */ - /* Only polling is supported, asynchronous mode is not. */ - cdrom_invalid_field(id); - cdrom_buf_free(id); - return; - } - - /* polling mode operation */ - - /* - * These are the supported events. - * - * We currently only support requests of the 'media' type. - * Notification class requests and supported event classes are bitmasks, - * but they are built from the same values as the "notification class" - * field. - */ - gesn_event_header->supported_events = 1 << GESN_MEDIA; - - /* - * We use |= below to set the class field; other bits in this byte - * are reserved now but this is useful to do if we have to use the - * reserved fields later. - */ - gesn_event_header->notification_class = 0; - - /* - * Responses to requests are to be based on request priority. The - * notification_class_request_type enum above specifies the - * priority: upper elements are higher prio than lower ones. - */ - if (gesn_cdb->class & (1 << GESN_MEDIA)) { - gesn_event_header->notification_class |= GESN_MEDIA; - - cdbufferb[4] = dev->media_status; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */ - cdbufferb[5] = 1; /* Power Status (1 = Active) */ - cdbufferb[6] = 0; - cdbufferb[7] = 0; - used_len = 8; - } else { - gesn_event_header->notification_class = 0x80; /* No event available */ - used_len = sizeof(*gesn_event_header); - } - gesn_event_header->len = used_len - sizeof(*gesn_event_header); - - memcpy(cdbufferb, gesn_event_header, 4); - - cdrom_set_buf_len(id, BufLen, &used_len); - - cdrom_data_command_finish(id, used_len, used_len, used_len, 0); - break; - - case GPCMD_READ_DISC_INFORMATION: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - - cdrom_buf_alloc(id, 65536); - - if (cdrom_drives[id].handler->pass_through) { - ret = cdrom_pass_through(id, &len, dev->current_cdb, cdbufferb); - if (!ret) { - cdrom_buf_free(id); - return; - } - alloc_length = cdbufferb[0]; - alloc_length <<= 8; - alloc_length |= cdbufferb[1]; - alloc_length += 2; - len = alloc_length; - } else { - memset(cdbufferb, 0, 34); - memset(cdbufferb, 1, 9); - cdbufferb[0] = 0; - cdbufferb[1] = 32; - cdbufferb[2] = 0xe; /* last session complete, disc finalized */ - cdbufferb[7] = 0x20; /* unrestricted use */ - cdbufferb[8] = 0x00; /* CD-ROM */ - len=34; - } - - len = MIN(len, max_len); - - cdrom_set_buf_len(id, BufLen, &len); - - cdrom_data_command_finish(id, len, len, len, 0); - break; - - case GPCMD_READ_TRACK_INFORMATION: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - - cdrom_buf_alloc(id, 65536); - - track = ((uint32_t) cdb[2]) << 24; - track |= ((uint32_t) cdb[3]) << 16; - track |= ((uint32_t) cdb[4]) << 8; - track |= (uint32_t) cdb[5]; - - if (cdrom_drives[id].handler->pass_through) { - ret = cdrom_pass_through(id, &len, dev->current_cdb, cdbufferb); - if (!ret) { - cdrom_buf_free(id); - return; - } - alloc_length = cdbufferb[0]; - alloc_length <<= 8; - alloc_length |= cdbufferb[1]; - alloc_length += 2; - len = MIN(len, alloc_length); - } else { - if (((cdb[1] & 0x03) != 1) || (track != 1)) { - cdrom_invalid_field(id); - cdrom_buf_free(id); - return; - } - - len = 36; - - memset(cdbufferb, 0, 36); - cdbufferb[0] = 0; - cdbufferb[1] = 34; - cdbufferb[2] = 1; /* track number (LSB) */ - cdbufferb[3] = 1; /* session number (LSB) */ - cdbufferb[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ - cdbufferb[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ - cdbufferb[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ - cdbufferb[24] = (cdrom_drives[id].handler->size(id) >> 24) & 0xff; /* track size */ - cdbufferb[25] = (cdrom_drives[id].handler->size(id) >> 16) & 0xff; /* track size */ - cdbufferb[26] = (cdrom_drives[id].handler->size(id) >> 8) & 0xff; /* track size */ - cdbufferb[27] = cdrom_drives[id].handler->size(id) & 0xff; /* track size */ - - if (len > max_len) { - len = max_len; - cdbufferb[0] = ((max_len - 2) >> 8) & 0xff; - cdbufferb[1] = (max_len - 2) & 0xff; - } - } - - cdrom_set_buf_len(id, BufLen, &len); - - cdrom_data_command_finish(id, len, len, max_len, 0); - break; - - case GPCMD_PLAY_AUDIO_10: - case GPCMD_PLAY_AUDIO_12: - case GPCMD_PLAY_AUDIO_MSF: - case GPCMD_PLAY_AUDIO_TRACK_INDEX: - cdrom_set_phase(id, SCSI_PHASE_STATUS); - - switch(cdb[0]) { - case GPCMD_PLAY_AUDIO_10: - msf = 0; - pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - len = (cdb[7] << 8) | cdb[8]; - break; - case GPCMD_PLAY_AUDIO_12: - msf = 0; - pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - break; - case GPCMD_PLAY_AUDIO_MSF: - /* This is apparently deprecated in the ATAPI spec, and apparently - has been since 1995 (!). Hence I'm having to guess most of it. */ - msf = 1; - pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - break; - case GPCMD_PLAY_AUDIO_TRACK_INDEX: - msf = 2; - pos = (cdb[4] << 8) | cdb[5]; - len = (cdb[7] << 8) | cdb[8]; - break; - } - - if (!cdrom_drives[id].handler->is_track_audio) - break; - - if ((cdrom_drives[id].host_drive < 1) || (dev->cd_status <= CD_STATUS_DATA_ONLY) || !cdrom_drives[id].handler->is_track_audio(id, pos, msf)) { - cdrom_illegal_mode(id); - break; - } - - if (cdrom_drives[id].handler->playaudio) - cdrom_drives[id].handler->playaudio(id, pos, len, msf); - else { - cdrom_illegal_mode(id); - break; - } - - cdrom_command_complete(id); - break; - - case GPCMD_READ_SUBCHANNEL: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - - max_len = cdb[7]; - max_len <<= 8; - max_len |= cdb[8]; - msf = (cdb[1] >> 1) & 1; - - cdrom_buf_alloc(id, 32); - - cdrom_log("CD-ROM %i: Getting page %i (%s)\n", id, cdb[3], msf ? "MSF" : "LBA"); - if ((cdrom_drives[id].handler->pass_through) && (cdb[3] != 1)) { - ret = cdrom_pass_through(id, &len, dev->current_cdb, cdbufferb); - if (!ret) { - cdrom_buf_free(id); - return; - } - switch(dev->cd_status) { - case CD_STATUS_PLAYING: - cdbufferb[1] = 0x11; - break; - case CD_STATUS_PAUSED: - cdbufferb[1] = 0x12; - break; - case CD_STATUS_DATA_ONLY: - cdbufferb[1] = 0x15; - break; - default: - cdbufferb[1] = 0x13; - break; - } - switch(cdb[3]) { - case 0: - alloc_length = 4; - break; - case 1: - alloc_length = 16; - break; - default: - alloc_length = 24; - break; - } - if (!(cdb[2] & 0x40) || (cdb[3] == 0)) - len = 4; - else - len = alloc_length; - } else { - if (cdb[3] > 3) { - /* cdrom_log("CD-ROM %i: Read subchannel check condition %02X\n", id, cdb[3]); */ - cdrom_invalid_field(id); - cdrom_buf_free(id); - return; - } - - switch(cdb[3]) { - case 0: - alloc_length = 4; - break; - case 1: - alloc_length = 16; - break; - default: - alloc_length = 24; - break; - } - - memset(cdbufferb, 0, 24); - pos = 0; - cdbufferb[pos++] = 0; - cdbufferb[pos++] = 0; /*Audio status*/ - cdbufferb[pos++] = 0; cdbufferb[pos++] = 0; /*Subchannel length*/ - cdbufferb[pos++] = cdb[3] & 3; /*Format code*/ - if (cdb[3] == 1) { - cdbufferb[1] = cdrom_drives[id].handler->getcurrentsubchannel(id, &cdbufferb[5], msf); - switch(dev->cd_status) { - case CD_STATUS_PLAYING: - cdbufferb[1] = 0x11; - break; - case CD_STATUS_PAUSED: - cdbufferb[1] = 0x12; - break; - case CD_STATUS_DATA_ONLY: - cdbufferb[1] = 0x15; - break; - default: - cdbufferb[1] = 0x13; - break; - } - } - if (!(cdb[2] & 0x40) || (cdb[3] == 0)) - len = 4; - else - len = alloc_length; - } - - len = MIN(len, max_len); - cdrom_set_buf_len(id, BufLen, &len); - - cdrom_log("CD-ROM %i: Read subchannel:", id); - for (i = 0; i < 32; i += 8) { - cdrom_log("[%02X] %02X %02X %02X %02X %02X %02X %02X %02X\n", i, - cdbufferb[i], cdbufferb[i + 1], cdbufferb[i + 2], cdbufferb[i + 3], - cdbufferb[i + 4], cdbufferb[i + 5], cdbufferb[i + 6], cdbufferb[i + 7]); - } - - cdrom_data_command_finish(id, len, len, len, 0); - break; - - case GPCMD_READ_DVD_STRUCTURE: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - - alloc_length = (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - - cdrom_buf_alloc(id, alloc_length); - - if (cdrom_drives[id].handler->pass_through) { - ret = cdrom_pass_through(id, &len, dev->current_cdb, cdbufferb); - if (!ret) { - cdrom_buf_free(id); - return; - } else { - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - if (*BufLen == -1) - *BufLen = len; - else { - *BufLen = MIN(len, *BufLen); - len = *BufLen; - } - } - } - } else { - len = cdrom_drives[id].handler->size(id); - - if (cdb[7] < 0xc0) { - if (len <= CD_MAX_SECTORS) { - cdrom_incompatible_format(id); - cdrom_buf_free(id); - return; - } - } - - memset(cdbufferb, 0, alloc_length); - - if (((cdb[7] >= 0x00) && (cdb[7] <= 0x7f)) || (cdb[7] == 0xff)) { - if (cdb[1] == 0) { - ret = cdrom_read_dvd_structure(id, format, cdb, cdbufferb); - - if (ret) { - cdrom_set_buf_len(id, BufLen, &alloc_length); - cdrom_data_command_finish(id, alloc_length, alloc_length, len, 0); - } else - cdrom_buf_free(id); - return; - } - } else { - cdrom_invalid_field(id); - cdrom_buf_free(id); - return; - } - } - break; - - case GPCMD_START_STOP_UNIT: - cdrom_set_phase(id, SCSI_PHASE_STATUS); - - switch(cdb[4] & 3) { - case 0: /* Stop the disc. */ - if (cdrom_drives[id].handler->stop) - cdrom_drives[id].handler->stop(id); - break; - case 1: /* Start the disc and read the TOC. */ - cdrom_drives[id].handler->medium_changed(id); /* This causes a TOC reload. */ - break; - case 2: /* Eject the disc if possible. */ - if (cdrom_drives[id].handler->stop) - cdrom_drives[id].handler->stop(id); - cdrom_eject(id); - break; - case 3: /* Load the disc (close tray). */ - cdrom_reload(id); - break; - } - - cdrom_command_complete(id); - break; - - case GPCMD_INQUIRY: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - - max_len = cdb[3]; - max_len <<= 8; - max_len |= cdb[4]; - - cdrom_buf_alloc(id, 65536); - - if (cdb[1] & 1) { - preamble_len = 4; - size_idx = 3; - - cdbufferb[idx++] = 05; - cdbufferb[idx++] = cdb[2]; - cdbufferb[idx++] = 0; - - idx++; - - switch (cdb[2]) { - case 0x00: - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 0x83; - break; - case 0x83: - if (idx + 24 > max_len) { - cdrom_data_phase_error(id); - cdrom_buf_free(id); - return; - } - - cdbufferb[idx++] = 0x02; - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 20; - ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Serial */ - idx += 20; - - if (idx + 72 > cdb[4]) - goto atapi_out; - cdbufferb[idx++] = 0x02; - cdbufferb[idx++] = 0x01; - cdbufferb[idx++] = 0x00; - cdbufferb[idx++] = 68; - ide_padstr8(cdbufferb + idx, 8, EMU_NAME); /* Vendor */ - idx += 8; - ide_padstr8(cdbufferb + idx, 40, device_identify_ex); /* Product */ - idx += 40; - ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Product */ - idx += 20; - break; - default: - cdrom_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - cdrom_invalid_field(id); - cdrom_buf_free(id); - return; - } - } else { - preamble_len = 5; - size_idx = 4; - - memset(cdbufferb, 0, 8); - cdbufferb[0] = 5; /*CD-ROM*/ - cdbufferb[1] = 0x80; /*Removable*/ - cdbufferb[2] = (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - cdbufferb[3] = (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) ? 0x12 : 0x21; - cdbufferb[4] = 31; - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - cdbufferb[6] = 1; /* 16-bit transfers supported */ - cdbufferb[7] = 0x20; /* Wide bus supported */ - } - - ide_padstr8(cdbufferb + 8, 8, EMU_NAME); /* Vendor */ - ide_padstr8(cdbufferb + 16, 16, device_identify); /* Product */ - ide_padstr8(cdbufferb + 32, 4, EMU_VERSION); /* Revision */ - idx = 36; - - if (max_len == 96) { - cdbufferb[4] = 91; - idx = 96; - } - } - -atapi_out: - cdbufferb[size_idx] = idx - preamble_len; - len=idx; - - len = MIN(len, max_len); - cdrom_set_buf_len(id, BufLen, &len); - - cdrom_data_command_finish(id, len, len, max_len, 0); - break; - - case GPCMD_PREVENT_REMOVAL: - cdrom_set_phase(id, SCSI_PHASE_STATUS); - cdrom_command_complete(id); - break; - - case GPCMD_PAUSE_RESUME_ALT: - case GPCMD_PAUSE_RESUME: - cdrom_set_phase(id, SCSI_PHASE_STATUS); - - if (cdb[8] & 1) { - if (cdrom_drives[id].handler->resume) - cdrom_drives[id].handler->resume(id); - else { - cdrom_illegal_mode(id); - break; - } - } else { - if (cdrom_drives[id].handler->pause) - cdrom_drives[id].handler->pause(id); - else { - cdrom_illegal_mode(id); - break; - } - } - cdrom_command_complete(id); - break; - - case GPCMD_SEEK_6: - case GPCMD_SEEK_10: - cdrom_set_phase(id, SCSI_PHASE_STATUS); - - switch(cdb[0]) { - case GPCMD_SEEK_6: - pos = (cdb[2] << 8) | cdb[3]; - break; - case GPCMD_SEEK_10: - pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; - break; - } - dev->seek_diff = ABS((int) (pos - dev->seek_pos)); - cdrom_seek(id, pos); - cdrom_command_complete(id); - break; - - case GPCMD_READ_CDROM_CAPACITY: - cdrom_set_phase(id, SCSI_PHASE_DATA_IN); - - cdrom_buf_alloc(id, 8); - - if (cdrom_read_capacity(id, dev->current_cdb, cdbufferb, &len) == 0) { - cdrom_buf_free(id); - return; - } - - cdrom_set_buf_len(id, BufLen, &len); - - cdrom_data_command_finish(id, len, len, len, 0); - break; - - case GPCMD_STOP_PLAY_SCAN: - cdrom_set_phase(id, SCSI_PHASE_STATUS); - - if (cdrom_drives[id].handler->stop) - cdrom_drives[id].handler->stop(id); - else { - cdrom_illegal_mode(id); - break; - } - cdrom_command_complete(id); - break; - - default: - cdrom_illegal_opcode(id); - break; - } - - /* cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", dev->phase, dev->request_length); */ - - if (cdrom_atapi_phase_to_scsi(id) == SCSI_PHASE_STATUS) - cdrom_buf_free(id); -} - -/* The command second phase function, needed for Mode Select. */ -uint8_t cdrom_phase_data_out(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - uint16_t block_desc_len; - uint16_t pos; - - uint8_t error = 0; - uint8_t page, page_len; - - uint16_t i = 0; - - uint8_t hdr_len, val, old_val, ch; - - FILE *f; - - switch(dev->current_cdb[0]) { - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - f = nvr_fopen(L"modeselect.bin", L"wb"); - fwrite(cdbufferb, 1, dev->total_length, f); - fclose(f); - - if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) - hdr_len = 8; - else - hdr_len = 4; - - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = cdbufferb[2]; - block_desc_len <<= 8; - block_desc_len |= cdbufferb[3]; - } else { - block_desc_len = cdbufferb[6]; - block_desc_len <<= 8; - block_desc_len |= cdbufferb[7]; - } - } else - block_desc_len = 0; - - pos = hdr_len + block_desc_len; - - while(1) { - page = cdbufferb[pos] & 0x3F; - page_len = cdbufferb[pos + 1]; - - pos += 2; - - if (!(cdrom_mode_sense_page_flags & (1LL << ((uint64_t) page)))) { - cdrom_log("Unimplemented page %02X\n", page); - error |= 1; - } else { - for (i = 0; i < page_len; i++) { - ch = cdrom_mode_sense_pages_changeable.pages[page][i + 2]; - val = cdbufferb[pos + i]; - old_val = cdrom_mode_sense_pages_saved[id].pages[page][i + 2]; - if (val != old_val) { - if (ch) - cdrom_mode_sense_pages_saved[id].pages[page][i + 2] = val; - else { - cdrom_log("Unchangeable value on position %02X on page %02X\n", i + 2, page); - error |= 1; - } - } - } - } - - pos += page_len; - - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - val = cdrom_mode_sense_pages_default_scsi.pages[page][0] & 0x80; - else - val = cdrom_mode_sense_pages_default.pages[page][0] & 0x80; - if (dev->do_page_save && val) - cdrom_mode_sense_save(id); - - if (pos >= dev->total_length) - break; - } - - if (error) { - cdrom_invalid_field_pl(id); - return 0; - } - break; - } - + dev->prev_status = dev->cd_status; + dev->cd_status = dev->handler->status(dev->id); + if (((dev->prev_status == CD_STATUS_PLAYING) || (dev->prev_status == CD_STATUS_PAUSED)) && ((dev->cd_status != CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_PAUSED))) return 1; -} - -/* This is the general ATAPI PIO request function. */ -void cdrom_pio_request(uint8_t id, uint8_t out) -{ - cdrom_t *dev = cdrom[id]; - - int old_pos = 0; - int ret = 0; - - if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) { - cdrom_log("CD-ROM %i: Lowering IDE IRQ\n", id); - ide_irq_lower(&(ide_drives[cdrom_drives[id].ide_channel])); - } - - dev->status = BUSY_STAT; - - if (dev->pos >= dev->packet_len) { - cdrom_log("CD-ROM %i: %i bytes %s, command done\n", id, dev->pos, out ? "written" : "read"); - - dev->pos = dev->request_pos = 0; - if (out) { - ret = cdrom_phase_data_out(id); - /* If ret = 0 (phase 1 error), then we do not do anything else other than - free the buffer, as the phase and callback have already been set by the - error function. */ - if (ret) - cdrom_command_complete(id); - } else - cdrom_command_complete(id); - cdrom_buf_free(id); - } else { - cdrom_log("CD-ROM %i: %i bytes %s, %i bytes are still left\n", id, dev->pos, out ? "written" : "read", dev->packet_len - dev->pos); - - /* Make sure to keep pos, and reset request_pos to 0. */ - /* Also make sure to not reset total_read. */ - - /* If less than (packet length) bytes are remaining, update packet length - accordingly. */ - if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) - dev->max_transfer_len = dev->packet_len - dev->pos; - cdrom_log("CD-ROM %i: Packet length %i, request length %i\n", id, dev->packet_len, dev->max_transfer_len); - - old_pos = dev->pos; - dev->packet_status = out ? CDROM_PHASE_DATA_OUT : CDROM_PHASE_DATA_IN; - cdrom_command_common(id); - dev->pos = old_pos; - - dev->request_pos = 0; - } -} - -void cdrom_phase_callback(uint8_t id); - -int cdrom_read_from_ide_dma(uint8_t channel) -{ - cdrom_t *dev; - - uint8_t id = atapi_cdrom_drives[channel]; - - if (id > CDROM_NUM) - return 0; - - dev = cdrom[id]; - - if (ide_bus_master_write) { - if (ide_bus_master_write(channel >> 1, cdbufferb, dev->packet_len)) - return 0; - else - return 1; - } else - return 0; - + else return 0; } -int cdrom_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) + +static void +cdrom_request_sense(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) { - cdrom_t *dev; + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + memcpy(buffer, dev->sense, alloc_length); + } - uint8_t id = scsi_cdrom_drives[scsi_id][scsi_lun]; - int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + buffer[0] = 0x70; - if (id > CDROM_NUM) - return 0; + if ((cdrom_sense_key > 0) && ((dev->cd_status < CD_STATUS_PLAYING) || + (dev->cd_status == CD_STATUS_STOPPED)) && cdrom_playing_completed(dev)) { + buffer[2]=SENSE_ILLEGAL_REQUEST; + buffer[12]=ASC_AUDIO_PLAY_OPERATION; + buffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; + } else if ((cdrom_sense_key == 0) && (dev->cd_status >= CD_STATUS_PLAYING) && + (dev->cd_status != CD_STATUS_STOPPED)) { + buffer[2]=SENSE_ILLEGAL_REQUEST; + buffer[12]=ASC_AUDIO_PLAY_OPERATION; + buffer[13]=(dev->cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; + } else { + if (dev->unit_attention && (cdrom_sense_key == 0)) { + buffer[2]=SENSE_UNIT_ATTENTION; + buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[13]=0; + } + } - dev = cdrom[id]; + cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); - cdrom_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(cdbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, *BufLen); - return 1; + if (buffer[2] == SENSE_UNIT_ATTENTION) { + /* If the last remaining sense is unit attention, clear + that condition. */ + dev->unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + cdrom_sense_clear(dev, GPCMD_REQUEST_SENSE); } -void cdrom_irq_raise(uint8_t id) + +void +cdrom_request_sense_for_scsi(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) { - if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) - ide_irq_raise(&(ide_drives[cdrom_drives[id].ide_channel])); + int ready = 0; + + if (dev->handler->medium_changed(dev->id)) + cdrom_insert(dev); + + ready = dev->handler->ready(dev->id); + + if (!ready && dev->unit_attention) { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + dev->unit_attention = 0; + } + + /* Do *NOT* advance the unit attention phase. */ + cdrom_request_sense(dev, buffer, alloc_length); } -int cdrom_read_from_dma(uint8_t id) + +static void +cdrom_set_buf_len(cdrom_t *dev, int32_t *BufLen, int32_t *src_len) { - cdrom_t *dev = cdrom[id]; - - int32_t *BufLen = &SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].BufferLength; - int ret = 0; - - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - ret = cdrom_read_from_scsi_dma(cdrom_drives[id].scsi_device_id, cdrom_drives[id].scsi_device_lun); - else - ret = cdrom_read_from_ide_dma(cdrom_drives[id].ide_channel); - - if (!ret) - return 0; - - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - cdrom_log("CD-ROM %i: SCSI Input data length: %i\n", id, *BufLen); - else - cdrom_log("CD-ROM %i: ATAPI Input data length: %i\n", id, dev->packet_len); - - ret = cdrom_phase_data_out(id); - - if (ret) - return 1; - else - return 0; + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + cdrom_log("CD-ROM %i: Actual transfer length: %i\n", dev->id, *BufLen); + } } -int cdrom_write_to_ide_dma(uint8_t channel) + +static void +cdrom_buf_alloc(cdrom_t *dev, uint32_t len) { - cdrom_t *dev; + cdrom_log("CD-ROM %i: Allocated buffer length: %i\n", dev->id, len); + cdbufferb = (uint8_t *) malloc(len); +} - uint8_t id = atapi_cdrom_drives[channel]; - if (id > CDROM_NUM) - return 0; +static void +cdrom_buf_free(cdrom_t *dev) +{ + if (cdbufferb) { + cdrom_log("CD-ROM %i: Freeing buffer...\n", dev->id); + free(cdbufferb); + cdbufferb = NULL; + } +} - dev = cdrom[id]; - if (ide_bus_master_read) { - if (ide_bus_master_read(channel >> 1, cdbufferb, dev->packet_len)) - return 0; +void +cdrom_command(cdrom_t *dev, uint8_t *cdb) +{ + int len, max_len, used_len, alloc_length, msf; + int pos = 0, i= 0, size_idx, idx = 0; + uint32_t feature; + unsigned preamble_len; + int toc_format, block_desc = 0; + int ret, format = 0; + int real_pos, track = 0; + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; + int32_t blen = 0, *BufLen; + uint8_t *b; + uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + BufLen = &SCSIDevices[dev->drv->scsi_device_id][dev->drv->scsi_device_lun].BufferLength; + dev->status &= ~ERR_STAT; + } else { + BufLen = &blen; + dev->error = 0; + } + + dev->packet_len = 0; + dev->request_pos = 0; + + device_identify[7] = dev->id + 0x30; + + device_identify_ex[7] = dev->id + 0x30; + device_identify_ex[10] = EMU_VERSION[0]; + device_identify_ex[12] = EMU_VERSION[2]; + device_identify_ex[13] = EMU_VERSION[3]; + + dev->data_pos = 0; + + memcpy(dev->current_cdb, cdb, dev->cdb_len); + + dev->cd_status = dev->handler->status(dev->id); + + if (cdb[0] != 0) { + cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", + dev->id, cdb[0], cdrom_sense_key, cdrom_asc, cdrom_ascq, dev->unit_attention); + cdrom_log("CD-ROM %i: Request length: %04X\n", dev->id, dev->request_length); + + cdrom_log("CD-ROM %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + msf = cdb[1] & 2; + dev->sector_len = 0; + + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (cdrom_pre_execution_check(dev, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_TEST_UNIT_READY: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + cdrom_command_complete(dev); + break; + + case GPCMD_REZERO_UNIT: + if (dev->handler->stop) + dev->handler->stop(dev->id); + dev->sector_pos = dev->sector_len = 0; + dev->seek_diff = dev->seek_pos; + cdrom_seek(dev, 0); + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + cdrom_buf_alloc(dev, 256); + cdrom_set_buf_len(dev, BufLen, &max_len); + cdrom_request_sense(dev, cdbufferb, max_len); + cdrom_data_command_finish(dev, 18, 18, cdb[4], 0); + break; + + case GPCMD_SET_SPEED: + case GPCMD_SET_SPEED_ALT: + dev->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; + if (dev->cur_speed < 1) + dev->cur_speed = 1; + else if (dev->cur_speed > dev->drv->speed) + dev->cur_speed = dev->drv->speed; + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + cdrom_command_complete(dev); + break; + + case GPCMD_MECHANISM_STATUS: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + cdrom_buf_alloc(dev, 8); + + cdrom_set_buf_len(dev, BufLen, &len); + + memset(cdbufferb, 0, 8); + cdbufferb[5] = 1; + + cdrom_data_command_finish(dev, 8, 8, len, 0); + break; + + case GPCMD_READ_TOC_PMA_ATIP: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + cdrom_buf_alloc(dev, 65536); + + toc_format = cdb[2] & 0xf; + + if (toc_format == 0) + toc_format = (cdb[9] >> 6) & 3; + + switch (toc_format) { + case 0: /*Normal*/ + len = dev->handler->readtoc(dev->id, cdbufferb, cdb[6], msf, max_len, + 0); + break; + case 1: /*Multi session*/ + len = dev->handler->readtoc_session(dev->id, cdbufferb, msf, max_len); + cdbufferb[0] = 0; cdbufferb[1] = 0xA; + break; + case 2: /*Raw*/ + len = dev->handler->readtoc_raw(dev->id, cdbufferb, max_len); + break; + default: + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + if (len > max_len) { + len = max_len; + + cdbufferb[0] = ((len - 2) >> 8) & 0xff; + cdbufferb[1] = (len - 2) & 0xff; + } + + cdrom_set_buf_len(dev, BufLen, &len); + + if (len >= 8) { + cdrom_log("CD-ROM %i: TOC: %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], + cdbufferb[4], cdbufferb[5], cdbufferb[6], cdbufferb[7]); + } + + if (len >= 16) { + cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", + cdbufferb[8], cdbufferb[9], cdbufferb[10], cdbufferb[11], + cdbufferb[12], cdbufferb[13], cdbufferb[14], cdbufferb[15]); + } + + if (len >= 24) { + cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", + cdbufferb[16], cdbufferb[17], cdbufferb[18], cdbufferb[19], + cdbufferb[20], cdbufferb[21], cdbufferb[22], cdbufferb[23]); + } + + if (len >= 32) { + cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", + cdbufferb[24], cdbufferb[25], cdbufferb[26], cdbufferb[27], + cdbufferb[28], cdbufferb[29], cdbufferb[30], cdbufferb[31]); + } + + if (len >= 36) { + cdrom_log(" %02X %02X %02X %02X\n", + cdbufferb[32], cdbufferb[33], cdbufferb[34], cdbufferb[35]); + } + + cdrom_data_command_finish(dev, len, len, len, 0); + /* cdrom_log("CD-ROM %i: READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", dev->id, + toc_format, ide->cylinder, cdbufferb[1]); */ + return; + + case GPCMD_READ_CD_OLD: + /* IMPORTANT: Convert the command to new read CD + for pass through purposes. */ + dev->current_cdb[0] = 0xbe; + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + case GPCMD_READ_CD: + case GPCMD_READ_CD_MSF: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + alloc_length = 2048; + + switch(cdb[0]) { + case GPCMD_READ_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + msf = 0; + break; + case GPCMD_READ_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, + dev->sector_pos); + msf = 0; + break; + case GPCMD_READ_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, + dev->sector_pos); + msf = 0; + break; + case GPCMD_READ_CD_MSF: + alloc_length = 2856; + dev->sector_len = MSFtoLBA(cdb[6], cdb[7], cdb[8]); + dev->sector_pos = MSFtoLBA(cdb[3], cdb[4], cdb[5]); + + dev->sector_len -= dev->sector_pos; + dev->sector_len++; + msf = 1; + break; + case GPCMD_READ_CD_OLD: + case GPCMD_READ_CD: + alloc_length = 2856; + dev->sector_len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + msf = 0; + break; + } + + dev->seek_diff = ABS((int) (pos - dev->seek_pos)); + dev->seek_pos = dev->sector_pos; + + if (!dev->sector_len) { + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + /* cdrom_log("CD-ROM %i: All done - callback set\n", dev->id); */ + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->callback = 20LL * CDROM_TIME; + cdrom_set_callback(dev); + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + cdrom_buf_alloc(dev, dev->packet_len); + + ret = cdrom_read_blocks(dev, &alloc_length, 1); + if (ret <= 0) { + cdrom_buf_free(dev); + return; + } + + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + cdrom_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + cdrom_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, + alloc_length, 0); + + dev->all_blocks_total = dev->block_total; + if (dev->packet_status != CDROM_PHASE_COMPLETE) + ui_sb_update_icon(SB_CDROM | dev->id, 1); else - return 1; - } else - return 0; + ui_sb_update_icon(SB_CDROM | dev->id, 0); + return; + + case GPCMD_READ_HEADER: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + alloc_length = ((cdb[7] << 8) | cdb[8]); + cdrom_buf_alloc(dev, 8); + + dev->sector_len = 1; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4]<<8) | cdb[5]; + if (msf) + real_pos = cdrom_lba_to_msf_accurate(dev->sector_pos); + else + real_pos = dev->sector_pos; + cdbufferb[0] = 1; /*2048 bytes user data*/ + cdbufferb[1] = cdbufferb[2] = cdbufferb[3] = 0; + cdbufferb[4] = (real_pos >> 24); + cdbufferb[5] = ((real_pos >> 16) & 0xff); + cdbufferb[6] = ((real_pos >> 8) & 0xff); + cdbufferb[7] = real_pos & 0xff; + + len = 8; + len = MIN(len, alloc_length); + + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_data_command_finish(dev, len, len, len, 0); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + else + block_desc = 0; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = cdb[4]; + cdrom_buf_alloc(dev, 256); + } else { + len = (cdb[8] | (cdb[7] << 8)); + cdrom_buf_alloc(dev, 65536); + } + + dev->current_page_code = cdb[2] & 0x3F; + + if (!(cdrom_mode_sense_page_flags & (1LL << dev->current_page_code))) { + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + memset(cdbufferb, 0, len); + alloc_length = len; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = cdrom_mode_sense(dev, cdbufferb, 4, cdb[2], block_desc); + len = MIN(len, alloc_length); + cdbufferb[0] = len - 1; + cdbufferb[1] = dev->handler->media_type_id(dev->id); + if (block_desc) + cdbufferb[3] = 8; + } else { + len = cdrom_mode_sense(dev, cdbufferb, 8, cdb[2], block_desc); + len = MIN(len, alloc_length); + cdbufferb[0]=(len - 2) >> 8; + cdbufferb[1]=(len - 2) & 255; + cdbufferb[2] = dev->handler->media_type_id(dev->id); + if (block_desc) { + cdbufferb[6] = 0; + cdbufferb[7] = 8; + } + } + + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", dev->id, cdb[2]); + + cdrom_data_command_finish(dev, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) { + len = cdb[4]; + cdrom_buf_alloc(dev, 256); + } else { + len = (cdb[7] << 8) | cdb[8]; + cdrom_buf_alloc(dev, 65536); + } + + cdrom_set_buf_len(dev, BufLen, &len); + + dev->total_length = len; + dev->do_page_save = cdb[1] & 1; + + dev->current_page_pos = 0; + + cdrom_data_command_finish(dev, len, len, len, 1); + return; + + case GPCMD_GET_CONFIGURATION: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + /* XXX: could result in alignment problems in some architectures */ + feature = (cdb[2] << 8) | cdb[3]; + max_len = (cdb[7] << 8) | cdb[8]; + + /* only feature 0 is supported */ + if ((cdb[2] != 0) || (cdb[3] > 2)) { + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + cdrom_buf_alloc(dev, 65536); + memset(cdbufferb, 0, max_len); + + alloc_length = 0; + b = cdbufferb; + + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (dev->handler->ready(dev->id)) { + len = dev->handler->size(dev->id); + if (len > CD_MAX_SECTORS) { + b[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; + b[7] = MMC_PROFILE_DVD_ROM & 0xff; + ret = 1; + } else { + b[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; + b[7] = MMC_PROFILE_CD_ROM & 0xff; + ret = 0; + } + } else + ret = 2; + + alloc_length = 8; + b += 8; + + if ((feature == 0) || ((cdb[1] & 3) < 2)) { + b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 8; + + alloc_length += 4; + b += 4; + + for (i = 0; i < 2; i++) { + b[0] = (profiles[i] >> 8) & 0xff; + b[1] = profiles[i] & 0xff; + + if (ret == i) + b[2] |= 1; + + alloc_length += 4; + b += 4; + } + } + if ((feature == 1) || ((cdb[1] & 3) < 2)) { + b[1] = 1; + b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 8; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + b[7] = 1; + else + b[7] = 2; + b[8] = 1; + + alloc_length += 12; + b += 12; + } + if ((feature == 2) || ((cdb[1] & 3) < 2)) { + b[1] = 2; + b[2] = (1 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 4; + + b[4] = 2; + + alloc_length += 8; + b += 8; + } + + cdbufferb[0] = ((alloc_length - 4) >> 24) & 0xff; + cdbufferb[1] = ((alloc_length - 4) >> 16) & 0xff; + cdbufferb[2] = ((alloc_length - 4) >> 8) & 0xff; + cdbufferb[3] = (alloc_length - 4) & 0xff; + + alloc_length = MIN(alloc_length, max_len); + + cdrom_set_buf_len(dev, BufLen, &alloc_length); + + cdrom_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); + break; + + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + cdrom_buf_alloc(dev, 8 + sizeof(gesn_event_header)); + + gesn_cdb = (void *) cdb; + gesn_event_header = (void *) cdbufferb; + + /* It is fine by the MMC spec to not support async mode operations. */ + if (!(gesn_cdb->polled & 0x01)) { + /* asynchronous mode */ + /* Only polling is supported, asynchronous mode is not. */ + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + * Notification class requests and supported event classes are bitmasks, + * but they are built from the same values as the "notification class" + * field. + */ + gesn_event_header->supported_events = 1 << GESN_MEDIA; + + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & (1 << GESN_MEDIA)) { + gesn_event_header->notification_class |= GESN_MEDIA; + + cdbufferb[4] = dev->media_status; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */ + cdbufferb[5] = 1; /* Power Status (1 = Active) */ + cdbufferb[6] = 0; + cdbufferb[7] = 0; + used_len = 8; + } else { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + gesn_event_header->len = used_len - sizeof(*gesn_event_header); + + memcpy(cdbufferb, gesn_event_header, 4); + + cdrom_set_buf_len(dev, BufLen, &used_len); + + cdrom_data_command_finish(dev, used_len, used_len, used_len, 0); + break; + + case GPCMD_READ_DISC_INFORMATION: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + cdrom_buf_alloc(dev, 65536); + + memset(cdbufferb, 0, 34); + memset(cdbufferb, 1, 9); + cdbufferb[0] = 0; + cdbufferb[1] = 32; + cdbufferb[2] = 0xe; /* last session complete, disc finalized */ + cdbufferb[7] = 0x20; /* unrestricted use */ + cdbufferb[8] = 0x00; /* CD-ROM */ + + len=34; + len = MIN(len, max_len); + + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_READ_TRACK_INFORMATION: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + cdrom_buf_alloc(dev, 65536); + + track = ((uint32_t) cdb[2]) << 24; + track |= ((uint32_t) cdb[3]) << 16; + track |= ((uint32_t) cdb[4]) << 8; + track |= (uint32_t) cdb[5]; + + if (((cdb[1] & 0x03) != 1) || (track != 1)) { + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + len = 36; + + memset(cdbufferb, 0, 36); + cdbufferb[0] = 0; + cdbufferb[1] = 34; + cdbufferb[2] = 1; /* track number (LSB) */ + cdbufferb[3] = 1; /* session number (LSB) */ + cdbufferb[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ + cdbufferb[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ + cdbufferb[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ + cdbufferb[24] = (dev->handler->size(dev->id) >> 24) & 0xff; /* track size */ + cdbufferb[25] = (dev->handler->size(dev->id) >> 16) & 0xff; /* track size */ + cdbufferb[26] = (dev->handler->size(dev->id) >> 8) & 0xff; /* track size */ + cdbufferb[27] = dev->handler->size(dev->id) & 0xff; /* track size */ + + if (len > max_len) { + len = max_len; + cdbufferb[0] = ((max_len - 2) >> 8) & 0xff; + cdbufferb[1] = (max_len - 2) & 0xff; + } + + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_data_command_finish(dev, len, len, max_len, 0); + break; + + case GPCMD_PLAY_AUDIO_10: + case GPCMD_PLAY_AUDIO_12: + case GPCMD_PLAY_AUDIO_MSF: + case GPCMD_PLAY_AUDIO_TRACK_INDEX: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_PLAY_AUDIO_10: + msf = 0; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 8) | cdb[8]; + break; + case GPCMD_PLAY_AUDIO_12: + msf = 0; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + break; + case GPCMD_PLAY_AUDIO_MSF: + /* This is apparently deprecated in the ATAPI spec, and apparently + has been since 1995 (!). Hence I'm having to guess most of it. */ + msf = 1; + pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + break; + case GPCMD_PLAY_AUDIO_TRACK_INDEX: + msf = 2; + pos = (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 8) | cdb[8]; + break; + } + + if ((dev->drv->host_drive < 1) || (dev->cd_status <= CD_STATUS_DATA_ONLY)) { + cdrom_illegal_mode(dev); + break; + } + + if (dev->handler->playaudio) + ret = dev->handler->playaudio(dev->id, pos, len, msf); + else + ret = 0; + + if (ret) + cdrom_command_complete(dev); + else + cdrom_illegal_mode(dev); + break; + + case GPCMD_READ_SUBCHANNEL: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + msf = (cdb[1] >> 1) & 1; + + cdrom_buf_alloc(dev, 32); + + cdrom_log("CD-ROM %i: Getting page %i (%s)\n", dev->id, cdb[3], msf ? "MSF" : "LBA"); + + if (cdb[3] > 3) { + /* cdrom_log("CD-ROM %i: Read subchannel check condition %02X\n", dev->id, + cdb[3]); */ + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + switch(cdb[3]) { + case 0: + alloc_length = 4; + break; + case 1: + alloc_length = 16; + break; + default: + alloc_length = 24; + break; + } + + memset(cdbufferb, 0, 24); + pos = 0; + cdbufferb[pos++] = 0; + cdbufferb[pos++] = 0; /*Audio status*/ + cdbufferb[pos++] = 0; cdbufferb[pos++] = 0; /*Subchannel length*/ + cdbufferb[pos++] = cdb[3] & 3; /*Format code*/ + if (cdb[3] == 1) { + cdbufferb[1] = dev->handler->getcurrentsubchannel(dev->id, &cdbufferb[5], msf); + switch(dev->cd_status) { + case CD_STATUS_PLAYING: + cdbufferb[1] = 0x11; + break; + case CD_STATUS_PAUSED: + cdbufferb[1] = 0x12; + break; + case CD_STATUS_DATA_ONLY: + cdbufferb[1] = 0x15; + break; + default: + cdbufferb[1] = 0x13; + break; + } + } + + if (!(cdb[2] & 0x40) || (cdb[3] == 0)) + len = 4; + else + len = alloc_length; + + len = MIN(len, max_len); + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_log("CD-ROM %i: Read subchannel:", dev->id); + for (i = 0; i < 32; i += 8) { + cdrom_log("[%02X] %02X %02X %02X %02X %02X %02X %02X %02X\n", i, + cdbufferb[i], cdbufferb[i + 1], cdbufferb[i + 2], cdbufferb[i + 3], + cdbufferb[i + 4], cdbufferb[i + 5], cdbufferb[i + 6], cdbufferb[i + 7]); + } + + cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_READ_DVD_STRUCTURE: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + alloc_length = (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + + cdrom_buf_alloc(dev, alloc_length); + + len = dev->handler->size(dev->id); + + if ((cdb[7] < 0xc0) && (len <= CD_MAX_SECTORS)) { + cdrom_incompatible_format(dev); + cdrom_buf_free(dev); + return; + } + + memset(cdbufferb, 0, alloc_length); + + if ((cdb[7] <= 0x7f) || (cdb[7] == 0xff)) { + if (cdb[1] == 0) { + ret = cdrom_read_dvd_structure(dev, format, cdb, cdbufferb); + if (ret) { + cdrom_set_buf_len(dev, BufLen, &alloc_length); + cdrom_data_command_finish(dev, alloc_length, alloc_length, + len, 0); + } else + cdrom_buf_free(dev); + return; + } + } else { + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + break; + + case GPCMD_START_STOP_UNIT: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[4] & 3) { + case 0: /* Stop the disc. */ + if (dev->handler->stop) + dev->handler->stop(dev->id); + break; + case 1: /* Start the disc and read the TOC. */ + dev->handler->medium_changed(dev->id); /* This causes a TOC reload. */ + break; + case 2: /* Eject the disc if possible. */ + if (dev->handler->stop) + dev->handler->stop(dev->id); + cdrom_eject(dev->id); + break; + case 3: /* Load the disc (close tray). */ + cdrom_reload(dev->id); + break; + } + + cdrom_command_complete(dev); + break; + + case GPCMD_INQUIRY: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + cdrom_buf_alloc(dev, 65536); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + cdbufferb[idx++] = 05; + cdbufferb[idx++] = cdb[2]; + cdbufferb[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + cdrom_data_phase_error(dev); + cdrom_buf_free(dev); + return; + } + + cdbufferb[idx++] = 0x02; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 20; + ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + cdbufferb[idx++] = 0x02; + cdbufferb[idx++] = 0x01; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 68; + ide_padstr8(cdbufferb + idx, 8, EMU_NAME); /* Vendor */ + idx += 8; + ide_padstr8(cdbufferb + idx, 40, device_identify_ex); /* Product */ + idx += 40; + ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + cdrom_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(cdbufferb, 0, 8); + cdbufferb[0] = 5; /*CD-ROM*/ + cdbufferb[1] = 0x80; /*Removable*/ + cdbufferb[2] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + cdbufferb[3] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x12 : 0x21; + cdbufferb[4] = 31; + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + cdbufferb[6] = 1; /* 16-bit transfers supported */ + cdbufferb[7] = 0x20; /* Wide bus supported */ + } + + ide_padstr8(cdbufferb + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(cdbufferb + 16, 16, device_identify); /* Product */ + ide_padstr8(cdbufferb + 32, 4, EMU_VERSION); /* Revision */ + idx = 36; + + if (max_len == 96) { + cdbufferb[4] = 91; + idx = 96; + } + } + +atapi_out: + cdbufferb[size_idx] = idx - preamble_len; + len=idx; + + len = MIN(len, max_len); + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_data_command_finish(dev, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + cdrom_command_complete(dev); + break; + + case GPCMD_PAUSE_RESUME_ALT: + case GPCMD_PAUSE_RESUME: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + if (cdb[8] & 1) { + if (dev->handler->resume) + dev->handler->resume(dev->id); + else { + cdrom_illegal_mode(dev); + break; + } + } else { + if (dev->handler->pause) + dev->handler->pause(dev->id); + else { + cdrom_illegal_mode(dev); + break; + } + } + cdrom_command_complete(dev); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + dev->seek_diff = ABS((int) (pos - dev->seek_pos)); + cdrom_seek(dev, pos); + cdrom_command_complete(dev); + break; + + case GPCMD_READ_CDROM_CAPACITY: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + cdrom_buf_alloc(dev, 8); + + if (cdrom_read_capacity(dev, dev->current_cdb, cdbufferb, (uint32_t *) &len) == 0) { + cdrom_buf_free(dev); + return; + } + + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_STOP_PLAY_SCAN: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + if (dev->handler->stop) + dev->handler->stop(dev->id); + else { + cdrom_illegal_mode(dev); + break; + } + cdrom_command_complete(dev); + break; + + default: + cdrom_illegal_opcode(dev); + break; + } + + /* cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", dev->phase, dev->request_length); */ + + if (cdrom_atapi_phase_to_scsi(dev) == SCSI_PHASE_STATUS) + cdrom_buf_free(dev); } -int cdrom_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) + +/* The command second phase function, needed for Mode Select. */ +static uint8_t +cdrom_phase_data_out(cdrom_t *dev) { - cdrom_t *dev; + uint16_t block_desc_len, pos; + uint16_t i = 0; - uint8_t id = scsi_cdrom_drives[scsi_id][scsi_lun]; - int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + uint8_t error = 0; + uint8_t page, page_len, hdr_len, val, old_val, ch; - if (id > CDROM_NUM) - return 0; + FILE *f; - dev = cdrom[id]; + switch(dev->current_cdb[0]) { + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + f = nvr_fopen(L"modeselect.bin", L"wb"); + fwrite(cdbufferb, 1, dev->total_length, f); + fclose(f); - cdrom_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, cdbufferb, *BufLen); - cdrom_log("CD-ROM %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], cdbufferb[4], cdbufferb[5], cdbufferb[6], cdbufferb[7]); - cdrom_log("CD-ROM %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); - return 1; + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = cdbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= cdbufferb[3]; + } else { + block_desc_len = cdbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= cdbufferb[7]; + } + } else + block_desc_len = 0; + + pos = hdr_len + block_desc_len; + + while(1) { + page = cdbufferb[pos] & 0x3F; + page_len = cdbufferb[pos + 1]; + + pos += 2; + + if (!(cdrom_mode_sense_page_flags & (1LL << ((uint64_t) page)))) { + cdrom_log("Unimplemented page %02X\n", page); + error |= 1; + } else { + for (i = 0; i < page_len; i++) { + ch = cdrom_mode_sense_pages_changeable.pages[page][i + 2]; + val = cdbufferb[pos + i]; + old_val = dev->ms_pages_saved.pages[page][i + 2]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved.pages[page][i + 2] = val; + else { + cdrom_log("Unchangeable value on position %02X on page %02X\n", i + 2, page); + error |= 1; + } + } + } + } + + pos += page_len; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + val = cdrom_mode_sense_pages_default_scsi.pages[page][0] & 0x80; + else + val = cdrom_mode_sense_pages_default.pages[page][0] & 0x80; + + if (dev->do_page_save && val) + cdrom_mode_sense_save(dev); + + if (pos >= dev->total_length) + break; + } + + if (error) { + cdrom_invalid_field_pl(dev); + return 0; + } + break; + } + + return 1; } -int cdrom_write_to_dma(uint8_t id) + +/* This is the general ATAPI PIO request function. */ +static void +cdrom_pio_request(cdrom_t *dev, uint8_t out) { - cdrom_t *dev = cdrom[id]; + int old_pos = 0; + int ret = 0; - int32_t *BufLen = &SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].BufferLength; - int ret = 0; + if (dev->drv->bus_type < CDROM_BUS_SCSI) { + cdrom_log("CD-ROM %i: Lowering IDE IRQ\n", dev->id); + ide_irq_lower(ide_drives[dev->drv->ide_channel]); + } - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - cdrom_log("Write to SCSI DMA: (%02X:%02X)\n", cdrom_drives[id].scsi_device_id, cdrom_drives[id].scsi_device_lun); - ret = cdrom_write_to_scsi_dma(cdrom_drives[id].scsi_device_id, cdrom_drives[id].scsi_device_lun); + dev->status = BUSY_STAT; + + if (dev->pos >= dev->packet_len) { + cdrom_log("CD-ROM %i: %i bytes %s, command done\n", dev->id, dev->pos, out ? "written" : "read"); + + dev->pos = dev->request_pos = 0; + if (out) { + ret = cdrom_phase_data_out(dev); + /* If ret = 0 (phase 1 error), then we do not do anything else other than + free the buffer, as the phase and callback have already been set by the + error function. */ + if (ret) + cdrom_command_complete(dev); } else - ret = cdrom_write_to_ide_dma(cdrom_drives[id].ide_channel); + cdrom_command_complete(dev); + cdrom_buf_free(dev); + } else { + cdrom_log("CD-ROM %i: %i bytes %s, %i bytes are still left\n", dev->id, dev->pos, + out ? "written" : "read", dev->packet_len - dev->pos); - if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) - cdrom_log("CD-ROM %i: SCSI Output data length: %i\n", id, *BufLen); - else - cdrom_log("CD-ROM %i: ATAPI Output data length: %i\n", id, dev->packet_len); + /* If less than (packet length) bytes are remaining, update packet length + accordingly. */ + if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) + dev->max_transfer_len = dev->packet_len - dev->pos; + cdrom_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, + dev->max_transfer_len); - if (ret) + old_pos = dev->pos; + dev->packet_status = out ? CDROM_PHASE_DATA_OUT : CDROM_PHASE_DATA_IN; + cdrom_command_common(dev); + dev->pos = old_pos; + + dev->request_pos = 0; + } +} + + +static int +cdrom_read_from_ide_dma(uint8_t channel) +{ + cdrom_t *dev; + + uint8_t id = atapi_cdrom_drives[channel]; + int ret; + + if (id > CDROM_NUM) + return 0; + + dev = cdrom[id]; + + if (ide_bus_master_write) { + ret = ide_bus_master_write(channel >> 1, + cdbufferb, dev->packet_len, + ide_bus_master_priv[channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + cdrom_bus_master_error(dev); + return 0; + } else return 1; - else - return 0; + } else + return 0; + + return 0; } + +static int +cdrom_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + cdrom_t *dev; + + uint8_t id = scsi_cdrom_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > CDROM_NUM) + return 0; + + dev = cdrom[id]; + + cdrom_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(cdbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, *BufLen); + return 1; +} + + +static void +cdrom_irq_raise(cdrom_t *dev) +{ + if (dev->drv->bus_type < CDROM_BUS_SCSI) + ide_irq_raise(ide_drives[dev->drv->ide_channel]); +} + + +static int +cdrom_read_from_dma(cdrom_t *dev) +{ + int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id][dev->drv->scsi_device_lun].BufferLength; + int ret = 0; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + ret = cdrom_read_from_scsi_dma(dev->drv->scsi_device_id, dev->drv->scsi_device_lun); + else + ret = cdrom_read_from_ide_dma(dev->drv->ide_channel); + + if (ret != 1) + return ret; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + cdrom_log("CD-ROM %i: SCSI Input data length: %i\n", dev->id, *BufLen); + else + cdrom_log("CD-ROM %i: ATAPI Input data length: %i\n", dev->id, dev->packet_len); + + ret = cdrom_phase_data_out(dev); + + if (ret) + return 1; + else + return 0; +} + + +static int +cdrom_write_to_ide_dma(uint8_t channel) +{ + cdrom_t *dev; + + uint8_t id = atapi_cdrom_drives[channel]; + int ret; + + if (id > CDROM_NUM) + return 0; + + dev = cdrom[id]; + + if (ide_bus_master_read) { + ret = ide_bus_master_read(channel >> 1, + cdbufferb, dev->packet_len, + ide_bus_master_priv[channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + cdrom_bus_master_error(dev); + return 0; + } else + return 1; + } else + return 0; +} + + +static int +cdrom_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + cdrom_t *dev; + + uint8_t id = scsi_cdrom_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > CDROM_NUM) + return 0; + + dev = cdrom[id]; + + cdrom_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, cdbufferb, *BufLen); + cdrom_log("CD-ROM %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], cdbufferb[4], cdbufferb[5], + cdbufferb[6], cdbufferb[7]); + cdrom_log("CD-ROM %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); + return 1; +} + + +static int +cdrom_write_to_dma(cdrom_t *dev) +{ + int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id][dev->drv->scsi_device_lun].BufferLength; + int ret = 0; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + cdrom_log("Write to SCSI DMA: (%02X:%02X)\n", dev->drv->scsi_device_id, dev->drv->scsi_device_lun); + ret = cdrom_write_to_scsi_dma(dev->drv->scsi_device_id, dev->drv->scsi_device_lun); + } else + ret = cdrom_write_to_ide_dma(dev->drv->ide_channel); + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + cdrom_log("CD-ROM %i: SCSI Output data length: %i\n", dev->id, *BufLen); + else + cdrom_log("CD-ROM %i: ATAPI Output data length: %i\n", dev->id, dev->packet_len); + + return ret; +} + + /* If the result is 1, issue an IRQ, otherwise not. */ -void cdrom_phase_callback(uint8_t id) +void +cdrom_phase_callback(cdrom_t *dev) { - cdrom_t *dev = cdrom[id]; - int ret; + int ret; - switch(dev->packet_status) { - case CDROM_PHASE_IDLE: - cdrom_log("CD-ROM %i: CDROM_PHASE_IDLE\n", id); - dev->pos=0; - dev->phase = 1; - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - return; - case CDROM_PHASE_COMMAND: - cdrom_log("CD-ROM %i: CDROM_PHASE_COMMAND\n", id); - dev->status = BUSY_STAT | (dev->status &ERR_STAT); - memcpy(dev->atapi_cdb, cdbufferb, dev->cdb_len); - cdrom_command(id, dev->atapi_cdb); - return; - case CDROM_PHASE_COMPLETE: - cdrom_log("CD-ROM %i: CDROM_PHASE_COMPLETE\n", id); - dev->status = READY_STAT; - dev->phase = 3; - dev->packet_status = 0xFF; - ui_sb_update_icon(SB_CDROM | id, 0); - cdrom_irq_raise(id); - return; - case CDROM_PHASE_DATA_OUT: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT\n", id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 0; - cdrom_irq_raise(id); - return; - case CDROM_PHASE_DATA_OUT_DMA: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT_DMA\n", id); - ret = cdrom_read_from_dma(id); - cdrom_command_complete(id); - - if (ret || (cdrom_drives[id].bus_type == CDROM_BUS_SCSI)) { - cdrom_log("CD-ROM %i: DMA data out phase done\n"); - cdrom_buf_free(id); - cdrom_command_complete(id); - } else { - cdrom_log("CD-ROM %i: DMA data out phase failure\n"); - cdrom_command_bus(id); - } - return; - case CDROM_PHASE_DATA_IN: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN\n", id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 2; - cdrom_irq_raise(id); - return; - case CDROM_PHASE_DATA_IN_DMA: - cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN_DMA\n", id); - ret = cdrom_write_to_dma(id); - - if (ret || (cdrom_drives[id].bus_type == CDROM_BUS_SCSI)) { - cdrom_log("CD-ROM %i: DMA data in phase done\n"); - cdrom_buf_free(id); - cdrom_command_complete(id); - } else { - cdrom_log("CD-ROM %i: DMA data in phase failure\n"); - cdrom_command_bus(id); - } - return; - case CDROM_PHASE_ERROR: - cdrom_log("CD-ROM %i: CDROM_PHASE_ERROR\n", id); - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - cdrom_irq_raise(id); - ui_sb_update_icon(SB_CDROM | id, 0); - return; - } -} - -/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ -uint32_t cdrom_read(uint8_t channel, int length) -{ - cdrom_t *dev; - - uint16_t *cdbufferw; - uint32_t *cdbufferl; - - uint8_t id = atapi_cdrom_drives[channel]; - - uint32_t temp = 0; - - if (id > CDROM_NUM) - return 0; - - dev = cdrom[id]; - - cdbufferw = (uint16_t *) cdbufferb; - cdbufferl = (uint32_t *) cdbufferb; - - if (!cdbufferb) - return 0; - - /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, - which can happen when issuing media access commands with an allocated length below minimum request length - (which is 1 sector = 2048 bytes). */ - switch(length) { - case 1: - temp = (dev->pos < dev->packet_len) ? cdbufferb[dev->pos] : 0; - dev->pos++; - dev->request_pos++; - break; - case 2: - temp = (dev->pos < dev->packet_len) ? cdbufferw[dev->pos >> 1] : 0; - dev->pos += 2; - dev->request_pos += 2; - break; - case 4: - temp = (dev->pos < dev->packet_len) ? cdbufferl[dev->pos >> 2] : 0; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return 0; - } - - if (dev->packet_status == CDROM_PHASE_DATA_IN) { - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - // cdrom_log("CD-ROM %i: Issuing read callback\n", id); - cdrom_pio_request(id, 0); - } - // cdrom_log("CD-ROM %i: Returning: %02X (buffer position: %i, request position: %i)\n", id, temp, dev->pos, dev->request_pos); - return temp; - } else { - // cdrom_log("CD-ROM %i: Returning zero (buffer position: %i, request position: %i)\n", id, dev->pos, dev->request_pos); - return 0; - } -} - -/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ -void cdrom_write(uint8_t channel, uint32_t val, int length) -{ - cdrom_t *dev; - - uint16_t *cdbufferw; - uint32_t *cdbufferl; - - uint8_t id = atapi_cdrom_drives[channel]; - - if (id > CDROM_NUM) + switch(dev->packet_status) { + case CDROM_PHASE_IDLE: + cdrom_log("CD-ROM %i: CDROM_PHASE_IDLE\n", dev->id); + dev->pos=0; + dev->phase = 1; + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); return; - - dev = cdrom[id]; - - if (dev->packet_status == CDROM_PHASE_IDLE) { - if (!cdbufferb) - cdrom_buf_alloc(id, dev->cdb_len); - } - - cdbufferw = (uint16_t *) cdbufferb; - cdbufferl = (uint32_t *) cdbufferb; - - if (!cdbufferb) + case CDROM_PHASE_COMMAND: + cdrom_log("CD-ROM %i: CDROM_PHASE_COMMAND\n", dev->id); + dev->status = BUSY_STAT | (dev->status &ERR_STAT); + memcpy(dev->atapi_cdb, cdbufferb, dev->cdb_len); + cdrom_command(dev, dev->atapi_cdb); return; + case CDROM_PHASE_COMPLETE: + cdrom_log("CD-ROM %i: CDROM_PHASE_COMPLETE\n", dev->id); + dev->status = READY_STAT; + dev->phase = 3; + dev->packet_status = 0xFF; + ui_sb_update_icon(SB_CDROM | dev->id, 0); + cdrom_irq_raise(dev); + return; + case CDROM_PHASE_DATA_OUT: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT\n", dev->id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 0; + cdrom_irq_raise(dev); + return; + case CDROM_PHASE_DATA_OUT_DMA: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT_DMA\n", dev->id); + ret = cdrom_read_from_dma(dev); - switch(length) { - case 1: - cdbufferb[dev->pos] = val & 0xff; - dev->pos++; - dev->request_pos++; - break; - case 2: - cdbufferw[dev->pos >> 1] = val & 0xffff; - dev->pos += 2; - dev->request_pos += 2; - break; - case 4: - cdbufferl[dev->pos >> 2] = val; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return; - } - - if (dev->packet_status == CDROM_PHASE_DATA_OUT) { - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - cdrom_pio_request(id, 1); + if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { + cdrom_log("CD-ROM %i: DMA data out phase done\n"); + cdrom_buf_free(dev); + cdrom_command_complete(dev); + } else if (ret == 2) { + cdrom_log("CD-ROM %i: DMA out not enabled, wait\n"); + cdrom_command_bus(dev); + } else { + cdrom_log("CD-ROM %i: DMA data out phase failure\n"); + cdrom_buf_free(dev); } return; - } else if (dev->packet_status == CDROM_PHASE_IDLE) { - if (dev->pos >= dev->cdb_len) { - dev->pos=0; - dev->status = BUSY_STAT; - dev->packet_status = CDROM_PHASE_COMMAND; - timer_process(); - cdrom_phase_callback(id); - timer_update_outstanding(); + case CDROM_PHASE_DATA_IN: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN\n", dev->id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 2; + cdrom_irq_raise(dev); + return; + case CDROM_PHASE_DATA_IN_DMA: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN_DMA\n", dev->id); + ret = cdrom_write_to_dma(dev); + + if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { + cdrom_log("CD-ROM %i: DMA data in phase done\n"); + cdrom_buf_free(dev); + cdrom_command_complete(dev); + } else if (ret == 2) { + cdrom_log("CD-ROM %i: DMA in not enabled, wait\n"); + cdrom_command_bus(dev); + } else { + cdrom_log("CD-ROM %i: DMA data in phase failure\n"); + cdrom_buf_free(dev); } return; - } + case CDROM_PHASE_ERROR: + cdrom_log("CD-ROM %i: CDROM_PHASE_ERROR\n", dev->id); + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + cdrom_irq_raise(dev); + ui_sb_update_icon(SB_CDROM | dev->id, 0); + return; + } } + +uint32_t +cdrom_read(uint8_t channel, int length) +{ + cdrom_t *dev; + + uint16_t *cdbufferw; + uint32_t *cdbufferl; + + uint8_t id = atapi_cdrom_drives[channel]; + + uint32_t temp = 0; + + if (id > CDROM_NUM) + return 0; + + dev = cdrom[id]; + + cdbufferw = (uint16_t *) cdbufferb; + cdbufferl = (uint32_t *) cdbufferb; + + if (!cdbufferb) + return 0; + + /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, + which can happen when issuing media access commands with an allocated length below minimum request length + (which is 1 sector = 2048 bytes). */ + switch(length) { + case 1: + temp = (dev->pos < dev->packet_len) ? cdbufferb[dev->pos] : 0; + dev->pos++; + dev->request_pos++; + break; + case 2: + temp = (dev->pos < dev->packet_len) ? cdbufferw[dev->pos >> 1] : 0; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + temp = (dev->pos < dev->packet_len) ? cdbufferl[dev->pos >> 2] : 0; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return 0; + } + + if (dev->packet_status == CDROM_PHASE_DATA_IN) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + cdrom_log("CD-ROM %i: Issuing read callback\n", id); + cdrom_pio_request(dev, 0); + } + cdrom_log("CD-ROM %i: Returning: %02X (buffer position: %i, request position: %i)\n", id, + temp, dev->pos, dev->request_pos); + return temp; + } else { + cdrom_log("CD-ROM %i: Returning zero (buffer position: %i, request position: %i)\n", id, + dev->pos, dev->request_pos); + return 0; + } +} + + +void +cdrom_write(uint8_t channel, uint32_t val, int length) +{ + cdrom_t *dev; + + uint16_t *cdbufferw; + uint32_t *cdbufferl; + + uint8_t id = atapi_cdrom_drives[channel]; + + if (id > CDROM_NUM) + return; + + dev = cdrom[id]; + + if ((dev->packet_status == CDROM_PHASE_IDLE) && !cdbufferb) + cdrom_buf_alloc(dev, dev->cdb_len); + + cdbufferw = (uint16_t *) cdbufferb; + cdbufferl = (uint32_t *) cdbufferb; + + if (!cdbufferb) + return; + + switch(length) { + case 1: + cdbufferb[dev->pos] = val & 0xff; + dev->pos++; + dev->request_pos++; + break; + case 2: + cdbufferw[dev->pos >> 1] = val & 0xffff; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + cdbufferl[dev->pos >> 2] = val; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return; + } + + cdrom_log("CD-ROM %i: Write: %u\n", id, dev->pos); + if (dev->packet_status == CDROM_PHASE_DATA_OUT) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + cdrom_pio_request(dev, 1); + } + return; + } else if (dev->packet_status == CDROM_PHASE_IDLE) { + if (dev->pos >= dev->cdb_len) { + cdrom_log("CD-ROM %i: Write: %u > 12\n", id, dev->pos); + dev->pos=0; + dev->status = BUSY_STAT; + dev->packet_status = CDROM_PHASE_COMMAND; + timer_process(); + cdrom_phase_callback(dev); + timer_update_outstanding(); + } + return; + } +} + + /* Peform a master init on the entire module. */ void cdrom_global_init(void) { - int c; - /* Clear the global data. */ memset(cdrom, 0x00, sizeof(cdrom)); memset(cdrom_drives, 0x00, sizeof(cdrom_drives)); - /* Initialize the host devices, if any. */ - cdrom_init_host_drives(); - /* Set all drives to NULL mode. */ - for (c=0; chandler and logging. */ + dev->id = c; + + cdrom_init(dev); + + if (dev->drv->host_drive == 200) { image_open(c, cdrom_image[c].image_path); image_reset(c); - } else if ((cdrom_drives[c].host_drive>='A') && (cdrom_drives[c].host_drive <= 'Z')) { - ioctl_open(c, cdrom_drives[c].host_drive); - ioctl_reset(c); } else - cdrom_null_open(c, cdrom_drives[c].host_drive); + cdrom_null_open(c); } + } - cdrom_mode_sense_load(c); + build_atapi_cdrom_map(); + + sound_cd_thread_reset(); +} + + +void +cdrom_close_handler(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + switch (dev->drv->host_drive) { + case 200: + image_close(id); + break; + default: + null_close(id); + break; } } void -cdrom_close(uint8_t id) +cdrom_close(void) { - switch (cdrom_drives[id].host_drive) { - case 0: - null_close(id); - break; - case 200: - image_close(id); - break; - default: - ioctl_close(id); - break; + cdrom_t *dev; + int c; + + for (c = 0; c < CDROM_NUM; c++) { + dev = cdrom[c]; + + if (dev) { + if (dev->drv && dev->handler) + cdrom_close_handler(c); + + free(cdrom[c]); + cdrom[c] = NULL; + } } } diff --git a/src/cdrom/cdrom.h b/src/cdrom/cdrom.h index 1a2607507..c0150e66b 100644 --- a/src/cdrom/cdrom.h +++ b/src/cdrom/cdrom.h @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)cdrom.h 1.0.10 2018/03/20 + * Version: @(#)cdrom.h 1.0.11 2018/03/26 * * Author: Miran Grca, * @@ -19,22 +19,22 @@ #define EMU_CDROM_H -#define CDROM_NUM 4 +#define CDROM_NUM 4 -#define CD_STATUS_EMPTY 0 -#define CD_STATUS_DATA_ONLY 1 -#define CD_STATUS_PLAYING 2 -#define CD_STATUS_PAUSED 3 -#define CD_STATUS_STOPPED 4 +#define CD_STATUS_EMPTY 0 +#define CD_STATUS_DATA_ONLY 1 +#define CD_STATUS_PLAYING 2 +#define CD_STATUS_PAUSED 3 +#define CD_STATUS_STOPPED 4 -#define CDROM_PHASE_IDLE 0 -#define CDROM_PHASE_COMMAND 1 -#define CDROM_PHASE_COMPLETE 2 -#define CDROM_PHASE_DATA_IN 3 -#define CDROM_PHASE_DATA_IN_DMA 4 -#define CDROM_PHASE_DATA_OUT 5 -#define CDROM_PHASE_DATA_OUT_DMA 6 -#define CDROM_PHASE_ERROR 0x80 +#define CDROM_PHASE_IDLE 0x00 +#define CDROM_PHASE_COMMAND 0x01 +#define CDROM_PHASE_COMPLETE 0x02 +#define CDROM_PHASE_DATA_IN 0x03 +#define CDROM_PHASE_DATA_IN_DMA 0x04 +#define CDROM_PHASE_DATA_OUT 0x05 +#define CDROM_PHASE_DATA_OUT_DMA 0x06 +#define CDROM_PHASE_ERROR 0x80 #define BUF_SIZE 32768 @@ -46,177 +46,106 @@ enum { CDROM_BUS_DISABLED = 0, - CDROM_BUS_ATAPI_PIO_ONLY = 4, - CDROM_BUS_ATAPI_PIO_AND_DMA, + CDROM_BUS_ATAPI = 4, CDROM_BUS_SCSI, - CDROM_BUS_USB = 8 + CDROM_BUS_USB }; typedef struct { - int (*ready)(uint8_t id); - int (*medium_changed)(uint8_t id); - int (*media_type_id)(uint8_t id); + int (*ready)(uint8_t id); + int (*medium_changed)(uint8_t id); + int (*media_type_id)(uint8_t id); - void (*audio_callback)(uint8_t id, int16_t *output, int len); - void (*audio_stop)(uint8_t id); - int (*readtoc)(uint8_t id, uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); - int (*readtoc_session)(uint8_t id, uint8_t *b, int msf, int maxlen); - int (*readtoc_raw)(uint8_t id, uint8_t *b, int maxlen); - uint8_t (*getcurrentsubchannel)(uint8_t id, uint8_t *b, int msf); - int (*pass_through)(uint8_t id, uint8_t *in_cdb, uint8_t *b, uint32_t *len); - int (*readsector_raw)(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len); - void (*playaudio)(uint8_t id, uint32_t pos, uint32_t len, int ismsf); - void (*load)(uint8_t id); - void (*eject)(uint8_t id); - void (*pause)(uint8_t id); - void (*resume)(uint8_t id); - uint32_t (*size)(uint8_t id); - int (*status)(uint8_t id); - int (*is_track_audio)(uint8_t id, uint32_t pos, int ismsf); - void (*stop)(uint8_t id); - void (*exit)(uint8_t id); + int (*audio_callback)(uint8_t id, int16_t *output, int len); + void (*audio_stop)(uint8_t id); + int (*readtoc)(uint8_t id, uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); + int (*readtoc_session)(uint8_t id, uint8_t *b, int msf, int maxlen); + int (*readtoc_raw)(uint8_t id, uint8_t *b, int maxlen); + uint8_t (*getcurrentsubchannel)(uint8_t id, uint8_t *b, int msf); + int (*readsector_raw)(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len); + uint8_t (*playaudio)(uint8_t id, uint32_t pos, uint32_t len, int ismsf); + void (*pause)(uint8_t id); + void (*resume)(uint8_t id); + uint32_t (*size)(uint8_t id); + int (*status)(uint8_t id); + void (*stop)(uint8_t id); + void (*exit)(uint8_t id); } CDROM; typedef struct { - uint8_t previous_command; + int host_drive; + int prev_host_drive; - int toctimes; - int media_status; + unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ - int is_dma; + uint8_t speed, ide_channel, + bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ - int requested_blocks; /* This will be set to something other than 1 when block reads are implemented. */ - - uint64_t current_page_code; - int current_page_len; - - int current_page_pos; - - int mode_select_phase; - - int total_length; - int written_length; - - int do_page_save; - - uint8_t error; - uint8_t features; - uint16_t request_length; - uint16_t max_transfer_len; - uint8_t status; - uint8_t phase; - - uint32_t sector_pos; - uint32_t sector_len; - - uint32_t packet_len; - int packet_status; - - uint8_t atapi_cdb[16]; - uint8_t current_cdb[16]; - - uint32_t pos; - - int callback; - - int data_pos; - uint32_t seek_diff; - - int cdb_len_setting; - int cdb_len; - - int cd_status; - int prev_status; - - int unit_attention; - uint8_t sense[256]; - - int request_pos; - - uint8_t *buffer; - - int times; - - uint32_t seek_pos; - - int total_read; - - int block_total; - int all_blocks_total; - - int old_len; - int block_descriptor_len; - - int init_length; - - int16_t cd_buffer[BUF_SIZE]; - - uint8_t rcbuf[16]; - uint8_t sub_q_data_format[16]; - uint8_t sub_q_channel_data[256]; - int last_subchannel_pos; - - uint32_t cd_end; - uint32_t cdrom_capacity; - - int cd_buflen; - int cd_state; - - int handler_inited; - int disc_changed; - - int cur_speed; -} cdrom_t; - -typedef struct { - CDROM *handler; - - int host_drive; - int prev_host_drive; - - unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ - uint8_t bus_mode; /* Bit 0 = PIO suported; - Bit 1 = DMA supportd. */ - - uint8_t ide_channel; - - unsigned int scsi_device_id; - unsigned int scsi_device_lun; - - unsigned int sound_on; - unsigned int atapi_dma; - - uint8_t speed; + unsigned int scsi_device_id, scsi_device_lun, + sound_on; } cdrom_drive_t; typedef struct { - int image_is_iso; - wchar_t image_path[1024]; - wchar_t *prev_image_path; - FILE* image; -} cdrom_image_t; + mode_sense_pages_t ms_pages_saved; + + CDROM *handler; + cdrom_drive_t *drv; + + uint8_t previous_command, + error, features, + status, phase, + id, *buffer, + atapi_cdb[16], + current_cdb[16], + sense[256]; + + uint16_t request_length, max_transfer_len; + int16_t cd_buffer[BUF_SIZE]; + + int media_status, is_dma, + packet_status, requested_blocks, + current_page_len, current_page_pos, + mode_select_phase, do_page_save, + total_length, written_length, + callback, data_pos, + cd_status, prev_status, + unit_attention, request_pos, + total_read, cur_speed, + block_total, all_blocks_total, + old_len, block_descriptor_len, + init_length, last_subchannel_pos, + cd_buflen, cd_state, + handler_inited, disc_changed; + + uint32_t sector_pos, sector_len, + seek_pos, seek_diff, + pos, packet_len, + cdb_len, cd_end, + cdrom_capacity; + + uint64_t current_page_code; +} cdrom_t; typedef struct { - char ioctl_path[8]; - int actual_requested_blocks; - int last_track_pos; - int last_track_nr; - int capacity_read; -} cdrom_ioctl_t; + int image_is_iso; + wchar_t image_path[1024], + *prev_image_path; + FILE* image; +} cdrom_image_t; extern cdrom_t *cdrom[CDROM_NUM]; extern cdrom_drive_t cdrom_drives[CDROM_NUM]; extern cdrom_image_t cdrom_image[CDROM_NUM]; -extern cdrom_ioctl_t cdrom_ioctl[CDROM_NUM]; extern uint8_t atapi_cdrom_drives[8]; extern uint8_t scsi_cdrom_drives[16][8]; -#define cdrom_sense_error cdrom[id]->sense[0] -#define cdrom_sense_key cdrom[id]->sense[2] -#define cdrom_asc cdrom[id]->sense[12] -#define cdrom_ascq cdrom[id]->sense[13] +#define cdrom_sense_error dev->sense[0] +#define cdrom_sense_key dev->sense[2] +#define cdrom_asc dev->sense[12] +#define cdrom_ascq dev->sense[13] #define cdrom_drive cdrom_drives[id].host_drive @@ -224,35 +153,34 @@ extern uint8_t scsi_cdrom_drives[16][8]; extern "C" { #endif -extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length); -extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length); -extern void (*ide_bus_master_set_irq)(int channel); -extern void ioctl_close(uint8_t id); +extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +extern void (*ide_bus_master_set_irq)(int channel, void *priv); +extern void *ide_bus_master_priv[2]; -extern uint32_t cdrom_mode_sense_get_channel(uint8_t id, int channel); -extern uint32_t cdrom_mode_sense_get_volume(uint8_t id, int channel); +extern uint32_t cdrom_mode_sense_get_channel(cdrom_t *dev, int channel); +extern uint32_t cdrom_mode_sense_get_volume(cdrom_t *dev, int channel); extern void build_atapi_cdrom_map(void); extern void build_scsi_cdrom_map(void); -extern int cdrom_CDROM_PHASE_to_scsi(uint8_t id); -extern int cdrom_atapi_phase_to_scsi(uint8_t id); -extern void cdrom_command(uint8_t id, uint8_t *cdb); -extern void cdrom_phase_callback(uint8_t id); +extern int cdrom_CDROM_PHASE_to_scsi(cdrom_t *dev); +extern int cdrom_atapi_phase_to_scsi(cdrom_t *dev); +extern void cdrom_command(cdrom_t *dev, uint8_t *cdb); +extern void cdrom_phase_callback(cdrom_t *dev); extern uint32_t cdrom_read(uint8_t channel, int length); extern void cdrom_write(uint8_t channel, uint32_t val, int length); extern int cdrom_lba_to_msf_accurate(int lba); -extern void cdrom_destroy_drives(void); -extern void cdrom_close(uint8_t id); -extern void cdrom_reset(uint8_t id); -extern void cdrom_set_signature(int id); -extern void cdrom_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length); +extern void cdrom_close_handler(uint8_t id); +extern void cdrom_close(void); +extern void cdrom_reset(cdrom_t *dev); +extern void cdrom_set_signature(cdrom_t *dev); +extern void cdrom_request_sense_for_scsi(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length); extern void cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks); -extern void cdrom_insert(uint8_t id); -extern void cdrom_new_image(uint8_t id); +extern void cdrom_insert(cdrom_t *dev); extern int find_cdrom_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun); -extern int cdrom_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len); +extern int cdrom_read_capacity(cdrom_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); extern void cdrom_global_init(void); extern void cdrom_global_reset(void); diff --git a/src/cdrom/cdrom_dosbox.cpp b/src/cdrom/cdrom_dosbox.cpp index 7fffa01b9..0408be688 100644 --- a/src/cdrom/cdrom_dosbox.cpp +++ b/src/cdrom/cdrom_dosbox.cpp @@ -87,12 +87,12 @@ uint64_t CDROM_Interface_Image::BinaryFile::getLength() CDROM_Interface_Image::CDROM_Interface_Image() { - printf("CDROM_Interface_Image constructor\n"); + // printf("CDROM_Interface_Image constructor\n"); } CDROM_Interface_Image::~CDROM_Interface_Image() { - printf("CDROM_Interface_Image destructor\n"); + // printf("CDROM_Interface_Image destructor\n"); ClearTracks(); } @@ -263,7 +263,7 @@ bool CDROM_Interface_Image::LoadIsoFile(char* filename) tracks.clear(); // data track - Track track = {0, 0, 0, 0, 0, 0, 0, false, NULL}; + Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL}; bool error; track.file = new BinaryFile(filename, error); if (error) { @@ -343,7 +343,7 @@ static string dirname(char * file) { bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) { - Track track = {0, 0, 0, 0, 0, 0, 0, false, NULL}; + Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL}; tracks.clear(); uint64_t shift = 0; uint64_t currPregap = 0; @@ -357,7 +357,6 @@ bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) ifstream in; in.open(cuefile, ios::in); if (in.fail()) return false; - int last_attr; while(!in.eof()) { // get next line @@ -429,7 +428,6 @@ bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) track.attr = DATA_TRACK; track.mode2 = true; } else success = false; - last_attr = track.attr; canAddTrack = true; } diff --git a/src/cdrom/cdrom_image.cc b/src/cdrom/cdrom_image.cc index 6a7c74e8c..c1a301ba6 100644 --- a/src/cdrom/cdrom_image.cc +++ b/src/cdrom/cdrom_image.cc @@ -1,8 +1,23 @@ -/* Copyright holders: RichardG867, Tenshi, bit - see COPYING for more details -*/ -/*CD-ROM image support*/ - +/* + * 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. + * + * CD-ROM image support. + * + * Version: @(#)cdrom_image.cc 1.0.0 2018/03/29 + * + * Author: RichardG867, + * Miran Grca, + * bit, + * + * Copyright 2015-2018 Richardg867. + * Copyright 2015-2018 Miran Grca. + * Copyright 2017,2018 bit. + */ #define __USE_LARGEFILE64 #define _LARGEFILE_SOURCE #define _LARGEFILE64_SOURCE @@ -14,6 +29,7 @@ #include #include "../config.h" #include "../plat.h" +#include "../scsi/scsi.h" #include "cdrom_dosbox.h" #include "cdrom.h" #include "cdrom_image.h" @@ -28,381 +44,55 @@ /* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start of the audio while audio still plays. With an absolute conversion, the counter is fine. */ -#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) -extern CDROM image_cdrom; - -enum -{ - CD_STOPPED = 0, - CD_PLAYING, - CD_PAUSED -}; - -#ifdef ENABLE_CDROM_IMAGE_LOG -int cdrom_image_do_log = ENABLE_CDROM_IMAGE_LOG; -#endif - -CDROM_Interface_Image* cdimg[CDROM_NUM] = { NULL, NULL, NULL, NULL }; - - -void cdrom_image_log(const char *format, ...) -{ -#ifdef ENABLE_CDROM_IMAGE_LOG - if (cdrom_image_do_log) - { - va_list ap; - va_start(ap, format); - vprintf(format, ap); - va_end(ap); - fflush(stdout); - } -/* #else - (void)format; */ -#endif -} - -void image_close(uint8_t id); - -void image_audio_callback(uint8_t id, int16_t *output, int len) -{ - cdrom_t *dev = cdrom[id]; - - if (!cdrom_drives[id].sound_on || (dev->cd_state != CD_PLAYING) || cdrom_image[id].image_is_iso) - { - cdrom_image_log("image_audio_callback(i): Not playing\n", id); - if (dev->cd_state == CD_PLAYING) - { - dev->seek_pos += (len >> 11); - } - memset(output, 0, len * 2); - return; - } - while (dev->cd_buflen < len) - { - if (dev->seek_pos < dev->cd_end) - { - if (!cdimg[id]->ReadSector((unsigned char*)&dev->cd_buffer[dev->cd_buflen], true, dev->seek_pos)) - { - memset(&dev->cd_buffer[dev->cd_buflen], 0, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_state = CD_STOPPED; - dev->cd_buflen = len; - } - else - { - dev->seek_pos++; - dev->cd_buflen += (RAW_SECTOR_SIZE / 2); - } - } - else - { - memset(&dev->cd_buffer[dev->cd_buflen], 0, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_state = CD_STOPPED; - dev->cd_buflen = len; - } - } - memcpy(output, dev->cd_buffer, len * 2); - memmove(dev->cd_buffer, &dev->cd_buffer[len], (BUF_SIZE - len) * 2); - dev->cd_buflen -= len; -} - -void image_audio_stop(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - dev->cd_state = CD_STOPPED; -} - -static void image_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) -{ - cdrom_t *dev = cdrom[id]; - if (!cdimg[id]) return; - int number; - unsigned char attr; - TMSF tmsf; - int m = 0, s = 0, f = 0; - cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); - if (attr == DATA_TRACK) - { - cdrom_image_log("Can't play data track\n"); - dev->seek_pos = 0; - dev->cd_state = CD_STOPPED; - return; - } - cdrom_image_log("Play audio - %08X %08X %i\n", pos, len, ismsf); - if (ismsf == 2) - { - cdimg[id]->GetAudioTrackInfo(pos, number, tmsf, attr); - pos = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; - cdimg[id]->GetAudioTrackInfo(len, number, tmsf, attr); - len = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; - } - else if (ismsf == 1) - { - m = (pos >> 16) & 0xff; - s = (pos >> 8) & 0xff; - f = pos & 0xff; - - if (pos == 0xffffff) - { - cdrom_image_log("Playing from current position (MSF)\n"); - pos = dev->seek_pos; - } - else - { - pos = MSFtoLBA(m, s, f) - 150; - } - - m = (len >> 16) & 0xff; - s = (len >> 8) & 0xff; - f = len & 0xff; - len = MSFtoLBA(m, s, f) - 150; - - cdrom_image_log("MSF - pos = %08X len = %08X\n", pos, len); - } - else if (ismsf == 0) - { - if (pos == 0xffffffff) - { - cdrom_image_log("Playing from current position\n"); - pos = dev->seek_pos; - } - len += pos; - } - dev->seek_pos = pos; - dev->cd_end = len; - dev->cd_state = CD_PLAYING; - dev->cd_buflen = 0; -} - -static void image_pause(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (!cdimg[id] || cdrom_image[id].image_is_iso) return; - if (dev->cd_state == CD_PLAYING) - dev->cd_state = CD_PAUSED; -} - -static void image_resume(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (!cdimg[id] || cdrom_image[id].image_is_iso) return; - if (dev->cd_state == CD_PAUSED) - dev->cd_state = CD_PLAYING; -} - -static void image_stop(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (!cdimg[id] || cdrom_image[id].image_is_iso) return; - dev->cd_state = CD_STOPPED; -} - -static int image_ready(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (!cdimg[id]) - return 0; - - if (wcslen(cdrom_image[id].image_path) == 0) - return 0; - - if (cdrom_drives[id].prev_host_drive != cdrom_drives[id].host_drive) - { - return 1; - } - - return 1; -} - -static int image_get_last_block(uint8_t id, UNUSED(uint8_t starttrack), UNUSED(int msf), UNUSED(int maxlen), UNUSED(int single)) -{ - int c; - uint32_t lb=0; - - if (!cdimg[id]) return 0; - - int first_track; - int last_track; - int number; - unsigned char attr; - TMSF tmsf; - cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); - - for (c = 0; c <= last_track; c++) - { - uint32_t address; - cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); - address = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150 here as well. */ - if (address > lb) - lb = address; - } - return lb; -} - -static int image_medium_changed(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (!cdimg[id]) - return 0; - - if (wcslen(cdrom_image[id].image_path) == 0) - { - return 0; - } - - if (cdrom_drives[id].prev_host_drive != cdrom_drives[id].host_drive) - { - cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; - return 1; - } - - return 0; -} - -static uint8_t image_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) -{ - cdrom_t *dev = cdrom[id]; - if (!cdimg[id]) return 0; - uint8_t ret; - int pos=0; - - uint32_t cdpos = dev->seek_pos; - TMSF relPos, absPos; - unsigned char attr, track, index; - cdimg[id]->GetAudioSub(cdpos, attr, track, index, relPos, absPos); - - if (cdrom_image[id].image_is_iso) - { - ret = 0x15; - } - else - { - if (dev->cd_state == CD_PLAYING) - ret = 0x11; - else if (dev->cd_state == CD_PAUSED) - ret = 0x12; - else - ret = 0x13; - } - - b[pos++] = attr; - b[pos++] = track; - b[pos++] = index; - - if (msf) - { - b[pos + 3] = (uint8_t) absPos.fr; - b[pos + 2] = (uint8_t) absPos.sec; - b[pos + 1] = (uint8_t) absPos.min; - b[pos] = 0; - pos += 4; - b[pos + 3] = (uint8_t) relPos.fr; - b[pos + 2] = (uint8_t) relPos.sec; - b[pos + 1] = (uint8_t) relPos.min; - b[pos] = 0; - pos += 4; - } - else - { - uint32_t dat = MSFtoLBA(absPos.min, absPos.sec, absPos.fr) - 150; - b[pos++] = (dat >> 24) & 0xff; - b[pos++] = (dat >> 16) & 0xff; - b[pos++] = (dat >> 8) & 0xff; - b[pos++] = dat & 0xff; - dat = MSFtoLBA(relPos.min, relPos.sec, relPos.fr); - b[pos++] = (dat >> 24) & 0xff; - b[pos++] = (dat >> 16) & 0xff; - b[pos++] = (dat >> 8) & 0xff; - b[pos++] = dat & 0xff; - } - - return ret; -} - -static void image_eject(UNUSED(uint8_t id)) -{ - return; -} - -static void image_load(UNUSED(uint8_t id)) -{ - return; -} - -static int image_is_track_audio(uint8_t id, uint32_t pos, int ismsf) -{ - int m, s, f; - unsigned char attr; - TMSF tmsf; - int number; - - if (!cdimg[id] || cdrom_image[id].image_is_iso) return 0; - - if (ismsf) - { - m = (pos >> 16) & 0xff; - s = (pos >> 8) & 0xff; - f = pos & 0xff; - pos = MSFtoLBA(m, s, f) - 150; - } - - /* GetTrack requires LBA. */ - cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); - - return attr == AUDIO_TRACK; -} +extern CDROM image_cdrom; typedef struct __attribute__((__packed__)) { - uint8_t user_data[2048]; - uint8_t ecc[288]; + uint8_t user_data[2048], + ecc[288]; } m1_data_t; typedef struct __attribute__((__packed__)) { - uint8_t sub_header[8]; - uint8_t user_data[2328]; + uint8_t sub_header[8], + user_data[2328]; } m2_data_t; typedef union __attribute__((__packed__)) { - m1_data_t m1_data; - m2_data_t m2_data; - uint8_t raw_data[2336]; + m1_data_t m1_data; + m2_data_t m2_data; + uint8_t raw_data[2336]; } sector_data_t; typedef struct __attribute__((__packed__)) { - uint8_t sync[12]; - uint8_t header[4]; - sector_data_t data; + uint8_t sync[12]; + uint8_t header[4]; + sector_data_t data; } sector_raw_data_t; typedef union __attribute__((__packed__)) { - sector_raw_data_t sector_data; - uint8_t raw_data[2352]; + sector_raw_data_t sector_data; + uint8_t raw_data[2352]; } sector_t; typedef struct __attribute__((__packed__)) { - sector_t sector; - uint8_t c2[296]; - uint8_t subchannel_raw[96]; - uint8_t subchannel_q[16]; - uint8_t subchannel_rw[96]; + sector_t sector; + uint8_t c2[296]; + uint8_t subchannel_raw[96]; + uint8_t subchannel_q[16]; + uint8_t subchannel_rw[96]; } cdrom_sector_t; typedef union __attribute__((__packed__)) { - cdrom_sector_t cdrom_sector; - uint8_t buffer[2856]; + cdrom_sector_t cdrom_sector; + uint8_t buffer[2856]; } sector_buffer_t; sector_buffer_t cdrom_sector_buffer; @@ -411,717 +101,1007 @@ int cdrom_sector_size; uint8_t raw_buffer[2448]; uint8_t extra_buffer[296]; -static int is_legal(int id, int cdrom_sector_type, int cdrom_sector_flags, int audio, int mode2, int form) +enum { - if (!(cdrom_sector_flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); - return 0; - } + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; - if ((cdrom_sector_type != 1) && !audio) - { - if (!(cdrom_sector_flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any Data Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); - return 0; - } - if ((cdrom_sector_flags & 0x06) == 0x06) { - cdrom_image_log("CD-ROM %i: [Any Data Mode] Invalid error flags\n", id); - return 0; - } +#ifdef ENABLE_CDROM_IMAGE_LOG +int cdrom_image_do_log = ENABLE_CDROM_IMAGE_LOG; +#endif - if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) { - cdrom_image_log("CD-ROM %i: [Any Data Mode] Invalid subchannel data flags (%02X)\n", id, cdrom_sector_flags & 0x700); - return 0; - } - if ((cdrom_sector_flags & 0x18) == 0x08) { /* EDC/ECC without user data is an illegal mode */ - cdrom_image_log("CD-ROM %i: [Any Data Mode] EDC/ECC without user data is an illegal mode\n", id); - return 0; - } +static CDROM_Interface_Image* cdimg[CDROM_NUM] = { NULL, NULL, NULL, NULL }; +static char afn[1024]; - if (((cdrom_sector_flags & 0xf0) == 0x90) || ((cdrom_sector_flags & 0xf0) == 0xc0)) { /* 0x90/0x98/0xC0/0xC8 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any Data Mode] 0x90/0x98/0xC0/0xC8 are illegal modes\n", id); - return 0; - } +void image_close(uint8_t id); - if (((cdrom_sector_type > 3) && (cdrom_sector_type != 8)) || (mode2 && form)) - { - if ((cdrom_sector_flags & 0xf0) == 0x30) { /* 0x30/0x38 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any XA Mode 2] 0x30/0x38 are illegal modes\n", id); - return 0; - } - if (((cdrom_sector_flags & 0xf0) == 0xb0) || ((cdrom_sector_flags & 0xf0) == 0xd0)) { /* 0xBx and 0xDx are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any XA Mode 2] 0xBx and 0xDx are illegal modes\n", id); - return 0; - } - } - } - return 1; +void +cdrom_image_log(const char *format, ...) +{ +#ifdef ENABLE_CDROM_IMAGE_LOG + if (cdrom_image_do_log) { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif } -static void read_sector_to_buffer(uint8_t id, uint8_t *raw_buffer, uint32_t msf, uint32_t lba, int mode2, int form, int len) + +int +image_audio_callback(uint8_t id, int16_t *output, int len) { - cdimg[id]->ReadSector(raw_buffer + 16, false, lba); + cdrom_t *dev = cdrom[id]; + int ret = 1; - uint8_t *bb = raw_buffer; - - /* sync bytes */ - bb[0] = 0; - memset(bb + 1, 0xff, 10); - bb[11] = 0; - bb += 12; - - bb[0] = (msf >> 16) & 0xff; - bb[1] = (msf >> 8) & 0xff; - bb[2] = msf & 0xff; - - bb[3] = 1; /* mode 1 data */ - bb += mode2 ? 12 : 4; - bb += len; - if (mode2 && (form == 1)) - memset(bb, 0, 280); - else if (!mode2) - memset(bb, 0, 288); -} - -static int image_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len) -{ - uint8_t *b; - uint8_t *temp_b; - uint32_t msf; - uint32_t lba; - int audio; - int mode2; - int m, s, f; - int form; - - if (!cdimg[id]) - return 0; - - if (!cdrom_drives[id].host_drive) - return 0; - - b = temp_b = buffer; - - *len = 0; - - if (ismsf) { - m = (sector >> 16) & 0xff; - s = (sector >> 8) & 0xff; - f = sector & 0xff; - lba = MSFtoLBA(m, s, f) - 150; - msf = sector; - } else { - lba = sector; - msf = cdrom_lba_to_msf_accurate(sector); - } - - if (cdrom_image[id].image_is_iso) { - audio = 0; - mode2 = cdimg[id]->IsMode2(lba) ? 1 : 0; - } else { - audio = image_is_track_audio(id, sector, ismsf); - mode2 = cdimg[id]->IsMode2(lba) ? 1 : 0; - } - form = cdimg[id]->GetMode2Form(lba); - - memset(raw_buffer, 0, 2448); - memset(extra_buffer, 0, 296); - - if (!(cdrom_sector_flags & 0xf0)) { /* 0x00 and 0x08 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Mode 1] 0x00 and 0x08 are illegal modes\n", id); - return 0; - } - - if ((cdrom_sector_type == 3) || ((cdrom_sector_type > 4) && (cdrom_sector_type != 8))) { - if (cdrom_sector_type == 3) - cdrom_image_log("CD-ROM %i: Attempting to read a Yellowbook Mode 2 data sector from an image\n", id); - if (cdrom_sector_type > 4) - cdrom_image_log("CD-ROM %i: Attempting to read a XA Mode 2 Form 2 data sector from an image\n", id); - return 0; - } - else if (cdrom_sector_type == 1) { - if (!audio || cdrom_image[id].image_is_iso) { - cdrom_image_log("CD-ROM %i: [Audio] Attempting to read an audio sector from a data image\n", id); - return 0; - } - -read_audio: - if (!is_legal(id, cdrom_sector_type, cdrom_sector_flags, audio, mode2, form)) - return 0; - - if (cdimg[id]->GetSectorSize(lba) == 2352) - cdimg[id]->ReadSector(raw_buffer, true, lba); - else - cdimg[id]->ReadSectorSub(raw_buffer, lba); - - memcpy(temp_b, raw_buffer, 2352); - cdrom_sector_size = 2352; - } else if (cdrom_sector_type == 2) { - if (audio || mode2) { - cdrom_image_log("CD-ROM %i: [Mode 1] Attempting to read a sector of another type\n", id); - return 0; - } - -read_mode1: - if (!is_legal(id, cdrom_sector_type, cdrom_sector_flags, audio, mode2, form)) - return 0; - - if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2048)) - read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, form, 2048); - else if (cdimg[id]->GetSectorSize(lba) == 2352) - cdimg[id]->ReadSector(raw_buffer, true, lba); - else - cdimg[id]->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_log("CD-ROM %i: [Mode 1] Sync\n", id); - memcpy(temp_b, raw_buffer, 12); - cdrom_sector_size += 12; - temp_b += 12; - } - - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_image_log("CD-ROM %i: [Mode 1] Header\n", id); - memcpy(temp_b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - temp_b += 4; - } - - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - if (!(cdrom_sector_flags & 0x10)) { /* No user data */ - cdrom_image_log("CD-ROM %i: [Mode 1] Sub-header\n", id); - memcpy(temp_b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - } - - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_image_log("CD-ROM %i: [Mode 1] User data\n", id); - memcpy(temp_b, raw_buffer + 16, 2048); - cdrom_sector_size += 2048; - temp_b += 2048; - } - - if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ - cdrom_image_log("CD-ROM %i: [Mode 1] EDC/ECC\n", id); - memcpy(temp_b, raw_buffer + 2064, 288); - cdrom_sector_size += 288; - temp_b += 288; - } - } else if (cdrom_sector_type == 3) { - if (audio || !mode2 || form) { - cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Attempting to read a sector of another type\n", id); - return 0; - } - -read_mode2_non_xa: - if (!is_legal(id, cdrom_sector_type, cdrom_sector_flags, audio, mode2, form)) - return 0; - - if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2336)) - read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, form, 2336); - else if (cdimg[id]->GetSectorSize(lba) == 2352) - cdimg[id]->ReadSector(raw_buffer, true, lba); - else - cdimg[id]->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Sync\n", id); - memcpy(temp_b, raw_buffer, 12); - cdrom_sector_size += 12; - temp_b += 12; - } - - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Header\n", id); - memcpy(temp_b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - temp_b += 4; - } - - /* Mode 1 sector, expected type is 1 type. */ - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Sub-header\n", id); - memcpy(temp_b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_image_log("CD-ROM %i: [Mode 2 Formless] User data\n", id); - memcpy(temp_b, raw_buffer + 24, 2336); - cdrom_sector_size += 2336; - temp_b += 2336; - } - } else if (cdrom_sector_type == 4) { - if (audio || !mode2 || (form != 1)) { - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Attempting to read a sector of another type\n", id); - return 0; - } - -read_mode2_xa_form1: - if (!is_legal(id, cdrom_sector_type, cdrom_sector_flags, audio, mode2, form)) - return 0; - - if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2048)) - read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, form, 2048); - else if (cdimg[id]->GetSectorSize(lba) == 2352) - cdimg[id]->ReadSector(raw_buffer, true, lba); - else - cdimg[id]->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sync\n", id); - memcpy(temp_b, raw_buffer, 12); - cdrom_sector_size += 12; - temp_b += 12; - } - - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Header\n", id); - memcpy(temp_b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - temp_b += 4; - } - - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sub-header\n", id); - memcpy(temp_b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] User data\n", id); - memcpy(temp_b, raw_buffer + 24, 2048); - cdrom_sector_size += 2048; - temp_b += 2048; - } - - if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC\n", id); - memcpy(temp_b, raw_buffer + 2072, 280); - cdrom_sector_size += 280; - temp_b += 280; - } - } else if (cdrom_sector_type == 5) { - if (audio || !mode2 || (form != 2)) { - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Attempting to read a sector of another type\n", id); - return 0; - } - -read_mode2_xa_form2: - if (!is_legal(id, cdrom_sector_type, cdrom_sector_flags, audio, mode2, form)) - return 0; - - if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2324)) - read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, form, 2324); - else if (cdimg[id]->GetSectorSize(lba) == 2352) - cdimg[id]->ReadSector(raw_buffer, true, lba); - else - cdimg[id]->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Sync\n", id); - memcpy(temp_b, raw_buffer, 12); - cdrom_sector_size += 12; - temp_b += 12; - } - - if (cdrom_sector_flags & 0x20) { /* Header */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Header\n", id); - memcpy(temp_b, raw_buffer + 12, 4); - cdrom_sector_size += 4; - temp_b += 4; - } - - if (cdrom_sector_flags & 0x40) { /* Sub-header */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Sub-header\n", id); - memcpy(temp_b, raw_buffer + 16, 8); - cdrom_sector_size += 8; - temp_b += 8; - } - - if (cdrom_sector_flags & 0x10) { /* User data */ - cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] User data\n", id); - memcpy(temp_b, raw_buffer + 24, 2328); - cdrom_sector_size += 2328; - temp_b += 2328; - } - } else if (cdrom_sector_type == 8) { - if (audio) { - cdrom_image_log("CD-ROM %i: [Any Data] Attempting to read a data sector from an audio track\n", id); - return 0; - } - - if (mode2 && (form == 1)) - goto read_mode2_xa_form1; - else if (!mode2) - goto read_mode1; - else { - cdrom_image_log("CD-ROM %i: [Any Data] Attempting to read a data sector whose cooked size is not 2048 bytes\n", id); - return 0; + if (!cdrom_drives[id].sound_on || (dev->cd_state != CD_PLAYING) || cdrom_image[id].image_is_iso) { + cdrom_image_log("image_audio_callback(i): Not playing\n", id); + if (dev->cd_state == CD_PLAYING) + dev->seek_pos += (len >> 11); + memset(output, 0, len * 2); + return 0; + } + while (dev->cd_buflen < len) { + if (dev->seek_pos < dev->cd_end) { + if (!cdimg[id]->ReadSector((unsigned char*)&dev->cd_buffer[dev->cd_buflen], true, + dev->seek_pos)) { + memset(&dev->cd_buffer[dev->cd_buflen], 0, (BUF_SIZE - dev->cd_buflen) * 2); + dev->cd_state = CD_STOPPED; + dev->cd_buflen = len; + ret = 0; + } else { + dev->seek_pos++; + dev->cd_buflen += (RAW_SECTOR_SIZE / 2); + ret = 1; } } else { - if (mode2) - if (form == 1) - goto read_mode2_xa_form1; - else if (form == 2) - goto read_mode2_xa_form2; - else - goto read_mode2_non_xa; - else { - if (audio) - goto read_audio; - else - goto read_mode1; - } + memset(&dev->cd_buffer[dev->cd_buflen], 0, (BUF_SIZE - dev->cd_buflen) * 2); + dev->cd_state = CD_STOPPED; + dev->cd_buflen = len; + ret = 0; } + } - if ((cdrom_sector_flags & 0x06) == 0x02) { - /* Add error flags. */ - cdrom_image_log("CD-ROM %i: Error flags\n", id); - memcpy(b + cdrom_sector_size, extra_buffer, 294); - cdrom_sector_size += 294; - } - else if ((cdrom_sector_flags & 0x06) == 0x04) { - /* Add error flags. */ - cdrom_image_log("CD-ROM %i: Full error flags\n", id); - memcpy(b + cdrom_sector_size, extra_buffer, 296); - cdrom_sector_size += 296; - } - - if ((cdrom_sector_flags & 0x700) == 0x100) { - cdrom_image_log("CD-ROM %i: Raw subchannel data\n", id); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); - cdrom_sector_size += 96; - } - else if ((cdrom_sector_flags & 0x700) == 0x200) { - cdrom_image_log("CD-ROM %i: Q subchannel data\n", id); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 16); - cdrom_sector_size += 16; - } - else if ((cdrom_sector_flags & 0x700) == 0x400) { - cdrom_image_log("CD-ROM %i: R/W subchannel data\n", id); - memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); - cdrom_sector_size += 96; - } - - *len = cdrom_sector_size; - - return 1; + memcpy(output, dev->cd_buffer, len * 2); + memmove(dev->cd_buffer, &dev->cd_buffer[len], (BUF_SIZE - len) * 2); + dev->cd_buflen -= len; + return ret; } -static uint32_t image_size(uint8_t id) +void +image_audio_stop(uint8_t id) { - cdrom_t *dev = cdrom[id]; + cdrom_t *dev = cdrom[id]; - return dev->cdrom_capacity; + dev->cd_state = CD_STOPPED; } -static int image_readtoc(uint8_t id, unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) + +static uint8_t +image_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) { - if (!cdimg[id]) return 0; - int len=4; - int c,d; - uint32_t temp; - - int first_track; - int last_track; - int number; - unsigned char attr; - TMSF tmsf; - - cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); - - b[2] = first_track; - b[3] = last_track; - - d = 0; - for (c = 0; c <= last_track; c++) - { - cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); - if (number >= starttrack) - { - d=c; - break; - } - } - - if (starttrack != 0xAA) - { - cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); - b[2] = number; - } - - for (c = d; c <= last_track; c++) - { - if ((len + 8) > maxlen) - break; - cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); - - b[len++] = 0; /* reserved */ - b[len++] = attr; - b[len++] = number; /* track number */ - b[len++] = 0; /* reserved */ - - if (msf) - { - b[len++] = 0; - b[len++] = tmsf.min; - b[len++] = tmsf.sec; - b[len++] = tmsf.fr; - } - else - { - temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; - b[len++] = temp >> 24; - b[len++] = temp >> 16; - b[len++] = temp >> 8; - b[len++] = temp; - } - if (single) - break; - } - b[0] = (uint8_t)(((len-2) >> 8) & 0xff); - b[1] = (uint8_t)((len-2) & 0xff); - return len; -} - -static int image_readtoc_session(uint8_t id, unsigned char *b, int msf, int maxlen) -{ - int len = 4; - - int number; - TMSF tmsf; - unsigned char attr; - - if (!cdimg[id]) return 0; - - cdimg[id]->GetAudioTrackInfo(1, number, tmsf, attr); - - if (number == 0) - { - number = 1; - } - - b[2] = 1; - b[3] = 1; - b[len++] = 0; /* reserved */ - b[len++] = attr; - b[len++] = number; /* track number */ - b[len++] = 0; /* reserved */ - if (msf) - { - b[len++] = 0; - b[len++] = tmsf.min; - b[len++] = tmsf.sec; - b[len++] = tmsf.fr; - } - else - { - uint32_t temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150. */ - b[len++] = temp >> 24; - b[len++] = temp >> 16; - b[len++] = temp >> 8; - b[len++] = temp; - } - - if (maxlen < len) - { - return maxlen; - } - - return len; -} - -static int image_readtoc_raw(uint8_t id, unsigned char *b, int maxlen) -{ - int track; - int len = 4; - - int first_track; - int last_track; - int number; - unsigned char attr; - TMSF tmsf; - - if (!cdimg[id]) return 0; - - cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); - - b[2] = first_track; - b[3] = last_track; - - for (track = first_track; track <= last_track; track++) - { - if ((len + 11) > maxlen) - { - cdrom_image_log("image_readtocraw: This iteration would fill the buffer beyond the bounds, aborting...\n"); - return len; - } - - cdimg[id]->GetAudioTrackInfo(track, number, tmsf, attr); - - b[len++] = track; - if (len == maxlen) return len; - b[len++]= attr; - if (len == maxlen) return len; - b[len++]=0; - if (len == maxlen) return len; - b[len++]=0; - if (len == maxlen) return len; - b[len++]=0; - if (len == maxlen) return len; - b[len++]=0; - if (len == maxlen) return len; - b[len++]=0; - if (len == maxlen) return len; - b[len++]=0; - if (len == maxlen) return len; - b[len++] = tmsf.min; - if (len == maxlen) return len; - b[len++] = tmsf.sec; - if (len == maxlen) return len; - b[len++] = tmsf.fr; - if (len == maxlen) return len; - } - return len; -} - -static int image_status(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - if (!cdimg[id]) return CD_STATUS_EMPTY; - if (cdrom_image[id].image_is_iso) return CD_STATUS_DATA_ONLY; - if (cdimg[id]->HasAudioTracks()) - { - switch(dev->cd_state) - { - case CD_PLAYING: - return CD_STATUS_PLAYING; - case CD_PAUSED: - return CD_STATUS_PAUSED; - case CD_STOPPED: - default: - return CD_STATUS_STOPPED; - } - } - return CD_STATUS_DATA_ONLY; -} - -void image_reset(UNUSED(uint8_t id)) -{ - return; -} - -void image_close(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - dev->cd_state = CD_STOPPED; - if (cdimg[id]) - { - delete cdimg[id]; - cdimg[id] = NULL; - } - memset(cdrom_image[id].image_path, 0, 2048); -} - -static char afn[1024]; - -int image_open(uint8_t id, wchar_t *fn) -{ - cdrom_t *dev = cdrom[id]; - - wcscpy(cdrom_image[id].image_path, fn); - - if (! wcscasecmp(plat_get_extension(fn), L"ISO")) - { - cdrom_image[id].image_is_iso = 1; - } - else - { - cdrom_image[id].image_is_iso = 0; - } - - cdimg[id] = new CDROM_Interface_Image(); - memset(afn, 0, sizeof(afn)); - wcstombs(afn, fn, sizeof(afn)); - if (!cdimg[id]->SetDevice(afn, false)) - { - image_close(id); - cdrom_set_null_handler(id); - return 1; - } - dev->cd_state = CD_STOPPED; + cdrom_t *dev = cdrom[id]; + if (!cdimg[id]) + return 0; + int number; + unsigned char attr; + TMSF tmsf; + int m = 0, s = 0, f = 0; + cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); + if (attr == DATA_TRACK) { + cdrom_image_log("Can't play data track\n"); dev->seek_pos = 0; - dev->cd_buflen = 0; - dev->cdrom_capacity = image_get_last_block(id, 0, 0, 4096, 0) + 1; - cdrom_drives[id].handler = &image_cdrom; + dev->cd_state = CD_STOPPED; + return 0; + } + cdrom_image_log("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf == 2) { + cdimg[id]->GetAudioTrackInfo(pos, number, tmsf, attr); + pos = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; + cdimg[id]->GetAudioTrackInfo(len, number, tmsf, attr); + len = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; + } else if (ismsf == 1) { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; - return 0; + if (pos == 0xffffff) { + cdrom_image_log("Playing from current position (MSF)\n"); + pos = dev->seek_pos; + } else + pos = MSFtoLBA(m, s, f) - 150; + + m = (len >> 16) & 0xff; + s = (len >> 8) & 0xff; + f = len & 0xff; + len = MSFtoLBA(m, s, f) - 150; + + cdrom_image_log("MSF - pos = %08X len = %08X\n", pos, len); + } else if (ismsf == 0) { + if (pos == 0xffffffff) { + cdrom_image_log("Playing from current position\n"); + pos = dev->seek_pos; + } + len += pos; + } + + dev->seek_pos = pos; + dev->cd_end = len; + dev->cd_state = CD_PLAYING; + dev->cd_buflen = 0; + + return 1; } -static void image_exit(uint8_t id) + +static void +image_pause(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + if (!cdimg[id] || cdrom_image[id].image_is_iso) return; + if (dev->cd_state == CD_PLAYING) + dev->cd_state = CD_PAUSED; +} + + +static void +image_resume(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + if (!cdimg[id] || cdrom_image[id].image_is_iso) + return; + if (dev->cd_state == CD_PAUSED) + dev->cd_state = CD_PLAYING; +} + + +static void +image_stop(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + if (!cdimg[id] || cdrom_image[id].image_is_iso) + return; + dev->cd_state = CD_STOPPED; +} + + +static int +image_ready(uint8_t id) +{ + if (!cdimg[id] || (wcslen(cdrom_image[id].image_path) == 0)) + return 0; + + return 1; +} + + +static int +image_get_last_block(uint8_t id) +{ + int first_track, last_track; + int number, c; + unsigned char attr; + TMSF tmsf; + uint32_t lb=0; + + if (!cdimg[id]) + return 0; + + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + for (c = 0; c <= last_track; c++) { + uint32_t address; + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + address = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150 here as well. */ + if (address > lb) + lb = address; + } + return lb; +} + + +static int +image_medium_changed(uint8_t id) +{ + /* There is no way to change the medium within an already mounted image. */ + return 0; +} + + +static uint8_t +image_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) +{ + cdrom_t *dev = cdrom[id]; + uint8_t ret; + int pos = 0; + uint32_t cdpos; + TMSF relPos, absPos; + unsigned char attr, track, index; + + cdpos = dev->seek_pos; + + if (!cdimg[id]) + return 0; + + cdimg[id]->GetAudioSub(cdpos, attr, track, index, relPos, absPos); + + if (cdrom_image[id].image_is_iso) + ret = 0x15; + else { + if (dev->cd_state == CD_PLAYING) + ret = 0x11; + else if (dev->cd_state == CD_PAUSED) + ret = 0x12; + else + ret = 0x13; + } + + b[pos++] = attr; + b[pos++] = track; + b[pos++] = index; + + if (msf) { + b[pos + 3] = (uint8_t) absPos.fr; + b[pos + 2] = (uint8_t) absPos.sec; + b[pos + 1] = (uint8_t) absPos.min; + b[pos] = 0; + pos += 4; + b[pos + 3] = (uint8_t) relPos.fr; + b[pos + 2] = (uint8_t) relPos.sec; + b[pos + 1] = (uint8_t) relPos.min; + b[pos] = 0; + pos += 4; + } else { + uint32_t dat = MSFtoLBA(absPos.min, absPos.sec, absPos.fr) - 150; + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + dat = MSFtoLBA(relPos.min, relPos.sec, relPos.fr); + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + } + + return ret; +} + + +static int +image_is_track_audio(uint8_t id, uint32_t pos, int ismsf) +{ + int m, s, f; + unsigned char attr; + TMSF tmsf; + int number; + + if (!cdimg[id] || cdrom_image[id].image_is_iso) + return 0; + + if (ismsf) { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + pos = MSFtoLBA(m, s, f) - 150; + } + + /* GetTrack requires LBA. */ + cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); + + return attr == AUDIO_TRACK; +} + + +static int +is_legal(int id, int cdrom_sector_type, int cdrom_sector_flags, int audio, int mode2) +{ + if (!(cdrom_sector_flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ + cdrom_image_log("CD-ROM %i: [Any Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); + return 0; + } + + if ((cdrom_sector_type != 1) && !audio) { + if (!(cdrom_sector_flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ + cdrom_image_log("CD-ROM %i: [Any Data Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); + return 0; + } + + if ((cdrom_sector_flags & 0x06) == 0x06) { + cdrom_image_log("CD-ROM %i: [Any Data Mode] Invalid error flags\n", id); + return 0; + } + + if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) { + cdrom_image_log("CD-ROM %i: [Any Data Mode] Invalid subchannel data flags (%02X)\n", id, cdrom_sector_flags & 0x700); + return 0; + } + + if ((cdrom_sector_flags & 0x18) == 0x08) { /* EDC/ECC without user data is an illegal mode */ + cdrom_image_log("CD-ROM %i: [Any Data Mode] EDC/ECC without user data is an illegal mode\n", id); + return 0; + } + + if (((cdrom_sector_flags & 0xf0) == 0x90) || ((cdrom_sector_flags & 0xf0) == 0xc0)) { /* 0x90/0x98/0xC0/0xC8 are illegal modes */ + cdrom_image_log("CD-ROM %i: [Any Data Mode] 0x90/0x98/0xC0/0xC8 are illegal modes\n", id); + return 0; + } + + if (((cdrom_sector_type > 3) && (cdrom_sector_type != 8)) || (mode2 && (mode2 & 0x03))) { + if ((cdrom_sector_flags & 0xf0) == 0x30) { /* 0x30/0x38 are illegal modes */ + cdrom_image_log("CD-ROM %i: [Any XA Mode 2] 0x30/0x38 are illegal modes\n", id); + return 0; + } + if (((cdrom_sector_flags & 0xf0) == 0xb0) || ((cdrom_sector_flags & 0xf0) == 0xd0)) { /* 0xBx and 0xDx are illegal modes */ + cdrom_image_log("CD-ROM %i: [Any XA Mode 2] 0xBx and 0xDx are illegal modes\n", id); + return 0; + } + } + } + + return 1; +} + + +static void +read_sector_to_buffer(uint8_t id, uint8_t *raw_buffer, uint32_t msf, uint32_t lba, int mode2, int len) +{ + uint8_t *bb = raw_buffer; + + cdimg[id]->ReadSector(raw_buffer + 16, false, lba); + + /* Sync bytes */ + bb[0] = 0; + memset(bb + 1, 0xff, 10); + bb[11] = 0; + bb += 12; + + /* Sector header */ + bb[0] = (msf >> 16) & 0xff; + bb[1] = (msf >> 8) & 0xff; + bb[2] = msf & 0xff; + + bb[3] = 1; /* mode 1 data */ + bb += mode2 ? 12 : 4; + bb += len; + if (mode2 && ((mode2 & 0x03) == 1)) + memset(bb, 0, 280); + else if (!mode2) + memset(bb, 0, 288); +} + + +static void +read_audio(int id, uint32_t lba, uint8_t *b) +{ + if (cdimg[id]->GetSectorSize(lba) == 2352) + cdimg[id]->ReadSector(raw_buffer, true, lba); + else + cdimg[id]->ReadSectorSub(raw_buffer, lba); + + memcpy(b, raw_buffer, 2352); + cdrom_sector_size = 2352; +} + + +static void +read_mode1(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +{ + if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2048)) + read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2048); + else if (cdimg[id]->GetSectorSize(lba) == 2352) + cdimg[id]->ReadSector(raw_buffer, true, lba); + else + cdimg[id]->ReadSectorSub(raw_buffer, lba); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_image_log("CD-ROM %i: [Mode 1] Sync\n", id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_image_log("CD-ROM %i: [Mode 1] Header\n", id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + if (!(cdrom_sector_flags & 0x10)) { /* No user data */ + cdrom_image_log("CD-ROM %i: [Mode 1] Sub-header\n", id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_image_log("CD-ROM %i: [Mode 1] User data\n", id); + memcpy(b, raw_buffer + 16, 2048); + cdrom_sector_size += 2048; + b += 2048; + } + + if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ + cdrom_image_log("CD-ROM %i: [Mode 1] EDC/ECC\n", id); + memcpy(b, raw_buffer + 2064, 288); + cdrom_sector_size += 288; + b += 288; + } +} + + +static void +read_mode2_non_xa(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +{ + if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2336)) + read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2336); + else if (cdimg[id]->GetSectorSize(lba) == 2352) + cdimg[id]->ReadSector(raw_buffer, true, lba); + else + cdimg[id]->ReadSectorSub(raw_buffer, lba); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Sync\n", id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Header\n", id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + /* Mode 1 sector, expected type is 1 type. */ + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Sub-header\n", id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_image_log("CD-ROM %i: [Mode 2 Formless] User data\n", id); + memcpy(b, raw_buffer + 24, 2336); + cdrom_sector_size += 2336; + b += 2336; + } +} + + +static void +read_mode2_xa_form1(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +{ + if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2048)) + read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2048); + else if (cdimg[id]->GetSectorSize(lba) == 2352) + cdimg[id]->ReadSector(raw_buffer, true, lba); + else + cdimg[id]->ReadSectorSub(raw_buffer, lba); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sync\n", id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Header\n", id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sub-header\n", id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] User data\n", id); + memcpy(b, raw_buffer + 24, 2048); + cdrom_sector_size += 2048; + b += 2048; + } + + if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC\n", id); + memcpy(b, raw_buffer + 2072, 280); + cdrom_sector_size += 280; + b += 280; + } +} + + +static void +read_mode2_xa_form2(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +{ + if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2324)) + read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2324); + else if (cdimg[id]->GetSectorSize(lba) == 2352) + cdimg[id]->ReadSector(raw_buffer, true, lba); + else + cdimg[id]->ReadSectorSub(raw_buffer, lba); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Sync\n", id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Header\n", id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Sub-header\n", id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] User data\n", id); + memcpy(b, raw_buffer + 24, 2328); + cdrom_sector_size += 2328; + b += 2328; + } +} + + +static int +image_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, + int cdrom_sector_flags, int *len) +{ + uint8_t *b, *temp_b; + uint32_t msf, lba; + int audio, mode2; + int m, s, f; + + if (!cdimg[id]) + return 0; + + if (!cdrom_drives[id].host_drive) + return 0; + + b = temp_b = buffer; + + *len = 0; + + if (ismsf) { + m = (sector >> 16) & 0xff; + s = (sector >> 8) & 0xff; + f = sector & 0xff; + lba = MSFtoLBA(m, s, f) - 150; + msf = sector; + } else { + lba = sector; + msf = cdrom_lba_to_msf_accurate(sector); + } + + if (cdrom_image[id].image_is_iso) { + audio = 0; + mode2 = cdimg[id]->IsMode2(lba) ? 1 : 0; + } else { + audio = image_is_track_audio(id, sector, ismsf); + mode2 = cdimg[id]->IsMode2(lba) ? 1 : 0; + } + mode2 <<= 2; + mode2 |= cdimg[id]->GetMode2Form(lba); + + memset(raw_buffer, 0, 2448); + memset(extra_buffer, 0, 296); + + if (!(cdrom_sector_flags & 0xf0)) { /* 0x00 and 0x08 are illegal modes */ + cdrom_image_log("CD-ROM %i: [Mode 1] 0x00 and 0x08 are illegal modes\n", id); + return 0; + } + + if (!is_legal(id, cdrom_sector_type, cdrom_sector_flags, audio, mode2)) + return 0; + + if ((cdrom_sector_type == 3) || ((cdrom_sector_type > 4) && (cdrom_sector_type != 8))) { + if (cdrom_sector_type == 3) + cdrom_image_log("CD-ROM %i: Attempting to read a Yellowbook Mode 2 data sector from an image\n", id); + if (cdrom_sector_type > 4) + cdrom_image_log("CD-ROM %i: Attempting to read a XA Mode 2 Form 2 data sector from an image\n", id); + return 0; + } else if (cdrom_sector_type == 1) { + if (!audio || cdrom_image[id].image_is_iso) { + cdrom_image_log("CD-ROM %i: [Audio] Attempting to read an audio sector from a data image\n", id); + return 0; + } + + read_audio(id, lba, temp_b); + } else if (cdrom_sector_type == 2) { + if (audio || mode2) { + cdrom_image_log("CD-ROM %i: [Mode 1] Attempting to read a sector of another type\n", id); + return 0; + } + + read_mode1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 3) { + if (audio || !mode2 || (mode2 & 0x03)) { + cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Attempting to read a sector of another type\n", id); + return 0; + } + + read_mode2_non_xa(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 4) { + if (audio || !mode2 || ((mode2 & 0x03) != 1)) { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Attempting to read a sector of another type\n", id); + return 0; + } + + read_mode2_xa_form1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 5) { + if (audio || !mode2 || ((mode2 & 0x03) != 2)) { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Attempting to read a sector of another type\n", id); + return 0; + } + + read_mode2_xa_form2(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 8) { + if (audio) { + cdrom_image_log("CD-ROM %i: [Any Data] Attempting to read a data sector from an audio track\n", id); + return 0; + } + + if (mode2 && ((mode2 & 0x03) == 1)) + read_mode2_xa_form1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + else if (!mode2) + read_mode1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + else { + cdrom_image_log("CD-ROM %i: [Any Data] Attempting to read a data sector whose cooked size is not 2048 bytes\n", id); + return 0; + } + } else { + if (mode2) { + if ((mode2 & 0x03) == 0x01) + read_mode2_xa_form1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + else if ((mode2 & 0x03) == 0x02) + read_mode2_xa_form2(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + else + read_mode2_non_xa(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else { + if (audio) + read_audio(id, lba, temp_b); + else + read_mode1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } + } + + if ((cdrom_sector_flags & 0x06) == 0x02) { + /* Add error flags. */ + cdrom_image_log("CD-ROM %i: Error flags\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 294); + cdrom_sector_size += 294; + } else if ((cdrom_sector_flags & 0x06) == 0x04) { + /* Add error flags. */ + cdrom_image_log("CD-ROM %i: Full error flags\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 296); + cdrom_sector_size += 296; + } + + if ((cdrom_sector_flags & 0x700) == 0x100) { + cdrom_image_log("CD-ROM %i: Raw subchannel data\n", id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); + cdrom_sector_size += 96; + } else if ((cdrom_sector_flags & 0x700) == 0x200) { + cdrom_image_log("CD-ROM %i: Q subchannel data\n", id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 16); + cdrom_sector_size += 16; + } else if ((cdrom_sector_flags & 0x700) == 0x400) { + cdrom_image_log("CD-ROM %i: R/W subchannel data\n", id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); + cdrom_sector_size += 96; + } + + *len = cdrom_sector_size; + + return 1; +} + + +static uint32_t +image_size(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + return dev->cdrom_capacity; +} + + +static int +image_readtoc(uint8_t id, unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + int number, len = 4; + int c, d, first_track, last_track; + uint32_t temp; + unsigned char attr; + TMSF tmsf; + + if (!cdimg[id]) + return 0; + + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + b[2] = first_track; + b[3] = last_track; + + d = 0; + for (c = 0; c <= last_track; c++) { + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + if (number >= starttrack) { + d=c; + break; + } + } + + if (starttrack != 0xAA) { + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + b[2] = number; + } + + for (c = d; c <= last_track; c++) { + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + + b[len++] = 0; /* reserved */ + b[len++] = attr; + b[len++] = number; /* track number */ + b[len++] = 0; /* reserved */ + + if (msf) { + b[len++] = 0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } else { + temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + + if (single) + break; + } + + b[0] = (uint8_t)(((len-2) >> 8) & 0xff); + b[1] = (uint8_t)((len-2) & 0xff); + + return len; +} + + +static int +image_readtoc_session(uint8_t id, unsigned char *b, int msf, int maxlen) +{ + int number, len = 4; + TMSF tmsf; + unsigned char attr; + uint32_t temp; + + if (!cdimg[id]) + return 0; + + cdimg[id]->GetAudioTrackInfo(1, number, tmsf, attr); + + if (number == 0) + number = 1; + + b[2] = b[3] = 1; + b[len++] = 0; /* reserved */ + b[len++] = attr; + b[len++] = number; /* track number */ + b[len++] = 0; /* reserved */ + if (msf) { + b[len++] = 0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } else { + temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150. */ + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + + if (maxlen < len) + return maxlen; + + return len; +} + + +static int +image_readtoc_raw(uint8_t id, unsigned char *b, int maxlen) +{ + int track, len = 4; + int first_track, last_track; + int number; + unsigned char attr; + TMSF tmsf; + + if (!cdimg[id]) + return 0; + + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + b[2] = first_track; + b[3] = last_track; + + for (track = first_track; track <= last_track; track++) { + cdimg[id]->GetAudioTrackInfo(track, number, tmsf, attr); + + b[len++] = track; + b[len++]= attr; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } + + return len; +} + + +static int +image_status(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + if (!cdimg[id]) + return CD_STATUS_EMPTY; + + if (cdrom_image[id].image_is_iso) + return CD_STATUS_DATA_ONLY; + + if (cdimg[id]->HasAudioTracks()) { + switch(dev->cd_state) { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + default: + return CD_STATUS_STOPPED; + } + } + + return CD_STATUS_DATA_ONLY; +} + + +void +image_reset(UNUSED(uint8_t id)) +{ + return; +} + + +void +image_close(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + dev->cd_state = CD_STOPPED; + if (cdimg[id]) { + delete cdimg[id]; + cdimg[id] = NULL; + } +} + + +int +image_open(uint8_t id, wchar_t *fn) +{ + cdrom_t *dev = cdrom[id]; + + wcscpy(cdrom_image[id].image_path, fn); + + if (! wcscasecmp(plat_get_extension(fn), L"ISO")) + cdrom_image[id].image_is_iso = 1; + else + cdrom_image[id].image_is_iso = 0; + + cdimg[id] = new CDROM_Interface_Image(); + memset(afn, 0, sizeof(afn)); + wcstombs(afn, fn, sizeof(afn)); + if (!cdimg[id]->SetDevice(afn, false)) { + image_close(id); + cdrom_set_null_handler(id); + cdrom_image_log("[f] image_open(): cdrom[%i]->handler = %08X\n", id, cdrom[id]->handler); + return 1; + } + dev->cd_state = CD_STOPPED; + dev->seek_pos = 0; + dev->cd_buflen = 0; + dev->cdrom_capacity = image_get_last_block(id) + 1; + cdrom[id]->handler = &image_cdrom; + + return 0; +} + + +static void +image_exit(uint8_t id) { cdrom_t *dev = cdrom[id]; dev->handler_inited = 0; } + /* TODO: Check for what data type a mixed CD is. */ static int image_media_type_id(uint8_t id) { - if (!cdrom_image[id].image_is_iso) - { - return 3; /* Mixed mode CD. */ - } - - if (image_size(id) <= 405000) - { + if (image_size(id) > 405000) + return 65; /* DVD. */ + else { + if (cdrom_image[id].image_is_iso) return 1; /* Data CD. */ - } else - { - return 65; /* DVD. */ - } + return 3; /* Mixed mode CD. */ + } } + CDROM image_cdrom = { - image_ready, - image_medium_changed, - image_media_type_id, - image_audio_callback, - image_audio_stop, - image_readtoc, - image_readtoc_session, - image_readtoc_raw, - image_getcurrentsubchannel, - NULL, - image_readsector_raw, - image_playaudio, - image_load, - image_eject, - image_pause, - image_resume, - image_size, - image_status, - image_is_track_audio, - image_stop, - image_exit + image_ready, + image_medium_changed, + image_media_type_id, + image_audio_callback, + image_audio_stop, + image_readtoc, + image_readtoc_session, + image_readtoc_raw, + image_getcurrentsubchannel, + image_readsector_raw, + image_playaudio, + image_pause, + image_resume, + image_size, + image_status, + image_stop, + image_exit }; diff --git a/src/cdrom/cdrom_null.c b/src/cdrom/cdrom_null.c index 3c939f7d6..15b2c937f 100644 --- a/src/cdrom/cdrom_null.c +++ b/src/cdrom/cdrom_null.c @@ -9,19 +9,20 @@ * Implementation of the CD-ROM null interface for unmounted * guest CD-ROM drives. * - * Version: @(#)cdrom_null.c 1.0.6 2017/11/04 + * Version: @(#)cdrom_null.c 1.0.7 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, * * Copyright 2008-2016 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2016-2018 Miran Grca. */ #include #include #include #include #include "../86box.h" +#include "../scsi/scsi.h" #include "cdrom.h" @@ -50,17 +51,6 @@ null_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) } -static void -null_eject(uint8_t id) -{ -} - - -static void -null_load(uint8_t id) -{ -} - static int null_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len) { @@ -114,7 +104,7 @@ cdrom_null_reset(uint8_t id) void cdrom_set_null_handler(uint8_t id); int -cdrom_null_open(uint8_t id, char d) +cdrom_null_open(uint8_t id) { cdrom_set_null_handler(id); @@ -134,20 +124,6 @@ void null_exit(uint8_t id) } -static int -null_is_track_audio(uint8_t id, uint32_t pos, int ismsf) -{ - return(0); -} - - -static int -null_pass_through(uint8_t id, uint8_t *in_cdb, uint8_t *b, uint32_t *len) -{ - return(0); -} - - static int null_media_type_id(uint8_t id) { @@ -158,7 +134,7 @@ null_media_type_id(uint8_t id) void cdrom_set_null_handler(uint8_t id) { - cdrom_drives[id].handler = &null_cdrom; + cdrom[id]->handler = &null_cdrom; cdrom_drives[id].host_drive = 0; memset(cdrom_image[id].image_path, 0, sizeof(cdrom_image[id].image_path)); } @@ -174,16 +150,12 @@ static CDROM null_cdrom = { null_readtoc_session, null_readtoc_raw, null_getcurrentsubchannel, - null_pass_through, null_readsector_raw, NULL, - null_load, - null_eject, NULL, NULL, null_size, null_status, - null_is_track_audio, NULL, null_exit }; diff --git a/src/cdrom/cdrom_null.h b/src/cdrom/cdrom_null.h index 0fb9ee166..480acb29c 100644 --- a/src/cdrom/cdrom_null.h +++ b/src/cdrom/cdrom_null.h @@ -9,18 +9,18 @@ * Implementation of the CD-ROM null interface for unmounted * guest CD-ROM drives. * - * Version: @(#)cdrom_null.h 1.0.3 2017/09/03 + * Version: @(#)cdrom_null.h 1.0.4 2018/03/31 * * Authors: Sarah Walker, * Miran Grca, - * Copyright 2008-2016 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ #ifndef EMU_CDROM_NULL_H #define EMU_CDROM_NULL_H -extern int cdrom_null_open(uint8_t id, char d); +extern int cdrom_null_open(uint8_t id); extern void cdrom_null_reset(uint8_t id); extern void null_close(uint8_t id); diff --git a/src/config.c b/src/config.c index 494600002..3ca98dd57 100644 --- a/src/config.c +++ b/src/config.c @@ -8,7 +8,7 @@ * * Configuration file handler. * - * Version: @(#)config.c 1.0.46 2018/03/18 + * Version: @(#)config.c 1.0.47 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, @@ -31,11 +31,10 @@ #include #include "86box.h" #include "cpu/cpu.h" +#include "device.h" #include "nvr.h" #include "config.h" -#include "device.h" #include "lpt.h" -#include "cdrom/cdrom.h" #include "disk/hdd.h" #include "disk/hdc.h" #include "disk/hdc_ide.h" @@ -47,6 +46,7 @@ #include "mouse.h" #include "network/network.h" #include "scsi/scsi.h" +#include "cdrom/cdrom.h" #include "sound/sound.h" #include "sound/midi.h" #include "sound/snd_dbopl.h" @@ -522,7 +522,6 @@ load_video(void) if (machines[machine].fixed_gfxcard) { config_delete_var(cat, "gfxcard"); - config_delete_var(cat, "voodoo"); gfxcard = GFX_INTERNAL; } else { p = config_get_string(cat, "gfxcard", NULL); @@ -536,11 +535,11 @@ load_video(void) } } gfxcard = video_get_video_from_internal_name(p); - - video_speed = config_get_int(cat, "video_speed", -1); - - voodoo_enabled = !!config_get_int(cat, "voodoo", 0); } + + video_speed = config_get_int(cat, "video_speed", -1); + + voodoo_enabled = !!config_get_int(cat, "voodoo", 0); } @@ -612,12 +611,12 @@ load_sound(void) GUS = !!config_get_int(cat, "gus", 0); memset(temp, '\0', sizeof(temp)); - p = config_get_string(cat, "opl3_type", "dbopl"); + p = config_get_string(cat, "opl_type", "dbopl"); strcpy(temp, p); if (!strcmp(temp, "nukedopl") || !strcmp(temp, "1")) - opl3_type = 1; - else - opl3_type = 0; + opl_type = 1; + else + opl_type = 0; memset(temp, '\0', sizeof(temp)); p = config_get_string(cat, "sound_type", "float"); @@ -714,8 +713,7 @@ static void load_other_peripherals(void) { char *cat = "Other peripherals"; - char temp[512], *p; - int c; + char *p; p = config_get_string(cat, "scsicard", NULL); if (p != NULL) @@ -747,34 +745,13 @@ load_other_peripherals(void) } config_set_string(cat, "hdc", hdc_name); - memset(temp, '\0', sizeof(temp)); - for (c=2; c<4; c++) { - sprintf(temp, "ide_%02i", c + 1); - p = config_get_string(cat, temp, NULL); - if (p == NULL) - p = "0, 00"; - sscanf(p, "%i, %02i", &ide_enable[c], &ide_irq[c]); - } + ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0); + ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0); bugger_enabled = !!config_get_int(cat, "bugger_enabled", 0); } -static int -tally_char(char *str, char c) -{ - int tally; - - tally = 0; - if (str != NULL) { - while (*str) - if (*str++ == c) tally++; - } - - return(tally); -} - - /* Load "Hard Disks" section. */ static void load_hard_disks(void) @@ -785,21 +762,15 @@ load_hard_disks(void) int c; char *p; wchar_t *wp; - int max_spt, max_hpc, max_tracks; - int board = 0, dev = 0; + uint32_t max_spt, max_hpc, max_tracks; + uint32_t board = 0, dev = 0; memset(temp, '\0', sizeof(temp)); for (c=0; c>1, c&1); p = config_get_string(cat, temp, tmp2); - if (! strstr(p, ":")) { - sscanf(p, "%i", (int *)&hdd[c].ide_channel); - hdd[c].ide_channel &= 7; - } else { - sscanf(p, "%01u:%01u", &board, &dev); - - board &= 3; - dev &= 1; - hdd[c].ide_channel = (board<<1) + dev; - } + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + hdd[c].ide_channel = (board<<1) + dev; if (hdd[c].ide_channel > 7) hdd[c].ide_channel = 7; @@ -889,12 +858,11 @@ load_hard_disks(void) /* SCSI */ sprintf(temp, "hdd_%02i_scsi_location", c+1); - if ((hdd[c].bus == HDD_BUS_SCSI) || - (hdd[c].bus == HDD_BUS_SCSI_REMOVABLE)) { + if (hdd[c].bus == HDD_BUS_SCSI) { sprintf(tmp2, "%02u:%02u", c, 0); p = config_get_string(cat, temp, tmp2); - sscanf(p, "%02u:%02u", + sscanf(p, "%02i:%02i", (int *)&hdd[c].scsi_id, (int *)&hdd[c].scsi_lun); if (hdd[c].scsi_id > 15) @@ -956,181 +924,6 @@ load_hard_disks(void) } -/* Load old "Removable Devices" section. */ -static void -load_removable_devices(void) -{ - char *cat = "Removable devices"; - char temp[512], tmp2[512], *p; - char s[512]; - unsigned int board = 0, dev = 0; - wchar_t *wp; - int c; - - if (find_section(cat) == NULL) - return; - - for (c=0; c 13) - fdd_set_type(c, 13); - - sprintf(temp, "fdd_%02i_fn", c + 1); - wp = config_get_wstring(cat, temp, L""); - -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the EXE path. Just strip - * that off for now... - */ - wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); - } else -#endif - wcsncpy(floppyfns[c], wp, sizeof_w(floppyfns[c])); - - /* if (*wp != L'\0') - pclog("Floppy%d: %ls\n", c, floppyfns[c]); */ - sprintf(temp, "fdd_%02i_writeprot", c+1); - ui_writeprot[c] = !!config_get_int(cat, temp, 0); - sprintf(temp, "fdd_%02i_turbo", c + 1); - fdd_set_turbo(c, !!config_get_int(cat, temp, 0)); - sprintf(temp, "fdd_%02i_check_bpb", c+1); - fdd_set_check_bpb(c, !!config_get_int(cat, temp, 1)); - - /* Check whether each value is default, if yes, delete it so that only non-default values will later be saved. */ - sprintf(temp, "fdd_%02i_type", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "fdd_%02i_fn", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "fdd_%02i_writeprot", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "fdd_%02i_turbo", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "fdd_%02i_check_bpb", c+1); - config_delete_var(cat, temp); - } - - memset(temp, 0x00, sizeof(temp)); - for (c=0; c>1, (c+2)&1); - p = config_get_string(cat, temp, tmp2); - if (! strstr(p, ":")) { - sscanf(p, "%i", (int *)&cdrom_drives[c].ide_channel); - cdrom_drives[c].ide_channel &= 7; - } else { - sscanf(p, "%01u:%01u", &board, &dev); - - board &= 3; - dev &= 1; - cdrom_drives[c].ide_channel = (board<<1)+dev; - } - - if (cdrom_drives[c].ide_channel > 7) - cdrom_drives[c].ide_channel = 7; - } else { - sprintf(temp, "cdrom_%02i_scsi_location", c+1); - if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) { - sprintf(tmp2, "%02u:%02u", c+2, 0); - p = config_get_string(cat, temp, tmp2); - sscanf(p, "%02u:%02u", - &cdrom_drives[c].scsi_device_id, - &cdrom_drives[c].scsi_device_lun); - - if (cdrom_drives[c].scsi_device_id > 15) - cdrom_drives[c].scsi_device_id = 15; - if (cdrom_drives[c].scsi_device_lun > 7) - cdrom_drives[c].scsi_device_lun = 7; - } else { - config_delete_var(cat, temp); - } - } - - sprintf(temp, "cdrom_%02i_image_path", c+1); - wp = config_get_wstring(cat, temp, L""); - -#if 0 - /* - * NOTE: - * Temporary hack to remove the absolute - * path currently saved in most config - * files. We should remove this before - * finalizing this release! --FvK - */ - if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { - /* - * Yep, its absolute and prefixed - * with the EXE path. Just strip - * that off for now... - */ - wcsncpy(cdrom_image[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom_image[c].image_path)); - } else -#endif - wcsncpy(cdrom_image[c].image_path, wp, sizeof_w(cdrom_image[c].image_path)); - - if (cdrom_drives[c].host_drive < 'A') - cdrom_drives[c].host_drive = 0; - - if ((cdrom_drives[c].host_drive == 0x200) && - (wcslen(cdrom_image[c].image_path) == 0)) - cdrom_drives[c].host_drive = 0; - - /* If the CD-ROM is disabled, delete all its variables. */ - sprintf(temp, "cdrom_%02i_host_drive", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "cdrom_%02i_parameters", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "cdrom_%02i_ide_channel", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "cdrom_%02i_scsi_location", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "cdrom_%02i_image_path", c+1); - config_delete_var(cat, temp); - - sprintf(temp, "cdrom_%02i_iso_path", c+1); - config_delete_var(cat, temp); - } - - delete_section_if_empty(cat); -} - - /* Load "Floppy Drives" section. */ static void load_floppy_drives(void) @@ -1235,20 +1028,13 @@ load_other_removable_devices(void) cdrom_drives[c].ide_channel = cdrom_drives[c].scsi_device_id = c + 2; sprintf(temp, "cdrom_%02i_ide_channel", c+1); - if ((cdrom_drives[c].bus_type == CDROM_BUS_ATAPI_PIO_ONLY) || - (cdrom_drives[c].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) { + if (cdrom_drives[c].bus_type == CDROM_BUS_ATAPI) { sprintf(tmp2, "%01u:%01u", (c+2)>>1, (c+2)&1); p = config_get_string(cat, temp, tmp2); - if (! strstr(p, ":")) { - sscanf(p, "%i", (int *)&cdrom_drives[c].ide_channel); - cdrom_drives[c].ide_channel &= 7; - } else { - sscanf(p, "%01u:%01u", &board, &dev); - - board &= 3; - dev &= 1; - cdrom_drives[c].ide_channel = (board<<1)+dev; - } + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + cdrom_drives[c].ide_channel = (board<<1)+dev; if (cdrom_drives[c].ide_channel > 7) cdrom_drives[c].ide_channel = 7; @@ -1335,20 +1121,13 @@ load_other_removable_devices(void) zip_drives[c].ide_channel = zip_drives[c].scsi_device_id = c + 2; sprintf(temp, "zip_%02i_ide_channel", c+1); - if ((zip_drives[c].bus_type == ZIP_BUS_ATAPI_PIO_ONLY) || - (zip_drives[c].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) { + if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) { sprintf(tmp2, "%01u:%01u", (c+2)>>1, (c+2)&1); p = config_get_string(cat, temp, tmp2); - if (! strstr(p, ":")) { - sscanf(p, "%i", (int *)&zip_drives[c].ide_channel); - zip_drives[c].ide_channel &= 7; - } else { - sscanf(p, "%01u:%01u", &board, &dev); - - board &= 3; - dev &= 1; - zip_drives[c].ide_channel = (board<<1)+dev; - } + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + zip_drives[c].ide_channel = (board<<1)+dev; if (zip_drives[c].ide_channel > 7) zip_drives[c].ide_channel = 7; @@ -1420,16 +1199,28 @@ load_other_removable_devices(void) void config_load(void) { + int i; + pclog("Loading config file '%ls'..\n", cfg_path); + memset(hdd, 0, sizeof(hard_disk_t)); + memset(cdrom_drives, 0, sizeof(cdrom_drive_t) * CDROM_NUM); + memset(cdrom_image, 0, sizeof(cdrom_image_t) * CDROM_NUM); +#ifdef USE_IOCTL + memset(cdrom_ioctl, 0, sizeof(cdrom_ioctl_t) * CDROM_NUM); +#endif + memset(zip_drives, 0, sizeof(zip_drive_t)); + if (! config_read(cfg_path)) { cpu = 0; #ifdef USE_LANGUAGE plat_langid = 0x0409; #endif scale = 1; + machine = machine_get_machine_from_internal_name("ibmpc"); gfxcard = GFX_CGA; - vid_api = plat_vidapi("default");; + vid_api = plat_vidapi("default"); + video_speed = -1; enable_sync = 1; joystick_type = 7; if (hdc_name) { @@ -1438,12 +1229,20 @@ config_load(void) } hdc_name = (char *) malloc((strlen("none")+1) * sizeof(char)); strcpy(hdc_name, "none"); - serial_enabled[0] = 0; - serial_enabled[1] = 0; - lpt_enabled = 0; - fdd_set_type(0, 2); - fdd_set_type(1, 2); + serial_enabled[0] = 1; + serial_enabled[1] = 1; + lpt_enabled = 1; + for (i = 0; i < FDD_NUM; i++) { + if (i < 2) + fdd_set_type(i, 2); + else + fdd_set_type(i, 0); + + fdd_set_turbo(i, 0); + fdd_set_check_bpb(i, 1); + } mem_size = 640; + opl_type = 0; pclog("Config file not present or invalid!\n"); return; @@ -1460,7 +1259,6 @@ config_load(void) load_hard_disks(); /* Hard disks */ load_floppy_drives(); /* Floppy drives */ load_other_removable_devices(); /* Other removable devices */ - load_removable_devices(); /* Removable devices (legacy) */ /* Mark the configuration as changed. */ config_changed = 1; @@ -1730,10 +1528,10 @@ save_sound(void) else config_set_int(cat, "gus", GUS); - if (opl3_type == 0) - config_delete_var(cat, "opl3_type"); + if (opl_type == 0) + config_delete_var(cat, "opl_type"); else - config_set_string(cat, "opl3_type", (opl3_type == 1) ? "nukedopl" : "dbopl"); + config_set_string(cat, "opl_type", (opl_type == 1) ? "nukedopl" : "dbopl"); if (sound_is_float == 1) config_delete_var(cat, "sound_type"); @@ -1821,8 +1619,6 @@ static void save_other_peripherals(void) { char *cat = "Other peripherals"; - char temp[512], tmp2[512]; - int c; if (scsi_card_current == 0) config_delete_var(cat, "scsicard"); @@ -1832,15 +1628,15 @@ save_other_peripherals(void) config_set_string(cat, "hdc", hdc_name); - memset(temp, '\0', sizeof(temp)); - for (c=2; c<4; c++) { - sprintf(temp, "ide_%02i", c + 1); - sprintf(tmp2, "%i, %02i", !!ide_enable[c], ide_irq[c]); - if (ide_enable[c] == 0) - config_delete_var(cat, temp); - else - config_set_string(cat, temp, tmp2); - } + if (ide_ter_enabled == 0) + config_delete_var(cat, "ide_ter"); + else + config_set_int(cat, "ide_ter", ide_ter_enabled); + + if (ide_qua_enabled == 0) + config_delete_var(cat, "ide_qua"); + else + config_set_int(cat, "ide_qua", ide_qua_enabled); if (bugger_enabled == 0) config_delete_var(cat, "bugger_enabled"); @@ -1865,7 +1661,7 @@ save_hard_disks(void) sprintf(temp, "hdd_%02i_parameters", c+1); if (hdd_is_valid(c)) { p = hdd_bus_to_string(hdd[c].bus, 0); - sprintf(tmp2, "%" PRIu64 ", %" PRIu64", %" PRIu64 ", %i, %s", + sprintf(tmp2, "%u, %u, %u, %i, %s", hdd[c].spt, hdd[c].hpc, hdd[c].tracks, hdd[c].wp, p); config_set_string(cat, temp, tmp2); } else { @@ -1878,9 +1674,9 @@ save_hard_disks(void) else config_delete_var(cat, temp); - sprintf(temp, "hdd_%02i_xtide_channel", c+1); - if (hdd_is_valid(c) && (hdd[c].bus == HDD_BUS_XTIDE)) - config_set_int(cat, temp, hdd[c].xtide_channel); + sprintf(temp, "hdd_%02i_xta_channel", c+1); + if (hdd_is_valid(c) && (hdd[c].bus == HDD_BUS_XTA)) + config_set_int(cat, temp, hdd[c].xta_channel); else config_delete_var(cat, temp); @@ -1891,7 +1687,7 @@ save_hard_disks(void) config_delete_var(cat, temp); sprintf(temp, "hdd_%02i_ide_channel", c+1); - if (! hdd_is_valid(c) || ((hdd[c].bus != HDD_BUS_IDE_PIO_ONLY) && (hdd[c].bus != HDD_BUS_IDE_PIO_AND_DMA))) { + if (! hdd_is_valid(c) || (hdd[c].bus != HDD_BUS_IDE)) { config_delete_var(cat, temp); } else { sprintf(tmp2, "%01u:%01u", hdd[c].ide_channel >> 1, hdd[c].ide_channel & 1); @@ -1899,7 +1695,7 @@ save_hard_disks(void) } sprintf(temp, "hdd_%02i_scsi_location", c+1); - if (! hdd_is_valid(c) || ((hdd[c].bus != HDD_BUS_SCSI) && (hdd[c].bus != HDD_BUS_SCSI_REMOVABLE))) { + if (! hdd_is_valid(c) || (hdd[c].bus != HDD_BUS_SCSI)) { config_delete_var(cat, temp); } else { sprintf(tmp2, "%02u:%02u", hdd[c].scsi_id, hdd[c].scsi_lun); @@ -2002,10 +1798,9 @@ save_other_removable_devices(void) } sprintf(temp, "cdrom_%02i_ide_channel", c+1); - if ((cdrom_drives[c].bus_type != CDROM_BUS_ATAPI_PIO_ONLY) && - (cdrom_drives[c].bus_type != CDROM_BUS_ATAPI_PIO_AND_DMA)) { + if (cdrom_drives[c].bus_type != CDROM_BUS_ATAPI) config_delete_var(cat, temp); - } else { + else { sprintf(tmp2, "%01u:%01u", cdrom_drives[c].ide_channel>>1, cdrom_drives[c].ide_channel & 1); config_set_string(cat, temp, tmp2); @@ -2040,10 +1835,9 @@ save_other_removable_devices(void) } sprintf(temp, "zip_%02i_ide_channel", c+1); - if ((zip_drives[c].bus_type != ZIP_BUS_ATAPI_PIO_ONLY) && - (zip_drives[c].bus_type != ZIP_BUS_ATAPI_PIO_AND_DMA)) { + if (zip_drives[c].bus_type != ZIP_BUS_ATAPI) config_delete_var(cat, temp); - } else { + else { sprintf(tmp2, "%01u:%01u", zip_drives[c].ide_channel>>1, zip_drives[c].ide_channel & 1); config_set_string(cat, temp, tmp2); @@ -2157,7 +1951,7 @@ config_get_hex16(char *head, char *name, int def) { section_t *section; entry_t *entry; - int value; + unsigned int value; section = find_section(head); if (section == NULL) @@ -2178,7 +1972,7 @@ config_get_hex20(char *head, char *name, int def) { section_t *section; entry_t *entry; - int value; + unsigned int value; section = find_section(head); if (section == NULL) @@ -2199,7 +1993,7 @@ config_get_mac(char *head, char *name, int def) { section_t *section; entry_t *entry; - int val0 = 0, val1 = 0, val2 = 0; + unsigned int val0 = 0, val1 = 0, val2 = 0; section = find_section(head); if (section == NULL) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index e95cf1c79..4ddb9f4f3 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -18,7 +18,7 @@ * 2 clocks - fetch opcode 1 2 clocks - execute * 2 clocks - fetch opcode 2 etc * - * Version: @(#)808x.c 1.0.2 2018/03/09 + * Version: @(#)808x.c 1.0.3 2018/04/19 * * Authors: Sarah Walker, * Miran Grca, @@ -58,9 +58,6 @@ #include "../nmi.h" #include "../pic.h" #include "../timer.h" -#include "../device.h" /* for scsi.h */ -#include "../keyboard.h" /* its WRONG to have this in here!! --FvK */ -#include "../scsi/scsi.h" /* its WRONG to have this in here!! --FvK */ #include "../plat.h" @@ -648,7 +645,6 @@ void resetx86() #endif x86_was_reset = 1; port_92_clear_reset(); - scsi_card_reset(); } void softresetx86() @@ -658,7 +654,12 @@ void softresetx86() cpu_cur_status = 0; msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); msw=0; - cr0=0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); cr4 = 0; eflags=0; cgate32=0; @@ -680,7 +681,6 @@ void softresetx86() x86seg_reset(); x86_was_reset = 1; port_92_clear_reset(); - scsi_card_reset(); } static void setznp8(uint8_t val) diff --git a/src/cpu/codegen_ops_fpu.h b/src/cpu/codegen_ops_fpu.h index b2519e5ea..481eadb8c 100644 --- a/src/cpu/codegen_ops_fpu.h +++ b/src/cpu/codegen_ops_fpu.h @@ -634,5 +634,12 @@ opFLDimm(L2T, 3.3219280948873623) opFLDimm(L2E, 1.4426950408889634); opFLDimm(PI, 3.141592653589793); opFLDimm(EG2, 0.3010299956639812); -opFLDimm(LN2, 0.693147180559945); opFLDimm(Z, 0.0) + +static uint32_t ropFLDLN2(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_LOAD_IMM_Q(0x3fe62e42fefa39f0ull); + + return op_pc; +} diff --git a/src/cpu/codegen_timing_686.c b/src/cpu/codegen_timing_686.c index 412840e89..fc818d7f1 100644 --- a/src/cpu/codegen_timing_686.c +++ b/src/cpu/codegen_timing_686.c @@ -59,6 +59,7 @@ static uint32_t prev_regmask; static uint64_t *prev_deps; static uint32_t prev_fetchdat; +static uint32_t last_regmask_modified; static uint32_t regmask_modified; static uint32_t opcode_timings[256] = @@ -776,7 +777,7 @@ static inline int COUNT(uint32_t c, int op_32) void codegen_timing_686_block_start() { prev_full = decode_delay = 0; - regmask_modified = 0; + regmask_modified = last_regmask_modified = 0; } void codegen_timing_686_start() @@ -787,6 +788,18 @@ void codegen_timing_686_start() void codegen_timing_686_prefix(uint8_t prefix, uint32_t fetchdat) { + if ((prefix & 0xf8) == 0xd8) + { + last_prefix = prefix; + return; + } + if (prefix == 0x0f && (fetchdat & 0xf0) == 0x80) + { + /*0fh prefix is 'free' when used on conditional jumps*/ + last_prefix = prefix; + return; + } + /*6x86 can decode 1 prefix per instruction per clock with no penalty. If either instruction has more than one prefix then decode is delayed by one cycle for each additional prefix*/ @@ -801,7 +814,16 @@ static int check_agi(uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int op_3 if (addr_regmask & IMPL_ESP) addr_regmask |= (1 << REG_ESP); - return regmask_modified & addr_regmask; + if (regmask_modified & addr_regmask) + { + regmask_modified = 0; + return 2; + } + + if (last_regmask_modified & addr_regmask) + return 1; + + return 0; } void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) @@ -914,6 +936,8 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) } } + /*One prefix per instruction is free*/ + decode_delay--; if (decode_delay < 0) decode_delay = 0; @@ -925,8 +949,7 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) if (regmask & IMPL_ESP) regmask |= SRCDEP_ESP | DSTDEP_ESP; - if (check_agi(prev_deps, prev_opcode, prev_fetchdat, prev_op_32)) - agi_stall = 2; + agi_stall = check_agi(prev_deps, prev_opcode, prev_fetchdat, prev_op_32); /*Second instruction in the pair*/ if ((timings[opcode] & PAIR_MASK) == PAIR_NP) @@ -936,6 +959,7 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; prev_full = 0; + last_regmask_modified = regmask_modified; regmask_modified = prev_regmask; } else if (((timings[opcode] & PAIR_MASK) == PAIR_X || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) @@ -946,6 +970,7 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; prev_full = 0; + last_regmask_modified = regmask_modified; regmask_modified = prev_regmask; } else if (prev_regmask & regmask) @@ -955,6 +980,7 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; prev_full = 0; + last_regmask_modified = regmask_modified; regmask_modified = prev_regmask; } else @@ -966,12 +992,12 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) if (!t_pair) fatal("Pairable 0 cycles! %02x %02x\n", opcode, prev_opcode); - if (check_agi(deps, opcode, fetchdat, op_32)) - agi_stall = 2; + agi_stall = check_agi(deps, opcode, fetchdat, op_32); codegen_block_cycles += t_pair + agi_stall; decode_delay = (-t_pair) + 1 + agi_stall; + last_regmask_modified = regmask_modified; regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8) | prev_regmask; prev_full = 0; return; @@ -985,12 +1011,12 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) { /*Instruction not pairable*/ int agi_stall = 0; - - if (check_agi(deps, opcode, fetchdat, op_32)) - agi_stall = 2; + + agi_stall = check_agi(deps, opcode, fetchdat, op_32); codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay + agi_stall; decode_delay = (-COUNT(timings[opcode], op_32)) + 1 + agi_stall; + last_regmask_modified = regmask_modified; regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); } else diff --git a/src/cpu/codegen_timing_pentium.c b/src/cpu/codegen_timing_pentium.c index 8ec6b2c78..60a6fbea0 100644 --- a/src/cpu/codegen_timing_pentium.c +++ b/src/cpu/codegen_timing_pentium.c @@ -963,7 +963,7 @@ void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) last_prefix = prefix; return; } - if (prefix == 0x0f && (opcode & 0xf0) == 0x80) + if (prefix == 0x0f && (fetchdat & 0xf0) == 0x80) { /*On Pentium 0fh prefix is 'free' when used on conditional jumps*/ last_prefix = prefix; diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 626b48f02..efaac3fb2 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -8,7 +8,7 @@ * * CPU type handler. * - * Version: @(#)cpu.c 1.0.14 2018/03/11 + * Version: @(#)cpu.c 1.0.15 2018/04/08 * * Authors: Sarah Walker, * leilei, @@ -1313,7 +1313,7 @@ void cpu_CPUID() EDX = CPUID_FPU; /*FPU*/ } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; case CPU_iDX4: @@ -1331,7 +1331,7 @@ void cpu_CPUID() EDX = CPUID_FPU | CPUID_VME; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; case CPU_Am486SX: @@ -1348,7 +1348,7 @@ void cpu_CPUID() EBX = ECX = EDX = 0; /*No FPU*/ } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; case CPU_Am486DX: @@ -1366,7 +1366,7 @@ void cpu_CPUID() EDX = CPUID_FPU; /*FPU*/ } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; case CPU_WINCHIP: @@ -1397,7 +1397,7 @@ void cpu_CPUID() EDX |= CPUID_MMX; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; case CPU_PENTIUM: @@ -1415,7 +1415,7 @@ void cpu_CPUID() EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; #ifdef DEV_BRANCH @@ -1435,7 +1435,7 @@ void cpu_CPUID() EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; case CPU_5K86: @@ -1487,7 +1487,7 @@ void cpu_CPUID() EDX = 0x10040120; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; case CPU_K6: @@ -1549,7 +1549,7 @@ void cpu_CPUID() EDX = 0x444D416E; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; #endif #endif @@ -1569,7 +1569,7 @@ void cpu_CPUID() EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; @@ -1588,7 +1588,7 @@ void cpu_CPUID() EDX = CPUID_FPU; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; @@ -1607,7 +1607,7 @@ void cpu_CPUID() EDX = CPUID_FPU | CPUID_CMPXCHG8B; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; @@ -1626,7 +1626,7 @@ void cpu_CPUID() EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; @@ -1646,7 +1646,7 @@ void cpu_CPUID() EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; #ifdef DEV_BRANCH @@ -1669,7 +1669,7 @@ void cpu_CPUID() { } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; /* case CPU_PENTIUM2: @@ -1693,7 +1693,7 @@ void cpu_CPUID() EDX = 0x0C040843; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; */ case CPU_PENTIUM2D: @@ -1717,7 +1717,7 @@ void cpu_CPUID() EDX = 0x0C040844; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; #endif #endif @@ -2260,7 +2260,7 @@ void cpu_update_waitstates() cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_write_cycles; } if (is486) - cpu_prefetch_cycles *= 4; + cpu_prefetch_cycles = (cpu_prefetch_cycles * 11) / 16; cpu_mem_prefetch_cycles = cpu_prefetch_cycles; if (cpu_s->rspeed <= 8000000) cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index f01b49438..b4efb8a3c 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -8,7 +8,7 @@ * * CPU type handler. * - * Version: @(#)cpu.h 1.0.10 2018/03/11 + * Version: @(#)cpu.h 1.0.11 2018/03/28 * * Authors: Sarah Walker, * leilei, @@ -258,7 +258,11 @@ struct _cpustate_ { #ifdef __MSC__ # define COMPILE_TIME_ASSERT(expr) /*nada*/ #else -# define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0]; +# ifdef EXTREME_DEBUG +# define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0]; +# else +# define COMPILE_TIME_ASSERT(expr) /*nada*/ +# endif #endif COMPILE_TIME_ASSERT(sizeof(cpu_state) <= 128) diff --git a/src/cpu/x86_ops_amd.h b/src/cpu/x86_ops_amd.h index 0b8a1e094..969862a1f 100644 --- a/src/cpu/x86_ops_amd.h +++ b/src/cpu/x86_ops_amd.h @@ -8,18 +8,20 @@ * * AMD SYSCALL and SYSRET CPU Instructions. * - * Version: @(#)x86_ops_amd.h 1.0.1 2018/01/01 + * Version: @(#)x86_ops_amd.h 1.0.2 2018/03/26 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. */ +#ifndef internal_illegal static int internal_illegal(char *s) { cpu_state.pc = cpu_state.oldpc; x86gpf(s, 0); return cpu_state.abrt; } +#endif /* 0 = Limit 0-15 1 = Base 0-15 diff --git a/src/cpu/x86_ops_i686.h b/src/cpu/x86_ops_i686.h index 1ef3693b9..27317f061 100644 --- a/src/cpu/x86_ops_i686.h +++ b/src/cpu/x86_ops_i686.h @@ -8,12 +8,21 @@ * * x86 i686 (Pentium Pro/Pentium II) CPU Instructions. * - * Version: @(#)x86_ops_i686.h 1.0.2 2018/01/01 + * Version: @(#)x86_ops_i686.h 1.0.3 2018/03/26 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. */ +#ifndef internal_illegal +static int internal_illegal(char *s) +{ + cpu_state.pc = cpu_state.oldpc; + x86gpf(s, 0); + return cpu_state.abrt; +} +#endif + /* 0 = Limit 0-15 1 = Base 0-15 2 = Base 16-23 (bits 0-7), Access rights diff --git a/src/cpu/x86_ops_misc.h b/src/cpu/x86_ops_misc.h index 7448007fb..9fa219919 100644 --- a/src/cpu/x86_ops_misc.h +++ b/src/cpu/x86_ops_misc.h @@ -8,12 +8,12 @@ * * Miscellaneous x86 CPU Instructions. * - * Version: @(#)x86_ops_misc.h 1.0.0 2017/05/30 + * Version: @(#)x86_ops_misc.h 1.0.1 2018/04/12 * * Author: Sarah Walker, * Miran Grca, - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016-2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ static int opCBW(uint32_t fetchdat) @@ -70,6 +70,10 @@ static int opF6_a16(uint32_t fetchdat) int8_t temps; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + { + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + } dst = geteab(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { @@ -120,6 +124,7 @@ static int opF6_a16(uint32_t fetchdat) { flags_rebuild(); flags |= 0x8D5; /*Not a Cyrix*/ + flags &= ~1; } } else @@ -127,8 +132,8 @@ static int opF6_a16(uint32_t fetchdat) x86_int(0); return 1; } - CLOCK_CYCLES(is486 ? 16 : 14); - PREFETCH_RUN(is486 ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 16 : 14); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; case 0x38: /*IDIV AL,b*/ tempws = (int)(int16_t)AX; @@ -142,6 +147,7 @@ static int opF6_a16(uint32_t fetchdat) { flags_rebuild(); flags|=0x8D5; /*Not a Cyrix*/ + flags &= ~1; } } else @@ -217,6 +223,7 @@ static int opF6_a32(uint32_t fetchdat) { flags_rebuild(); flags |= 0x8D5; /*Not a Cyrix*/ + flags &= ~1; } } else @@ -224,8 +231,8 @@ static int opF6_a32(uint32_t fetchdat) x86_int(0); return 1; } - CLOCK_CYCLES(is486 ? 16 : 14); - PREFETCH_RUN(is486 ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 16 : 14); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; case 0x38: /*IDIV AL,b*/ tempws = (int)(int16_t)AX; @@ -239,6 +246,7 @@ static int opF6_a32(uint32_t fetchdat) { flags_rebuild(); flags|=0x8D5; /*Not a Cyrix*/ + flags &= ~1; } } else @@ -323,8 +331,8 @@ static int opF7_w_a16(uint32_t fetchdat) x86_int(0); return 1; } - CLOCK_CYCLES(is486 ? 24 : 22); - PREFETCH_RUN(is486 ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 24 : 22); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; case 0x38: /*IDIV AX,w*/ tempws = (int)((DX << 16)|AX); @@ -415,8 +423,8 @@ static int opF7_w_a32(uint32_t fetchdat) x86_int(0); return 1; } - CLOCK_CYCLES(is486 ? 24 : 22); - PREFETCH_RUN(is486 ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 24 : 22); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; case 0x38: /*IDIV AX,w*/ tempws = (int)((DX << 16)|AX); diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index eca24046d..7e77e953e 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -24,6 +24,7 @@ #include #include "../86box.h" #include "cpu.h" +#include "../device.h" #include "../machine/machine.h" #include "../mem.h" #include "../nvr.h" diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index 08c0b44bc..122998eb3 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -8,15 +8,15 @@ * * x87 FPU instructions core. * - * Version: @(#)x87_ops.h 1.0.1 2017/10/28 + * Version: @(#)x87_ops.h 1.0.2 2018/04/05 * * Author: Sarah Walker, * leilei, * Miran Grca, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016-2017 leilei. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016-2018 Miran Grca. */ #include #include @@ -80,6 +80,21 @@ static __inline void x87_push(double i) cpu_state.tag[cpu_state.TOP&7] = (i == 0.0) ? 1 : 0; } +static inline void x87_push_u64(uint64_t i) +{ + union + { + double d; + uint64_t ll; + } td; + + td.ll = i; + + cpu_state.TOP=(cpu_state.TOP-1)&7; + cpu_state.ST[cpu_state.TOP] = td.d; + cpu_state.tag[cpu_state.TOP&7] = (td.d == 0.0) ? 1 : 0; +} + static __inline double x87_pop() { double t = cpu_state.ST[cpu_state.TOP]; diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index fd1cc3de6..bf4eb3c7f 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -478,7 +478,7 @@ static int opFLDLN2(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; if (fplog) pclog("FLDLN2\n"); - x87_push(0.693147180559945); + x87_push_u64(0x3fe62e42fefa39f0ull); CLOCK_CYCLES(8); return 0; } diff --git a/src/device.c b/src/device.c index 98f665a5e..66a917be6 100644 --- a/src/device.c +++ b/src/device.c @@ -9,7 +9,7 @@ * Implementation of the generic device interface to handle * all devices attached to the emulator. * - * Version: @(#)device.c 1.0.5 2018/03/18 + * Version: @(#)device.c 1.0.6 2018/03/26 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -82,18 +82,22 @@ device_add(const device_t *d) device_current = (device_t *)d; + devices[c] = (device_t *)d; + if (d->init != NULL) { priv = d->init(d); if (priv == NULL) { if (d->name) pclog("DEVICE: device '%s' init failed\n", d->name); - else + else pclog("DEVICE: device init failed\n"); + + device_priv[c] = NULL; + return(NULL); } } - devices[c] = (device_t *)d; device_priv[c] = priv; return(priv); @@ -152,6 +156,21 @@ device_reset_all(void) } +/* Reset all attached PCI devices - needed for PCI turbo reset control. */ +void +device_reset_all_pci(void) +{ + int c; + + for (c=0; creset != NULL) && (devices[c]->flags & DEVICE_PCI)) + devices[c]->reset(device_priv[c]); + } + } +} + + void * device_get_priv(const device_t *d) { diff --git a/src/device.h b/src/device.h index 32f803aff..9b8f82859 100644 --- a/src/device.h +++ b/src/device.h @@ -8,7 +8,7 @@ * * Definitions for the device handler. * - * Version: @(#)device.h 1.0.3 2018/03/15 + * Version: @(#)device.h 1.0.4 2018/03/26 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -119,6 +119,7 @@ extern void *device_add(const device_t *d); extern void device_add_ex(const device_t *d, void *priv); extern void device_close_all(void); extern void device_reset_all(void); +extern void device_reset_all_pci(void); extern void *device_get_priv(const device_t *d); extern int device_available(const device_t *d); extern void device_speed_changed(void); diff --git a/src/disk/hdc.c b/src/disk/hdc.c index f2cb9b2b3..fc827800c 100644 --- a/src/disk/hdc.c +++ b/src/disk/hdc.c @@ -8,7 +8,7 @@ * * Common code to handle all sorts of disk controllers. * - * Version: @(#)hdc.c 1.0.12 2018/03/19 + * Version: @(#)hdc.c 1.0.13 2018/04/04 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -25,6 +25,7 @@ #include "../device.h" #include "hdc.h" #include "hdc_ide.h" +#include "hdd.h" char *hdc_name; /* configured HDC name */ @@ -106,6 +107,9 @@ static const struct { { "[ISA] [IDE] PS/2 AT XTIDE (1.1.5)", "xtide_at_ps2", &xtide_at_ps2_device }, + { "[ISA] [IDE] WDXT-150 IDE (XTA) Adapter", "xta_wdxt150", + &xta_wdxt150_device }, + { "[ISA] [XT IDE] Acculogic XT IDE", "xtide_acculogic", &xtide_acculogic_device }, @@ -146,6 +150,9 @@ hdc_init(char *name) break; } } + + /* Zero all the hard disk image arrays. */ + hdd_image_init(); } @@ -154,20 +161,17 @@ void hdc_reset(void) { pclog("HDC: reset(current=%d, internal=%d)\n", - hdc_current, (machines[machine].flags & MACHINE_HDC)?1:0); + hdc_current, (machines[machine].flags & MACHINE_HDC) ? 1 : 0); /* If we have a valid controller, add its device. */ if (hdc_current > 1) device_add(controllers[hdc_current].device); - /* Reconfire and reset the IDE layer. */ - ide_ter_disable(); - ide_qua_disable(); - if (ide_enable[2]) - ide_ter_init(); - if (ide_enable[3]) - ide_qua_init(); - ide_reset_hard(); + /* Now, add the tertiary and/or quaternary IDE controllers. */ + if (ide_ter_enabled) + device_add(&ide_ter_device); + if (ide_qua_enabled) + device_add(&ide_qua_device); } @@ -185,6 +189,22 @@ hdc_get_internal_name(int hdc) } +int +hdc_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen((char *) controllers[c].internal_name)) + { + if (!strcmp((char *) controllers[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + + const device_t * hdc_get_device(int hdc) { @@ -192,6 +212,19 @@ hdc_get_device(int hdc) } +int +hdc_has_config(int hdc) +{ + const device_t *dev = hdc_get_device(hdc); + + if (dev == NULL) return(0); + + if (dev->config == NULL) return(0); + + return(1); +} + + int hdc_get_flags(int hdc) { diff --git a/src/disk/hdc.h b/src/disk/hdc.h index 8dd1ac8a5..89e34a1d9 100644 --- a/src/disk/hdc.h +++ b/src/disk/hdc.h @@ -8,7 +8,7 @@ * * Definitions for the common disk controller handler. * - * Version: @(#)hdc.h 1.0.7 2018/03/19 + * Version: @(#)hdc.h 1.0.8 2018/04/05 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -22,7 +22,7 @@ #define MFM_NUM 2 /* 2 drives per controller supported */ #define ESDI_NUM 2 /* 2 drives per controller supported */ -#define XTIDE_NUM 2 /* 2 drives per controller supported */ +#define XTA_NUM 2 /* 2 drives per controller supported */ #define IDE_NUM 8 #define SCSI_NUM 16 /* theoretically the controller can have at * least 7 devices, with each device being @@ -47,6 +47,12 @@ extern const device_t ide_vlb_2ch_device; /* vlb_ide_2ch */ extern const device_t ide_pci_device; /* pci_ide */ extern const device_t ide_pci_2ch_device; /* pci_ide_2ch */ +extern const device_t ide_ter_device; +extern const device_t ide_qua_device; + +extern const device_t xta_wdxt150_device; /* xta_wdxt150 */ +extern const device_t xta_hd20_device; /* EuroPC internal */ + extern const device_t xtide_device; /* xtide_xt */ extern const device_t xtide_at_device; /* xtide_at */ extern const device_t xtide_acculogic_device; /* xtide_ps2 */ @@ -58,6 +64,8 @@ extern void hdc_reset(void); extern char *hdc_get_name(int hdc); extern char *hdc_get_internal_name(int hdc); +extern int hdc_get_from_internal_name(char *s); +extern int hdc_has_config(int hdc); extern const device_t *hdc_get_device(int hdc); extern int hdc_get_flags(int hdc); extern int hdc_available(int hdc); diff --git a/src/disk/hdc_esdi_at.c b/src/disk/hdc_esdi_at.c index fe8dd1870..3149704da 100644 --- a/src/disk/hdc_esdi_at.c +++ b/src/disk/hdc_esdi_at.c @@ -8,7 +8,7 @@ * * Driver for the ESDI controller (WD1007-vse1) for PC/AT. * - * Version: @(#)hdc_esdi_at.c 1.0.9 2018/03/18 + * Version: @(#)hdc_esdi_at.c 1.0.10 2018/04/17 * * Authors: Sarah Walker, * Miran Grca, @@ -104,35 +104,28 @@ typedef struct { } esdi_t; -static __inline void irq_raise(esdi_t *esdi) +static inline void +irq_raise(esdi_t *esdi) { - /* If not already pending.. */ - if (! esdi->irqstat) { - /* If enabled in the control register.. */ - if (! (esdi->fdisk & 0x02)) { - /* .. raise IRQ14. */ - picint(1<<14); - } + if (!(esdi->fdisk&2)) + picint(1 << 14); - /* Remember this. */ - esdi->irqstat = 1; - } + esdi->irqstat=1; } -static __inline void irq_lower(esdi_t *esdi) +static inline void +irq_lower(esdi_t *esdi) { - /* If raised.. */ - if (esdi->irqstat) { - /* If enabled in the control register.. */ - if (! (esdi->fdisk & 0x02)) { - /* .. drop IRQ14. */ - picintc(1<<14); - } + picintc(1 << 14); +} - /* Remember this. */ - esdi->irqstat = 0; - } + +static void +irq_update(esdi_t *esdi) +{ + if (esdi->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(esdi->fdisk & 2)) + picint(1 << 14); } @@ -384,6 +377,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) esdi->status = STAT_BUSY; } esdi->fdisk = val; + irq_update(esdi); break; } } diff --git a/src/disk/hdc_esdi_mca.c b/src/disk/hdc_esdi_mca.c index b7dbeb515..79504c6c2 100644 --- a/src/disk/hdc_esdi_mca.c +++ b/src/disk/hdc_esdi_mca.c @@ -52,7 +52,7 @@ * however, are auto-configured by the system software as * shown above. * - * Version: @(#)hdc_esdi_mca.c 1.0.9 2018/03/18 + * Version: @(#)hdc_esdi_mca.c 1.0.11 2018/04/17 * * Authors: Sarah Walker, * Fred N. van Kempen, @@ -101,8 +101,6 @@ typedef struct esdi_drive { } drive_t; typedef struct esdi { - uint16_t base; - int8_t irq; int8_t dma; uint32_t bios; @@ -190,6 +188,7 @@ typedef struct esdi { #define CMD_GET_POS_INFO 0x0a #define STATUS_LEN(x) ((x) << 8) +#define STATUS_DEVICE(x) ((x) << 5) #define STATUS_DEVICE_HOST_ADAPTER (7 << 5) @@ -197,14 +196,14 @@ static __inline void set_irq(esdi_t *dev) { if (dev->basic_ctrl & CTRL_IRQ_ENA) - picint(1 << dev->irq); + picint(1 << 14); } static __inline void clear_irq(esdi_t *dev) { - picintc(1 << dev->irq); + picintc(1 << 14); } @@ -250,23 +249,42 @@ device_not_present(esdi_t *dev) set_irq(dev); } -static void rba_out_of_range(esdi_t *dev) -{ - dev->status_len = 9; - dev->status_data[0] = dev->command | STATUS_LEN(9) | dev->cmd_dev; - dev->status_data[1] = 0x0e01; /*Command block error, invalid parameter*/ - dev->status_data[2] = 0x0007; /*RBA out of range*/ - dev->status_data[3] = 0; - dev->status_data[4] = 0; - dev->status_data[5] = 0; - dev->status_data[6] = 0; - dev->status_data[7] = 0; - dev->status_data[8] = 0; - dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; - dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE; - dev->irq_in_progress = 1; - set_irq(dev); +static void +rba_out_of_range(esdi_t *dev) +{ + dev->status_len = 9; + dev->status_data[0] = dev->command | STATUS_LEN(9) | dev->cmd_dev; + dev->status_data[1] = 0x0e01; /*Command block error, invalid parameter*/ + dev->status_data[2] = 0x0007; /*RBA out of range*/ + dev->status_data[3] = 0; + dev->status_data[4] = 0; + dev->status_data[5] = 0; + dev->status_data[6] = 0; + dev->status_data[7] = 0; + dev->status_data[8] = 0; + + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE; + dev->irq_in_progress = 1; + set_irq(dev); +} + + +static void +complete_command_status(esdi_t *dev) +{ + dev->status_len = 7; + if (dev->cmd_dev == ATTN_DEVICE_0) + dev->status_data[0] = CMD_READ | STATUS_LEN(7) | STATUS_DEVICE(0); + else + dev->status_data[0] = CMD_READ | STATUS_LEN(7) | STATUS_DEVICE(1); + dev->status_data[1] = 0x0000; /*Error bits*/ + dev->status_data[2] = 0x1900; /*Device status*/ + dev->status_data[3] = 0; /*Number of blocks left to do*/ + dev->status_data[4] = (dev->rba-1) & 0xffff; /*Last RBA processed*/ + dev->status_data[5] = (dev->rba-1) >> 8; + dev->status_data[6] = 0; /*Number of blocks requiring error recovery*/ } #define ESDI_ADAPTER_ONLY() do \ @@ -377,7 +395,8 @@ esdi_callback(void *priv) break; case 2: - dev->status = STATUS_IRQ; + complete_command_status(dev); + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; dev->irq_in_progress = 1; set_irq(dev); @@ -438,11 +457,11 @@ esdi_callback(void *priv) hdd_image_write(drive->hdd_num, dev->rba, 1, (uint8_t *)dev->data); dev->rba++; dev->sector_pos++; - ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1); + ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, + dev->cmd_dev == ATTN_DEVICE_0 ? 0 : 1); dev->data_pos = 0; } - ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); dev->status = STATUS_CMD_IN_PROGRESS; dev->cmd_state = 2; @@ -450,7 +469,8 @@ esdi_callback(void *priv) break; case 2: - dev->status = STATUS_IRQ; + complete_command_status(dev); + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; dev->irq_in_progress = 1; set_irq(dev); @@ -471,7 +491,9 @@ esdi_callback(void *priv) return; } - dev->status = STATUS_IRQ; + dev->rba += dev->sector_count; + complete_command_status(dev); + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; dev->irq_in_progress = 1; set_irq(dev); @@ -485,7 +507,8 @@ esdi_callback(void *priv) return; } - dev->status = STATUS_IRQ; + complete_command_status(dev); + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; dev->irq_in_progress = 1; set_irq(dev); @@ -499,8 +522,6 @@ esdi_callback(void *priv) return; } - if (dev->status_pos) - fatal("Status send in progress\n"); if ((dev->status & STATUS_IRQ) || dev->irq_in_progress) fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress); @@ -529,8 +550,6 @@ esdi_callback(void *priv) return; } - if (dev->status_pos) - fatal("Status send in progress\n"); if ((dev->status & STATUS_IRQ) || dev->irq_in_progress) fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress); @@ -557,8 +576,7 @@ esdi_callback(void *priv) case CMD_GET_POS_INFO: ESDI_ADAPTER_ONLY(); - if (dev->status_pos) - fatal("Status send in progress\n"); + if ((dev->status & STATUS_IRQ) || dev->irq_in_progress) fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress); @@ -567,8 +585,8 @@ esdi_callback(void *priv) dev->status_data[1] = 0xffdd; /*MCA ID*/ dev->status_data[2] = dev->pos_regs[3] | (dev->pos_regs[2] << 8); - dev->status_data[3] = 0xffff; - dev->status_data[4] = 0xffff; + dev->status_data[3] = 0xff; + dev->status_data[4] = 0xff; dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS; @@ -688,8 +706,6 @@ esdi_callback(void *priv) case 0x12: ESDI_ADAPTER_ONLY(); - if (dev->status_pos) - fatal("Status send in progress\n"); if ((dev->status & STATUS_IRQ) || dev->irq_in_progress) fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress); @@ -715,7 +731,7 @@ esdi_read(uint16_t port, void *priv) esdi_t *dev = (esdi_t *)priv; uint8_t ret = 0xff; - switch (port-dev->base) { + switch (port & 7) { case 2: /*Basic status register*/ ret = dev->status; break; @@ -739,9 +755,9 @@ esdi_write(uint16_t port, uint8_t val, void *priv) esdi_t *dev = (esdi_t *)priv; #if 0 - pclog("ESDI: wr(%04x, %02x)\n", port-dev->base, val); + pclog("ESDI: wr(%04x, %02x)\n", port & 7, val); #endif - switch (port-dev->base) { + switch (port & 7) { case 2: /*Basic control register*/ if ((dev->basic_ctrl & CTRL_RESET) && !(val & CTRL_RESET)) { dev->in_reset = 1; @@ -751,7 +767,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) dev->basic_ctrl = val; if (! (dev->basic_ctrl & CTRL_IRQ_ENA)) - picintc(1 << dev->irq); + picintc(1 << 14); break; case 3: /*Attention register*/ @@ -765,6 +781,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) dev->cmd_dev = ATTN_HOST_ADAPTER; dev->status |= STATUS_BUSY; dev->cmd_pos = 0; + dev->status_pos = 0; break; case ATTN_EOI: @@ -793,6 +810,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) dev->cmd_dev = ATTN_DEVICE_0; dev->status |= STATUS_BUSY; dev->cmd_pos = 0; + dev->status_pos = 0; break; case ATTN_EOI: @@ -815,6 +833,7 @@ esdi_write(uint16_t port, uint8_t val, void *priv) dev->cmd_dev = ATTN_DEVICE_1; dev->status |= STATUS_BUSY; dev->cmd_pos = 0; + dev->status_pos = 0; break; case ATTN_EOI: @@ -845,12 +864,11 @@ esdi_readw(uint16_t port, void *priv) esdi_t *dev = (esdi_t *)priv; uint16_t ret = 0xffff; - switch (port-dev->base) { + switch (port & 7) { case 0: /*Status Interface Register*/ if (dev->status_pos >= dev->status_len) return(0); - ret = dev->status_data[dev->status_pos++]; - if (dev->status_pos >= dev->status_len) { + ret = dev->status_data[dev->status_pos++]; if (dev->status_pos >= dev->status_len) { dev->status &= ~STATUS_STATUS_OUT_FULL; dev->status_pos = dev->status_len = 0; } @@ -870,9 +888,9 @@ esdi_writew(uint16_t port, uint16_t val, void *priv) esdi_t *dev = (esdi_t *)priv; #if 0 - pclog("ESDI: wrw(%04x, %04x)\n", port-dev->base, val); + pclog("ESDI: wrw(%04x, %04x)\n", port & 7, val); #endif - switch (port-dev->base) { + switch (port & 7) { case 0: /*Command Interface Register*/ if (dev->cmd_pos >= 4) fatal("CIR pos 4\n"); @@ -919,123 +937,55 @@ esdi_mca_write(int port, uint8_t val, void *priv) pclog("ESDI: mcawr(%04x, %02x) pos[2]=%02x pos[3]=%02x\n", port, val, dev->pos_regs[2], dev->pos_regs[3]); #endif - if (port < 0x102) return; - - /* - * The PS/2 Model 80 BIOS always enables a card if it finds one, - * even if no resources were assigned yet (because we only added - * the card, but have not run AutoConfig yet...) - * - * So, remove current address, if any. - * - * Note by Kotori: Moved this to the beginning of esdi_mca_write, - * so the *old* base is removed rather than the - * new base. - */ - io_removehandler(dev->base, 8, - esdi_read, esdi_readw, NULL, - esdi_write, esdi_writew, NULL, dev); - mem_mapping_disable(&dev->bios_rom.mapping); + if (port < 0x102) + return; /* Save the new value. */ dev->pos_regs[port & 7] = val; - /* Extract the new I/O base. */ - switch(dev->pos_regs[2] & 0x02) { - case 0x00: /* PRIMARY [0]=XXxx xx0X 0x3510 */ - dev->base = ESDI_IOADDR_PRI; - break; + io_removehandler(ESDI_IOADDR_PRI, 8, + esdi_read, esdi_readw, NULL, + esdi_write, esdi_writew, NULL, dev); + mem_mapping_disable(&dev->bios_rom.mapping); - case 0x02: /* SECONDARY [0]=XXxx xx1X 0x3518 */ - dev->base = ESDI_IOADDR_SEC; - break; - } - - /* Extract the new DMA channel. */ switch(dev->pos_regs[2] & 0x3c) { - case 0x14: /* DMA 5 [0]=XX01 01XX */ + case 0x14: dev->dma = 5; break; - - case 0x18: /* DMA 6 [0]=XX01 10XX */ + case 0x18: dev->dma = 6; break; - - case 0x1c: /* DMA 7 [0]=XX01 11XX */ + case 0x1c: dev->dma = 7; break; - - case 0x00: /* DMA 0 [0]=XX00 00XX */ + case 0x00: dev->dma = 0; break; - - case 0x01: /* DMA 1 [0]=XX00 01XX */ + case 0x04: dev->dma = 1; break; - - case 0x04: /* DMA 3 [0]=XX00 11XX */ + case 0x0c: dev->dma = 3; break; - - case 0x10: /* DMA 4 [0]=XX01 00XX */ + case 0x10: dev->dma = 4; break; } - /* Extract the new BIOS address. */ - if (! (dev->pos_regs[3] & 0x08)) switch(dev->pos_regs[3] & 0x0f) { - case 0: /* ROM C000 [1]=XXXX 0000 */ - dev->bios = 0xC0000; - break; - - case 1: /* ROM C400 [1]=XXXX 0001 */ - dev->bios = 0xC4000; - break; - - case 2: /* ROM C800 [1]=XXXX 0010 */ - dev->bios = 0xC8000; - break; - - case 3: /* ROM CC00 [1]=XXXX 0011 */ - dev->bios = 0xCC000; - break; - - case 4: /* ROM D000 [1]=XXXX 0100 */ - dev->bios = 0xD0000; - break; - - case 5: /* ROM D400 [1]=XXXX 0101 */ - dev->bios = 0xD4000; - break; - - case 6: /* ROM D800 [1]=XXXX 0110 */ - dev->bios = 0xD8000; - break; - - case 7: /* ROM DC00 [1]=XXXX 0111 */ - dev->bios = 0xDC000; - break; - } else { - /* BIOS ROM disabled. */ - dev->bios = 0x000000; - } - - if (dev->pos_regs[2] & 0x01) { - /* Card enabled; register (new) I/O handler. */ - io_sethandler(dev->base, 8, + if (dev->pos_regs[2] & 1) { + io_sethandler(ESDI_IOADDR_PRI, 8, esdi_read, esdi_readw, NULL, esdi_write, esdi_writew, NULL, dev); - /* Enable or disable the BIOS ROM. */ - if (dev->bios != 0x000000) { + if (!(dev->pos_regs[3] & 8)) { mem_mapping_enable(&dev->bios_rom.mapping); mem_mapping_set_addr(&dev->bios_rom.mapping, - dev->bios, 0x4000); + ((dev->pos_regs[3] & 7) * 0x4000) + 0xc0000, 0x4000); } /* Say hello. */ - pclog("ESDI: I/O=%04x, IRQ=%d, DMA=%d, BIOS @%05X\n", - dev->base, dev->irq, dev->dma, dev->bios); + pclog("ESDI: I/O=3510, IRQ=14, DMA=%d, BIOS @%05X\n", + dev->dma, dev->bios); } } @@ -1054,9 +1004,6 @@ esdi_init(const device_t *info) /* Mark as unconfigured. */ dev->irq_status = 0xff; - /* This is hardwired. */ - dev->irq = ESDI_IRQCHAN; - rom_init_interleaved(&dev->bios_rom, BIOS_FILE_H, BIOS_FILE_L, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); @@ -1080,7 +1027,7 @@ esdi_init(const device_t *info) drive->spt = hdd[i].spt; drive->hpc = hdd[i].hpc; drive->tracks = hdd[i].tracks; - drive->sectors = hdd[i].spt*hdd[i].hpc*hdd[i].tracks; + drive->sectors = hdd_image_get_last_sector(i) + 1; drive->hdd_num = i; /* Mark drive as present. */ diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index d5a5f36d5..9207b36fd 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdc_ide.c 1.0.43 2018/03/20 + * Version: @(#)hdc_ide.c 1.0.44 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, @@ -36,8 +36,8 @@ #include "../pci.h" #include "../timer.h" #include "../device.h" -#include "../cdrom/cdrom.h" #include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" #include "../plat.h" #include "../ui.h" #include "hdc.h" @@ -47,22 +47,30 @@ /* Bits of 'atastat' */ -#define ERR_STAT 0x01 -#define DRQ_STAT 0x08 /* Data request */ -#define DSC_STAT 0x10 -#define SERVICE_STAT 0x10 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 +#define ERR_STAT 0x01 /* Error */ +#define IDX_STAT 0x02 /* Index */ +#define CORR_STAT 0x04 /* Corrected data */ +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 /* Drive seek complete */ +#define SERVICE_STAT 0x10 /* ATAPI service */ +#define DWF_STAT 0x20 /* Drive write fault */ +#define DRDY_STAT 0x40 /* Ready */ +#define BSY_STAT 0x80 /* Busy */ /* Bits of 'error' */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* Media change request */ +#define AMNF_ERR 0x01 /* Address mark not found */ +#define TK0NF_ERR 0x02 /* Track 0 not found */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ +#define IDNF_ERR 0x10 /* Sector ID not found */ +#define MC_ERR 0x20 /* Media change */ +#define UNC_ERR 0x40 /* Uncorrectable data error */ +#define BBK_ERR 0x80 /* Bad block mark detected */ /* ATA Commands */ #define WIN_NOP 0x00 #define WIN_SRST 0x08 /* ATAPI Device Reset */ #define WIN_RECAL 0x10 -#define WIN_RESTORE WIN_RECAL #define WIN_READ 0x20 /* 28-Bit Read */ #define WIN_READ_NORETRY 0x21 /* 28-Bit Read - no retry*/ #define WIN_WRITE 0x30 /* 28-Bit Write */ @@ -91,31 +99,55 @@ #define WIN_SET_FEATURES 0xEF #define WIN_READ_NATIVE_MAX 0xF8 -#define FEATURE_SET_TRANSFER_MODE 0x03 -#define FEATURE_ENABLE_IRQ_OVERLAPPED 0x5d -#define FEATURE_ENABLE_IRQ_SERVICE 0x5e -#define FEATURE_DISABLE_REVERT 0x66 -#define FEATURE_ENABLE_REVERT 0xcc -#define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd -#define FEATURE_DISABLE_IRQ_SERVICE 0xde +#define FEATURE_SET_TRANSFER_MODE 0x03 +#define FEATURE_ENABLE_IRQ_OVERLAPPED 0x5d +#define FEATURE_ENABLE_IRQ_SERVICE 0x5e +#define FEATURE_DISABLE_REVERT 0x66 +#define FEATURE_ENABLE_REVERT 0xcc +#define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd +#define FEATURE_DISABLE_IRQ_SERVICE 0xde +#if 0 +/* In the future, there's going to be just the IDE_ATAPI type, + leaving it to the common ATAPI/SCSI device handler to know + what type the device is. */ enum { - IDE_NONE = 0, - IDE_HDD, - IDE_CDROM, - IDE_ZIP + IDE_NONE = 0, + IDE_HDD, + IDE_ATAPI }; +#else +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_CDROM, + IDE_ZIP +}; +#endif -IDE ide_drives[IDE_NUM + XTIDE_NUM]; -IDE *ext_ide; -int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length); -int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length); -void (*ide_bus_master_set_irq)(int channel); -int64_t idecallback[5] = {0LL, 0LL, 0LL, 0LL, 0LL}; -int cur_ide[5]; -int ide_init_ch[2] = {0, 0}; +typedef struct { + int enable, cur_dev, + irq; + int64_t callback; +} ide_board_t; + +static ide_board_t *ide_boards[4]; + +ide_t *ide_drives[IDE_NUM]; +int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +void (*ide_bus_master_set_irq)(int channel, void *priv); +void *ide_bus_master_priv[2]; +int ide_inited = 0; +int ide_ter_enabled = 0, ide_qua_enabled = 0; + +static uint16_t ide_base_main[4] = { 0x1f0, 0x170, 0x168, 0x1e8 }; +static uint16_t ide_side_main[4] = { 0x3f6, 0x376, 0x36e, 0x3ee }; + +static void ide_callback(void *priv); #ifdef ENABLE_IDE_LOG @@ -123,139 +155,197 @@ int ide_do_log = ENABLE_IDE_LOG; #endif -static void ide_log(const char *fmt, ...) +static void +ide_log(const char *fmt, ...) { #ifdef ENABLE_IDE_LOG - va_list ap; + va_list ap; - if (ide_do_log) - { + if (ide_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); - } + } #endif } -uint8_t getstat(IDE *ide) { return ide->atastat; } - - -int ide_drive_is_cdrom(IDE *ide) -{ - if (ide->channel >= 8) - { - return 0; - } - - if (atapi_cdrom_drives[ide->channel] >= CDROM_NUM) - { - return 0; - } - else - { - if ((cdrom_drives[atapi_cdrom_drives[ide->channel]].bus_type == CDROM_BUS_ATAPI_PIO_ONLY) || (cdrom_drives[atapi_cdrom_drives[ide->channel]].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) - { - return 1; - } - else - { - return 0; - } - } +uint8_t +getstat(ide_t *ide) { + return ide->atastat; } -int ide_drive_is_zip(IDE *ide) -{ - if (ide->channel >= 8) - { - return 0; - } - if (atapi_zip_drives[ide->channel] >= ZIP_NUM) - { - return 0; - } - else - { - if ((zip_drives[atapi_zip_drives[ide->channel]].bus_type == ZIP_BUS_ATAPI_PIO_ONLY) || (zip_drives[atapi_zip_drives[ide->channel]].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) - { - return 1; +int64_t +ide_get_period(ide_t *ide, int size) +{ + double period = 10.0 / 3.0; + + switch(ide->mdma_mode & 0x300) { + case 0x000: /* PIO */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 10.0 / 3.0; + break; + case 1: + period = (period * 600.0) / 383.0; + break; + case 2: + period = 25.0 / 3.0; + break; + case 3: + period = 100.0 / 9.0; + break; + case 4: + period = 50.0 / 3.0; + break; } - else - { - return 0; + break; + case 0x100: /* Single Word DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 25.0 / 12.0; + break; + case 1: + period = 25.0 / 6.0; + break; + case 2: + period = 25.0 / 3.0; + break; } - } + break; + case 0x200: /* Multiword DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 25.0 / 6.0; + break; + case 1: + period = 40.0 / 3.0; + break; + case 2: + period = 50.0 / 3.0; + break; + } + break; + case 0x300: /* Ultra DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 50.0 / 3.0; + break; + case 1: + period = 25.0; + break; + case 2: + period = 100.0 / 3.0; + break; + case 3: + period = 400.0 / 9.0; + break; + case 4: + period = 200.0 / 3.0; + break; + case 5: + period = 100.0; + break; + } + break; + } + + period *= 1048576.0; /* period * MB */ + period = 1000000.0 / period; + period *= (double) TIMER_USEC; + period *= (double) size; + return (int64_t) period; } -int ide_enable[5] = { 1, 1, 0, 0, 1 }; -int ide_irq[5] = { 14, 15, 10, 11, 0 }; -void ide_irq_raise(IDE *ide) +int +ide_drive_is_cdrom(ide_t *ide) { - /* ide_log("Attempting to raise IRQ %i (board %i)\n", ide_irq[ide->board], ide->board); */ + int ch = ide->channel; - if ((ide->board > 3) || ide->irqstat) - { - ide->irqstat=1; - ide->service=1; + if (ch >= 8) + return 0; - return; - } + if (atapi_cdrom_drives[ch] >= CDROM_NUM) + return 0; + else { + if (cdrom_drives[atapi_cdrom_drives[ch]].bus_type == CDROM_BUS_ATAPI) + return 1; + else + return 0; + } +} - ide_log("Raising IRQ %i (board %i)\n", ide_irq[ide->board], ide->board); - - if (!(ide->fdisk&2)) - { - if (pci_use_mirq(0) && (ide->board == 1)) - { - pci_set_mirq(0); - } - else - { - picint(1 << ide_irq[ide->board]); - } - if (ide->board < 2) - { - if (ide_bus_master_set_irq) - { - ide_bus_master_set_irq(ide->board | 0x40); - } - } - } +int +ide_drive_is_zip(ide_t *ide) +{ + int ch = ide->channel; + if (ch >= 8) + return 0; + + if (atapi_zip_drives[ch] >= ZIP_NUM) + return 0; + else { + if (zip_drives[atapi_zip_drives[ch]].bus_type == ZIP_BUS_ATAPI) + return 1; + else + return 0; + } +} + + +void +ide_irq_raise(ide_t *ide) +{ + if (!ide_boards[ide->board]) + return; + + /* ide_log("Raising IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ + + if ((ide_boards[ide->board]->irq == -1) || ide->irqstat) { ide->irqstat=1; ide->service=1; -} -void ide_irq_lower(IDE *ide) -{ - if ((ide->board > 3) || !(ide->irqstat)) - { - ide->irqstat=0; - return; - } + return; + } - ide_log("Lowering IRQ %i (board %i)\n", ide_irq[ide->board], ide->board); - - if (pci_use_mirq(0) && (ide->board == 1)) - { - pci_clear_mirq(0); - } + if (!(ide->fdisk&2)) { + if ((ide->board < 2) && ide_bus_master_set_irq) + ide_bus_master_set_irq(ide->board | 0x40, ide_bus_master_priv[ide->board]); else - { - picintc(1 << ide_irq[ide->board]); - } + picint(1 << ide_boards[ide->board]->irq); + } - if (ide_bus_master_set_irq) - { - ide_bus_master_set_irq(ide->board); - } - ide->irqstat=0; + ide->irqstat=1; + ide->service=1; } + +void +ide_irq_lower(ide_t *ide) +{ + if (!ide_boards[ide->board]) + return; + + /* ide_log("Lowering IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ + + if ((ide_boards[ide->board]->irq == -1) || !(ide->irqstat)) { + ide->irqstat=0; + return; + } + + if ((ide->board < 2) && ide_bus_master_set_irq) + ide_bus_master_set_irq(ide->board, ide_bus_master_priv[ide->board]); + else + picintc(1 << ide_boards[ide->board]->irq); + + ide->irqstat=0; +} + + /** * Copy a string into a buffer, padding with spaces, and placing characters as * if they were packed into 16-bit values, stored little-endian. @@ -268,22 +358,18 @@ void ide_irq_lower(IDE *ide) static void ide_padstr(char *str, const char *src, int len) { - int i, v; + int i, v; - for (i = 0; i < len; i++) - { - if (*src != '\0') - { - v = *src++; - } - else - { - v = ' '; - } - str[i ^ 1] = v; - } + for (i = 0; i < len; i++) { + if (*src != '\0') + v = *src++; + else + v = ' '; + str[i ^ 1] = v; + } } + /** * Copy a string into a buffer, padding with spaces. Does not add string * terminator. @@ -295,1017 +381,1066 @@ ide_padstr(char *str, const char *src, int len) */ void ide_padstr8(uint8_t *buf, int buf_size, const char *src) { - int i; + int i; - for (i = 0; i < buf_size; i++) - { - if (*src != '\0') - { - buf[i] = *src++; - } - else - { - buf[i] = ' '; - } - } + for (i = 0; i < buf_size; i++) { + if (*src != '\0') + buf[i] = *src++; + else + buf[i] = ' '; + } } + +/* Type: + 0 = PIO, + 1 = SDMA, + 2 = MDMA, + 3 = UDMA + Return: + -1 = Not supported, + Anything else = maximum mode + + This will eventually be hookable. */ +enum { + TYPE_PIO = 0, + TYPE_SDMA, + TYPE_MDMA, + TYPE_UDMA +}; + +static int +ide_get_max(ide_t *ide, int type) +{ + switch(type) { + case TYPE_PIO: /* PIO */ + if (!PCI || (ide->board >= 2)) + return 0; /* Maximum PIO 0 for legacy PIO-only drive. */ + else { + if (ide_drive_is_zip(ide)) + return 3; + else + return 4; + } + break; + case TYPE_SDMA: /* SDMA */ + if (!PCI || (ide->board >= 2) || ide_drive_is_zip(ide)) + return -1; + else + return 2; + case TYPE_MDMA: /* MDMA */ + if (!PCI || (ide->board >= 2)) + return -1; + else { + if (ide_drive_is_zip(ide)) + return 1; + else + return 2; + } + case TYPE_UDMA: /* UDMA */ + if (!PCI || (ide->board >= 2)) + return -1; + else + return 2; + default: + fatal("Unknown transfer type: %i\n", type); + return -1; + } +} + + +/* Return: + 0 = Not supported, + Anything else = timings + + This will eventually be hookable. */ +enum { + TIMINGS_DMA = 0, + TIMINGS_PIO, + TIMINGS_PIO_FC +}; + +static int +ide_get_timings(ide_t *ide, int type) +{ + switch(type) { + case TIMINGS_DMA: + if (!PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0x96; + else + return 120; + } + break; + case TIMINGS_PIO: + if (!PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0xb4; + else + return 120; + } + break; + case TIMINGS_PIO_FC: + if (!PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0xb4; + else + return 0; + } + break; + default: + fatal("Unknown transfer type: %i\n", type); + return 0; + } +} + + /** * Fill in ide->buffer with the output of the "IDENTIFY DEVICE" command */ -static void ide_identify(IDE *ide) +static void ide_hd_identify(ide_t *ide) { - uint32_t d; - char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; - uint64_t d_hpc, d_spt, d_tracks; - uint64_t full_size = (hdd[ide->hdd_num].tracks * hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + uint32_t d_hpc, d_spt, d_tracks; + uint64_t full_size = (hdd[ide->hdd_num].tracks * hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); - device_identify[6] = (ide->hdd_num / 10) + 0x30; - device_identify[7] = (ide->hdd_num % 10) + 0x30; - ide_log("IDE Identify: %s\n", device_identify); + device_identify[6] = (ide->hdd_num / 10) + 0x30; + device_identify[7] = (ide->hdd_num % 10) + 0x30; + ide_log("IDE Identify: %s\n", device_identify); - memset(ide->buffer, 0, 512); - d_spt = ide->spt; - if (ide->hpc <= 16) { - /* HPC <= 16, report as needed. */ - d_tracks = ide->tracks; - d_hpc = ide->hpc; + d_spt = ide->spt; + if (ide->hpc <= 16) { + /* HPC <= 16, report as needed. */ + d_tracks = ide->tracks; + d_hpc = ide->hpc; + } else { + /* HPC > 16, convert to 16 HPC. */ + d_hpc = 16; + d_tracks = (ide->tracks * ide->hpc) / 16; + } + + /* Specify default CHS translation */ + if (full_size <= 16514064) { + ide->buffer[1] = d_tracks; /* Tracks in default CHS translation. */ + ide->buffer[3] = d_hpc; /* Heads in default CHS translation. */ + ide->buffer[6] = d_spt; /* Heads in default CHS translation. */ + } else { + ide->buffer[1] = 16383; /* Tracks in default CHS translation. */ + ide->buffer[3] = 16; /* Heads in default CHS translation. */ + ide->buffer[6] = 63; /* Heads in default CHS translation. */ + } + ide_log("Default CHS translation: %i, %i, %i\n", ide->buffer[1], ide->buffer[3], ide->buffer[6]); + + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ + ide->buffer[20] = 3; /*Buffer type*/ + ide->buffer[21] = 512; /*Buffer size*/ + ide->buffer[50] = 0x4000; /* Capabilities */ + ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; + + if ((ide->tracks >= 1024) || (ide->hpc > 16) || (ide->spt > 63)) { + ide->buffer[49] = (1 << 9); + ide_log("LBA supported\n"); + + ide->buffer[60] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[61] = (full_size >> 16) & 0x0FFF; + ide_log("Full size: %" PRIu64 "\n", full_size); + + /* + Bit 0 = The fields reported in words 54-58 are valid; + Bit 1 = The fields reported in words 64-70 are valid; + Bit 2 = The fields reported in word 88 are valid. */ + ide->buffer[53] = 1; + + if (ide->specify_success) { + ide->buffer[54] = (full_size / ide->t_hpc) / ide->t_spt; + ide->buffer[55] = ide->t_hpc; + ide->buffer[56] = ide->t_spt; } else { - /* HPC > 16, convert to 16 HPC. */ - d_hpc = 16; - d_tracks = (ide->tracks * ide->hpc) / 16; - } - - /* Specify default CHS translation */ - if (full_size <= 16514064) { - ide->buffer[1] = d_tracks; /* Tracks in default CHS translation. */ - ide->buffer[3] = d_hpc; /* Heads in default CHS translation. */ - ide->buffer[6] = d_spt; /* Heads in default CHS translation. */ - } else { - ide->buffer[1] = 16383; /* Tracks in default CHS translation. */ - ide->buffer[3] = 16; /* Heads in default CHS translation. */ - ide->buffer[6] = 63; /* Heads in default CHS translation. */ - } - ide_log("Default CHS translation: %i, %i, %i\n", ide->buffer[1], ide->buffer[3], ide->buffer[6]); - - ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ - ide->buffer[20] = 3; /*Buffer type*/ - ide->buffer[21] = 512; /*Buffer size*/ - ide->buffer[48] = 1; /*Dword transfers supported*/ - if (PCI && (ide->board < 2) && (hdd[ide->hdd_num].bus == HDD_BUS_IDE_PIO_AND_DMA)) { - ide->buffer[47] = 32 | 0x8000; /*Max sectors on multiple transfer command*/ - ide->buffer[49] = (1 << 8); /* LBA and DMA supported */ - } else { - ide->buffer[47] = 16 | 0x8000; /*Max sectors on multiple transfer command*/ - ide->buffer[49] = 0; - } - if ((ide->tracks >= 1024) || (ide->hpc > 16) || (ide->spt > 63)) - { - ide->buffer[49] |= (1 << 9); - ide_log("LBA supported\n"); - } - ide->buffer[50] = 0x4000; /* Capabilities */ - ide->buffer[51] = 2 << 8; /*PIO timing mode*/ - - if (ide->buffer[49] & (1 << 9)) - { - ide->buffer[60] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ - ide->buffer[61] = (full_size >> 16) & 0x0FFF; - ide_log("Full size: %" PRIu64 "\n", full_size); - - ide->buffer[53] |= 1; - - if (ide->specify_success) { - ide->buffer[54] = (full_size / ide->t_hpc) / ide->t_spt; - ide->buffer[55] = ide->t_hpc; - ide->buffer[56] = ide->t_spt; + if (full_size <= 16514064) { + ide->buffer[54] = d_tracks; + ide->buffer[55] = d_hpc; + ide->buffer[56] = d_spt; } else { - if (full_size <= 16514064) { - ide->buffer[54] = d_tracks; - ide->buffer[55] = d_hpc; - ide->buffer[56] = d_spt; - } else { - ide->buffer[54] = 16383; - ide->buffer[55] = 16; - ide->buffer[56] = 63; - } + ide->buffer[54] = 16383; + ide->buffer[55] = 16; + ide->buffer[56] = 63; } - - full_size = ((uint64_t) ide->buffer[54]) * ((uint64_t) ide->buffer[55]) * ((uint64_t) ide->buffer[56]); - - ide->buffer[57] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ - ide->buffer[58] = (full_size >> 16) & 0x0FFF; - - ide_log("Current CHS translation: %i, %i, %i\n", ide->buffer[54], ide->buffer[55], ide->buffer[56]); } - ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; + full_size = ((uint64_t) ide->buffer[54]) * ((uint64_t) ide->buffer[55]) * ((uint64_t) ide->buffer[56]); - if (ide->buffer[49] & (1 << 8)) - { - ide->buffer[51] = 120; - ide->buffer[52] = 120; /*DMA timing mode*/ - ide->buffer[53] |= 6; + ide->buffer[57] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[58] = (full_size >> 16) & 0x0FFF; - ide->buffer[62] = 7; - ide->buffer[63] = 7; - ide->buffer[64] = 3; /*PIO Modes 3 & 4*/ - ide->buffer[88] = 7; - if (ide->mdma_mode != -1) - { - d = (ide->mdma_mode & 0xff); - d <<= 8; - if ((ide->mdma_mode & 0x300) == 0x200) - ide->buffer[88] |= d; - else if ((ide->mdma_mode & 0x300) == 0x100) - ide->buffer[63] |= d; - else if ((ide->mdma_mode & 0x300) == 0x400) { - if ((ide->mdma_mode & 0xff) >= 3) - ide->buffer[64] |= d; - } else - ide->buffer[62] |= d; - ide_log(" IDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); - } - ide->buffer[65] = 120; - ide->buffer[66] = 120; - ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ - ide->buffer[81] = 0x18; /*ATA-4 revision 18 supported*/ - } else { - ide->buffer[80] = 0x0e; /*ATA-1 to ATA-3 supported*/ - } + ide_log("Current CHS translation: %i, %i, %i\n", ide->buffer[54], ide->buffer[55], ide->buffer[56]); + } + + if (PCI && (ide->board < 2)) { + ide->buffer[47] = 32 | 0x8000; /*Max sectors on multiple transfer command*/ + ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ + ide->buffer[81] = 0x18; /*ATA-4 revision 18 supported*/ + } else { + ide->buffer[47] = 16 | 0x8000; /*Max sectors on multiple transfer command*/ + ide->buffer[80] = 0x0e; /*ATA-1 to ATA-3 supported*/ + } } + /** * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command */ -static void ide_atapi_identify(IDE *ide) +static void +ide_atapi_cdrom_identify(ide_t *ide) { - char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; - uint8_t cdrom_id; - int32_t d; + uint8_t cdrom_id; - memset(ide->buffer, 0, 512); - cdrom_id = atapi_cdrom_drives[ide->channel]; + cdrom_id = atapi_cdrom_drives[ide->channel]; - device_identify[7] = cdrom_id + 0x30; - ide_log("ATAPI Identify: %s\n", device_identify); + device_identify[7] = cdrom_id + 0x30; + ide_log("ATAPI Identify: %s\n", device_identify); - ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ - ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ - ide->buffer[48] = 1; /*Dword transfers supported*/ - ide->buffer[49] = 0x200; /* LBA supported */ - ide->buffer[51] = 2 << 8; /*PIO timing mode*/ - ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ - if (PCI && (ide->board < 2) && (cdrom_drives[cdrom_id].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) - { - ide->buffer[49] |= 0x100; /* DMA supported */ - ide->buffer[51] = 120; - ide->buffer[52] = 120; /*DMA timing mode*/ - ide->buffer[53] = 7; - ide->buffer[62] = 7; - ide->buffer[63] = 7; - ide->buffer[64] = 3; /*PIO Modes 3 & 4*/ - ide->buffer[88] = 7; - if (ide->mdma_mode != -1) - { - d = (ide->mdma_mode & 0xff); - d <<= 8; - if ((ide->mdma_mode & 0x300) == 0x200) - ide->buffer[88] |= d; - else if ((ide->mdma_mode & 0x300) == 0x100) - ide->buffer[63] |= d; - else if ((ide->mdma_mode & 0x300) == 0x400) { - if ((ide->mdma_mode & 0xff) >= 3) - ide->buffer[64] |= d; - } else - ide->buffer[62] |= d; - ide_log("PIDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); - } - ide->buffer[65] = 120; - ide->buffer[66] = 120; - ide->buffer[67] = 120; - ide->buffer[71] = 30; - ide->buffer[72] = 30; - ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ - ide->buffer[81] = 0x18; /*ATA-4 revision 18 supported*/ - } + if (PCI && (ide->board < 2)) { + ide->buffer[71] = 30; + ide->buffer[72] = 30; + } } -static void ide_atapi_zip_identify(IDE *ide) + +static void +ide_atapi_zip_100_identify(ide_t *ide) { - uint8_t zip_id; - int32_t d; - - memset(ide->buffer, 0, 512); - zip_id = atapi_zip_drives[ide->channel]; - - /* Using (2<<5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive - as a LS-120. */ - ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (1<<5); /* ATAPI device, direct-access device, removable media, interrupt DRQ */ - ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - if (zip_drives[zip_id].is_250) { - ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ - } else { - ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ - } - - ide->buffer[48] = 1; /*Dword transfers supported*/ - ide->buffer[49] = 0x200; /* LBA supported */ - - /* Note by Kotori: Look at this if this is supported by ZIP at all. */ - ide->buffer[51] = 2 << 8; /*PIO timing mode*/ - - ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ - - if (PCI && (ide->board < 2) && (zip_drives[zip_id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) - { - ide->buffer[49] |= 0x100; /* DMA supported */ - if (zip_drives[zip_id].is_250) { - ide->buffer[52] = 0 << 8; /*DMA timing mode*/ - ide->buffer[53] = 6; - ide->buffer[63] = 3; - ide->buffer[88] = 7; - ide->buffer[64] = 0x0001; /*PIO Mode 3*/ - ide->buffer[65] = 0x96; - ide->buffer[66] = 0x96; - ide->buffer[67] = 0xb4; - ide->buffer[68] = 0xb4; - ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ - ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ - } else { - ide->buffer[51] = 120; - ide->buffer[52] = 120; - ide->buffer[53] = 2; /*Words 64-70 are valid*/ - ide->buffer[63] = 0x0003; /*Multi-word DMA 0 & 1*/ - ide->buffer[88] = 7; - ide->buffer[64] = 0x0001; /*PIO Mode 3*/ - ide->buffer[65] = 120; - ide->buffer[66] = 120; - ide->buffer[67] = 120; - } - - if (ide->mdma_mode != -1) - { - d = (ide->mdma_mode & 0xff); - d <<= 8; - if ((ide->mdma_mode & 0x300) == 0x200) - ide->buffer[88] |= d; - else if ((ide->mdma_mode & 0x300) == 0x100) - ide->buffer[63] |= d; - else if ((ide->mdma_mode & 0x300) == 0x400) { - if ((ide->mdma_mode & 0xff) >= 3) - ide->buffer[64] |= d; - } - ide_log("PIDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); - } - } + ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ } + +static void +ide_atapi_zip_250_identify(ide_t *ide) +{ + ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ + + if (PCI && (ide->board < 2)) { + ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ + ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ + } +} + + +static void +ide_atapi_zip_identify(ide_t *ide) +{ + uint8_t zip_id; + + zip_id = atapi_zip_drives[ide->channel]; + + /* Using (2<<5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive + as a LS-120. */ + ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (1<<5); /* ATAPI device, direct-access device, removable media, interrupt DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (zip_drives[zip_id].is_250) + ide_atapi_zip_250_identify(ide); + else + ide_atapi_zip_100_identify(ide); +} + +static void +ide_identify(ide_t *ide) +{ + int d, i, max_pio, max_sdma, max_mdma, max_udma; + + ide_log("IDE IDENTIFY or IDENTIFY PACKET DEVICE on board %i (channel %i)\n", ide->board, ide->channel); + + memset(ide->buffer, 0, 512); + + if (ide_drive_is_cdrom(ide)) + ide_atapi_cdrom_identify(ide); + else if (ide_drive_is_zip(ide)) + ide_atapi_zip_identify(ide); + else if (ide->type != IDE_NONE) + ide_hd_identify(ide); + else { + fatal("IDE IDENTIFY or IDENTIFY PACKET DEVICE on non-attached IDE device\n"); + return; + } + + max_pio = ide_get_max(ide, TYPE_PIO); + max_sdma = ide_get_max(ide, TYPE_SDMA); + max_mdma = ide_get_max(ide, TYPE_MDMA); + max_udma = ide_get_max(ide, TYPE_UDMA); + + ide->buffer[48] |= 1; /*Dword transfers supported*/ + ide->buffer[51] = ide_get_timings(ide, TIMINGS_PIO); + ide->buffer[53] &= 0x0006; + ide->buffer[52] = ide->buffer[62] = ide->buffer[63] = ide->buffer[64] = 0x0000; + ide->buffer[65] = ide->buffer[66] = ide->buffer[67] = ide->buffer[68] = 0x0000; + ide->buffer[88] = 0x0000; + + if (max_pio >= 3) { + ide->buffer[53] |= 0x0002; + ide->buffer[67] = ide_get_timings(ide, TIMINGS_PIO); + ide->buffer[68] = ide_get_timings(ide, TIMINGS_PIO_FC); + for (i = 3; i <= max_pio; i++) + ide->buffer[64] |= (1 << (i - 3)); + } + if (max_sdma != -1) { + for (i = 0; i <= max_sdma; i++) + ide->buffer[62] |= (1 << i); + } + if (max_mdma != -1) { + for (i = 0; i <= max_mdma; i++) + ide->buffer[63] |= (1 << i); + } + if (max_udma != -1) { + ide->buffer[53] |= 0x0004; + for (i = 0; i <= max_udma; i++) + ide->buffer[88] |= (1 << i); + } + + if ((max_sdma != -1) || (max_mdma != -1) || (max_udma != -1)) { + ide->buffer[49] |= 0x100; /* DMA supported */ + ide->buffer[52] = ide_get_timings(ide, TIMINGS_DMA); + } + + if ((max_mdma != -1) || (max_udma != -1)) { + ide->buffer[65] = ide_get_timings(ide, TIMINGS_DMA); + ide->buffer[66] = ide_get_timings(ide, TIMINGS_DMA); + } + + if (ide->mdma_mode != -1) { + d = (ide->mdma_mode & 0xff); + d <<= 8; + if ((ide->mdma_mode & 0x300) == 0x000) { + if ((ide->mdma_mode & 0xff) >= 3) + ide->buffer[64] |= d; + } else if ((ide->mdma_mode & 0x300) == 0x100) + ide->buffer[62] |= d; + else if ((ide->mdma_mode & 0x300) == 0x200) + ide->buffer[63] |= d; + else if ((ide->mdma_mode & 0x300) == 0x300) + ide->buffer[88] |= d; + ide_log("PIDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); + } +} + + /* * Return the sector offset for the current register values */ -static off64_t ide_get_sector(IDE *ide) +static off64_t +ide_get_sector(ide_t *ide) { - if (ide->lba) - { - return (off64_t)ide->lba_addr + ide->skip512; - } - else - { - uint32_t heads = ide->t_hpc; - uint32_t sectors = ide->t_spt; + uint32_t heads, sectors; - return ((((off64_t) ide->cylinder * heads) + ide->head) * - sectors) + (ide->sector - 1) + ide->skip512; - } + if (ide->lba) + return (off64_t)ide->lba_addr + ide->skip512; + else { + heads = ide->t_hpc; + sectors = ide->t_spt; + + return ((((off64_t) ide->cylinder * heads) + ide->head) * + sectors) + (ide->sector - 1) + ide->skip512; + } } + /** * Move to the next sector using CHS addressing */ -static void ide_next_sector(IDE *ide) +static void +ide_next_sector(ide_t *ide) { - if (ide->lba) - { - ide->lba_addr++; - } - else - { - ide->sector++; - if (ide->sector == (ide->t_spt + 1)) - { - ide->sector = 1; - ide->head++; - if (ide->head == ide->t_hpc) - { - ide->head = 0; - ide->cylinder++; - } - } - } -} - -static void loadhd(IDE *ide, int d, const wchar_t *fn) -{ - if (! hdd_image_load(d)) { - ide->type = IDE_NONE; - return; - } - - ide->spt = hdd[d].spt; - ide->hpc = hdd[d].hpc; - ide->tracks = hdd[d].tracks; - ide->type = IDE_HDD; - ide->hdd_num = d; - ide->hdi = hdd_image_get_type(d); -} - -void ide_set_signature(IDE *ide) -{ - uint8_t cdrom_id = atapi_cdrom_drives[ide->channel]; - uint8_t zip_id = atapi_zip_drives[ide->channel]; - ide->sector=1; - ide->head=0; - if (ide_drive_is_zip(ide)) - { - zip_set_signature(zip_id); - ide->secount = zip[zip_id].phase; - ide->cylinder = zip[zip_id].request_length; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom_set_signature(cdrom_id); - ide->secount = cdrom[cdrom_id]->phase; - ide->cylinder = cdrom[cdrom_id]->request_length; - } - else - { - ide->secount=1; - ide->cylinder=((ide->type == IDE_HDD) ? 0 : 0xFFFF); - if (ide->type == IDE_HDD) - { - ide->drive = 0; + if (ide->lba) + ide->lba_addr++; + else { + ide->sector++; + if (ide->sector == (ide->t_spt + 1)) { + ide->sector = 1; + ide->head++; + if (ide->head == ide->t_hpc) { + ide->head = 0; + ide->cylinder++; } } + } } -static int ide_set_features(IDE *ide) + +static void +loadhd(ide_t *ide, int d, const wchar_t *fn) { - uint8_t features, features_data; - uint8_t mode, submode; + if (! hdd_image_load(d)) { + ide->type = IDE_NONE; + return; + } - int bus, dma; - int max_pio = 2, max_mdma = 2; + ide->spt = hdd[d].spt; + ide->hpc = hdd[d].hpc; + ide->tracks = hdd[d].tracks; + ide->type = IDE_HDD; + ide->hdd_num = d; +} - features = ide->cylprecomp; - features_data = ide->secount; - if (ide_drive_is_zip(ide)) { - bus = zip_drives[atapi_zip_drives[ide->channel]].bus_type; - dma = (bus == ZIP_BUS_ATAPI_PIO_AND_DMA); - if (!PCI || !dma || (ide->board >= 2)) - max_pio = 0; - else - max_pio = 3; - max_mdma = 1; - } else if (ide_drive_is_cdrom(ide)) { - bus = cdrom_drives[atapi_cdrom_drives[ide->channel]].bus_type; - dma = (bus == CDROM_BUS_ATAPI_PIO_AND_DMA); - if (!PCI || !dma || (ide->board >= 2)) - max_pio = 0; - else - max_pio = 4; - } else { - bus = hdd[ide->hdd_num].bus; - dma = (bus == HDD_BUS_IDE_PIO_AND_DMA); - if (!PCI || !dma || (ide->board >= 2)) - max_pio = 0; - else - max_pio = 4; - } +void +ide_set_signature(ide_t *ide) +{ + uint8_t cdrom_id = atapi_cdrom_drives[ide->channel]; + uint8_t zip_id = atapi_zip_drives[ide->channel]; - ide_log("Features code %02X\n", features); + ide->sector=1; + ide->head=0; - ide_log("IDE %02X: Set features: %02X, %02X\n", ide->channel, features, features_data); + if (ide_drive_is_zip(ide)) { + zip_set_signature(zip_id); + ide->secount = zip[zip_id]->phase; + ide->cylinder = zip[zip_id]->request_length; + } else if (ide_drive_is_cdrom(ide)) { + cdrom_set_signature(cdrom[cdrom_id]); + ide->secount = cdrom[cdrom_id]->phase; + ide->cylinder = cdrom[cdrom_id]->request_length; + } else { + ide->secount=1; + ide->cylinder=((ide->type == IDE_HDD) ? 0 : 0xFFFF); + if (ide->type == IDE_HDD) + ide->drive = 0; + } +} - switch(features) - { - case FEATURE_SET_TRANSFER_MODE: /* Set transfer mode. */ - ide_log("Transfer mode %02X\n", features_data >> 3); - mode = (features_data >> 3); - submode = features_data & 7; +static int +ide_set_features(ide_t *ide) +{ + uint8_t features, features_data; + int mode, submode, max; - switch(mode) - { - case 0x00: /* PIO default */ - if (submode != 0) - { - return 0; - } - ide->mdma_mode = -1; - ide_log("IDE %02X: Setting DPIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); - break; + features = ide->cylprecomp; + features_data = ide->secount; - case 0x01: /* PIO mode */ - if (submode > max_pio) - { - return 0; - } - ide->mdma_mode = (1 << submode) | 0x400; - ide_log("IDE %02X: Setting PIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); - break; + ide_log("Features code %02X\n", features); - case 0x02: /* Singleword DMA mode */ - if (!PCI || !dma || ide_drive_is_zip(ide) || (ide->board >= 2) || (submode > 2)) - { - return 0; - } - ide->mdma_mode = (1 << submode); - ide_log("IDE %02X: Setting SDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); - break; + ide_log("IDE %02X: Set features: %02X, %02X\n", ide->channel, features, features_data); - case 0x04: /* Multiword DMA mode */ - if (!PCI || !dma || (ide->board >= 2) || (submode > max_mdma)) - { - return 0; - } - ide->mdma_mode = (1 << submode) | 0x100; - ide_log("IDE %02X: Setting MDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); - break; + switch(features) { + case FEATURE_SET_TRANSFER_MODE: /* Set transfer mode. */ + ide_log("Transfer mode %02X\n", features_data >> 3); - case 0x08: /* Ultra DMA mode */ - if (!PCI || !dma || (ide->board >= 2) || (submode > 2)) - { - return 0; - } - ide->mdma_mode = (1 << submode) | 0x200; - ide_log("IDE %02X: Setting UDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); - break; + mode = (features_data >> 3); + submode = features_data & 7; - default: + switch(mode) { + case 0x00: /* PIO default */ + if (submode != 0) return 0; - } + max = ide_get_max(ide, TYPE_PIO); + ide->mdma_mode = (1 << max); + ide_log("IDE %02X: Setting DPIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; - case FEATURE_ENABLE_IRQ_OVERLAPPED: - case FEATURE_ENABLE_IRQ_SERVICE: - case FEATURE_DISABLE_IRQ_OVERLAPPED: - case FEATURE_DISABLE_IRQ_SERVICE: - if (!PCI || !dma || (ide->board >= 2)) + case 0x01: /* PIO mode */ + max = ide_get_max(ide, TYPE_PIO); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode); + ide_log("IDE %02X: Setting PIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x02: /* Singleword DMA mode */ + max = ide_get_max(ide, TYPE_SDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x100; + ide_log("IDE %02X: Setting SDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x04: /* Multiword DMA mode */ + max = ide_get_max(ide, TYPE_MDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x200; + ide_log("IDE %02X: Setting MDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x08: /* Ultra DMA mode */ + max = ide_get_max(ide, TYPE_UDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x300; + ide_log("IDE %02X: Setting UDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + default: return 0; - else - return 1; + } - case FEATURE_DISABLE_REVERT: /* Disable reverting to power on defaults. */ - case FEATURE_ENABLE_REVERT: /* Enable reverting to power on defaults. */ + case FEATURE_ENABLE_IRQ_OVERLAPPED: + case FEATURE_ENABLE_IRQ_SERVICE: + case FEATURE_DISABLE_IRQ_OVERLAPPED: + case FEATURE_DISABLE_IRQ_SERVICE: + max = ide_get_max(ide, TYPE_MDMA); + if (max == -1) + return 0; + else return 1; - default: - return 0; - } + case FEATURE_DISABLE_REVERT: /* Disable reverting to power on defaults. */ + case FEATURE_ENABLE_REVERT: /* Enable reverting to power on defaults. */ + return 1; - return 1; -} + default: + return 0; + } -void ide_set_sector(IDE *ide, int64_t sector_num) -{ - unsigned int cyl, r; - if (ide->lba) - { - ide->head = (sector_num >> 24); - ide->cylinder = (sector_num >> 8); - ide->sector = (sector_num); - } - else - { - cyl = sector_num / (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); - r = sector_num % (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); - ide->cylinder = cyl; - ide->head = ((r / hdd[ide->hdd_num].spt) & 0x0f); - ide->sector = (r % hdd[ide->hdd_num].spt) + 1; - } -} - -void ide_ter_disable_cond(); -void ide_qua_disable_cond(); - - -void ide_destroy_buffers(void) -{ - int d; - - for (d = 0; d < (IDE_NUM+XTIDE_NUM); d++) - { - if (ide_drives[d].buffer) { - free(ide_drives[d].buffer); - ide_drives[d].buffer = NULL; - } - - if (ide_drives[d].sector_buffer) { - free(ide_drives[d].sector_buffer); - ide_drives[d].sector_buffer = NULL; - } - } -} - -void ide_reset(void) -{ - int c, d; - - build_atapi_cdrom_map(); - build_atapi_zip_map(); - - /* Close hard disk image files (if previously open) */ - for (d = 0; d < (IDE_NUM+XTIDE_NUM); d++) - { - ide_drives[d].channel = d; - ide_drives[d].type = IDE_NONE; - if (ide_drives[d].hdd_num != -1) - hdd_image_close(ide_drives[d].hdd_num); - if ((d < 8) && ide_drive_is_zip(&ide_drives[d])) - { - zip[atapi_zip_drives[d]].status = READY_STAT | DSC_STAT; - } - else if ((d < 8) && ide_drive_is_cdrom(&ide_drives[d])) - { - cdrom[atapi_cdrom_drives[d]]->status = READY_STAT | DSC_STAT; - } - ide_drives[d].atastat = READY_STAT | DSC_STAT; - ide_drives[d].service = 0; - ide_drives[d].board = d >> 1; - - if (ide_drives[d].buffer) { - free(ide_drives[d].buffer); - ide_drives[d].buffer = NULL; - } - - if (ide_drives[d].sector_buffer) { - free(ide_drives[d].sector_buffer); - ide_drives[d].sector_buffer = NULL; - } - } - - idecallback[0]=idecallback[1]=0LL; - idecallback[2]=idecallback[3]=0LL; - idecallback[4]=0LL; - - ide_log("IDE: loading disks...\n"); - c = 0; - for (d = 0; d < HDD_NUM; d++) - { - if (((hdd[d].bus == HDD_BUS_IDE_PIO_ONLY) || (hdd[d].bus == HDD_BUS_IDE_PIO_AND_DMA)) && (hdd[d].ide_channel < IDE_NUM)) - { - ide_log("Found IDE hard disk on channel %i\n", hdd[d].ide_channel); - loadhd(&ide_drives[hdd[d].ide_channel], d, hdd[d].fn); - ide_drives[hdd[d].ide_channel].sector_buffer = (uint8_t *) malloc(256*512); - memset(ide_drives[hdd[d].ide_channel].sector_buffer, 0, 256*512); - if (++c >= (IDE_NUM+XTIDE_NUM)) break; - } - if ((hdd[d].bus==HDD_BUS_XTIDE) && (hdd[d].xtide_channel < XTIDE_NUM)) - { - ide_log("Found XT IDE hard disk on channel %i\n", hdd[d].xtide_channel); - loadhd(&ide_drives[hdd[d].xtide_channel | 8], d, hdd[d].fn); - ide_drives[hdd[d].xtide_channel | 8].sector_buffer = (uint8_t *) malloc(256*512); - memset(ide_drives[hdd[d].ide_channel].sector_buffer, 0, 256*512); - if (++c >= (IDE_NUM+XTIDE_NUM)) break; - } - } - ide_log("IDE: done, loaded %d disks.\n", c); - - for (d = 0; d < IDE_NUM; d++) - { - if (ide_drive_is_zip(&ide_drives[d]) && (ide_drives[d].type == IDE_NONE)) - ide_drives[d].type = IDE_ZIP; - else if (ide_drive_is_cdrom(&ide_drives[d]) && (ide_drives[d].type == IDE_NONE)) - ide_drives[d].type = IDE_CDROM; - - if (ide_drives[d].type != IDE_NONE) { - ide_drives[d].buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); - memset(ide_drives[d].buffer, 0, 65536 * sizeof(uint16_t)); - } - - ide_set_signature(&ide_drives[d]); - - ide_drives[d].mdma_mode = -1; - ide_drives[d].error = 1; - } - - for (d = 0; d < XTIDE_NUM; d++) - { - ide_set_signature(&ide_drives[d | 8]); - - ide_drives[d | 8].mdma_mode = -1; - ide_drives[d | 8].error = 1; - } - - for (d = 0; d < 5; d++) - { - cur_ide[d] = d << 1; - } - - ide_ter_disable_cond(); - ide_qua_disable_cond(); + return 1; } -void ide_set_all_signatures(void) +void +ide_set_sector(ide_t *ide, int64_t sector_num) { - int d; - - for (d = 0; d < IDE_NUM; d++) - { - ide_set_signature(&ide_drives[d]); - - if (ide_drives[d].sector_buffer) - memset(ide_drives[d].sector_buffer, 0, 256*512); - - if (ide_drives[d].buffer) - memset(ide_drives[d].buffer, 0, 65536 * sizeof(uint16_t)); - } + unsigned int cyl, r; + if (ide->lba) { + ide->head = (sector_num >> 24); + ide->cylinder = (sector_num >> 8); + ide->sector = (sector_num); + } else { + cyl = sector_num / (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + r = sector_num % (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + ide->cylinder = cyl; + ide->head = ((r / hdd[ide->hdd_num].spt) & 0x0f); + ide->sector = (r % hdd[ide->hdd_num].spt) + 1; + } } -void ide_reset_hard(void) +static void +ide_zero(int d) { - int d; + ide_t *dev; + ide_drives[d] = (ide_t *) malloc(sizeof(ide_t)); + memset(ide_drives[d], 0, sizeof(ide_t)); + dev = ide_drives[d]; + dev->channel = d; + dev->type = IDE_NONE; + dev->hdd_num = -1; + dev->atastat = DRDY_STAT | DSC_STAT; + dev->service = 0; + dev->board = d >> 1; +} - for (d = 0; d < (IDE_NUM+XTIDE_NUM); d++) - { - ide_drives[d].t_spt = ide_drives[d].spt; - ide_drives[d].t_hpc = ide_drives[d].hpc; - ide_drives[d].specify_success = 0; + +static void +ide_board_close(int board) +{ + ide_t *dev; + int c, d; + + /* Close hard disk image files (if previously open) */ + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if ((dev->type == IDE_HDD) && (dev->hdd_num != -1)) + hdd_image_close(dev->hdd_num); + + if (board < 4) { + if (ide_drive_is_zip(dev)) + zip[atapi_zip_drives[c]]->status = DRDY_STAT | DSC_STAT; + else if (ide_drive_is_cdrom(dev)) + cdrom[atapi_cdrom_drives[c]]->status = DRDY_STAT | DSC_STAT; } - ide_reset(); + if (dev->buffer) + free(dev->buffer); + + if (dev->sector_buffer) + free(dev->sector_buffer); + + if (dev) + free(dev); + } } -int idetimes = 0; - -void ide_set_callback(uint8_t channel, int64_t callback) +static void +ide_board_init(int board) { - IDE *ide = &ide_drives[channel]; - if (callback) - idecallback[ide->board] += callback; - else - idecallback[ide->board] = 0LL; + ide_t *dev; + int c, d; + int max, ch; + int is_ide, valid_ch; + int min_ch, max_ch; + + min_ch = (board << 1); + max_ch = min_ch + 1; + + ide_log("IDE: board %i: loading disks...\n", board); + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + ide_zero(c); + } + + c = 0; + for (d = 0; d < HDD_NUM; d++) { + is_ide = (hdd[d].bus == HDD_BUS_IDE); + ch = hdd[d].ide_channel; + + if (board == 4) { + valid_ch = ((ch >= 0) && (ch <= 1)); + ch |= 8; + } else + valid_ch = ((ch >= min_ch) && (ch <= max_ch)); + + if (is_ide && valid_ch) { + ide_log("Found IDE hard disk on channel %i\n", ch); + loadhd(ide_drives[ch], d, hdd[d].fn); + ide_drives[ch]->sector_buffer = (uint8_t *) malloc(256*512); + memset(ide_drives[ch]->sector_buffer, 0, 256*512); + if (++c >= 2) break; + } + } + ide_log("IDE: board %i: done, loaded %d disks.\n", board, c); + + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if (board < 4) { + if (ide_drive_is_zip(dev) && (dev->type == IDE_NONE)) + dev->type = IDE_ZIP; + else if (ide_drive_is_cdrom(dev) && (dev->type == IDE_NONE)) + dev->type = IDE_CDROM; + } + + if (dev->type != IDE_NONE) { + dev->buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); + memset(dev->buffer, 0, 65536 * sizeof(uint16_t)); + } + + ide_set_signature(dev); + + max = ide_get_max(dev, TYPE_PIO); + dev->mdma_mode = (1 << max); + dev->error = 1; + } } -void ide_write_data(int ide_board, uint32_t val, int length) + +void +ide_set_callback(uint8_t board, int64_t callback) { - IDE *ide = &ide_drives[cur_ide[ide_board]]; + ide_board_t *dev = ide_boards[board]; - uint8_t *idebufferb = (uint8_t *) ide->buffer; - uint16_t *idebufferw = ide->buffer; - uint32_t *idebufferl = (uint32_t *) ide->buffer; - - if (ide->command == WIN_PACKETCMD) - { - ide->pos = 0; + ide_log("ide_set_callback(%i)\n", board); - if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) - { - return; - } + if (!dev) { + ide_log("Set callback failed\n"); + return; + } - if (ide_drive_is_zip(ide)) - zip_write(cur_ide[ide_board], val, length); - else - cdrom_write(cur_ide[ide_board], val, length); + if (callback) + dev->callback = callback; + else + dev->callback = 0LL; +} + + +void +ide_write_data(ide_t *ide, uint32_t val, int length) +{ + int ch = ide->channel; + + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint16_t *idebufferw = ide->buffer; + uint32_t *idebufferl = (uint32_t *) ide->buffer; + + if (ide->command == WIN_PACKETCMD) { + ide->pos = 0; + + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) return; - } + + if (ide_drive_is_zip(ide)) + zip_write(ch, val, length); else - { - switch(length) - { - case 1: - idebufferb[ide->pos] = val & 0xff; - ide->pos++; - break; - case 2: - idebufferw[ide->pos >> 1] = val & 0xffff; - ide->pos += 2; - break; - case 4: - idebufferl[ide->pos >> 2] = val; - ide->pos += 4; - break; - default: - return; - } - - if (ide->pos>=512) - { - ide->pos=0; - ide->atastat = BUSY_STAT; - timer_process(); - if (ide->command == WIN_WRITE_MULTIPLE) - { - callbackide(ide_board); - } - else - { - idecallback[ide_board]=6LL*IDE_TIME; - } - timer_update_outstanding(); - } + cdrom_write(ch, val, length); + return; + } else { + switch(length) { + case 1: + idebufferb[ide->pos] = val & 0xff; + ide->pos++; + break; + case 2: + idebufferw[ide->pos >> 1] = val & 0xffff; + ide->pos += 2; + break; + case 4: + idebufferl[ide->pos >> 2] = val; + ide->pos += 4; + break; + default: + return; } + + if (ide->pos>=512) { + ide->pos=0; + ide->atastat = BSY_STAT; + timer_process(); + if (ide->command == WIN_WRITE_MULTIPLE) + ide_callback(ide_boards[ide->board]); + else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + timer_update_outstanding(); + } + } } -void writeidew(int ide_board, uint16_t val) + +void +ide_writew(uint16_t addr, uint16_t val, void *priv) { - ide_write_data(ide_board, val, 2); + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + /* ide_log("ide_writew %04X %04X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); */ + + addr &= 0x7; + + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; + + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val, 2); + break; + } } -void writeidel(int ide_board, uint32_t val) + +static void +ide_writel(uint16_t addr, uint32_t val, void *priv) { - writeidew(ide_board, val); - writeidew(ide_board, val >> 16); + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + /* ide_log("ide_writel %04X %08X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); */ + + addr &= 0x7; + + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; + + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val & 0xffff, 2); + ide_write_data(ide, val >> 16, 2); + break; + } } -void writeide(int ide_board, uint16_t addr, uint8_t val) + +void +ide_write_devctl(uint16_t addr, uint8_t val, void *priv) { - IDE *ide = &ide_drives[cur_ide[ide_board]]; - IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; + ide_board_t *dev = (ide_board_t *) priv; - ide_log("WriteIDE %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); - addr|=0x90; - addr&=0xFFF7; + ide_t *ide, *ide_other; + int ch; - if (ide->type == IDE_NONE && (addr == 0x1f0 || addr == 0x1f7)) return; - - switch (addr) - { - case 0x1F0: /* Data */ - writeidew(ide_board, val | (val << 8)); - return; + ch = dev->cur_dev; + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; - /* Note to self: for ATAPI, bit 0 of this is DMA if set, PIO if clear. */ - case 0x1F1: /* Features */ - if (ide_drive_is_zip(ide)) - { - ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); - zip[atapi_zip_drives[cur_ide[ide_board]]].features = val; - } - else if (ide_drive_is_cdrom(ide)) - { - ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); - cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->features = val; - } - ide->cylprecomp = val; + ide_log("ide_write_devctl %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); - if (ide_drive_is_zip(ide_other)) - { - zip[atapi_zip_drives[cur_ide[ide_board] ^ 1]].features = val; - } - else if (ide_drive_is_cdrom(ide_other)) - { - cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]]->features = val; - } - ide_other->cylprecomp = val; - return; + if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) { + timer_process(); + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 0LL; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; + ide_set_callback(ide->board, 500LL * IDE_TIME); + timer_update_outstanding(); - case 0x1F2: /* Sector count */ - if (ide_drive_is_zip(ide)) - { - ide_log("Sector count write: %i\n", val); - zip[atapi_zip_drives[cur_ide[ide_board]]].phase = val; - } - else if (ide_drive_is_cdrom(ide)) - { - ide_log("Sector count write: %i\n", val); - cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->phase = val; - } - ide->secount = val; + if (ide->type != IDE_NONE) + ide->reset = 1; + if (ide_other->type != IDE_NONE) + ide->reset = 1; + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + ide->atastat = ide_other->atastat = BSY_STAT; + } - if (ide_drive_is_zip(ide_other)) - { - ide_log("Other sector count write: %i\n", val); - zip[atapi_zip_drives[cur_ide[ide_board] ^ 1]].phase = val; - } - else if (ide_drive_is_cdrom(ide_other)) - { - ide_log("Other sector count write: %i\n", val); - cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]]->phase = val; - } - ide_other->secount = val; - return; + if (val & 4) { + /*Drive held in reset*/ + timer_process(); + ide_set_callback(ide->board, 0LL); + timer_update_outstanding(); + ide->atastat = ide_other->atastat = BSY_STAT; + } + ide->fdisk = ide_other->fdisk = val; + return; +} - case 0x1F3: /* Sector */ - ide->sector = val; - ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val; - ide_other->sector = val; - ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val; - return; - case 0x1F4: /* Cylinder low */ - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[cur_ide[ide_board]]].request_length &= 0xFF00; - zip[atapi_zip_drives[cur_ide[ide_board]]].request_length |= val; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->request_length &= 0xFF00; - cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->request_length |= val; - } - ide->cylinder = (ide->cylinder & 0xFF00) | val; - ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); +void +ide_writeb(uint16_t addr, uint8_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; - if (ide_drive_is_zip(ide_other)) - { - zip[atapi_zip_drives[cur_ide[ide_board] ^ 1]].request_length &= 0xFF00; - zip[atapi_zip_drives[cur_ide[ide_board] ^ 1]].request_length |= val; - } - else if (ide_drive_is_cdrom(ide_other)) - { - cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]]->request_length &= 0xFF00; - cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]]->request_length |= val; - } - ide_other->cylinder = (ide_other->cylinder&0xFF00) | val; - ide_other->lba_addr = (ide_other->lba_addr&0xFFF00FF) | (val << 8); - return; + ide_t *ide, *ide_other; + int ch; - case 0x1F5: /* Cylinder high */ - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[cur_ide[ide_board]]].request_length &= 0xFF; - zip[atapi_zip_drives[cur_ide[ide_board]]].request_length |= (val << 8); - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->request_length &= 0xFF; - cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->request_length |= (val << 8); - } - ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); - ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); + ch = dev->cur_dev; + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; - if (ide_drive_is_zip(ide_other)) - { - zip[atapi_zip_drives[cur_ide[ide_board] ^ 1]].request_length &= 0xFF; - zip[atapi_zip_drives[cur_ide[ide_board] ^ 1]].request_length |= (val << 8); - } - else if (ide_drive_is_cdrom(ide_other)) - { - cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]]->request_length &= 0xFF; - cdrom[atapi_cdrom_drives[cur_ide[ide_board] ^ 1]]->request_length |= (val << 8); - } - ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); - ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); - return; + ide_log("ide_write %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); - case 0x1F6: /* Drive/Head */ - if (cur_ide[ide_board] != ((val>>4)&1)+(ide_board<<1)) - { - cur_ide[ide_board]=((val>>4)&1)+(ide_board<<1); + addr &= 0x7; - if (ide->reset || ide_other->reset) - { - ide->atastat = ide_other->atastat = READY_STAT | DSC_STAT; - ide->error = ide_other->error = 1; - ide->secount = ide_other->secount = 1; - ide->sector = ide_other->sector = 1; - ide->head = ide_other->head = 0; - ide->cylinder = ide_other->cylinder = 0; - ide->reset = ide_other->reset = 0; + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].status = READY_STAT | DSC_STAT; - zip[atapi_zip_drives[ide->channel]].error = 1; - zip[atapi_zip_drives[ide->channel]].phase = 1; - zip[atapi_zip_drives[ide->channel]].request_length = 0xEB14; - zip[atapi_zip_drives[ide->channel]].callback = 0LL; - ide->cylinder = 0xEB14; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->status = READY_STAT | DSC_STAT; - cdrom[atapi_cdrom_drives[ide->channel]]->error = 1; - cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; - cdrom[atapi_cdrom_drives[ide->channel]]->request_length = 0xEB14; - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; - ide->cylinder = 0xEB14; - } + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val | (val << 8), 2); + return; - if (ide_drive_is_zip(ide_other)) - { - zip[atapi_zip_drives[ide_other->channel]].status = READY_STAT | DSC_STAT; - zip[atapi_zip_drives[ide_other->channel]].error = 1; - zip[atapi_zip_drives[ide_other->channel]].phase = 1; - zip[atapi_zip_drives[ide_other->channel]].request_length = 0xEB14; - zip[atapi_zip_drives[ide_other->channel]].callback = 0LL; - ide->cylinder = 0xEB14; - } - else if (ide_drive_is_cdrom(ide_other)) - { - cdrom[atapi_cdrom_drives[ide_other->channel]]->status = READY_STAT | DSC_STAT; - cdrom[atapi_cdrom_drives[ide_other->channel]]->error = 1; - cdrom[atapi_cdrom_drives[ide_other->channel]]->phase = 1; - cdrom[atapi_cdrom_drives[ide_other->channel]]->request_length = 0xEB14; - cdrom[atapi_cdrom_drives[ide_other->channel]]->callback = 0LL; - ide->cylinder = 0xEB14; - } + /* Note to self: for ATAPI, bit 0 of this is DMA if set, PIO if clear. */ + case 0x1: /* Features */ + if (ide_drive_is_zip(ide)) { + ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); + zip[atapi_zip_drives[ch]]->features = val; + } else if (ide_drive_is_cdrom(ide)) { + ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); + cdrom[atapi_cdrom_drives[ch]]->features = val; + } + ide->cylprecomp = val; - idecallback[ide_board] = 0LL; - timer_update_outstanding(); - return; + if (ide_drive_is_zip(ide_other)) + zip[atapi_zip_drives[ch ^ 1]]->features = val; + else if (ide_drive_is_cdrom(ide_other)) + cdrom[atapi_cdrom_drives[ch ^ 1]]->features = val; + ide_other->cylprecomp = val; + return; + + case 0x2: /* Sector count */ + if (ide_drive_is_zip(ide)) { + ide_log("Sector count write: %i\n", val); + zip[atapi_zip_drives[ch]]->phase = val; + } else if (ide_drive_is_cdrom(ide)) { + ide_log("Sector count write: %i\n", val); + cdrom[atapi_cdrom_drives[ch]]->phase = val; + } + ide->secount = val; + + if (ide_drive_is_zip(ide_other)) { + ide_log("Other sector count write: %i\n", val); + zip[atapi_zip_drives[ch ^ 1]]->phase = val; + } else if (ide_drive_is_cdrom(ide_other)) { + ide_log("Other sector count write: %i\n", val); + cdrom[atapi_cdrom_drives[ch ^ 1]]->phase = val; + } + ide_other->secount = val; + return; + + case 0x3: /* Sector */ + ide->sector = val; + ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val; + ide_other->sector = val; + ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val; + return; + + case 0x4: /* Cylinder low */ + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->request_length &= 0xFF00; + zip[atapi_zip_drives[ch]]->request_length |= val; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF00; + cdrom[atapi_cdrom_drives[ch]]->request_length |= val; + } + ide->cylinder = (ide->cylinder & 0xFF00) | val; + ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); + + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF00; + zip[atapi_zip_drives[ch ^ 1]]->request_length |= val; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF00; + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= val; + } + ide_other->cylinder = (ide_other->cylinder & 0xFF00) | val; + ide_other->lba_addr = (ide_other->lba_addr & 0xFFF00FF) | (val << 8); + return; + + case 0x5: /* Cylinder high */ + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->request_length &= 0xFF; + zip[atapi_zip_drives[ch]]->request_length |= (val << 8); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF; + cdrom[atapi_cdrom_drives[ch]]->request_length |= (val << 8); + } + ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); + ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); + + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF; + zip[atapi_zip_drives[ch ^ 1]]->request_length |= (val << 8); + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF; + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= (val << 8); + } + ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); + ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); + return; + + case 0x6: /* Drive/Head */ + if (ch != ((val >> 4) & 1) + (ide->board << 1)) { + ide_boards[ide->board]->cur_dev = ((val >> 4) & 1) + (ide->board << 1); + ch = ide_boards[ide->board]->cur_dev; + + if (ide->reset || ide_other->reset) { + ide->atastat = ide_other->atastat = DRDY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + ide->reset = ide_other->reset = 0; + + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ide->channel]]->error = 1; + zip[atapi_zip_drives[ide->channel]]->phase = 1; + zip[atapi_zip_drives[ide->channel]]->request_length = 0xEB14; + zip[atapi_zip_drives[ide->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->error = 1; + cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; + cdrom[atapi_cdrom_drives[ide->channel]]->request_length = 0xEB14; + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; } - ide = &ide_drives[cur_ide[ide_board]]; - } - - ide->head = val & 0xF; - ide->lba = val & 0x40; - ide_other->head = val & 0xF; - ide_other->lba = val & 0x40; - - ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); - ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF)|((val & 0xF) << 24); + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ide_other->channel]]->error = 1; + zip[atapi_zip_drives[ide_other->channel]]->phase = 1; + zip[atapi_zip_drives[ide_other->channel]]->request_length = 0xEB14; + zip[atapi_zip_drives[ide_other->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide_other->channel]]->error = 1; + cdrom[atapi_cdrom_drives[ide_other->channel]]->phase = 1; + cdrom[atapi_cdrom_drives[ide_other->channel]]->request_length = 0xEB14; + cdrom[atapi_cdrom_drives[ide_other->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } - return; - - case 0x1F7: /* Command register */ - if (ide->type == IDE_NONE) - { + ide_set_callback(ide->board, 0LL); + timer_update_outstanding(); return; } + ide = ide_drives[ch]; + } + + ide->head = val & 0xF; + ide->lba = val & 0x40; + ide_other->head = val & 0xF; + ide_other->lba = val & 0x40; + + ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); + ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF)|((val & 0xF) << 24); + return; + + case 0x7: /* Command register */ + if (ide->type == IDE_NONE) + return; + ide_irq_lower(ide); ide->command=val; ide->error=0; if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].error = 0; - } + zip[atapi_zip_drives[ide->channel]]->error = 0; else if (ide_drive_is_cdrom(ide)) - { cdrom[atapi_cdrom_drives[ide->channel]]->error = 0; - } - if (((val >= WIN_RESTORE) && (val <= 0x1F)) || ((val >= WIN_SEEK) && (val <= 0x7F))) - { + + if (((val >= WIN_RECAL) && (val <= 0x1F)) || ((val >= WIN_SEEK) && (val <= 0x7F))) { if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].status = READY_STAT; - } + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT; else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->status = READY_STAT; - } + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT; else - { - ide->atastat = BUSY_STAT; - } + ide->atastat = BSY_STAT; timer_process(); + if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].callback = 100LL*IDE_TIME; - } - if (ide_drive_is_cdrom(ide)) - { + zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; - } - idecallback[ide_board]=40000LL * TIMER_USEC /*100LL*IDE_TIME*/; + ide_set_callback(ide->board, 100LL * IDE_TIME); timer_update_outstanding(); return; } - switch (val) - { + + switch (val) { case WIN_SRST: /* ATAPI Device Reset */ if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].status = BUSY_STAT; - } + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->status = BUSY_STAT; - } + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; else - { - ide->atastat = READY_STAT; - } + ide->atastat = DRDY_STAT; timer_process(); + if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].callback = 100LL*IDE_TIME; - } + zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; else if (ide_drive_is_cdrom(ide)) - { cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; - } - idecallback[ide_board]=100LL*IDE_TIME; - timer_update_outstanding(); - return; + ide_set_callback(ide->board, 100LL * IDE_TIME); + timer_update_outstanding(); + return; case WIN_READ_MULTIPLE: /* Fatal removed in accordance with the official ATAPI reference: @@ -1314,124 +1449,99 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) disabled, the Read Multiple operation is rejected with an Aborted Com- mand error. */ ide->blockcount = 0; + /* Turn on the activity indicator *here* so that it gets turned on + less times. */ + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ case WIN_READ: case WIN_READ_NORETRY: case WIN_READ_DMA: case WIN_READ_DMA_ALT: if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].status = BUSY_STAT; - } + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->status = BUSY_STAT; - } + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; else - { - ide->atastat = BUSY_STAT; - } + ide->atastat = BSY_STAT; timer_process(); + if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].callback = 200LL*IDE_TIME; - } + zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; else if (ide_drive_is_cdrom(ide)) - { cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; - } - idecallback[ide_board]=200LL*IDE_TIME; + if (ide->type == IDE_HDD) { + if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { + if (ide->secount) + ide_set_callback(ide->board, ide_get_period(ide, (int) ide->secount << 9)); + else + ide_set_callback(ide->board, ide_get_period(ide, 131072)); + } else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + } else + ide_set_callback(ide->board, 200LL * IDE_TIME); timer_update_outstanding(); ide->do_initial_read = 1; return; case WIN_WRITE_MULTIPLE: if (!ide->blocksize && !ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) - { fatal("Write_MULTIPLE - blocksize = 0\n"); - } ide->blockcount = 0; + /* Turn on the activity indicator *here* so that it gets turned on + less times. */ + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ case WIN_WRITE: case WIN_WRITE_NORETRY: - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].status = DRQ_STAT | DSC_STAT | READY_STAT; - zip[atapi_zip_drives[ide->channel]].pos = 0; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | READY_STAT; + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; + zip[atapi_zip_drives[ide->channel]]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; cdrom[atapi_cdrom_drives[ide->channel]]->pos = 0; - } - else - { - ide->atastat = DRQ_STAT | DSC_STAT | READY_STAT; + } else { + ide->atastat = DRQ_STAT | DSC_STAT | DRDY_STAT; ide->pos=0; } return; case WIN_WRITE_DMA: case WIN_WRITE_DMA_ALT: - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].status = BUSY_STAT; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->status = BUSY_STAT; - } - else - { - ide->atastat = BUSY_STAT; - } - timer_process(); - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].callback = 200LL*IDE_TIME; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; - } - idecallback[ide_board]=200LL*IDE_TIME; - timer_update_outstanding(); - return; - case WIN_VERIFY: case WIN_VERIFY_ONCE: + case WIN_IDENTIFY: /* Identify Device */ + case WIN_SET_FEATURES: /* Set Features */ + case WIN_READ_NATIVE_MAX: if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].status = BUSY_STAT; - } + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->status = BUSY_STAT; - } + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; else - { - ide->atastat = BUSY_STAT; - } + ide->atastat = BSY_STAT; timer_process(); + if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].callback = 200LL*IDE_TIME; - } + zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; else if (ide_drive_is_cdrom(ide)) - { cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; - } - idecallback[ide_board]=200LL*IDE_TIME; + if ((ide->type == IDE_HDD) && + ((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) { + if (ide->secount) + ide_set_callback(ide->board, ide_get_period(ide, (int) ide->secount << 9)); + else + ide_set_callback(ide->board, ide_get_period(ide, 131072)); + } else if ((ide->type == IDE_HDD) && + ((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) + ide_set_callback(ide->board, ide_get_period(ide, 512)); + else + ide_set_callback(ide->board, 200LL * IDE_TIME); timer_update_outstanding(); return; case WIN_FORMAT: if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) - { goto ide_bad_command; - } - else - { + else { ide->atastat = DRQ_STAT; ide->pos=0; } @@ -1439,51 +1549,42 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) case WIN_SPECIFY: /* Initialize Drive Parameters */ if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].status = BUSY_STAT; - } + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->status = BUSY_STAT; - } + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; else - { - ide->atastat = BUSY_STAT; - } + ide->atastat = BSY_STAT; timer_process(); + if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].callback = 30LL*IDE_TIME; - } + zip[atapi_zip_drives[ide->channel]]->callback = 30LL*IDE_TIME; else if (ide_drive_is_cdrom(ide)) - { cdrom[atapi_cdrom_drives[ide->channel]]->callback = 30LL*IDE_TIME; - } - idecallback[ide_board]=30LL*IDE_TIME; + ide_set_callback(ide->board, 30LL * IDE_TIME); timer_update_outstanding(); return; case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]].status = BUSY_STAT; + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BUSY_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; else - ide->atastat = BUSY_STAT; + ide->atastat = BSY_STAT; if (ide_drive_is_zip(ide_other)) - zip[atapi_zip_drives[ide_other->channel]].status = BUSY_STAT; + zip[atapi_zip_drives[ide_other->channel]]->status = BSY_STAT; else if (ide_drive_is_cdrom(ide_other)) - cdrom[atapi_cdrom_drives[ide_other->channel]]->status = BUSY_STAT; + cdrom[atapi_cdrom_drives[ide_other->channel]]->status = BSY_STAT; else - ide_other->atastat = BUSY_STAT; + ide_other->atastat = BSY_STAT; timer_process(); if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]].callback = 200LL * IDE_TIME; + zip[atapi_zip_drives[ide->channel]]->callback = 200LL * IDE_TIME; else if (ide_drive_is_cdrom(ide)) cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL * IDE_TIME; - idecallback[ide_board] = 200LL * IDE_TIME; + ide_set_callback(ide->board, 200LL * IDE_TIME); timer_update_outstanding(); return; @@ -1496,66 +1597,33 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) case WIN_CHECKPOWERMODE1: case WIN_SLEEP1: if (ide_drive_is_zip(ide)) - zip[atapi_zip_drives[ide->channel]].status = BUSY_STAT; + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; else if (ide_drive_is_cdrom(ide)) - cdrom[atapi_cdrom_drives[ide->channel]]->status = BUSY_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; else - ide->atastat = BUSY_STAT; + ide->atastat = BSY_STAT; timer_process(); - callbackide(ide_board); - timer_update_outstanding(); - return; - - case WIN_IDENTIFY: /* Identify Device */ - case WIN_SET_FEATURES: /* Set Features */ - case WIN_READ_NATIVE_MAX: - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].status = BUSY_STAT; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->status = BUSY_STAT; - } - else - { - ide->atastat = BUSY_STAT; - } - timer_process(); - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].callback = 200LL*IDE_TIME; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; - } - idecallback[ide_board]=200LL*IDE_TIME; + ide_callback(dev); timer_update_outstanding(); return; case WIN_PACKETCMD: /* ATAPI Packet */ /* Skip the command callback wait, and process immediately. */ - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].packet_status = ZIP_PHASE_IDLE; - zip[atapi_zip_drives[ide->channel]].pos=0; - zip[atapi_zip_drives[ide->channel]].phase = 1; - zip[atapi_zip_drives[ide->channel]].status = READY_STAT | DRQ_STAT; - ide_irq_raise(ide); /* Interrupt IRQ, requires IRQ on any DRQ. */ - } - else if (ide_drive_is_cdrom(ide)) - { + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->packet_status = ZIP_PHASE_IDLE; + zip[atapi_zip_drives[ide->channel]]->pos=0; + zip[atapi_zip_drives[ide->channel]]->phase = 1; + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; + ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */ + } else if (ide_drive_is_cdrom(ide)) { cdrom[atapi_cdrom_drives[ide->channel]]->packet_status = CDROM_PHASE_IDLE; cdrom[atapi_cdrom_drives[ide->channel]]->pos=0; cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; - cdrom[atapi_cdrom_drives[ide->channel]]->status = READY_STAT | DRQ_STAT; - } - else - { - ide->atastat = BUSY_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; + } else { + ide->atastat = BSY_STAT; timer_process(); - idecallback[ide_board]=200LL*IDE_TIME; + ide_set_callback(ide->board, 200LL * IDE_TIME); timer_update_outstanding(); ide->pos=0; } @@ -1564,1318 +1632,1042 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) case 0xF0: default: ide_bad_command: - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].status = READY_STAT | ERR_STAT | DSC_STAT; - zip[atapi_zip_drives[ide->channel]].error = ABRT_ERR; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->status = READY_STAT | ERR_STAT | DSC_STAT; + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + zip[atapi_zip_drives[ide->channel]]->error = ABRT_ERR; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; cdrom[atapi_cdrom_drives[ide->channel]]->error = ABRT_ERR; - } - else - { - ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; + } else { + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; ide->error = ABRT_ERR; } ide_irq_raise(ide); return; } return; - - case 0x3F6: /* Device control */ - if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) - { - timer_process(); - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].callback = 0LL; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; - } - idecallback[ide_board]=500LL*IDE_TIME; - timer_update_outstanding(); - - if (ide->type != IDE_NONE) - { - ide->reset = 1; - } - if (ide_other->type != IDE_NONE) - { - ide->reset = 1; - } - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[ide->channel]].status = BUSY_STAT; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[ide->channel]]->status = BUSY_STAT; - } - ide->atastat = ide_other->atastat = BUSY_STAT; - } - if (val & 4) - { - /*Drive held in reset*/ - timer_process(); - idecallback[ide_board] = 0LL; - timer_update_outstanding(); - ide->atastat = ide_other->atastat = BUSY_STAT; - } - ide->fdisk = ide_other->fdisk = val; - return; - } + } } -uint32_t ide_read_data(int ide_board, int length) + +static uint32_t +ide_read_data(ide_t *ide, int length) { - IDE *ide = &ide_drives[cur_ide[ide_board]]; - uint32_t temp; - - if (!ide->buffer) { - switch (length) - { - case 1: - return 0xff; - case 2: - return 0xffff; - case 4: - return 0xffffffff; - default: - return 0; - } - } - - uint8_t *idebufferb = (uint8_t *) ide->buffer; - uint16_t *idebufferw = ide->buffer; - uint32_t *idebufferl = (uint32_t *) ide->buffer; - - if (ide->command == WIN_PACKETCMD) - { - ide->pos = 0; - if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) - { - ide_log("Drive not ZIP or CD-ROM (position: %i)\n", ide->pos); - return 0; - } - if (ide_drive_is_zip(ide)) - temp = zip_read(cur_ide[ide_board], length); - else - temp = cdrom_read(cur_ide[ide_board], length); - } - else - { - switch (length) - { - case 1: - temp = idebufferb[ide->pos]; - ide->pos++; - break; - case 2: - temp = idebufferw[ide->pos >> 1]; - ide->pos += 2; - break; - case 4: - temp = idebufferl[ide->pos >> 2]; - ide->pos += 4; - break; - default: - return 0; - } - } - if (ide->pos>=512 && ide->command != WIN_PACKETCMD) - { - ide->pos=0; - ide->atastat = READY_STAT | DSC_STAT; - if (ide_drive_is_zip(ide)) - { - zip[atapi_zip_drives[cur_ide[ide_board]]].status = READY_STAT | DSC_STAT; - zip[atapi_zip_drives[cur_ide[ide_board]]].packet_status = ZIP_PHASE_IDLE; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->status = READY_STAT | DSC_STAT; - cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->packet_status = CDROM_PHASE_IDLE; - } - if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) - { - ide->secount = (ide->secount - 1) & 0xff; - if (ide->secount) - { - ide_next_sector(ide); - ide->atastat = BUSY_STAT; - timer_process(); - if (ide->command == WIN_READ_MULTIPLE) - { - callbackide(ide_board); - } - else - { - idecallback[ide_board]=6LL*IDE_TIME; - } - timer_update_outstanding(); - } - else - { - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); - } - } - } - - return temp; -} - -uint8_t readide(int ide_board, uint16_t addr) -{ - IDE *ide = &ide_drives[cur_ide[ide_board]]; - uint8_t temp; - uint16_t tempw; - - addr |= 0x90; - addr &= 0xFFF7; - - switch (addr) - { - case 0x1F0: /* Data */ - tempw = readidew(ide_board); - temp = tempw & 0xff; - break; - - /* For ATAPI: Bits 7-4 = sense key, bit 3 = MCR (media change requested), - Bit 2 = ABRT (aborted command), Bit 1 = EOM (end of media), - and Bit 0 = ILI (illegal length indication). */ - case 0x1F1: /* Error */ - if (ide->type == IDE_NONE) - { - temp = 0; - } - else - { - if (ide_drive_is_zip(ide)) - { - temp = zip[atapi_zip_drives[cur_ide[ide_board]]].error; - } - else if (ide_drive_is_cdrom(ide)) - { - temp = cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->error; - } - else - { - temp = ide->error; - } - } - break; - - /* For ATAPI: - Bit 0: Command or Data: - Data if clear, Command if set; - Bit 1: I/OB - Direction: - To device if set; - From device if clear. - IO DRQ CoD - 0 1 1 Ready to accept command packet - 1 1 1 Message - ready to send message to host - 1 1 0 Data to host - 0 1 0 Data from host - 1 0 1 Status. */ - case 0x1F2: /* Sector count */ - if (ide_drive_is_zip(ide)) - { - temp = zip[atapi_zip_drives[cur_ide[ide_board]]].phase; - } - else if (ide_drive_is_cdrom(ide)) - { - temp = cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->phase; - } - else - { - temp = ide->secount; - } - break; - - case 0x1F3: /* Sector */ - temp = (uint8_t)ide->sector; - break; - - case 0x1F4: /* Cylinder low */ - if (ide->type == IDE_NONE) - { - temp = 0xFF; - } - else - { - if (ide_drive_is_zip(ide)) - { - temp = zip[atapi_zip_drives[cur_ide[ide_board]]].request_length & 0xff; - } - else if (ide_drive_is_cdrom(ide)) - { - temp = cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->request_length & 0xff; - } - else - { - temp = ide->cylinder & 0xff; - } - } - break; - - case 0x1F5: /* Cylinder high */ - if (ide->type == IDE_NONE) - { - temp = 0xFF; - } - else - { - if (ide_drive_is_zip(ide)) - { - temp = zip[atapi_zip_drives[cur_ide[ide_board]]].request_length >> 8; - } - else if (ide_drive_is_cdrom(ide)) - { - temp = cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->request_length >> 8; - } - else - { - temp = ide->cylinder >> 8; - } - } - break; - - case 0x1F6: /* Drive/Head */ - temp = (uint8_t)(ide->head | ((cur_ide[ide_board] & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); - break; - - /* For ATAPI: Bit 5 is DMA ready, but without overlapped or interlaved DMA, it is - DF (drive fault). */ - case 0x1F7: /* Status */ - ide_irq_lower(ide); - if (ide->type == IDE_NONE) - { - temp = 0; - } - else - { - if (ide_drive_is_zip(ide)) - { - temp = (zip[atapi_zip_drives[cur_ide[ide_board]]].status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); - } - else if (ide_drive_is_cdrom(ide)) - { - temp = (cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); - } - else - { - temp = ide->atastat; - } - } - break; - - case 0x3F6: /* Alternate Status */ - if (ide->type == IDE_NONE) - { - temp = 0; - } - else - { - if (ide_drive_is_zip(ide)) - { - temp = (zip[atapi_zip_drives[cur_ide[ide_board]]].status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); - } - else if (ide_drive_is_cdrom(ide)) - { - temp = (cdrom[atapi_cdrom_drives[cur_ide[ide_board]]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); - } - else - { - temp = ide->atastat; - } - } - break; + int ch = ide->channel; + uint32_t temp; + if (!ide->buffer) { + switch (length) { + case 1: + return 0xff; + case 2: + return 0xffff; + case 4: + return 0xffffffff; default: - temp = 0xff; - break; + return 0; } - /* if (ide_board) */ ide_log("Read IDEb %04X %02X %02X %02X %i %04X:%04X %i\n", addr, temp, ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,cpu_state.pc,ide_board); - return temp; -} + } -uint8_t cdb[16]; + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint16_t *idebufferw = ide->buffer; + uint32_t *idebufferl = (uint32_t *) ide->buffer; -int old_len = 0; - -int total_read = 0; - -int block_total = 0; -int all_blocks_total = 0; - -uint16_t readidew(int ide_board) -{ - return ide_read_data(ide_board, 2); -} - -uint32_t readidel(int ide_board) -{ - uint16_t temp; - temp = readidew(ide_board); - return temp | (readidew(ide_board) << 16); -} - -int times30=0; -void callbackide(int ide_board) -{ - IDE *ide, *ide_other; - int64_t snum; - int cdrom_id; - int cdrom_id_other; - int zip_id; - int zip_id_other; - uint64_t full_size = 0; - - ide = &ide_drives[cur_ide[ide_board]]; - ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; - if (ide->type == IDE_HDD) - { - full_size = (hdd[ide->hdd_num].tracks * hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + if (ide->command == WIN_PACKETCMD) { + ide->pos = 0; + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) { + ide_log("Drive not ZIP or CD-ROM (position: %i)\n", ide->pos); + return 0; } - ext_ide = ide; - - if (ide->command==0x30) times30++; - /*if (ide_board) */ide_log("CALLBACK %02X %i %i %i\n",ide->command,times30,ide->reset,cur_ide[ide_board]); - - if (ide->reset) - { - ide->atastat = ide_other->atastat = READY_STAT | DSC_STAT; - ide->error = ide_other->error = 1; - ide->secount = ide_other->secount = 1; - ide->sector = ide_other->sector = 1; - ide->head = ide_other->head = 0; - ide->cylinder = ide_other->cylinder = 0; - ide->reset = ide_other->reset = 0; - - if (ide_drive_is_zip(ide)) - { - zip_id = atapi_zip_drives[cur_ide[ide_board]]; - zip[zip_id].status = READY_STAT | DSC_STAT; - zip[zip_id].error = 1; - zip[zip_id].phase = 1; - zip[zip_id].request_length=0xEB14; - ide->cylinder = 0xEB14; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom_id = atapi_cdrom_drives[cur_ide[ide_board]]; - cdrom[cdrom_id]->status = READY_STAT | DSC_STAT; - cdrom[cdrom_id]->error = 1; - cdrom[cdrom_id]->phase = 1; - cdrom[cdrom_id]->request_length=0xEB14; - ide->cylinder = 0xEB14; - if (cdrom_drives[cdrom_id].handler->stop) - { - cdrom_drives[cdrom_id].handler->stop(cdrom_id); - } - } - if (ide->type == IDE_NONE) - { - ide->cylinder=0xFFFF; - } - if (ide_drive_is_zip(ide_other)) - { - zip_id_other = atapi_zip_drives[cur_ide[ide_board] ^ 1]; - zip[zip_id_other].status = READY_STAT | DSC_STAT; - zip[zip_id_other].error = 1; - zip[zip_id_other].phase = 1; - zip[zip_id_other].request_length=0xEB14; - ide->cylinder = 0xEB14; - } - else if (ide_drive_is_cdrom(ide_other)) - { - cdrom_id_other = atapi_cdrom_drives[cur_ide[ide_board] ^ 1]; - cdrom[cdrom_id_other]->status = READY_STAT | DSC_STAT; - cdrom[cdrom_id_other]->error = 1; - cdrom[cdrom_id_other]->phase = 1; - cdrom[cdrom_id_other]->request_length=0xEB14; - ide_other->cylinder = 0xEB14; - if (cdrom_drives[cdrom_id_other].handler->stop) - { - cdrom_drives[cdrom_id_other].handler->stop(cdrom_id_other); - } - } - if (ide_other->type == IDE_NONE) - { - ide_other->cylinder=0xFFFF; - } - return; - } - - cdrom_id = atapi_cdrom_drives[cur_ide[ide_board]]; - cdrom_id_other = atapi_cdrom_drives[cur_ide[ide_board] ^ 1]; - - zip_id = atapi_zip_drives[cur_ide[ide_board]]; - zip_id_other = atapi_zip_drives[cur_ide[ide_board] ^ 1]; - - if (((ide->command >= WIN_RESTORE) && (ide->command <= 0x1F)) || ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F))) - { - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) - { - goto abort_cmd; - } - if ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F)) - { - full_size /= ide->t_hpc; - full_size /= ide->t_spt; - - if ((ide->cylinder >= full_size) || (ide->head >= ide->t_hpc) || !ide->sector || (ide->sector > ide->t_spt)) - goto id_not_found; - } - ide->atastat = READY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - } - switch (ide->command) - { - /* Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, - Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h. */ - case WIN_SRST: /*ATAPI Device Reset */ - ide->atastat = READY_STAT | DSC_STAT; - ide->error=1; /*Device passed*/ - ide->secount = ide->sector = 1; - ide_set_signature(ide); - - if (ide_drive_is_zip(ide)) - { - zip[zip_id].status = READY_STAT | DSC_STAT; - zip[zip_id].error = 1; - zip[zip_id].phase = 1; - zip_reset(zip_id); - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[cdrom_id]->status = READY_STAT | DSC_STAT; - cdrom[cdrom_id]->error = 1; - cdrom[cdrom_id]->phase = 1; - cdrom_reset(cdrom_id); - } - ide_irq_raise(ide); - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) - { - ide->service = 0; - } - return; - - case WIN_NOP: - case WIN_STANDBYNOW1: - case WIN_IDLENOW1: - case WIN_SETIDLE1: - if (ide_drive_is_zip(ide)) - { - zip[zip_id].status = READY_STAT | DSC_STAT; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[cdrom_id]->status = READY_STAT | DSC_STAT; - } - else - { - ide->atastat = READY_STAT | DSC_STAT; - } - ide_irq_raise(ide); - return; - - case WIN_CHECKPOWERMODE1: - case WIN_SLEEP1: - if (ide_drive_is_zip(ide)) - { - zip[zip_id].phase = 0xFF; - zip[zip_id].status = READY_STAT | DSC_STAT; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[cdrom_id]->phase = 0xFF; - cdrom[cdrom_id]->status = READY_STAT | DSC_STAT; - } - ide->secount = 0xFF; - ide->atastat = READY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - - case WIN_READ: - case WIN_READ_NORETRY: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) - { - ide_set_signature(ide); - goto abort_cmd; - } - if (!ide->specify_success) - { - goto id_not_found; - } - - if (ide->do_initial_read) - { - ide->do_initial_read = 0; - ide->sector_pos = 0; - if (ide->secount) - { - hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); - } - else - { - hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); - } - } - - memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); - - ide->sector_pos++; - ide->pos=0; - - ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; - - ide_irq_raise(ide); - - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); - return; - - case WIN_READ_DMA: - case WIN_READ_DMA_ALT: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) - { - ide_log("IDE %i: DMA read aborted (bad device or board)\n", ide->channel); - goto abort_cmd; - } - if (!ide->specify_success) - { - ide_log("IDE %i: DMA read aborted (SPECIFY failed)\n", ide->channel); - goto id_not_found; - } - - ide->sector_pos = 0; - if (ide->secount) - { - ide->sector_pos = ide->secount; - } - else - { - ide->sector_pos = 256; - } - hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); - - ide->pos=0; - - if (ide_bus_master_read) - { - if (ide_bus_master_read(ide_board, ide->sector_buffer, ide->sector_pos * 512)) - { - ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); - goto abort_cmd; - } - else - { - /*DMA successful*/ - ide_log("IDE %i: DMA read successful\n", ide->channel); - - ide->atastat = READY_STAT | DSC_STAT; - - ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); - } - } else { - ide_log("IDE %i: DMA read aborted (no bus master)\n", ide->channel); - goto abort_cmd; - } - - return; - - case WIN_READ_MULTIPLE: - /* According to the official ATA reference: - - If the Read Multiple command is attempted before the Set Multiple Mode - command has been executed or when Read Multiple commands are - disabled, the Read Multiple operation is rejected with an Aborted Com- - mand error. */ - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || !ide->blocksize) - { - goto abort_cmd; - } - if (!ide->specify_success) - { - goto id_not_found; - } - - if (ide->do_initial_read) - { - ide->do_initial_read = 0; - ide->sector_pos = 0; - if (ide->secount) - { - hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); - } - else - { - hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); - } - } - - memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); - - ide->sector_pos++; - ide->pos=0; - - ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; - if (!ide->blockcount) - { - ide_irq_raise(ide); - } - ide->blockcount++; - if (ide->blockcount >= ide->blocksize) - { - ide->blockcount = 0; - } - - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); - return; - - case WIN_WRITE: - case WIN_WRITE_NORETRY: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) - { - goto abort_cmd; - } - if (!ide->specify_success) - { - goto id_not_found; - } - hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); - ide_irq_raise(ide); - ide->secount = (ide->secount - 1) & 0xff; - if (ide->secount) - { - ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; - ide->pos=0; - ide_next_sector(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); - } - else - { - ide->atastat = READY_STAT | DSC_STAT; - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); - } - - return; - - case WIN_WRITE_DMA: - case WIN_WRITE_DMA_ALT: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide_board >= 2)) - { - ide_log("IDE %i: DMA write aborted (bad device type or board)\n", ide->channel); - goto abort_cmd; - } - if (!ide->specify_success) - { - ide_log("IDE %i: DMA write aborted (SPECIFY failed)\n", ide->channel); - goto id_not_found; - } - - if (ide_bus_master_read) - { - if (ide->secount) - ide->sector_pos = ide->secount; - else - ide->sector_pos = 256; - - if (ide_bus_master_write(ide_board, ide->sector_buffer, ide->sector_pos * 512)) - { - ide_log("IDE %i: DMA write aborted (failed)\n", ide->channel); - goto abort_cmd; - } - else - { - /*DMA successful*/ - ide_log("IDE %i: DMA write successful\n", ide->channel); - - hdd_image_write(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); - - ide->atastat = READY_STAT | DSC_STAT; - - ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); - } - } else { - ide_log("IDE %i: DMA write aborted (no bus master)\n", ide->channel); - goto abort_cmd; - } - - return; - - case WIN_WRITE_MULTIPLE: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) - { - goto abort_cmd; - } - if (!ide->specify_success) - { - goto id_not_found; - } - hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); - ide->blockcount++; - if (ide->blockcount >= ide->blocksize || ide->secount == 1) - { - ide->blockcount = 0; - ide_irq_raise(ide); - } - ide->secount = (ide->secount - 1) & 0xff; - if (ide->secount) - { - ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; - ide->pos=0; - ide_next_sector(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); - } - else - { - ide->atastat = READY_STAT | DSC_STAT; - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); - } - return; - - case WIN_VERIFY: - case WIN_VERIFY_ONCE: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) - { - goto abort_cmd; - } - if (!ide->specify_success) - { - goto id_not_found; - } - ide->pos=0; - ide->atastat = READY_STAT | DSC_STAT; - ide_irq_raise(ide); - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); - return; - - case WIN_FORMAT: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) - { - goto abort_cmd; - } - if (!ide->specify_success) - { - goto id_not_found; - } - hdd_image_zero(ide->hdd_num, ide_get_sector(ide), ide->secount); - - ide->atastat = READY_STAT | DSC_STAT; - ide_irq_raise(ide); - - /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ - return; - - case WIN_DRIVE_DIAGNOSTICS: - ide_set_signature(ide); - ide->error=1; /*No error detected*/ - - if (ide_drive_is_zip(ide)) - { - zip[zip_id].status = 0; - zip[zip_id].error = 1; - ide_irq_raise(ide); - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[cdrom_id]->status = 0; - cdrom[cdrom_id]->error = 1; - ide_irq_raise(ide); - } - else - { - ide->atastat = READY_STAT | DSC_STAT; - ide->error = 1; - ide_irq_raise(ide); - } - - ide_set_signature(ide_other); - ide_other->error=1; /*No error detected*/ - - if (ide_drive_is_zip(ide_other)) - { - zip[zip_id_other].status = 0; - zip[zip_id_other].error = 1; - } - else if (ide_drive_is_cdrom(ide_other)) - { - cdrom[cdrom_id_other]->status = 0; - cdrom[cdrom_id_other]->error = 1; - } - else - { - ide_other->atastat = READY_STAT | DSC_STAT; - ide_other->error = 1; - } - - cur_ide[ide_board] &= ~1; - return; - - case WIN_SPECIFY: /* Initialize Drive Parameters */ - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) - { - goto abort_cmd; - } - full_size /= (ide->head+1); - full_size /= ide->secount; - ide->specify_success = 1; - hdd_image_specify(ide->hdd_num, ide->head + 1, ide->secount); - ide->t_spt=ide->secount; - ide->t_hpc=ide->head; - ide->t_hpc++; - ide->atastat = READY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - - case WIN_PIDENTIFY: /* Identify Packet Device */ - if (ide_drive_is_zip(ide)) - { - ide_atapi_zip_identify(ide); - ide->pos = 0; - zip[zip_id].phase = 2; - zip[zip_id].pos = 0; - zip[zip_id].error = 0; - zip[zip_id].status = DRQ_STAT | READY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - } - else if (ide_drive_is_cdrom(ide)) - { - ide_atapi_identify(ide); - ide->pos = 0; - cdrom[cdrom_id]->phase = 2; - cdrom[cdrom_id]->pos = 0; - cdrom[cdrom_id]->error = 0; - cdrom[cdrom_id]->status = DRQ_STAT | READY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - } - goto abort_cmd; - - case WIN_SET_MULTIPLE_MODE: - if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) - { - goto abort_cmd; - } - ide->blocksize = ide->secount; - ide->atastat = READY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - - case WIN_SET_FEATURES: - if (ide->type == IDE_NONE) - { - goto abort_cmd; - } - - if (!ide_set_features(ide)) - { - goto abort_cmd; - } - else - { - if (ide_drive_is_zip(ide)) { - zip[zip_id].status = READY_STAT | DSC_STAT; - zip[zip_id].pos = 0; - } - else if (ide_drive_is_cdrom(ide)) { - cdrom[cdrom_id]->status = READY_STAT | DSC_STAT; - cdrom[cdrom_id]->pos = 0; - } - ide->atastat = READY_STAT | DSC_STAT; - ide_irq_raise(ide); - } - return; - - case WIN_READ_NATIVE_MAX: - if (ide->type != IDE_HDD) - { - goto abort_cmd; - } - snum = hdd[ide->hdd_num].spt; - snum *= hdd[ide->hdd_num].hpc; - snum *= hdd[ide->hdd_num].tracks; - ide_set_sector(ide, snum - 1); - ide->atastat = READY_STAT | DSC_STAT; - ide_irq_raise(ide); - return; - - case WIN_IDENTIFY: /* Identify Device */ - if (ide->type != IDE_HDD) - { - ide_set_signature(ide); - goto abort_cmd; - } - else - { - ide_identify(ide); - ide->pos=0; - ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; - ide_irq_raise(ide); - } - return; - - case WIN_PACKETCMD: /* ATAPI Packet */ - if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) - { - goto abort_cmd; - } - - if (ide_drive_is_zip(ide)) - zip_phase_callback(atapi_zip_drives[cur_ide[ide_board]]); - else - cdrom_phase_callback(atapi_cdrom_drives[cur_ide[ide_board]]); - ide_log("IDE callback now: %i\n", idecallback[ide_board]); - return; - - case 0xFF: - goto abort_cmd; - } - -abort_cmd: - ide->command = 0; if (ide_drive_is_zip(ide)) - { - zip[zip_id].status = READY_STAT | ERR_STAT | DSC_STAT; - zip[zip_id].error = ABRT_ERR; - zip[zip_id].pos = 0; - } - else if (ide_drive_is_cdrom(ide)) - { - cdrom[cdrom_id]->status = READY_STAT | ERR_STAT | DSC_STAT; - cdrom[cdrom_id]->error = ABRT_ERR; - cdrom[cdrom_id]->pos = 0; - } + temp = zip_read(ch, length); else - { - ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; - ide->error = ABRT_ERR; - ide->pos = 0; + temp = cdrom_read(ch, length); + } else { + switch (length) { + case 1: + temp = idebufferb[ide->pos]; + ide->pos++; + break; + case 2: + temp = idebufferw[ide->pos >> 1]; + ide->pos += 2; + break; + case 4: + temp = idebufferl[ide->pos >> 2]; + ide->pos += 4; + break; + default: + return 0; } + } + if (ide->pos>=512 && ide->command != WIN_PACKETCMD) { + ide->pos=0; + ide->atastat = DRDY_STAT | DSC_STAT; + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ch]]->packet_status = ZIP_PHASE_IDLE; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ch]]->packet_status = CDROM_PHASE_IDLE; + } + if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) { + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide_next_sector(ide); + ide->atastat = BSY_STAT; + timer_process(); + if (ide->command == WIN_READ_MULTIPLE) + ide_callback(ide_boards[ide->board]); + else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + timer_update_outstanding(); + } else { + if (ide->command != WIN_READ_MULTIPLE) + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } + } + + return temp; +} + + +static uint8_t +ide_status(ide_t *ide, int ch) +{ + if (ide->type == IDE_NONE) + return 0; + else { + if (ide_drive_is_zip(ide)) + return (zip[atapi_zip_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + else if (ide_drive_is_cdrom(ide)) + return (cdrom[atapi_cdrom_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + else + return ide->atastat; + } +} + + +uint8_t +ide_readb(uint16_t addr, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + int ch; + ide_t *ide; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + uint8_t temp = 0xff; + uint16_t tempw; + + addr |= 0x90; + addr &= 0xFFF7; + + switch (addr & 0x7) { + case 0x0: /* Data */ + tempw = ide_read_data(ide, 2); + temp = tempw & 0xff; + break; + + /* For ATAPI: Bits 7-4 = sense key, bit 3 = MCR (media change requested), + Bit 2 = ABRT (aborted command), Bit 1 = EOM (end of media), + and Bit 0 = ILI (illegal length indication). */ + case 0x1: /* Error */ + if (ide->type == IDE_NONE) + temp = 0; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->error; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->error; + else + temp = ide->error; + } + break; + + /* For ATAPI: + Bit 0: Command or Data: + Data if clear, Command if set; + Bit 1: I/OB + Direction: + To device if set; + From device if clear. + IO DRQ CoD + 0 1 1 Ready to accept command packet + 1 1 1 Message - ready to send message to host + 1 1 0 Data to host + 0 1 0 Data from host + 1 0 1 Status. */ + case 0x2: /* Sector count */ + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->phase; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->phase; + else + temp = ide->secount; + break; + + case 0x3: /* Sector */ + temp = (uint8_t)ide->sector; + break; + + case 0x4: /* Cylinder low */ + if (ide->type == IDE_NONE) + temp = 0xFF; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->request_length & 0xff; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->request_length & 0xff; + else + temp = ide->cylinder & 0xff; + } + break; + + case 0x5: /* Cylinder high */ + if (ide->type == IDE_NONE) + temp = 0xFF; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->request_length >> 8; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->request_length >> 8; + else + temp = ide->cylinder >> 8; + } + break; + + case 0x6: /* Drive/Head */ + temp = (uint8_t)(ide->head | ((ch & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); + break; + + /* For ATAPI: Bit 5 is DMA ready, but without overlapped or interlaved DMA, it is + DF (drive fault). */ + case 0x7: /* Status */ + ide_irq_lower(ide); + temp = ide_status(ide, ch); + break; + } + + ide_log("ide_readb(%04X, %08X) = %02X\n", addr, priv, temp); + return temp; +} + + +uint8_t +ide_read_alt_status(uint16_t addr, void *priv) +{ + uint8_t temp = 0xff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + ide_irq_lower(ide); + temp = ide_status(ide, ch); + + ide_log("ide_read_alt_status(%04X, %08X) = %02X\n", addr, priv, temp); + return temp; +} + + +uint16_t +ide_readw(uint16_t addr, void *priv) +{ + uint16_t temp = 0xffff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + switch (addr & 0x7) { + case 0x0: /* Data */ + temp = ide_read_data(ide, 2); + break; + + default: + temp = 0xff; + break; + } + + /* ide_log("ide_readw(%04X, %08X) = %04X\n", addr, priv, temp); */ + return temp; +} + + +static uint32_t +ide_readl(uint16_t addr, void *priv) +{ + uint16_t temp2; + uint32_t temp = 0xffffffff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + switch (addr & 0x7) { + case 0x0: /* Data */ + temp2 = ide_read_data(ide, 2); + temp = temp2 | (ide_read_data(ide, 2) << 16); + break; + } + + /* ide_log("ide_readl(%04X, %08X) = %04X\n", addr, priv, temp); */ + return temp; +} + + +static void +ide_callback(void *priv) +{ + ide_t *ide, *ide_other; + int snum, ret, ch; + int cdrom_id, cdrom_id_other; + int zip_id, zip_id_other; + uint64_t full_size = 0; + + ide_board_t *dev = (ide_board_t *) priv; + ch = dev->cur_dev; + + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; + + ide_set_callback(ide->board, 0LL); + + if (ide->type == IDE_HDD) + full_size = (hdd[ide->hdd_num].tracks * hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + + if (ide->reset) { + ide_log("CALLBACK RESET %i %i\n", ide->reset,ch); + + ide->atastat = ide_other->atastat = DRDY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + ide->reset = ide_other->reset = 0; + + ide_set_signature(ide); + if (ide_drive_is_zip(ide)) { + zip_id = atapi_zip_drives[ch]; + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->error = 1; + } else if (ide_drive_is_cdrom(ide)) { + cdrom_id = atapi_cdrom_drives[ch]; + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->error = 1; + if (cdrom[cdrom_id]->handler->stop) + cdrom[cdrom_id]->handler->stop(cdrom_id); + } + + ide_set_signature(ide_other); + if (ide_drive_is_zip(ide_other)) { + zip_id_other = atapi_zip_drives[ch ^ 1]; + zip[zip_id_other]->status = DRDY_STAT | DSC_STAT; + zip[zip_id_other]->error = 1; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; + cdrom[cdrom_id_other]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id_other]->error = 1; + if (cdrom[cdrom_id_other]->handler->stop) + cdrom[cdrom_id_other]->handler->stop(cdrom_id_other); + } + + return; + } + + ide_log("CALLBACK %02X %i %i\n", ide->command, ide->reset,ch); + + cdrom_id = atapi_cdrom_drives[ch]; + cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; + + zip_id = atapi_zip_drives[ch]; + zip_id_other = atapi_zip_drives[ch ^ 1]; + + if (((ide->command >= WIN_RECAL) && (ide->command <= 0x1F)) || + ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F))) { + if (ide->type != IDE_HDD) + goto abort_cmd; + if ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F)) { + if ((ide->cylinder >= ide->tracks) || (ide->head >= ide->hpc) || + !ide->sector || (ide->sector > ide->spt)) + goto id_not_found; + } + ide->atastat = DRDY_STAT | DSC_STAT; ide_irq_raise(ide); return; + } + + switch (ide->command) { + /* Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, + Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h. */ + case WIN_SRST: /*ATAPI Device Reset */ + ide->atastat = DRDY_STAT | DSC_STAT; + ide->error=1; /*Device passed*/ + ide->secount = ide->sector = 1; + + ide_set_signature(ide); + + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->error = 1; + zip_reset(zip_id); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->error = 1; + cdrom_reset(cdrom[cdrom_id]); + } + ide_irq_raise(ide); + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + ide->service = 0; + return; + + case WIN_NOP: + case WIN_STANDBYNOW1: + case WIN_IDLENOW1: + case WIN_SETIDLE1: + if (ide_drive_is_zip(ide)) + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + else + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_CHECKPOWERMODE1: + case WIN_SLEEP1: + if (ide_drive_is_zip(ide)) { + zip[zip_id]->phase = 0xFF; + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->phase = 0xFF; + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + } + ide->secount = 0xFF; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_READ: + case WIN_READ_NORETRY: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) { + ide_set_signature(ide); + goto abort_cmd; + } + if (!ide->specify_success) + goto id_not_found; + + if (ide->do_initial_read) { + ide->do_initial_read = 0; + ide->sector_pos = 0; + if (ide->secount) + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); + else + hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); + } + + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + + ide->sector_pos++; + ide->pos = 0; + + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + return; + + case WIN_READ_DMA: + case WIN_READ_DMA_ALT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + ide_log("IDE %i: DMA read aborted (bad device or board)\n", ide->channel); + goto abort_cmd; + } + if (!ide->specify_success) { + ide_log("IDE %i: DMA read aborted (SPECIFY failed)\n", ide->channel); + goto id_not_found; + } + + ide->sector_pos = 0; + if (ide->secount) + ide->sector_pos = ide->secount; + else + ide->sector_pos = 256; + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); + + ide->pos=0; + + if (ide_bus_master_read) { + /* We should not abort - we should simply wait for the host to start DMA. */ + ret = ide_bus_master_read(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + ide_bus_master_priv[ide->board]); + if (ret == 2) { + /* Bus master DMA disabled, simply wait for the host to enable DMA. */ + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_set_callback(ide->board, 6LL * IDE_TIME); + return; + } else if (ret == 1) { + /* Bus master DMAS error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; + } else { + /*DMA successful*/ + ide_log("IDE %i: DMA read successful\n", ide->channel); + + ide->atastat = DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } else { + ide_log("IDE %i: DMA read aborted (no bus master)\n", ide->channel); + goto abort_cmd; + } + return; + + case WIN_READ_MULTIPLE: + /* According to the official ATA reference: + + If the Read Multiple command is attempted before the Set Multiple Mode + command has been executed or when Read Multiple commands are + disabled, the Read Multiple operation is rejected with an Aborted Com- + mand error. */ + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || !ide->blocksize) + goto abort_cmd; + if (!ide->specify_success) + goto id_not_found; + + if (ide->do_initial_read) { + ide->do_initial_read = 0; + ide->sector_pos = 0; + if (ide->secount) + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); + else + hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); + } + + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + + ide->sector_pos++; + ide->pos=0; + + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + if (!ide->blockcount) + ide_irq_raise(ide); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize) + ide->blockcount = 0; + return; + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (!ide->specify_success) + goto id_not_found; + hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); + ide_irq_raise(ide); + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + return; + + case WIN_WRITE_DMA: + case WIN_WRITE_DMA_ALT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + ide_log("IDE %i: DMA write aborted (bad device type or board)\n", ide->channel); + goto abort_cmd; + } + if (!ide->specify_success) { + ide_log("IDE %i: DMA write aborted (SPECIFY failed)\n", ide->channel); + goto id_not_found; + } + + if (ide_bus_master_read) { + if (ide->secount) + ide->sector_pos = ide->secount; + else + ide->sector_pos = 256; + + ret = ide_bus_master_write(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + ide_bus_master_priv[ide->board]); + + if (ret == 2) { + /* Bus master DMA disabled, simply wait for the host to enable DMA. */ + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_set_callback(ide->board, 6LL * IDE_TIME); + return; + } else if (ret == 1) { + /* Bus master DMA error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; + } else { + /*DMA successful*/ + ide_log("IDE %i: DMA write successful\n", ide->channel); + + hdd_image_write(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); + + ide->atastat = DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } else { + ide_log("IDE %i: DMA write aborted (no bus master)\n", ide->channel); + goto abort_cmd; + } + + return; + + case WIN_WRITE_MULTIPLE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (!ide->specify_success) + goto id_not_found; + hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize || ide->secount == 1) { + ide->blockcount = 0; + ide_irq_raise(ide); + } + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + return; + + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (!ide->specify_success) + goto id_not_found; + ide->pos=0; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + return; + + case WIN_FORMAT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (!ide->specify_success) + goto id_not_found; + hdd_image_zero(ide->hdd_num, ide_get_sector(ide), ide->secount); + + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + return; + + case WIN_DRIVE_DIAGNOSTICS: + ide_set_signature(ide); + ide->error=1; /*No error detected*/ + + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = 0; + zip[zip_id]->error = 1; + ide_irq_raise(ide); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = 0; + cdrom[cdrom_id]->error = 1; + ide_irq_raise(ide); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ide->error = 1; + ide_irq_raise(ide); + } + + ide_set_signature(ide_other); + ide_other->error=1; /*No error detected*/ + + if (ide_drive_is_zip(ide_other)) { + zip[zip_id_other]->status = 0; + zip[zip_id_other]->error = 1; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[cdrom_id_other]->status = 0; + cdrom[cdrom_id_other]->error = 1; + } else { + ide_other->atastat = DRDY_STAT | DSC_STAT; + ide_other->error = 1; + } + + ide_boards[ide->board]->cur_dev &= ~1; + ch = ide_boards[ide->board]->cur_dev; + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + full_size /= (ide->head+1); + full_size /= ide->secount; + ide->specify_success = 1; + hdd_image_specify(ide->hdd_num, ide->head + 1, ide->secount); + ide->t_spt=ide->secount; + ide->t_hpc=ide->head; + ide->t_hpc++; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_PIDENTIFY: /* Identify Packet Device */ + if (ide_drive_is_zip(ide)) { + ide_identify(ide); + ide->pos = 0; + zip[zip_id]->phase = 2; + zip[zip_id]->pos = 0; + zip[zip_id]->error = 0; + zip[zip_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } else if (ide_drive_is_cdrom(ide)) { + ide_identify(ide); + ide->pos = 0; + cdrom[cdrom_id]->phase = 2; + cdrom[cdrom_id]->pos = 0; + cdrom[cdrom_id]->error = 0; + cdrom[cdrom_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } + goto abort_cmd; + + case WIN_SET_MULTIPLE_MODE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + ide->blocksize = ide->secount; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_SET_FEATURES: + if (ide->type == IDE_NONE) + goto abort_cmd; + + if (!ide_set_features(ide)) + goto abort_cmd; + else { + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->pos = 0; + } + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + return; + + case WIN_READ_NATIVE_MAX: + if (ide->type != IDE_HDD) + goto abort_cmd; + snum = hdd[ide->hdd_num].spt; + snum *= hdd[ide->hdd_num].hpc; + snum *= hdd[ide->hdd_num].tracks; + ide_set_sector(ide, snum - 1); + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_IDENTIFY: /* Identify Device */ + if (ide->type != IDE_HDD) { + ide_set_signature(ide); + goto abort_cmd; + } else { + ide_identify(ide); + ide->pos=0; + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + goto abort_cmd; + + if (ide_drive_is_zip(ide)) + zip_phase_callback(atapi_zip_drives[ch]); + else + cdrom_phase_callback(cdrom[atapi_cdrom_drives[ch]]); + return; + + case 0xFF: + goto abort_cmd; + } + +abort_cmd: + ide->command = 0; + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + zip[zip_id]->error = ABRT_ERR; + zip[zip_id]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + cdrom[cdrom_id]->error = ABRT_ERR; + cdrom[cdrom_id]->pos = 0; + } else { + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide->pos = 0; + } + ide_irq_raise(ide); + return; id_not_found: - ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; - ide->error = ABRT_ERR | 0x10; - ide->pos = 0; - ide_irq_raise(ide); -} - -void ide_callback_pri() -{ - idecallback[0] = 0LL; - callbackide(0); -} - -void ide_callback_sec() -{ - idecallback[1] = 0LL; - callbackide(1); -} - -void ide_callback_ter() -{ - idecallback[2] = 0LL; - callbackide(2); -} - -void ide_callback_qua() -{ - idecallback[3] = 0LL; - callbackide(3); -} - -void ide_callback_xtide() -{ - idecallback[4] = 0LL; - callbackide(4); -} - -void ide_write_pri(uint16_t addr, uint8_t val, void *priv) -{ - writeide(0, addr, val); -} -void ide_write_pri_w(uint16_t addr, uint16_t val, void *priv) -{ - writeidew(0, val); -} -void ide_write_pri_l(uint16_t addr, uint32_t val, void *priv) -{ - writeidel(0, val); -} -uint8_t ide_read_pri(uint16_t addr, void *priv) -{ - return readide(0, addr); -} -uint16_t ide_read_pri_w(uint16_t addr, void *priv) -{ - return readidew(0); -} -uint32_t ide_read_pri_l(uint16_t addr, void *priv) -{ - return readidel(0); -} - -void ide_write_sec(uint16_t addr, uint8_t val, void *priv) -{ - writeide(1, addr, val); -} -void ide_write_sec_w(uint16_t addr, uint16_t val, void *priv) -{ - writeidew(1, val); -} -void ide_write_sec_l(uint16_t addr, uint32_t val, void *priv) -{ - writeidel(1, val); -} -uint8_t ide_read_sec(uint16_t addr, void *priv) -{ - return readide(1, addr); -} -uint16_t ide_read_sec_w(uint16_t addr, void *priv) -{ - return readidew(1); -} -uint32_t ide_read_sec_l(uint16_t addr, void *priv) -{ - return readidel(1); -} - -void ide_write_ter(uint16_t addr, uint8_t val, void *priv) -{ - writeide(2, addr, val); -} -void ide_write_ter_w(uint16_t addr, uint16_t val, void *priv) -{ - writeidew(2, val); -} -void ide_write_ter_l(uint16_t addr, uint32_t val, void *priv) -{ - writeidel(2, val); -} -uint8_t ide_read_ter(uint16_t addr, void *priv) -{ - return readide(2, addr); -} -uint16_t ide_read_ter_w(uint16_t addr, void *priv) -{ - return readidew(2); -} -uint32_t ide_read_ter_l(uint16_t addr, void *priv) -{ - return readidel(2); -} - -void ide_write_qua(uint16_t addr, uint8_t val, void *priv) -{ - writeide(3, addr, val); -} -void ide_write_qua_w(uint16_t addr, uint16_t val, void *priv) -{ - writeidew(3, val); -} -void ide_write_qua_l(uint16_t addr, uint32_t val, void *priv) -{ - writeidel(3, val); -} -uint8_t ide_read_qua(uint16_t addr, void *priv) -{ - return readide(3, addr); -} -uint16_t ide_read_qua_w(uint16_t addr, void *priv) -{ - return readidew(3); -} -uint32_t ide_read_qua_l(uint16_t addr, void *priv) -{ - return readidel(3); -} - -static uint16_t ide_base_main[2] = { 0x1f0, 0x170 }; -static uint16_t ide_side_main[2] = { 0x3f6, 0x376 }; - - -void ide_pri_enable(void) -{ - io_sethandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); - io_sethandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); - ide_base_main[0] = 0x1f0; - ide_side_main[0] = 0x3f6; -} - -void ide_pri_enable_ex(void) -{ - if (ide_base_main[0] & 0x300) - { - ide_log("Enabling primary base (%04X)...\n", ide_base_main[0]); - io_sethandler(ide_base_main[0], 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); - } - if (ide_side_main[0] & 0x300) - { - ide_log("Enabling primary side (%04X)...\n", ide_side_main[0]); - io_sethandler(ide_side_main[0], 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); - } -} - -void ide_pri_disable(void) -{ - io_removehandler(ide_base_main[0], 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); - io_removehandler(ide_side_main[0], 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); -} - -void ide_sec_enable(void) -{ - io_sethandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); - io_sethandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); - ide_base_main[1] = 0x170; - ide_side_main[1] = 0x376; -} - -void ide_sec_enable_ex(void) -{ - if (ide_base_main[1] & 0x300) - { - io_sethandler(ide_base_main[1], 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); - } - if (ide_side_main[1] & 0x300) - { - io_sethandler(ide_side_main[1], 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); - } -} - -void ide_sec_disable(void) -{ - io_removehandler(ide_base_main[1], 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); - io_removehandler(ide_side_main[1], 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR | 0x10; + ide->pos = 0; + ide_irq_raise(ide); } -void ide_set_base(int controller, uint16_t port) +static void +ide_set_handlers(uint8_t board) { - ide_base_main[controller] = port; -} - -void ide_set_side(int controller, uint16_t port) -{ - ide_side_main[controller] = port; -} - -void ide_ter_enable(void) -{ - io_sethandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL); - io_sethandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL); -} - -void ide_ter_disable(void) -{ - io_removehandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL); - io_removehandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL); -} - -void ide_ter_disable_cond(void) -{ - if ((ide_drives[4].type == IDE_NONE) && (ide_drives[5].type == IDE_NONE)) - { - ide_ter_disable(); - } -} - -void ide_ter_init(void) -{ - ide_ter_enable(); - - timer_add(ide_callback_ter, &idecallback[2], &idecallback[2], NULL); -} - -void ide_qua_enable(void) -{ - io_sethandler(0x01e8, 0x0008, ide_read_qua, ide_read_qua_w, ide_read_qua_l, ide_write_qua, ide_write_qua_w, ide_write_qua_l, NULL); - io_sethandler(0x03ee, 0x0001, ide_read_qua, NULL, NULL, ide_write_qua, NULL, NULL , NULL); -} - -void ide_qua_disable_cond(void) -{ - if ((ide_drives[6].type == IDE_NONE) && (ide_drives[7].type == IDE_NONE)) - { - ide_qua_disable(); - } -} - -void ide_qua_disable(void) -{ - io_removehandler(0x01e8, 0x0008, ide_read_qua, ide_read_qua_w, ide_read_qua_l, ide_write_qua, ide_write_qua_w, ide_write_qua_l, NULL); - io_removehandler(0x03ee, 0x0001, ide_read_qua, NULL, NULL, ide_write_qua, NULL, NULL , NULL); -} - -void ide_qua_init(void) -{ - ide_qua_enable(); - - timer_add(ide_callback_qua, &idecallback[3], &idecallback[3], NULL); + if (ide_base_main[board] & 0x300) { + io_sethandler(ide_base_main[board], 8, + ide_readb, ide_readw, ide_readl, + ide_writeb, ide_writew, ide_writel, + ide_boards[board]); + } + if (ide_side_main[board] & 0x300) { + io_sethandler(ide_side_main[board], 1, + ide_read_alt_status, NULL, NULL, + ide_write_devctl, NULL, NULL, + ide_boards[board]); + } } -/*FIXME: this will go away after Kotori's rewrite. --FvK */ -void ide_init_first(void) +static void +ide_remove_handlers(uint8_t board) { - int d; - - memset(ide_drives, 0x00, sizeof(ide_drives)); - for (d = 0; d < (IDE_NUM+XTIDE_NUM); d++) - { - ide_drives[d].channel = d; - ide_drives[d].type = IDE_NONE; - ide_drives[d].hdd_num = -1; - ide_drives[d].atastat = READY_STAT | DSC_STAT; - ide_drives[d].service = 0; - ide_drives[d].board = d >> 1; - } + io_removehandler(ide_base_main[board], 8, + ide_readb, ide_readw, ide_readl, + ide_writeb, ide_writew, ide_writel, + ide_boards[board]); + io_removehandler(ide_side_main[board], 1, + ide_read_alt_status, NULL, NULL, + ide_write_devctl, NULL, NULL, + ide_boards[board]); } -void ide_xtide_init(void) +void +ide_pri_enable(void) { - ide_bus_master_read = ide_bus_master_write = NULL; - - timer_add(ide_callback_xtide, &idecallback[4], &idecallback[4], NULL); + ide_set_handlers(0); } -void ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length), int (*write)(int channel, uint8_t *data, int transfer_length), void (*set_irq)(int channel)) + +void +ide_pri_disable(void) { - ide_bus_master_read = read; - ide_bus_master_write = write; - ide_bus_master_set_irq = set_irq; + ide_remove_handlers(0); } -void secondary_ide_check(void) -{ - int i = 0; - int secondary_cdroms = 0; - int secondary_zips = 0; - for (i=0; i= 2) && (zip_drives[i].ide_channel <= 3) && ((zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_ONLY) || (zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA))) - secondary_zips++; - } - for (i=0; i= 2) && (cdrom_drives[i].ide_channel <= 3) && ((cdrom_drives[i].bus_type == CDROM_BUS_ATAPI_PIO_ONLY) || (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA))) - secondary_cdroms++; - } - if (!secondary_zips && !secondary_cdroms) { - ide_sec_disable(); - ide_init_ch[1] = 0; - } +void +ide_sec_enable(void) +{ + ide_set_handlers(1); +} + + +void +ide_sec_disable(void) +{ + ide_remove_handlers(1); +} + + +void +ide_set_base(int controller, uint16_t port) +{ + ide_base_main[controller] = port; +} + + +void +ide_set_side(int controller, uint16_t port) +{ + ide_side_main[controller] = port; +} + + +static void * +ide_ter_init(const device_t *info) +{ + ide_boards[2] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[2], 0, sizeof(ide_board_t)); + + ide_boards[2]->irq = device_get_config_int("irq"); + ide_boards[2]->cur_dev = 4; + + ide_set_handlers(2); + + timer_add(ide_callback, &ide_boards[2]->callback, &ide_boards[2]->callback, ide_boards[2]); + + ide_board_init(2); + + return(ide_drives); +} + + +/* Close a standalone IDE unit. */ +static void +ide_ter_close(void *priv) +{ + if (ide_boards[2]) { + free(ide_boards[2]); + ide_boards[2] = NULL; + + ide_board_close(2); + } +} + + +static void * +ide_qua_init(const device_t *info) +{ + ide_boards[3] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[3], 0, sizeof(ide_board_t)); + + ide_boards[3]->irq = device_get_config_int("irq"); + ide_boards[3]->cur_dev = 6; + + ide_set_handlers(3); + + timer_add(ide_callback, &ide_boards[3]->callback, &ide_boards[3]->callback, ide_boards[3]); + + ide_board_init(3); + + return(ide_drives); +} + + +/* Close a standalone IDE unit. */ +static void +ide_qua_close(void *priv) +{ + if (ide_boards[3]) { + free(ide_boards[3]); + ide_boards[3] = NULL; + + ide_board_close(3); + } +} + + +static void +ide_clear_bus_master(void) +{ + ide_bus_master_read = ide_bus_master_write = NULL; + ide_bus_master_set_irq = NULL; + ide_bus_master_priv[0] = ide_bus_master_priv[1] = NULL; +} + + +void * +ide_xtide_init(void) +{ + ide_clear_bus_master(); + + if (!ide_boards[0]) { + ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[0], 0, sizeof(ide_board_t)); + ide_boards[0]->cur_dev = 0; + + timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, + ide_boards[0]); + + ide_board_init(0); + } + ide_boards[0]->irq = -1; + + return ide_boards[0]; +} + + +void +ide_xtide_close(void) +{ + if (ide_boards[0]) { + free(ide_boards[0]); + ide_boards[0] = NULL; + + ide_board_close(0); + } +} + + +void +ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length, void *priv), + int (*write)(int channel, uint8_t *data, int transfer_length, void *priv), + void (*set_irq)(int channel, void *priv), + void *priv0, void *priv1) +{ + ide_bus_master_read = read; + ide_bus_master_write = write; + ide_bus_master_set_irq = set_irq; + ide_bus_master_priv[0] = priv0; + ide_bus_master_priv[1] = priv1; +} + + +void +secondary_ide_check(void) +{ + int i = 0; + int secondary_cdroms = 0; + int secondary_zips = 0; + + for (i=0; i= 2) && (zip_drives[i].ide_channel <= 3) && + (zip_drives[i].bus_type == ZIP_BUS_ATAPI)) + secondary_zips++; + } + for (i=0; i= 2) && (cdrom_drives[i].ide_channel <= 3) && + (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI)) + secondary_cdroms++; + } + if (!secondary_zips && !secondary_cdroms) + ide_remove_handlers(1); } @@ -2890,6 +2682,8 @@ void secondary_ide_check(void) static void * ide_sainit(const device_t *info) { + ide_log("Initializing IDE...\n"); + switch(info->local) { case 0: /* ISA, single-channel */ case 2: /* ISA, dual-channel */ @@ -2898,23 +2692,47 @@ ide_sainit(const device_t *info) case 6: /* VLB, dual-channel */ case 8: /* PCI, single-channel */ case 10: /* PCI, dual-channel */ - if (!ide_init_ch[0]) { - ide_pri_enable(); - timer_add(ide_callback_pri, &idecallback[0], &idecallback[0], NULL); - ide_init_ch[0] = 1; + if (!ide_inited) { + if (!(info->local & 8)) + ide_clear_bus_master(); } - if ((info->local & 2) && !ide_init_ch[1]) { - ide_sec_enable(); - timer_add(ide_callback_sec, &idecallback[1], &idecallback[1], NULL); - ide_init_ch[1] = 1; + if (!(ide_inited & 1)) { + ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[0], 0, sizeof(ide_board_t)); + ide_boards[0]->irq = 14; + ide_boards[0]->cur_dev = 0; + ide_base_main[0] = 0x1f0; + ide_side_main[0] = 0x3f6; + ide_set_handlers(0); + timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, + ide_boards[0]); + ide_log("Callback 0 pointer: %08X\n", &ide_boards[0]->callback); + + ide_board_init(0); + + ide_inited |= 1; + } + + if ((info->local & 3) && !(ide_inited & 2)) { + ide_boards[1] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[1], 0, sizeof(ide_board_t)); + ide_boards[1]->irq = 15; + ide_boards[1]->cur_dev = 2; + ide_base_main[1] = 0x170; + ide_side_main[1] = 0x376; + ide_set_handlers(1); + timer_add(ide_callback, &ide_boards[1]->callback, &ide_boards[1]->callback, + ide_boards[1]); + ide_log("Callback 1 pointer: %08X\n", &ide_boards[1]->callback); + + ide_board_init(1); if (info->local & 1) secondary_ide_check(); - } - if (!(info->local & 8)) - ide_bus_master_read = ide_bus_master_write = NULL; + ide_inited |= 2; + } break; } @@ -2922,11 +2740,70 @@ ide_sainit(const device_t *info) } +static void +ide_drive_reset(int d) +{ + ide_drives[d]->channel = d; + ide_drives[d]->atastat = DRDY_STAT | DSC_STAT; + ide_drives[d]->service = 0; + ide_drives[d]->board = d >> 1; + + if (ide_boards[d >> 1]) { + ide_boards[d >> 1]->cur_dev = d & ~1; + ide_boards[d >> 1]->callback = 0LL; + } + + ide_set_signature(ide_drives[d]); + + if (ide_drives[d]->sector_buffer) + memset(ide_drives[d]->sector_buffer, 0, 256*512); + + if (ide_drives[d]->buffer) + memset(ide_drives[d]->buffer, 0, 65536 * sizeof(uint16_t)); +} + + +/* Reset a standalone IDE unit. */ +static void +ide_sareset(void *p) +{ + int d; + + ide_log("Resetting IDE...\n"); + + if (ide_inited & 1) { + for (d = 0; d < 2; d++) + ide_drive_reset(d); + } + + if (ide_inited & 2) { + for (d = 2; d < 4; d++) + ide_drive_reset(d); + } +} + + /* Close a standalone IDE unit. */ static void ide_saclose(void *priv) { - ide_init_ch[0] = ide_init_ch[1] = 0; + ide_log("Closing IDE...\n"); + + if ((ide_inited & 1) && (ide_boards[0])) { + free(ide_boards[0]); + ide_boards[0] = NULL; + + ide_board_close(0); + } + + if ((ide_inited & 2) && (ide_boards[1])) { + free(ide_boards[1]); + ide_boards[1] = NULL; + + ide_board_close(1); + } + + ide_inited = 0; } @@ -2934,7 +2811,7 @@ const device_t ide_isa_device = { "ISA PC/AT IDE Controller", DEVICE_ISA | DEVICE_AT, 0, - ide_sainit, ide_saclose, NULL, + ide_sainit, ide_saclose, ide_sareset, NULL, NULL, NULL, NULL, NULL }; @@ -2943,7 +2820,7 @@ const device_t ide_isa_2ch_device = { "ISA PC/AT IDE Controller (Dual-Channel)", DEVICE_ISA | DEVICE_AT, 2, - ide_sainit, ide_saclose, NULL, + ide_sainit, ide_saclose, ide_sareset, NULL, NULL, NULL, NULL, NULL }; @@ -2952,7 +2829,7 @@ const device_t ide_isa_2ch_opt_device = { "ISA PC/AT IDE Controller (Single/Dual)", DEVICE_ISA | DEVICE_AT, 3, - ide_sainit, ide_saclose, NULL, + ide_sainit, ide_saclose, ide_sareset, NULL, NULL, NULL, NULL, NULL }; @@ -2961,7 +2838,7 @@ const device_t ide_vlb_device = { "VLB IDE Controller", DEVICE_VLB | DEVICE_AT, 4, - ide_sainit, ide_saclose, NULL, + ide_sainit, ide_saclose, ide_sareset, NULL, NULL, NULL, NULL, NULL }; @@ -2970,7 +2847,7 @@ const device_t ide_vlb_2ch_device = { "VLB IDE Controller (Dual-Channel)", DEVICE_VLB | DEVICE_AT, 6, - ide_sainit, ide_saclose, NULL, + ide_sainit, ide_saclose, ide_sareset, NULL, NULL, NULL, NULL, NULL }; @@ -2979,7 +2856,7 @@ const device_t ide_pci_device = { "PCI IDE Controller", DEVICE_PCI | DEVICE_AT, 8, - ide_sainit, ide_saclose, NULL, + ide_sainit, ide_saclose, ide_sareset, NULL, NULL, NULL, NULL, NULL }; @@ -2988,7 +2865,109 @@ const device_t ide_pci_2ch_device = { "PCI IDE Controller (Dual-Channel)", DEVICE_PCI | DEVICE_AT, 10, - ide_sainit, ide_saclose, NULL, + ide_sainit, ide_saclose, ide_sareset, NULL, NULL, NULL, NULL, NULL }; + +static const device_config_t ide_ter_config[] = +{ + { + "irq", "IRQ", CONFIG_SELECTION, "", 10, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t ide_qua_config[] = +{ + { + "irq", "IRQ", CONFIG_SELECTION, "", 11, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t ide_ter_device = { + "Tertiary IDE Controller", + DEVICE_AT, + 0, + ide_ter_init, ide_ter_close, NULL, + NULL, NULL, NULL, NULL, + ide_ter_config +}; + +const device_t ide_qua_device = { + "Quaternary IDE Controller", + DEVICE_AT, + 0, + ide_qua_init, ide_qua_close, NULL, + NULL, NULL, NULL, NULL, + ide_qua_config +}; diff --git a/src/disk/hdc_ide.h b/src/disk/hdc_ide.h index 5258d389e..c78c327f7 100644 --- a/src/disk/hdc_ide.h +++ b/src/disk/hdc_ide.h @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdd_ide.h 1.0.8 2018/03/20 + * Version: @(#)hdd_ide.h 1.0.9 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, @@ -21,59 +21,53 @@ typedef struct { - int type; - int board; - uint8_t atastat; - uint8_t error; - int secount,sector,cylinder,head,drive,cylprecomp; - uint8_t command; - uint8_t fdisk; - int pos; - int packlen; - int spt,hpc; - int t_spt,t_hpc; - int tracks; - int packetstatus; - uint8_t asc; - int reset; + uint8_t atastat, error, + command, fdisk; + int type, board, + irqstat, service, + blocksize, blockcount, + hdd_num, channel, + pos, sector_pos, + lba, skip512, + reset, specify_success, + mdma_mode, do_initial_read, + spt, hpc, + tracks; + uint32_t secount, sector, + cylinder, head, + drive, cylprecomp, + t_spt, t_hpc, + lba_addr; + uint16_t *buffer; - int irqstat; - int service; - int lba; - int channel; - uint32_t lba_addr; - int skip512; - int blocksize, blockcount; - uint16_t dma_identify_data[3]; - int hdi,base; - int hdd_num; - uint8_t specify_success; - int mdma_mode; uint8_t *sector_buffer; - int do_initial_read; - int sector_pos; -} IDE; +} ide_t; extern int ideboard; +extern int ide_ter_enabled, ide_qua_enabled; -extern int ide_enable[5]; -extern int ide_irq[5]; - -extern IDE ide_drives[IDE_NUM + XTIDE_NUM]; +extern ide_t *ide_drives[IDE_NUM]; extern int64_t idecallback[5]; -extern void ide_irq_raise(IDE *ide); -extern void ide_irq_lower(IDE *ide); +extern void ide_irq_raise(ide_t *ide); +extern void ide_irq_lower(ide_t *ide); -extern void writeide(int ide_board, uint16_t addr, uint8_t val); -extern void writeidew(int ide_board, uint16_t val); -extern uint8_t readide(int ide_board, uint16_t addr); -extern uint16_t readidew(int ide_board); -extern void callbackide(int ide_board); +extern void * ide_xtide_init(void); +extern void ide_xtide_close(void); -extern void ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length), int (*write)(int channel, uint8_t *data, int transfer_length), void (*set_irq)(int channel)); +extern void ide_writew(uint16_t addr, uint16_t val, void *priv); +extern void ide_write_devctl(uint16_t addr, uint8_t val, void *priv); +extern void ide_writeb(uint16_t addr, uint8_t val, void *priv); +extern uint8_t ide_readb(uint16_t addr, void *priv); +extern uint8_t ide_read_alt_status(uint16_t addr, void *priv); +extern uint16_t ide_readw(uint16_t addr, void *priv); + +extern void ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length, void *priv), + int (*write)(int channel, uint8_t *data, int transfer_length, void *priv), + void (*set_irq)(int channel, void *priv), + void *priv0, void *priv1); extern void win_cdrom_eject(uint8_t id); extern void win_cdrom_reload(uint8_t id); @@ -81,36 +75,20 @@ extern void win_cdrom_reload(uint8_t id); extern void ide_set_base(int controller, uint16_t port); extern void ide_set_side(int controller, uint16_t port); -extern void ide_init_first(void); - -extern void ide_reset(void); -extern void ide_reset_hard(void); - -extern void ide_set_all_signatures(void); - -extern void ide_xtide_init(void); - extern void ide_pri_enable(void); -extern void ide_pri_enable_ex(void); extern void ide_pri_disable(void); extern void ide_sec_enable(void); extern void ide_sec_disable(void); -extern void ide_ter_enable(void); -extern void ide_ter_disable(void); -extern void ide_ter_init(void); -extern void ide_qua_enable(void); -extern void ide_qua_disable(void); -extern void ide_qua_init(void); extern void ide_set_callback(uint8_t channel, int64_t callback); extern void secondary_ide_check(void); extern void ide_padstr8(uint8_t *buf, int buf_size, const char *src); -extern void ide_destroy_buffers(void); -extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length); -extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length); -extern void (*ide_bus_master_set_irq)(int channel); +extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +extern void (*ide_bus_master_set_irq)(int channel, void *priv); +extern void *ide_bus_master_priv[2]; #endif /*EMU_IDE_H*/ diff --git a/src/disk/hdc_mfm_at.c b/src/disk/hdc_mfm_at.c index 0879c75b5..43417b567 100644 --- a/src/disk/hdc_mfm_at.c +++ b/src/disk/hdc_mfm_at.c @@ -12,7 +12,7 @@ * based design. Most cards were WD1003-WA2 or -WAH, where the * -WA2 cards had a floppy controller as well (to save space.) * - * Version: @(#)hdc_mfm_at.c 1.0.13 2018/03/18 + * Version: @(#)hdc_mfm_at.c 1.0.14 2018/04/16 * * Authors: Sarah Walker, * Fred N. van Kempen, @@ -110,35 +110,28 @@ typedef struct { } mfm_t; -static __inline void irq_raise(mfm_t *mfm) +static inline void +irq_raise(mfm_t *mfm) { - /* If not already pending.. */ - if (! mfm->irqstat) { - /* If enabled in the control register.. */ - if (! (mfm->fdisk&0x02)) { - /* .. raise IRQ14. */ - picint(1<<14); - } + if (!(mfm->fdisk&2)) + picint(1 << 14); - /* Remember this. */ - mfm->irqstat = 1; - } + mfm->irqstat=1; } -static __inline void irq_lower(mfm_t *mfm) +static inline void +irq_lower(mfm_t *mfm) { - /* If raised.. */ - if (mfm->irqstat) { - /* If enabled in the control register.. */ - if (! (mfm->fdisk&0x02)) { - /* .. drop IRQ14. */ - picintc(1<<14); - } + picintc(1 << 14); +} - /* Remember this. */ - mfm->irqstat = 0; - } + +static void +irq_update(mfm_t *mfm) +{ + if (mfm->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(mfm->fdisk & 2)) + picint(1 << 14); } @@ -233,6 +226,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) } irq_lower(mfm); + mfm->command = val; mfm->error = 0; switch (val & 0xf0) { @@ -244,13 +238,13 @@ mfm_cmd(mfm_t *mfm, uint8_t val) #endif drive->curcyl = 0; mfm->status = STAT_READY|STAT_DSC; - mfm->command = 0x00; + mfm->command &= 0xf0; irq_raise(mfm); break; case CMD_SEEK: drive->steprate = (val & 0x0f); - mfm->command = (val & 0xf0); + mfm->command &= 0xf0; mfm->status = STAT_BUSY; timer_clock(); mfm->callback = 200LL*MFM_TIME; @@ -258,6 +252,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) break; default: + mfm->command = val; switch (val) { case CMD_READ: case CMD_READ+1: @@ -267,7 +262,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) pclog("WD1003(%d) read, opt=%d\n", mfm->drvsel, val&0x03); #endif - mfm->command = (val & 0xf0); + mfm->command &= 0xfc; if (val & 2) fatal("WD1003: READ with ECC\n"); mfm->status = STAT_BUSY; @@ -284,7 +279,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) pclog("WD1003(%d) write, opt=%d\n", mfm->drvsel, val & 0x03); #endif - mfm->command = (val & 0xf0); + mfm->command &= 0xfc; if (val & 2) fatal("WD1003: WRITE with ECC\n"); mfm->status = STAT_DRQ|STAT_DSC; @@ -293,7 +288,7 @@ mfm_cmd(mfm_t *mfm, uint8_t val) case CMD_VERIFY: case CMD_VERIFY+1: - mfm->command = (val & 0xfe); + mfm->command &= 0xfe; mfm->status = STAT_BUSY; timer_clock(); mfm->callback = 200LL*MFM_TIME; @@ -301,13 +296,11 @@ mfm_cmd(mfm_t *mfm, uint8_t val) break; case CMD_FORMAT: - mfm->command = val; mfm->status = STAT_DRQ|STAT_BUSY; mfm->pos = 0; break; case CMD_DIAGNOSE: - mfm->command = val; mfm->status = STAT_BUSY; timer_clock(); mfm->callback = 200LL*MFM_TIME; @@ -417,7 +410,7 @@ mfm_write(uint16_t port, uint8_t val, void *priv) mfm->drvsel = (val & 0x10) ? 1 : 0; if (mfm->drives[mfm->drvsel].present) mfm->status = STAT_READY|STAT_DSC; - else + else mfm->status = 0; return; @@ -428,21 +421,22 @@ mfm_write(uint16_t port, uint8_t val, void *priv) case 0x03f6: /* device control */ val &= 0x0f; if ((mfm->fdisk & 0x04) && !(val & 0x04)) { - mfm->status = STAT_BUSY; - mfm->reset = 1; timer_clock(); mfm->callback = 500LL*MFM_TIME; timer_update_outstanding(); + mfm->reset = 1; + mfm->status = STAT_BUSY; } if (val & 0x04) { /* Drive held in reset. */ - mfm->status = STAT_BUSY; - mfm->callback = 0LL; timer_clock(); + mfm->callback = 0LL; timer_update_outstanding(); + mfm->status = STAT_BUSY; } mfm->fdisk = val; + irq_update(mfm); break; } } @@ -619,19 +613,18 @@ do_callback(void *priv) } hdd_image_write(drive->hdd_num, addr, 1,(uint8_t *)mfm->buffer); + irq_raise(mfm); + mfm->secount = (mfm->secount - 1) & 0xff; mfm->status = STAT_READY|STAT_DSC; - mfm->secount = (mfm->secount - 1) & 0xff; if (mfm->secount) { /* More sectors to do.. */ mfm->status |= STAT_DRQ; mfm->pos = 0; next_sector(mfm); ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - } else { + } else ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); - } - irq_raise(mfm); break; case CMD_VERIFY: diff --git a/src/disk/hdc_mfm_xt.c b/src/disk/hdc_mfm_xt.c index 2eb2fd2c4..4ccb1653e 100644 --- a/src/disk/hdc_mfm_xt.c +++ b/src/disk/hdc_mfm_xt.c @@ -41,7 +41,7 @@ * Since all controllers (including the ones made by DTC) use * (mostly) the same API, we keep them all in this module. * - * Version: @(#)hdc_mfm_xt.c 1.0.14 2018/03/18 + * Version: @(#)hdc_mfm_xt.c 1.0.15 2018/04/18 * * Authors: Sarah Walker, * Fred N. van Kempen, @@ -71,7 +71,8 @@ #include "hdd.h" -#define MFM_TIME (2000LL*TIMER_USEC) +// #define MFM_TIME (2000LL*TIMER_USEC) +#define MFM_TIME (50LL*TIMER_USEC) #define XEBEC_BIOS_FILE L"roms/hdd/mfm_xebec/ibm_xebec_62x0822_1985.bin" #define DTC_BIOS_FILE L"roms/hdd/mfm_xebec/dtc_cxd21a.bin" @@ -429,7 +430,7 @@ mfm_callback(void *priv) } hdd_image_zero(drive->hdd_num, addr, 17); - + mfm_complete(mfm); break; @@ -757,7 +758,7 @@ loadhd(mfm_t *mfm, int c, int d, const wchar_t *fn) { drive_t *drive = &mfm->drives[d]; - if (! hdd_image_load(d)) { + if (! hdd_image_load(c)) { drive->present = 0; return; } @@ -859,7 +860,7 @@ mfm_close(void *priv) static int xebec_available(void) { - return(rom_present(XEBEC_BIOS_FILE)); + return(rom_present(XEBEC_BIOS_FILE)); } @@ -884,7 +885,7 @@ dtc5150x_init(const device_t *info) pclog("MFM: looking for disks..\n"); for (i=0; i MFM_NUM) break; diff --git a/src/disk/hdc_xta.c b/src/disk/hdc_xta.c new file mode 100644 index 000000000..bf02fb54f --- /dev/null +++ b/src/disk/hdc_xta.c @@ -0,0 +1,1200 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of a generic IDE-XTA disk controller. + * + * XTA is the acronym for 'XT-Attached', which was basically + * the XT-counterpart to what we know now as IDE (which is + * also named ATA - AT Attachment.) The basic ideas was to + * put the actual drive controller electronics onto the drive + * itself, and have the host machine just talk to that using + * a simpe, standardized I/O path- hence the name IDE, for + * Integrated Drive Electronics. + * + * In the ATA version of IDE, the programming interface of + * the IBM PC/AT (which used the Western Digitial 1002/1003 + * controllers) was kept, and, so, ATA-IDE assumes a 16bit + * data path: it reads and writes 16bit words of data. The + * disk drives for this bus commonly have an 'A' suffix to + * identify them as 'ATBUS'. + * + * In XTA-IDE, which is slightly older, the programming + * interface of the IBM PC/XT (which used the MFM controller + * from Xebec) was kept, and, so, it uses an 8bit data path. + * Disk drives for this bus commonly have the 'X' suffix to + * mark them as being for this XTBUS variant. + * + * So, XTA and ATA try to do the same thing, but they use + * different ways to achive their goal. + * + * Also, XTA is **not** the same as XTIDE. XTIDE is a modern + * variant of ATA-IDE, but retro-fitted for use on 8bit XT + * systems: an extra register is used to deal with the extra + * data byte per transfer. XTIDE uses regular IDE drives, + * and uses the regular ATA/IDE programming interface, just + * with the extra register. + * + * NOTE: This driver implements both the 'standard' XTA interface, + * sold by Western Digital as the WDXT-140 (no BIOS) and the + * WDXT-150 (with BIOS), as well as some variants customized + * for specific machines. + * + * NOTE: The XTA interface is 0-based for sector numbers !! + * + * Version: @(#)hdc_ide_xta.c 1.0.3 2018/04/25 + * + * Author: Fred N. van Kempen, + * + * Based on my earlier HD20 driver for the EuroPC. + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../timer.h" +#include "../plat.h" +#include "../ui.h" +#include "hdc.h" +#include "hdd.h" + + +#define HDC_TIME (50*TIMER_USEC) + +#define WD_BIOS_FILE L"disk/xta/idexywd2.bin" + + +enum { + STATE_IDLE = 0, + STATE_RECV, + STATE_RDATA, + STATE_RDONE, + STATE_SEND, + STATE_SDATA, + STATE_SDONE, + STATE_COMPL +}; + + +/* Command values. */ +#define CMD_TEST_READY 0x00 +#define CMD_RECALIBRATE 0x01 + /* unused 0x02 */ +#define CMD_READ_SENSE 0x03 +#define CMD_FORMAT_DRIVE 0x04 +#define CMD_READ_VERIFY 0x05 +#define CMD_FORMAT_TRACK 0x06 +#define CMD_FORMAT_BAD_TRACK 0x07 +#define CMD_READ_SECTORS 0x08 + /* unused 0x09 */ +#define CMD_WRITE_SECTORS 0x0a +#define CMD_SEEK 0x0b +#define CMD_SET_DRIVE_PARAMS 0x0c +#define CMD_READ_ECC_BURST 0x0d +#define CMD_READ_SECTOR_BUFFER 0x0e +#define CMD_WRITE_SECTOR_BUFFER 0x0f +#define CMD_RAM_DIAGS 0xe0 + /* unused 0xe1 */ + /* unused 0xe2 */ +#define CMD_DRIVE_DIAGS 0xe3 +#define CMD_CTRL_DIAGS 0xe4 +#define CMD_READ_LONG 0xe5 +#define CMD_WRITE_LONG 0xe6 + +/* Status register (reg 1) values. */ +#define STAT_REQ 0x01 /* controller needs data transfer */ +#define STAT_IO 0x02 /* direction of transfer (TO bus) */ +#define STAT_CD 0x04 /* transfer of Command or Data */ +#define STAT_BSY 0x08 /* controller is busy */ +#define STAT_DRQ 0x10 /* DMA requested */ +#define STAT_IRQ 0x20 /* interrupt requested */ +#define STAT_DCB 0x80 /* not seen by driver */ + +/* Sense Error codes. */ +#define ERR_NOERROR 0x00 /* no error detected */ +#define ERR_NOINDEX 0x01 /* drive did not detect IDX pulse */ +#define ERR_NOSEEK 0x02 /* drive did not complete SEEK */ +#define ERR_WRFAULT 0x03 /* write fault during last cmd */ +#define ERR_NOTRDY 0x04 /* drive did not go READY after cmd */ +#define ERR_NOTRK000 0x06 /* drive did not see TRK0 signal */ +#define ERR_LONGSEEK 0x08 /* long seek in progress */ +#define ERR_IDREAD 0x10 /* ECC error during ID field */ +#define ERR_DATA 0x11 /* uncorrectable ECC err in data */ +#define ERR_NOMARK 0x12 /* no address mark detected */ +#define ERR_NOSECT 0x14 /* sector not found */ +#define ERR_SEEK 0x15 /* seek error */ +#define ERR_ECCDATA 0x18 /* ECC corrected data */ +#define ERR_BADTRK 0x19 /* bad track detected */ +#define ERR_ILLCMD 0x20 /* invalid command received */ +#define ERR_ILLADDR 0x21 /* invalid disk address received */ +#define ERR_BADRAM 0x30 /* bad RAM in sector data buffer */ +#define ERR_BADROM 0x31 /* bad checksum in ROM test */ +#define ERR_BADECC 0x32 /* ECC polynomial generator bad */ + +/* Completion Byte fields. */ +#define COMP_DRIVE 0x20 +#define COMP_ERR 0x02 + +#define IRQ_ENA 0x02 +#define DMA_ENA 0x01 + + +/* The device control block (6 bytes) */ +#pragma pack(push,1) +typedef struct { + uint8_t cmd; /* [7:5] class, [4:0] opcode */ + + uint8_t head :5, /* [4:0] head number */ + drvsel :1, /* [5] drive select */ + mbz :2; /* [7:6] 00 */ + + uint8_t sector :6, /* [5:0] sector number 0-63 */ + cyl_high :2; /* [7:6] cylinder [9:8] bits */ + + uint8_t cyl_low; /* [7:0] cylinder [7:0] bits */ + + uint8_t count; /* [7:0] blk count / interleave */ + + uint8_t ctrl; /* [7:0] control field */ +} dcb_t; +#pragma pack(pop) + +/* The (configured) Drive Parameters. */ +#pragma pack(push,1) +typedef struct { + uint8_t cyl_high; /* (MSB) number of cylinders */ + uint8_t cyl_low; /* (LSB) number of cylinders */ + uint8_t heads; /* number of heads per cylinder */ + uint8_t rwc_high; /* (MSB) reduced write current cylinder */ + uint8_t rwc_low; /* (LSB) reduced write current cylinder */ + uint8_t wp_high; /* (MSB) write precompensation cylinder */ + uint8_t wp_low; /* (LSB) write precompensation cylinder */ + uint8_t maxecc; /* max ECC data burst length */ +} dprm_t; +#pragma pack(pop) + +/* Define an attached drive. */ +typedef struct { + int8_t id, /* drive ID on bus */ + present, /* drive is present */ + hdd_num, /* index to global disk table */ + type; /* drive type ID */ + + uint16_t cur_cyl; /* last known position of heads */ + + uint8_t spt, /* active drive parameters */ + hpc; + uint16_t tracks; + + uint8_t cfg_spt, /* configured drive parameters */ + cfg_hpc; + uint16_t cfg_tracks; +} drive_t; + + +typedef struct { + const char *name; /* controller name */ + + uint16_t base; /* controller base I/O address */ + int8_t irq; /* controller IRQ channel */ + int8_t dma; /* controller DMA channel */ + int8_t type; /* controller type ID */ + + uint32_t rom_addr; /* address where ROM is */ + rom_t bios_rom; /* descriptor for the BIOS */ + + /* Controller state. */ + int8_t state; /* controller state */ + uint8_t sense; /* current SENSE ERROR value */ + uint8_t status; /* current operational status */ + uint8_t intr; + int64_t callback; + + /* Data transfer. */ + int16_t buf_idx, /* buffer index and pointer */ + buf_len; + uint8_t *buf_ptr; + + /* Current operation parameters. */ + dcb_t dcb; /* device control block */ + uint16_t track; /* requested track# */ + uint8_t head, /* requested head# */ + sector, /* requested sector# */ + comp; /* operation completion byte */ + int count; /* requested sector count */ + + drive_t drives[XTA_NUM]; /* the attached drive(s) */ + + uint8_t data[512]; /* data buffer */ + uint8_t sector_buf[512]; /* sector buffer */ +} hdc_t; + + +static void +set_intr(hdc_t *dev) +{ + dev->status = STAT_REQ|STAT_CD|STAT_IO|STAT_BSY; + dev->state = STATE_COMPL; + + if (dev->intr & IRQ_ENA) { + dev->status |= STAT_IRQ; + picint(1 << dev->irq); + } +} + + +/* Get the logical (block) address of a CHS triplet. */ +static int +get_sector(hdc_t *dev, drive_t *drive, off64_t *addr) +{ + if (drive->cur_cyl != dev->track) { + pclog("%s: get_sector: wrong cylinder %d/%d\n", + dev->name, drive->cur_cyl, dev->track); + dev->sense = ERR_ILLADDR; + return(1); + } + + if (dev->head >= drive->hpc) { + pclog("%s: get_sector: past end of heads\n", dev->name); + dev->sense = ERR_ILLADDR; + return(1); + } + + if (dev->sector >= drive->spt) { + pclog("%s: get_sector: past end of sectors\n", dev->name); + dev->sense = ERR_ILLADDR; + return(1); + } + + /* Calculate logical address (block number) of desired sector. */ + *addr = ((((off64_t) dev->track*drive->hpc) + \ + dev->head)*drive->spt) + dev->sector; + + return(0); +} + + +static void +next_sector(hdc_t *dev, drive_t *drive) +{ + if (++dev->sector >= drive->spt) { + dev->sector = 0; + if (++dev->head >= drive->hpc) { + dev->head = 0; + dev->track++; + if (++drive->cur_cyl >= drive->tracks) + drive->cur_cyl = (drive->tracks - 1); + } + } +} + + +/* Perform the seek operation. */ +static void +do_seek(hdc_t *dev, drive_t *drive, int cyl) +{ + dev->track = cyl; + + if (dev->track >= drive->tracks) + drive->cur_cyl = (drive->tracks - 1); + else + drive->cur_cyl = dev->track; + + if (drive->cur_cyl < 0) + drive->cur_cyl = 0; +} + + +/* Format a track or an entire drive. */ +static void +do_format(hdc_t *dev, drive_t *drive, dcb_t *dcb) +{ + int start_cyl, end_cyl; + int start_hd, end_hd; + off64_t addr; + int h, s; + + /* Get the parameters from the DCB. */ + if (dcb->cmd == CMD_FORMAT_DRIVE) { + start_cyl = 0; + start_hd = 0; + end_cyl = drive->tracks; + end_hd = drive->hpc; + } else { + start_cyl = (dcb->cyl_low | (dcb->cyl_high << 8)); + start_hd = dcb->head; + end_cyl = start_cyl + 1; + end_hd = start_hd + 1; + } + + switch (dev->state) { + case STATE_IDLE: + /* Seek to cylinder. */ + do_seek(dev, drive, start_cyl); + dev->head = dcb->head; + dev->sector = 0; + +#ifdef ENABLE_HDC_LOG + pclog("%s: format_%s(%d) %d,%d\n", dev->name, + (dcb->cmd==CMD_FORMAT_DRIVE)?"drive":"track", + drive->id, dev->track, dev->head); +#endif + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); + +do_fmt: + /* + * For now, we don't use the interleave factor (in + * dcb->count), although we should one day use an + * image format that can handle it.. + * + * That said, we have been given a sector_buf of + * data to fill the sectors with, so we will use + * that at least. + */ + for (h = start_hd; h < end_hd; h++) { + for (s = 0; s < drive->spt; s++) { + /* Set the sector we need to write. */ + dev->head = h; + dev->sector = s; + + /* Get address of sector to write. */ + if (get_sector(dev, drive, &addr)) break; + + /* Write the block to the image. */ + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *)dev->sector_buf); + } + } + + /* One more track done. */ + if (++start_cyl == end_cyl) break; + + /* This saves us a LOT of code. */ + goto do_fmt; + } + + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); +} + + +/* Execute the DCB we just received. */ +static void +hdc_callback(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + dcb_t *dcb = &dev->dcb; + drive_t *drive; + dprm_t *params; + off64_t addr; + int no_data = 0; + int val; + + /* Cancel timer. */ + dev->callback = 0; + + drive = &dev->drives[dcb->drvsel]; + dev->comp = (dcb->drvsel) ? COMP_DRIVE : 0x00; + dev->status |= STAT_DCB; + + switch (dcb->cmd) { + case CMD_TEST_READY: +#ifdef ENABLE_HDC_LOG + pclog("%s: test_ready(%d) ready=%d\n", + dev->name, dcb->drvsel, drive->present); +#endif + if (! drive->present) { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + } + set_intr(dev); + break; + + case CMD_RECALIBRATE: +#ifdef ENABLE_HDC_LOG + pclog("%s: recalibrate(%d) ready=%d\n", + dev->name, dcb->drvsel, drive->present); +#endif + if (! drive->present) { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + } else { + dev->track = drive->cur_cyl = 0; + } + set_intr(dev); + break; + + case CMD_READ_SENSE: + switch(dev->state) { + case STATE_IDLE: +#ifdef ENABLE_HDC_LOG + pclog("%s: sense(%d)\n", + dev->name, dcb->drvsel); +#endif + dev->buf_idx = 0; + dev->buf_len = 4; + dev->buf_ptr = dev->data; + dev->buf_ptr[0] = dev->sense; + dev->buf_ptr[1] = dcb->drvsel ? 0x20 : 0x00; + dev->buf_ptr[2] = (drive->cur_cyl >> 2) | \ + (dev->sector & 0x3f); + dev->buf_ptr[3] = (drive->cur_cyl & 0xff); + dev->sense = ERR_NOERROR; + dev->status |= (STAT_IO | STAT_REQ); + dev->state = STATE_SDATA; + break; + + case STATE_SDONE: + set_intr(dev); + } + break; + + case CMD_READ_VERIFY: + no_data = 1; + /*FALLTHROUGH*/ + + case CMD_READ_SECTORS: + if (! drive->present) { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + set_intr(dev); + break; + } + + switch (dev->state) { + case STATE_IDLE: + /* Seek to cylinder. */ + do_seek(dev, drive, + (dcb->cyl_low|(dcb->cyl_high<<8))); + dev->head = dcb->head; + dev->sector = dcb->sector; + + /* Get sector count; count=0 means 256. */ + dev->count = (int)dcb->count; + if (dev->count == 0) + dev->count = 256; + dev->buf_len = 512; + + dev->state = STATE_SEND; + /*FALLTHROUGH*/ + + case STATE_SEND: + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); +#ifdef ENABLE_HDC_LOG + pclog("%s: read_%s(%d: %d,%d,%d) cnt=%d\n", + dev->name, (no_data)?"verify":"sector", + drive->id, dev->track, dev->head, + dev->sector, dev->count); +#endif +do_send: + /* Get address of sector to load. */ + if (get_sector(dev, drive, &addr)) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + dev->comp |= COMP_ERR; + set_intr(dev); + return; + } + + /* Read the block from the image. */ + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)dev->sector_buf); + + /* Ready to transfer the data out. */ + dev->state = STATE_SDATA; + dev->buf_idx = 0; + if (no_data) { + /* Delay a bit, no actual transfer. */ + dev->callback = HDC_TIME; + } else { + if (dev->intr & DMA_ENA) { + /* DMA enabled. */ + dev->buf_ptr = dev->sector_buf; + dev->callback = HDC_TIME; + } else { + /* Copy from sector to data. */ + memcpy(dev->data, + dev->sector_buf, + dev->buf_len); + dev->buf_ptr = dev->data; + + dev->status |= (STAT_IO | STAT_REQ); + } + } + break; + + case STATE_SDATA: + if (! no_data) { + /* Perform DMA. */ + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_write(dev->dma, + *dev->buf_ptr); + if (val == DMA_NODATA) { + pclog("%s: CMD_READ_SECTORS out of data (idx=%d, len=%d)!\n", dev->name, dev->buf_idx, dev->buf_len); + + dev->status |= (STAT_CD | STAT_IO| STAT_REQ); + dev->callback = HDC_TIME; + return; + } + dev->buf_ptr++; + dev->buf_idx++; + } + } + dev->callback = HDC_TIME; + dev->state = STATE_SDONE; + break; + + case STATE_SDONE: + dev->buf_idx = 0; + if (--dev->count == 0) { +#ifdef ENABLE_HDC_LOG + pclog("%s: read_%s(%d) DONE\n", + dev->name, + (no_data)?"verify":"sector", + drive->id); +#endif + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + set_intr(dev); + return; + } + + /* Addvance to next sector. */ + next_sector(dev, drive); + + /* This saves us a LOT of code. */ + dev->state = STATE_SEND; + goto do_send; + } + break; + +#if 0 + case CMD_WRITE_VERIFY: + no_data = 1; + /*FALLTHROUGH*/ +#endif + + case CMD_WRITE_SECTORS: + if (! drive->present) { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + set_intr(dev); + break; + } + + switch (dev->state) { + case STATE_IDLE: + /* Seek to cylinder. */ + do_seek(dev, drive, + (dcb->cyl_low|(dcb->cyl_high<<8))); + dev->head = dcb->head; + dev->sector = dcb->sector; + + /* Get sector count; count=0 means 256. */ + dev->count = (int)dev->dcb.count; + if (dev->count == 0) + dev->count = 256; + dev->buf_len = 512; + + dev->state = STATE_RECV; + /*FALLTHROUGH*/ + + case STATE_RECV: + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); +#ifdef ENABLE_HDC_LOG + pclog("%s: write_%s(%d: %d,%d,%d) cnt=%d\n", + dev->name, (no_data)?"verify":"sector", + dcb->drvsel, dev->track, + dev->head, dev->sector, dev->count); +#endif +do_recv: + /* Ready to transfer the data in. */ + dev->state = STATE_RDATA; + dev->buf_idx = 0; + if (no_data) { + /* Delay a bit, no actual transfer. */ + dev->callback = HDC_TIME; + } else { + if (dev->intr & DMA_ENA) { + /* DMA enabled. */ + dev->buf_ptr = dev->sector_buf; + dev->callback = HDC_TIME; + } else { + /* No DMA, do PIO. */ + dev->buf_ptr = dev->data; + dev->status |= STAT_REQ; + } + } + break; + + case STATE_RDATA: + if (! no_data) { + /* Perform DMA. */ + dev->status = STAT_BSY; + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { + pclog("%s: CMD_WRITE_SECTORS out of data (idx=%d, len=%d)!\n", dev->name, dev->buf_idx, dev->buf_len); + + pclog("%s: CMD_WRITE_SECTORS out of data!\n", dev->name); + dev->status |= (STAT_CD | STAT_IO | STAT_REQ); + dev->callback = HDC_TIME; + return; + } + + dev->buf_ptr[dev->buf_idx] = (val & 0xff); + dev->buf_idx++; + } + dev->state = STATE_RDONE; + dev->callback = HDC_TIME; + } + break; + + case STATE_RDONE: + /* Copy from data to sector if PIO. */ + if (! (dev->intr & DMA_ENA)) + memcpy(dev->sector_buf, dev->data, + dev->buf_len); + + /* Get address of sector to write. */ + if (get_sector(dev, drive, &addr)) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + dev->comp |= COMP_ERR; + set_intr(dev); + return; + } + + /* Write the block to the image. */ + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *)dev->sector_buf); + + dev->buf_idx = 0; + if (--dev->count == 0) { +#ifdef ENABLE_HDC_LOG + pclog("HDC: write_%s(%d) DONE\n", + (no_data)?"verify":"sector", + drive->id); +#endif + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + set_intr(dev); + return; + } + + /* Advance to next sector. */ + next_sector(dev, drive); + + /* This saves us a LOT of code. */ + dev->state = STATE_RECV; + goto do_recv; + } + break; + + case CMD_FORMAT_DRIVE: + case CMD_FORMAT_TRACK: + if (drive->present) { + do_format(dev, drive, dcb); + } else { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + } + set_intr(dev); + break; + + case CMD_SEEK: + /* Seek to cylinder. */ + val = (dcb->cyl_low | (dcb->cyl_high << 8)); +#ifdef ENABLE_HDC_LOG + pclog("%s: seek(%d) %d/%d ready=%d\n", dev->name, + dcb->drvsel, val, drive->cur_cyl, drive->present); +#endif + if (drive->present) { + do_seek(dev, drive, val); + if (val != drive->cur_cyl) { + dev->comp |= COMP_ERR; + dev->sense = ERR_SEEK; + } + } else { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + } + set_intr(dev); + break; + + case CMD_SET_DRIVE_PARAMS: + switch(dev->state) { + case STATE_IDLE: + dev->state = STATE_RDATA; + dev->buf_idx = 0; + dev->buf_len = sizeof(dprm_t); + dev->buf_ptr = (uint8_t *)dev->data; + dev->status |= STAT_REQ; + break; + + case STATE_RDONE: + params = (dprm_t *)dev->data; + drive->tracks = + (params->cyl_high << 8) | params->cyl_low; + drive->hpc = params->heads; + drive->spt = 17 /*hardcoded*/; +#ifdef ENABLE_HDC_LOG + pclog("%s: set_params(%d) cyl=%d,hd=%d,spt=%d\n", + dev->name, dcb->drvsel, drive->tracks, + drive->hpc, drive->spt); +#endif + dev->status &= ~STAT_REQ; + set_intr(dev); + break; + } + break; + + case CMD_WRITE_SECTOR_BUFFER: + switch (dev->state) { + case STATE_IDLE: +#ifdef ENABLE_HDC_LOG + pclog("%s: write_sector_buffer()\n", + dev->name); +#endif + dev->buf_idx = 0; + dev->buf_len = 512; + dev->state = STATE_RDATA; + if (dev->intr & DMA_ENA) { + dev->buf_ptr = dev->sector_buf; + dev->callback = HDC_TIME; + } else { + dev->buf_ptr = dev->data; + dev->status |= STAT_REQ; + } + break; + + case STATE_RDATA: + if (dev->intr & DMA_ENA) { + /* Perform DMA. */ + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { + pclog("%s: CMD_WRITE_BUFFER out of data!\n", dev->name); + dev->status |= (STAT_CD | STAT_IO | STAT_REQ); + dev->callback = HDC_TIME; + return; + } + + dev->buf_ptr[dev->buf_idx] = (val & 0xff); + dev->buf_idx++; + } + dev->state = STATE_RDONE; + dev->callback = HDC_TIME; + } + break; + + case STATE_RDONE: + if (! (dev->intr & DMA_ENA)) + memcpy(dev->sector_buf, + dev->data, dev->buf_len); + set_intr(dev); + break; + } + break; + + case CMD_RAM_DIAGS: + switch(dev->state) { + case STATE_IDLE: +#ifdef ENABLE_HDC_LOG + pclog("%s: ram_diags\n", dev->name); +#endif + dev->state = STATE_RDONE; + dev->callback = 5*HDC_TIME; + break; + + case STATE_RDONE: + set_intr(dev); + break; + } + break; + + case CMD_DRIVE_DIAGS: + switch(dev->state) { + case STATE_IDLE: +#ifdef ENABLE_HDC_LOG + pclog("%s: drive_diags(%d) ready=%d\n", + dev->name, dcb->drvsel, drive->present); +#endif + if (drive->present) { + dev->state = STATE_RDONE; + dev->callback = 5*HDC_TIME; + } else { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + set_intr(dev); + } + break; + + case STATE_RDONE: + set_intr(dev); + break; + } + break; + + case CMD_CTRL_DIAGS: + switch(dev->state) { + case STATE_IDLE: +#ifdef ENABLE_HDC_LOG + pclog("%s: ctrl_diags\n", dev->name); +#endif + dev->state = STATE_RDONE; + dev->callback = 10*HDC_TIME; + break; + + case STATE_RDONE: + set_intr(dev); + break; + } + break; + + default: + pclog("%s: unknown command - %02x\n", dev->name, dcb->cmd); + dev->comp |= COMP_ERR; + dev->sense = ERR_ILLCMD; + set_intr(dev); + } +} + + +/* Read one of the controller registers. */ +static uint8_t +hdc_read(uint16_t port, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: /* DATA register */ + dev->status &= ~STAT_IRQ; + + if (dev->state == STATE_SDATA) { + if (dev->buf_idx > dev->buf_len) { + pclog("%s: read with empty buffer!\n", + dev->name); + dev->comp |= COMP_ERR; + dev->sense = ERR_ILLCMD; + break; + } + + ret = dev->buf_ptr[dev->buf_idx]; + if (++dev->buf_idx == dev->buf_len) { + /* All data sent. */ + dev->status &= ~STAT_REQ; + dev->state = STATE_SDONE; + dev->callback = HDC_TIME; + } + } else if (dev->state == STATE_COMPL) { +pclog("DCB=%02X status=%02X comp=%02X\n", dev->dcb.cmd, dev->status, dev->comp); + ret = dev->comp; + dev->status = 0x00; + dev->state = STATE_IDLE; + } + break; + + case 1: /* STATUS register */ + ret = (dev->status & ~STAT_DCB); + break; + + case 2: /* "read option jumpers" */ + ret = 0xff; /* all switches off */ + break; + } + + return(ret); +} + + +/* Write to one of the controller registers. */ +static void +hdc_write(uint16_t port, uint8_t val, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + + switch (port & 7) { + case 0: /* DATA register */ + if (dev->state == STATE_RDATA) { + if (! (dev->status & STAT_REQ)) { + pclog("%s: not ready for command/data!\n", dev->name); + dev->comp |= COMP_ERR; + dev->sense = ERR_ILLCMD; + break; + } + + if (dev->buf_idx >= dev->buf_len) { + pclog("%s: write with full buffer!\n", dev->name); + dev->comp |= COMP_ERR; + dev->sense = ERR_ILLCMD; + break; + } + + /* Store the data into the buffer. */ + dev->buf_ptr[dev->buf_idx] = val; + if (++dev->buf_idx == dev->buf_len) { + /* We got all the data we need. */ + dev->status &= ~STAT_REQ; + if (dev->status & STAT_DCB) + dev->state = STATE_RDONE; + else + dev->state = STATE_IDLE; + dev->status &= ~STAT_CD; + dev->callback = HDC_TIME; + } + } + break; + + case 1: /* RESET register */ + dev->sense = 0x00; + dev->state = STATE_IDLE; + break; + + case 2: /* "controller-select" */ + /* Reset the DCB buffer. */ + dev->buf_idx = 0; + dev->buf_len = sizeof(dcb_t); + dev->buf_ptr = (uint8_t *)&dev->dcb; + dev->state = STATE_RDATA; + dev->status = (STAT_BSY | STAT_CD | STAT_REQ); + break; + + case 3: /* DMA/IRQ intr register */ +//pclog("%s: WriteMASK(%02X)\n", dev->name, val); + dev->intr = val; + break; + } +} + + +static void * +xta_init(const device_t *info) +{ + drive_t *drive; + wchar_t *fn = NULL; + hdc_t *dev; + int c, i; + + /* Allocate and initialize device block. */ + dev = malloc(sizeof(hdc_t)); + memset(dev, 0x00, sizeof(hdc_t)); + dev->type = info->local; + + /* Do per-controller-type setup. */ + switch(dev->type) { + case 0: /* WDXT-150, with BIOS */ + dev->name = "WDXT-150"; + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->rom_addr = device_get_config_hex20("bios_addr"); + dev->dma = 3; + fn = WD_BIOS_FILE; + break; + + case 1: /* EuroPC */ + dev->name = "HD20"; + dev->base = 0x0320; + dev->irq = 5; + dev->dma = 3; + break; + } + + pclog("%s: initializing (I/O=%04X, IRQ=%d, DMA=%d", + dev->name, dev->base, dev->irq, dev->dma); + if (dev->rom_addr != 0x000000) + pclog(", BIOS=%06X", dev->rom_addr); + pclog(")\n"); + + /* Load any disks for this device class. */ + c = 0; + for (i = 0; i < HDD_NUM; i++) { + if ((hdd[i].bus == HDD_BUS_XTA) && (hdd[i].ide_channel < XTA_NUM)) { + drive = &dev->drives[hdd[i].ide_channel]; + + if (! hdd_image_load(i)) { + drive->present = 0; + continue; + } + drive->id = c; + drive->hdd_num = i; + drive->present = 1; + + /* These are the "hardware" parameters (from the image.) */ + drive->cfg_spt = (uint8_t)(hdd[i].spt & 0xff); + drive->cfg_hpc = (uint8_t)(hdd[i].hpc & 0xff); + drive->cfg_tracks = (uint16_t)hdd[i].tracks; + + /* Use them as "configured" parameters until overwritten. */ + drive->spt = drive->cfg_spt; + drive->hpc = drive->cfg_hpc; + drive->tracks = drive->cfg_tracks; + + pclog("%s: drive%d (cyl=%d,hd=%d,spt=%d), disk %d\n", + dev->name, hdd[i].ide_channel, drive->tracks, + drive->hpc, drive->spt, i); + + if (++c > XTA_NUM) break; + } + } + + /* Enable the I/O block. */ + io_sethandler(dev->base, 4, + hdc_read,NULL,NULL, hdc_write,NULL,NULL, dev); + + /* Load BIOS if it has one. */ + if (dev->rom_addr != 0x000000) + rom_init(&dev->bios_rom, fn, + dev->rom_addr, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + + /* Create a timer for command delays. */ + timer_add(hdc_callback, &dev->callback, &dev->callback, dev); + + return(dev); +} + + +static void +xta_close(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + drive_t *drive; + int d; + + /* Remove the I/O handler. */ + io_removehandler(dev->base, 4, + hdc_read,NULL,NULL, hdc_write,NULL,NULL, dev); + + /* Close all disks and their images. */ + for (d = 0; d < XTA_NUM; d++) { + drive = &dev->drives[d]; + + hdd_image_close(drive->hdd_num); + } + + /* Release the device. */ + free(dev); +} + + +static const device_config_t wdxt150_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x0320, /*W2*/ + { + { + "320H", 0x0320 + }, + { + "324H", 0x0324 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, /*W3*/ + { + { + "IRQ 5", 5 + }, + { + "IRQ 4", 4 + }, + { + "" + } + }, + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xc8000, /*W1*/ + { + { + "C800H", 0xc8000 + }, + { + "CA00H", 0xca000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + + +const device_t xta_wdxt150_device = { + "WDXT-150 Fixed Disk Controller", + DEVICE_ISA, + 0, + xta_init, xta_close, NULL, + NULL, NULL, NULL, NULL, + wdxt150_config +}; + + +const device_t xta_hd20_device = { + "EuroPC HD20 Fixed Disk Controller", + DEVICE_ISA, + 1, + xta_init, xta_close, NULL, + NULL, NULL, NULL, NULL, + NULL +}; diff --git a/src/disk/hdc_xtide.c b/src/disk/hdc_xtide.c index bc4cdcd92..7a3d388ff 100644 --- a/src/disk/hdc_xtide.c +++ b/src/disk/hdc_xtide.c @@ -21,7 +21,7 @@ * already on their way out, the newer IDE standard based on the * PC/AT controller and 16b design became the IDE we now know. * - * Version: @(#)hdc_xtide.c 1.0.11 2018/03/18 + * Version: @(#)hdc_xtide.c 1.0.12 2018/04/05 * * Authors: Sarah Walker, * Miran Grca, @@ -52,6 +52,7 @@ typedef struct { + void *ide_board; uint8_t data_high; rom_t bios_rom; } xtide_t; @@ -64,7 +65,7 @@ xtide_write(uint16_t port, uint8_t val, void *priv) switch (port & 0xf) { case 0x0: - writeidew(4, val | (xtide->data_high << 8)); + ide_writew(0x0, val | (xtide->data_high << 8), xtide->ide_board); return; case 0x1: @@ -74,7 +75,7 @@ xtide_write(uint16_t port, uint8_t val, void *priv) case 0x5: case 0x6: case 0x7: - writeide(4, (port & 0xf) | 0x1f0, val); + ide_writeb((port & 0xf), val, xtide->ide_board); return; case 0x8: @@ -82,7 +83,7 @@ xtide_write(uint16_t port, uint8_t val, void *priv) return; case 0xe: - writeide(4, 0x3f6, val); + ide_write_devctl(0x0, val, xtide->ide_board); return; } } @@ -96,7 +97,7 @@ xtide_read(uint16_t port, void *priv) switch (port & 0xf) { case 0x0: - tempw = readidew(4); + tempw = ide_readw(0x0, xtide->ide_board); xtide->data_high = tempw >> 8; break; @@ -107,7 +108,7 @@ xtide_read(uint16_t port, void *priv) case 0x5: case 0x6: case 0x7: - tempw = readide(4, (port & 0xf) | 0x1f0); + tempw = ide_readb((port & 0xf), xtide->ide_board); break; case 0x8: @@ -115,7 +116,7 @@ xtide_read(uint16_t port, void *priv) break; case 0xe: - tempw = readide(4, 0x3f6); + tempw = ide_read_alt_status(0x0, xtide->ide_board); break; default: @@ -136,7 +137,7 @@ xtide_init(const device_t *info) rom_init(&xtide->bios_rom, ROM_PATH_XT, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - ide_xtide_init(); + xtide->ide_board = ide_xtide_init(); io_sethandler(0x0300, 16, xtide_read, NULL, NULL, @@ -186,7 +187,7 @@ xtide_acculogic_init(const device_t *info) rom_init(&xtide->bios_rom, ROM_PATH_PS2, 0xc8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - ide_xtide_init(); + xtide->ide_board = ide_xtide_init(); io_sethandler(0x0360, 16, xtide_read, NULL, NULL, @@ -203,6 +204,17 @@ xtide_acculogic_available(void) } +static void +xtide_close(void *priv) +{ + xtide_t *xtide = (xtide_t *)priv; + + free(xtide); + + ide_xtide_close(); +} + + static void * xtide_at_ps2_init(const device_t *info) { @@ -227,7 +239,7 @@ xtide_at_ps2_available(void) static void -xtide_close(void *priv) +xtide_at_close(void *priv) { xtide_t *xtide = (xtide_t *)priv; @@ -248,7 +260,7 @@ const device_t xtide_at_device = { "XTIDE (AT)", DEVICE_ISA | DEVICE_AT, 0, - xtide_at_init, xtide_close, NULL, + xtide_at_init, xtide_at_close, NULL, xtide_at_available, NULL, NULL, NULL, NULL }; @@ -266,7 +278,7 @@ const device_t xtide_at_ps2_device = { "XTIDE (AT) (1.1.5)", DEVICE_ISA | DEVICE_PS2, 0, - xtide_at_ps2_init, xtide_close, NULL, + xtide_at_ps2_init, xtide_at_close, NULL, xtide_at_ps2_available, NULL, NULL, NULL, NULL }; diff --git a/src/disk/hdd.c b/src/disk/hdd.c index e4f682dd9..30b031249 100644 --- a/src/disk/hdd.c +++ b/src/disk/hdd.c @@ -8,13 +8,13 @@ * * Common code to handle all sorts of hard disk images. * - * Version: @(#)hdd.c 1.0.7 2017/11/18 + * Version: @(#)hdd.c 1.0.8 2018/04/24 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016,2017 Miran Grca. - * Copyright 2017 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. */ #include #include @@ -63,53 +63,35 @@ no_cdrom: } if (! strcmp(str, "ide_pio_only")) - return(HDD_BUS_IDE_PIO_ONLY); + return(HDD_BUS_IDE); if (! strcmp(str, "ide")) - return(HDD_BUS_IDE_PIO_ONLY); + return(HDD_BUS_IDE); if (! strcmp(str, "atapi_pio_only")) - return(HDD_BUS_IDE_PIO_ONLY); + return(HDD_BUS_IDE); if (! strcmp(str, "atapi")) - return(HDD_BUS_IDE_PIO_ONLY); + return(HDD_BUS_IDE); if (! strcmp(str, "eide")) - return(HDD_BUS_IDE_PIO_ONLY); + return(HDD_BUS_IDE); - if (! strcmp(str, "xtide")) - return(HDD_BUS_XTIDE); + if (! strcmp(str, "xta")) + return(HDD_BUS_XTA); if (! strcmp(str, "atide")) - return(HDD_BUS_IDE_PIO_ONLY); + return(HDD_BUS_IDE); if (! strcmp(str, "ide_pio_and_dma")) - return(HDD_BUS_IDE_PIO_AND_DMA); + return(HDD_BUS_IDE); if (! strcmp(str, "atapi_pio_and_dma")) - return(HDD_BUS_IDE_PIO_AND_DMA); + return(HDD_BUS_IDE); if (! strcmp(str, "scsi")) return(HDD_BUS_SCSI); - if (! strcmp(str, "removable")) { - if (cdrom) goto no_cdrom; - - return(HDD_BUS_SCSI_REMOVABLE); - } - - if (! strcmp(str, "scsi_removable")) { - if (cdrom) goto no_cdrom; - - return(HDD_BUS_SCSI_REMOVABLE); - } - - if (! strcmp(str, "removable_scsi")) { - if (cdrom) goto no_cdrom; - - return(HDD_BUS_SCSI_REMOVABLE); - } - if (! strcmp(str, "usb")) ui_msgbox(MBX_ERROR, (wchar_t *)IDS_4110); @@ -131,29 +113,21 @@ hdd_bus_to_string(int bus, int cdrom) s = "mfm"; break; - case HDD_BUS_XTIDE: - s = "xtide"; + case HDD_BUS_XTA: + s = "xta"; break; case HDD_BUS_ESDI: s = "esdi"; break; - case HDD_BUS_IDE_PIO_ONLY: - s = cdrom ? "atapi_pio_only" : "ide_pio_only"; - break; - - case HDD_BUS_IDE_PIO_AND_DMA: - s = cdrom ? "atapi_pio_and_dma" : "ide_pio_and_dma"; + case HDD_BUS_IDE: + s = cdrom ? "atapi" : "ide"; break; case HDD_BUS_SCSI: s = "scsi"; break; - - case HDD_BUS_SCSI_REMOVABLE: - s = "scsi_removable"; - break; } return(s); @@ -163,12 +137,14 @@ hdd_bus_to_string(int bus, int cdrom) int hdd_is_valid(int c) { - if (hdd[c].bus == HDD_BUS_DISABLED) return(0); + if (hdd[c].bus == HDD_BUS_DISABLED) + return(0); - if ((wcslen(hdd[c].fn) == 0) && - (hdd[c].bus != HDD_BUS_SCSI_REMOVABLE)) return(0); + if (wcslen(hdd[c].fn) == 0) + return(0); - if ((hdd[c].tracks==0) || (hdd[c].hpc==0) || (hdd[c].spt==0)) return(0); + if ((hdd[c].tracks==0) || (hdd[c].hpc==0) || (hdd[c].spt==0)) + return(0); return(1); } diff --git a/src/disk/hdd.h b/src/disk/hdd.h index dbb951bac..a9a81baf9 100644 --- a/src/disk/hdd.h +++ b/src/disk/hdd.h @@ -8,12 +8,12 @@ * * Definitions for the hard disk image handler. * - * Version: @(#)hdd.h 1.0.3 2017/10/05 + * Version: @(#)hdd.h 1.0.4 2018/03/29 * * Authors: Miran Grca, * Fred N. van Kempen, - * Copyright 2016,2017 Miran Grca. - * Copyright 2017 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. */ #ifndef EMU_HDD_H # define EMU_HDD_H @@ -23,17 +23,53 @@ /* Hard Disk bus types. */ +#if 0 +/* Bit 4 = DMA supported (0 = no, 1 yes) - used for IDE and ATAPI only; + Bit 5 = Removable (0 = no, 1 yes). */ + +enum { + BUS_DISABLED = 0x00, + + BUS_MFM = 0x01, /* These four are for hard disk only. */ + BUS_XIDE = 0x02, + BUS_XTA = 0x03, + BUS_ESDI = 0x04, + + BUS_PANASONIC = 0x21, / These four are for CD-ROM only. */ + BUS_PHILIPS = 0x22, + BUS_SONY = 0x23, + BUS_MITSUMI = 0x24, + + BUS_IDE_PIO_ONLY = 0x05, + BUS_IDE_PIO_AND_DMA = 0x15, + BUS_IDE_R_PIO_ONLY = 0x25, + BUS_IDE_R_PIO_AND_DMA = 0x35, + + BUS_ATAPI_PIO_ONLY = 0x06, + BUS_ATAPI_PIO_AND_DMA = 0x16, + BUS_ATAPI_R_PIO_ONLY = 0x26, + BUS_ATAPI_R_PIO_AND_DMA = 0x36, + + BUS_SASI = 0x07, + BUS_SASI_R = 0x27, + + BUS_SCSI = 0x08, + BUS_SCSI_R = 0x28, + + BUS_USB = 0x09, + BUS_USB_R = 0x29 +}; +#else enum { HDD_BUS_DISABLED = 0, HDD_BUS_MFM, - HDD_BUS_XTIDE, + HDD_BUS_XTA, HDD_BUS_ESDI, - HDD_BUS_IDE_PIO_ONLY, - HDD_BUS_IDE_PIO_AND_DMA, + HDD_BUS_IDE, HDD_BUS_SCSI, - HDD_BUS_SCSI_REMOVABLE, HDD_BUS_USB }; +#endif /* Define the virtual Hard Disk. */ @@ -45,18 +81,16 @@ typedef struct { uint8_t mfm_channel; /* should rename and/or unionize */ uint8_t esdi_channel; - uint8_t xtide_channel; + uint8_t xta_channel; uint8_t ide_channel; uint8_t scsi_id; uint8_t scsi_lun; - uint32_t base; - - uint64_t spt, + uint32_t base, + spt, hpc, /* physical geometry parameters */ - tracks; - - uint64_t at_spt, /* [Translation] parameters */ + tracks, + at_spt, /* [Translation] parameters */ at_hpc; FILE *f; /* current file handle to image */ @@ -67,7 +101,7 @@ typedef struct { extern hard_disk_t hdd[HDD_NUM]; -extern uint64_t hdd_table[128][3]; +extern unsigned int hdd_table[128][3]; extern int hdd_init(void); @@ -75,6 +109,7 @@ extern int hdd_string_to_bus(char *str, int cdrom); extern char *hdd_bus_to_string(int bus, int cdrom); extern int hdd_is_valid(int c); +extern void hdd_image_init(void); extern int hdd_image_load(int id); extern void hdd_image_seek(uint8_t id, uint32_t sector); extern void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer); diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index 272138b38..8d8a419db 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -8,7 +8,7 @@ * * Handling of hard disk image files. * - * Version: @(#)hdd_image.c 1.0.13 2018/03/19 + * Version: @(#)hdd_image.c 1.0.14 2018/03/28 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -34,11 +34,11 @@ typedef struct { - FILE *file; - uint32_t base; - uint32_t last_sector; - uint8_t type; - uint8_t loaded; + FILE *file; + uint32_t base; + uint32_t last_sector; + uint8_t type; + uint8_t loaded; } hdd_image_t; @@ -69,393 +69,442 @@ hdd_image_log(const char *fmt, ...) } -int image_is_hdi(const wchar_t *s) +int +image_is_hdi(const wchar_t *s) { - int len; - wchar_t ext[5] = { 0, 0, 0, 0, 0 }; - char *ws = (char *) s; - len = wcslen(s); - if ((len < 4) || (s[0] == L'.')) - return 0; - memcpy(ext, ws + ((len - 4) << 1), 8); - if (! wcscasecmp(ext, L".HDI")) - return 1; - else - return 0; + int len; + wchar_t ext[5] = { 0, 0, 0, 0, 0 }; + char *ws = (char *) s; + len = wcslen(s); + if ((len < 4) || (s[0] == L'.')) + return 0; + memcpy(ext, ws + ((len - 4) << 1), 8); + if (! wcscasecmp(ext, L".HDI")) + return 1; + else + return 0; } int image_is_hdx(const wchar_t *s, int check_signature) { - int len; - FILE *f; - uint64_t filelen; - uint64_t signature; - char *ws = (char *) s; - wchar_t ext[5] = { 0, 0, 0, 0, 0 }; - len = wcslen(s); - if ((len < 4) || (s[0] == L'.')) - return 0; - memcpy(ext, ws + ((len - 4) << 1), 8); - if (wcscasecmp(ext, L".HDX") == 0) { - if (check_signature) { - f = plat_fopen((wchar_t *)s, L"rb"); - if (!f) - return 0; - fseeko64(f, 0, SEEK_END); - filelen = ftello64(f); - fseeko64(f, 0, SEEK_SET); - if (filelen < 44) - return 0; - fread(&signature, 1, 8, f); - fclose(f); - if (signature == 0xD778A82044445459ll) - return 1; - return 0; - } - return 1; - } + int len; + FILE *f; + uint64_t filelen; + uint64_t signature; + char *ws = (char *) s; + wchar_t ext[5] = { 0, 0, 0, 0, 0 }; + len = wcslen(s); + if ((len < 4) || (s[0] == L'.')) return 0; + memcpy(ext, ws + ((len - 4) << 1), 8); + if (wcscasecmp(ext, L".HDX") == 0) { + if (check_signature) { + f = plat_fopen((wchar_t *)s, L"rb"); + if (!f) + return 0; + fseeko64(f, 0, SEEK_END); + filelen = ftello64(f); + fseeko64(f, 0, SEEK_SET); + if (filelen < 44) + return 0; + fread(&signature, 1, 8, f); + fclose(f); + if (signature == 0xD778A82044445459ll) + return 1; + else + return 0; + } else + return 1; + } else + return 0; } -int hdd_image_load(int id) +static int +prepare_new_hard_disk(uint8_t id, uint64_t full_size) { - uint32_t sector_size = 512; - uint32_t zero = 0; - uint64_t signature = 0xD778A82044445459ll; - uint64_t full_size = 0; - uint64_t spt = 0, hpc = 0, tracks = 0; - int c; - uint64_t i = 0, s = 0, t = 0; - wchar_t *fn = hdd[id].fn; - int is_hdx[2] = { 0, 0 }; + uint64_t target_size = (full_size + hdd_images[id].base) - ftello64(hdd_images[id].file); - memset(empty_sector, 0, sizeof(empty_sector)); + uint32_t size; + uint32_t t, i; - hdd_images[id].base = 0; + t = (uint32_t) (target_size >> 20); /* Amount of 1 MB blocks. */ + size = (uint32_t) (target_size & 0xfffff); /* 1 MB mask. */ - if (hdd_images[id].loaded) { - if (hdd_images[id].file) { - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - } - hdd_images[id].loaded = 0; + empty_sector_1mb = (char *) malloc(1048576); + memset(empty_sector_1mb, 0, 1048576); + + /* Temporarily switch off suppression of seen messages so that the + progress gets displayed. */ + pclog_toggle_suppr(); + pclog("Writing image sectors: ["); + + /* First, write all the 1 MB blocks. */ + if (t > 0) { + for (i = 0; i < t; i++) { + fwrite(empty_sector_1mb, 1, 1045876, hdd_images[id].file); + pclog("#"); } + } - is_hdx[0] = image_is_hdx(fn, 0); - is_hdx[1] = image_is_hdx(fn, 1); + /* Then, write the remainder. */ + fwrite(empty_sector_1mb, 1, size, hdd_images[id].file); + pclog("#]\n"); + /* Switch the suppression of seen messages back on. */ + pclog_toggle_suppr(); - /* Try to open existing hard disk image */ - if (fn[0] == '.') { - hdd_image_log("File name starts with .\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; + free(empty_sector_1mb); + + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + + hdd_images[id].loaded = 1; + + return 1; +} + + +void +hdd_image_init(void) +{ + int i; + + for (i = 0; i < HDD_NUM; i++) + memset(&hdd_images[i], 0, sizeof(hdd_image_t)); +} + + +int +hdd_image_load(int id) +{ + uint32_t sector_size = 512; + uint32_t zero = 0; + uint64_t signature = 0xD778A82044445459ll; + uint64_t full_size = 0; + uint64_t spt = 0, hpc = 0, tracks = 0; + int c; + uint64_t s = 0; + wchar_t *fn = hdd[id].fn; + int is_hdx[2] = { 0, 0 }; + + memset(empty_sector, 0, sizeof(empty_sector)); + + hdd_images[id].base = 0; + + if (hdd_images[id].loaded) { + if (hdd_images[id].file) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; } - hdd_images[id].file = plat_fopen(fn, L"rb+"); - if (hdd_images[id].file == NULL) { - /* Failed to open existing hard disk image */ - if (errno == ENOENT) { - /* Failed because it does not exist, - so try to create new file */ - if (hdd[id].wp) { - hdd_image_log("A write-protected image must exist\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } + hdd_images[id].loaded = 0; + } - hdd_images[id].file = plat_fopen(fn, L"wb+"); - if (hdd_images[id].file == NULL) { - hdd_image_log("Unable to open image\n"); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } else { - if (image_is_hdi(fn)) { - full_size = hdd[id].spt * hdd[id].hpc * hdd[id].tracks * 512; - hdd_images[id].base = 0x1000; - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file); - fwrite(&full_size, 1, 4, hdd_images[id].file); - fwrite(§or_size, 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); - for (c = 0; c < 0x3f8; c++) - fwrite(&zero, 1, 4, hdd_images[id].file); - hdd_images[id].type = 1; - } else if (is_hdx[0]) { - full_size = hdd[id].spt * hdd[id].hpc * hdd[id].tracks * 512; - hdd_images[id].base = 0x28; - fwrite(&signature, 1, 8, hdd_images[id].file); - fwrite(&full_size, 1, 8, hdd_images[id].file); - fwrite(§or_size, 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - fwrite(&zero, 1, 4, hdd_images[id].file); - hdd_images[id].type = 2; - } - else - hdd_images[id].type = 0; - hdd_images[id].last_sector = 0; - } + is_hdx[0] = image_is_hdx(fn, 0); + is_hdx[1] = image_is_hdx(fn, 1); - s = full_size = hdd[id].spt * hdd[id].hpc * hdd[id].tracks * 512; - - goto prepare_new_hard_disk; - } else { - /* Failed for another reason */ - hdd_image_log("Failed for another reason\n"); + /* Try to open existing hard disk image */ + if (fn[0] == '.') { + hdd_image_log("File name starts with .\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + hdd_images[id].file = plat_fopen(fn, L"rb+"); + if (hdd_images[id].file == NULL) { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) { + /* Failed because it does not exist, + so try to create new file */ + if (hdd[id].wp) { + hdd_image_log("A write-protected image must exist\n"); memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); return 0; } - } else { - if (image_is_hdi(fn)) { - fseeko64(hdd_images[id].file, 0x8, SEEK_SET); - fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file); - fseeko64(hdd_images[id].file, 0xC, SEEK_SET); - full_size = 0; - fread(&full_size, 1, 4, hdd_images[id].file); - fseeko64(hdd_images[id].file, 0x10, SEEK_SET); - fread(§or_size, 1, 4, hdd_images[id].file); - if (sector_size != 512) { - /* Sector size is not 512 */ - hdd_image_log("HDI: Sector size is not 512\n"); - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - fread(&spt, 1, 4, hdd_images[id].file); - fread(&hpc, 1, 4, hdd_images[id].file); - fread(&tracks, 1, 4, hdd_images[id].file); - if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) { - if ((spt != hdd[id].spt) || (hpc != hdd[id].hpc) || (tracks != hdd[id].tracks)) { - hdd_image_log("HDI: Geometry mismatch\n"); - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - } - hdd[id].spt = spt; - hdd[id].hpc = hpc; - hdd[id].tracks = tracks; - hdd_images[id].type = 1; - } - else if (is_hdx[1]) { - hdd_images[id].base = 0x28; - fseeko64(hdd_images[id].file, 8, SEEK_SET); - fread(&full_size, 1, 8, hdd_images[id].file); - fseeko64(hdd_images[id].file, 0x10, SEEK_SET); - fread(§or_size, 1, 4, hdd_images[id].file); - if (sector_size != 512) { - /* Sector size is not 512 */ - hdd_image_log("HDX: Sector size is not 512\n"); - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - fread(&spt, 1, 4, hdd_images[id].file); - fread(&hpc, 1, 4, hdd_images[id].file); - fread(&tracks, 1, 4, hdd_images[id].file); - if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) { - if ((spt != hdd[id].spt) || (hpc != hdd[id].hpc) || (tracks != hdd[id].tracks)) { - hdd_image_log("HDX: Geometry mismatch\n"); - fclose(hdd_images[id].file); - hdd_images[id].file = NULL; - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - return 0; - } - } - hdd[id].spt = spt; - hdd[id].hpc = hpc; - hdd[id].tracks = tracks; - fread(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); - fread(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); - hdd_images[id].type = 2; + + hdd_images[id].file = plat_fopen(fn, L"wb+"); + if (hdd_images[id].file == NULL) { + hdd_image_log("Unable to open image\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; } else { - full_size = hdd[id].spt * hdd[id].hpc * hdd[id].tracks * 512; - hdd_images[id].type = 0; - } - } - - fseeko64(hdd_images[id].file, 0, SEEK_END); - if (ftello64(hdd_images[id].file) < (full_size + hdd_images[id].base)) { - s = (full_size + hdd_images[id].base) - ftello64(hdd_images[id].file); -prepare_new_hard_disk: - t = s >> 20; /* Amount of 1 MB blocks. */ - s &= 0xfffff; /* 1 MB mask. */ - - empty_sector_1mb = (char *) malloc(1048576); - memset(empty_sector_1mb, 0, 1048576); - - /* Temporarily switch off suppression of seen messages so that the - progress gets displayed. */ - pclog_toggle_suppr(); - pclog("Writing image sectors: ["); - - /* First, write all the 1 MB blocks. */ - if (t > 0) { - for (i = 0; i < t; i++) { - fwrite(empty_sector_1mb, 1, 1045876, hdd_images[id].file); - pclog("#"); + if (image_is_hdi(fn)) { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].base = 0x1000; + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file); + fwrite(&full_size, 1, 4, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); + for (c = 0; c < 0x3f8; c++) + fwrite(&zero, 1, 4, hdd_images[id].file); + hdd_images[id].type = 1; + } else if (is_hdx[0]) { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].base = 0x28; + fwrite(&signature, 1, 8, hdd_images[id].file); + fwrite(&full_size, 1, 8, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + hdd_images[id].type = 2; } + else + hdd_images[id].type = 0; + hdd_images[id].last_sector = 0; } - /* Then, write the remainder. */ - fwrite(empty_sector_1mb, 1, s, hdd_images[id].file); - pclog("#]\n"); - pclog_toggle_suppr(); + s = full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; - free(empty_sector_1mb); + return prepare_new_hard_disk(id, full_size); + } else { + /* Failed for another reason */ + hdd_image_log("Failed for another reason\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; } - - hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; - - hdd_images[id].loaded = 1; - - return 1; -} - -void hdd_image_seek(uint8_t id, uint32_t sector) -{ - off64_t addr = sector; - addr = (uint64_t)sector * 512; - - fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET); -} - -void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) -{ - fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET); - fread(buffer, 1, count * 512, hdd_images[id].file); -} - -uint32_t hdd_sectors(uint8_t id) -{ - fseeko64(hdd_images[id].file, 0, SEEK_END); - return (uint32_t) (ftello64(hdd_images[id].file) >> 9); -} - -int hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) -{ - uint32_t transfer_sectors = count; - uint32_t sectors = hdd_sectors(id); - - if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; - - fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET); - fread(buffer, 1, transfer_sectors * 512, hdd_images[id].file); - - if (count != transfer_sectors) - return 1; - return 0; -} - -void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) -{ - fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET); - fwrite(buffer, count * 512, 1, hdd_images[id].file); -} - -int hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) -{ - uint32_t transfer_sectors = count; - uint32_t sectors = hdd_sectors(id); - - if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; - - fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET); - fwrite(buffer, transfer_sectors * 512, 1, hdd_images[id].file); - - if (count != transfer_sectors) - return 1; - return 0; -} - -void hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) -{ - int i = 0; - - fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET); - for (i = 0; i < count; i++) - fwrite(empty_sector, 512, 1, hdd_images[id].file); -} - -int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count) -{ - int i = 0; - - uint32_t transfer_sectors = count; - uint32_t sectors = hdd_sectors(id); - - if ((sectors - sector) < transfer_sectors) - transfer_sectors = sectors - sector; - - fseeko64(hdd_images[id].file, ((uint64_t)sector * 512) + hdd_images[id].base, SEEK_SET); - for (i = 0; i < transfer_sectors; i++) - fwrite(empty_sector, 1, 512, hdd_images[id].file); - - if (count != transfer_sectors) - return 1; - return 0; -} - -uint32_t hdd_image_get_last_sector(uint8_t id) -{ - return hdd_images[id].last_sector; -} - -uint8_t hdd_image_get_type(uint8_t id) -{ - return hdd_images[id].type; -} - -void hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt) -{ - if (hdd_images[id].type == 2) - { - hdd[id].at_hpc = hpc; - hdd[id].at_spt = spt; - fseeko64(hdd_images[id].file, 0x20, SEEK_SET); - fwrite(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); - } -} - -void hdd_image_unload(uint8_t id, int fn_preserve) -{ - if (wcslen(hdd[id].fn) == 0) - return; - - if (hdd_images[id].loaded) { - if (hdd_images[id].file != NULL) { + } else { + if (image_is_hdi(fn)) { + fseeko64(hdd_images[id].file, 0x8, SEEK_SET); + fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file); + fseeko64(hdd_images[id].file, 0xC, SEEK_SET); + full_size = 0LL; + fread(&full_size, 1, 4, hdd_images[id].file); + fseeko64(hdd_images[id].file, 0x10, SEEK_SET); + fread(§or_size, 1, 4, hdd_images[id].file); + if (sector_size != 512) { + /* Sector size is not 512 */ + hdd_image_log("HDI: Sector size is not 512\n"); fclose(hdd_images[id].file); hdd_images[id].file = NULL; + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; } - hdd_images[id].loaded = 0; + fread(&spt, 1, 4, hdd_images[id].file); + fread(&hpc, 1, 4, hdd_images[id].file); + fread(&tracks, 1, 4, hdd_images[id].file); + hdd[id].spt = spt; + hdd[id].hpc = hpc; + hdd[id].tracks = tracks; + hdd_images[id].type = 1; + } else if (is_hdx[1]) { + hdd_images[id].base = 0x28; + fseeko64(hdd_images[id].file, 8, SEEK_SET); + fread(&full_size, 1, 8, hdd_images[id].file); + fseeko64(hdd_images[id].file, 0x10, SEEK_SET); + fread(§or_size, 1, 4, hdd_images[id].file); + if (sector_size != 512) { + /* Sector size is not 512 */ + hdd_image_log("HDX: Sector size is not 512\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + fread(&spt, 1, 4, hdd_images[id].file); + fread(&hpc, 1, 4, hdd_images[id].file); + fread(&tracks, 1, 4, hdd_images[id].file); + hdd[id].spt = spt; + hdd[id].hpc = hpc; + hdd[id].tracks = tracks; + fread(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); + fread(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); + hdd_images[id].type = 2; + } else { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].type = 0; } + } - hdd_images[id].last_sector = -1; - - memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn)); - if (fn_preserve) - wcscpy(hdd[id].prev_fn, hdd[id].fn); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + fseeko64(hdd_images[id].file, 0, SEEK_END); + s = ftello64(hdd_images[id].file); + if (s < (full_size + hdd_images[id].base)) + return prepare_new_hard_disk(id, full_size); + else { + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + hdd_images[id].loaded = 1; + return 1; + } } -void hdd_image_close(uint8_t id) + +void +hdd_image_seek(uint8_t id, uint32_t sector) { + off64_t addr = sector; + addr = (uint64_t)sector * 512; + + fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET); +} + + +void +hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + fread(buffer, 1, count << 9, hdd_images[id].file); +} + + +uint32_t +hdd_sectors(uint8_t id) +{ + fseeko64(hdd_images[id].file, 0, SEEK_END); + return (uint32_t) ((ftello64(hdd_images[id].file) - hdd_images[id].base) >> 9); +} + + +int +hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; + + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + fread(buffer, 1, transfer_sectors << 9, hdd_images[id].file); + + if (count != transfer_sectors) + return 1; + return 0; +} + + +void +hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + fwrite(buffer, count << 9, 1, hdd_images[id].file); +} + + +int +hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; + + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + fwrite(buffer, transfer_sectors << 9, 1, hdd_images[id].file); + + if (count != transfer_sectors) + return 1; + return 0; +} + + +void +hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) +{ + uint32_t i = 0; + + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + for (i = 0; i < count; i++) + fwrite(empty_sector, 512, 1, hdd_images[id].file); +} + + +int +hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count) +{ + uint32_t i = 0; + + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; + + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + for (i = 0; i < transfer_sectors; i++) + fwrite(empty_sector, 1, 512, hdd_images[id].file); + + if (count != transfer_sectors) + return 1; + return 0; +} + + +uint32_t +hdd_image_get_last_sector(uint8_t id) +{ + return hdd_images[id].last_sector; +} + + +uint8_t +hdd_image_get_type(uint8_t id) +{ + return hdd_images[id].type; +} + + +void +hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt) +{ + if (hdd_images[id].type == 2) { + hdd[id].at_hpc = hpc; + hdd[id].at_spt = spt; + fseeko64(hdd_images[id].file, 0x20, SEEK_SET); + fwrite(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); + } +} + + +void +hdd_image_unload(uint8_t id, int fn_preserve) +{ + if (wcslen(hdd[id].fn) == 0) + return; + + if (hdd_images[id].loaded) { if (hdd_images[id].file != NULL) { fclose(hdd_images[id].file); hdd_images[id].file = NULL; } hdd_images[id].loaded = 0; + } + + hdd_images[id].last_sector = -1; + + memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn)); + if (fn_preserve) + wcscpy(hdd[id].prev_fn, hdd[id].fn); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); +} + + +void +hdd_image_close(uint8_t id) +{ + hdd_image_log("hdd_image_close(%i)\n", id); + + if (!hdd_images[id].loaded) + return; + + if (hdd_images[id].file != NULL) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } + memset(&hdd_images[id], 0, sizeof(hdd_image_t)); + hdd_images[id].loaded = 0; } diff --git a/src/disk/hdd_table.c b/src/disk/hdd_table.c index 95490a014..0ef0829e1 100644 --- a/src/disk/hdd_table.c +++ b/src/disk/hdd_table.c @@ -9,13 +9,13 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdd_table.c 1.0.5 2017/11/01 + * Version: @(#)hdd_table.c 1.0.5 2018/04/08 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016,2017 Miran Grca. - * Copyright 2017 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. */ #include #include @@ -26,7 +26,7 @@ #include "hdd.h" -uint64_t hdd_table[128][3] = { +unsigned int hdd_table[128][3] = { { 306, 4, 17 }, /* 0 - 7 */ { 615, 2, 17 }, { 306, 4, 26 }, diff --git a/src/disk/zip.c b/src/disk/zip.c index 1a7289503..c0b015265 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -9,7 +9,7 @@ * Implementation of the Iomega ZIP drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)zip.c 1.0.19 2018/03/21 + * Version: @(#)zip.c 1.0.20 2018/03/26 * * Author: Miran Grca, * @@ -48,7 +48,10 @@ #define ABRT_ERR 0x04 /* Command aborted */ #define MCR_ERR 0x08 /* Media change request */ -zip_t zip[ZIP_NUM]; +#define zipbufferb dev->buffer + + +zip_t *zip[ZIP_NUM]; zip_drive_t zip_drives[ZIP_NUM]; uint8_t atapi_zip_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; uint8_t scsi_zip_drives[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, @@ -94,7 +97,7 @@ const uint8_t zip_command_flags[0x100] = IMPLEMENTED | SCSI_ONLY, /* 0x16 */ IMPLEMENTED | SCSI_ONLY, /* 0x17 */ 0, 0, - IMPLEMENTED, + IMPLEMENTED, /* 0x1A */ IMPLEMENTED | CHECK_READY, /* 0x1B */ 0, IMPLEMENTED, /* 0x1D */ @@ -139,324 +142,335 @@ const uint8_t zip_command_flags[0x100] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -uint64_t zip_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << 0x02LL) | (1LL << 0x2FLL) | (1LL << GPMODE_ALL_PAGES); -uint64_t zip_250_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << 0x05LL) | (1LL << 0x08LL) | (1LL << 0x2FLL) | (1LL << GPMODE_ALL_PAGES); +static uint64_t zip_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | + (1LL << 0x02LL) | (1LL << 0x2FLL) | + (1LL << GPMODE_ALL_PAGES); +static uint64_t zip_250_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | + (1LL << 0x05LL) | (1LL << 0x08LL) | + (1LL << 0x2FLL) | + (1LL << GPMODE_ALL_PAGES); static const mode_sense_pages_t zip_mode_sense_pages_default = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } -} }; +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; static const mode_sense_pages_t zip_250_mode_sense_pages_default = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } -} }; +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } -} }; +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } -} }; +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; static const mode_sense_pages_t zip_mode_sense_pages_changeable = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } -} }; +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } -} }; +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; static mode_sense_pages_t zip_mode_sense_pages_saved[ZIP_NUM]; +static void zip_command_complete(uint8_t id); + +void zip_init(int id, int cdb_len_setting); +void zip_phase_callback(uint8_t id); + + #ifdef ENABLE_ZIP_LOG int zip_do_log = ENABLE_ZIP_LOG; #endif @@ -466,2100 +480,2338 @@ static void zip_log(const char *format, ...) { #ifdef ENABLE_ZIP_LOG - va_list ap; + va_list ap; - if (zip_do_log) - { - va_start(ap, format); - pclog_ex(format, ap); - va_end(ap); - } + if (zip_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } #endif } -int find_zip_for_channel(uint8_t channel) +int +find_zip_for_channel(uint8_t channel) { - uint8_t i = 0; + uint8_t i = 0; - for (i = 0; i < ZIP_NUM; i++) { - if (((zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_ONLY) || (zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) && (zip_drives[i].ide_channel == channel)) - return i; + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && (zip_drives[i].ide_channel == channel)) + return i; + } + return 0xff; +} + + +void +zip_destroy_drives(void) +{ + int i; + + for (i = 0; i < ZIP_NUM; i++) { + if (zip[i]) { + free(zip[i]); + zip[i] = NULL; } - return 0xff; + } } -void zip_init(int id, int cdb_len_setting); -int zip_load(uint8_t id, wchar_t *fn) +int +zip_load(uint8_t id, wchar_t *fn) { - int read_only = zip_drives[id].ui_writeprot; - int size = 0; + int read_only = zip_drives[id].ui_writeprot; + int size = 0; - zip_drives[id].f = plat_fopen(fn, zip_drives[id].ui_writeprot ? L"rb" : L"rb+"); - if (!zip_drives[id].ui_writeprot && !zip_drives[id].f) { - zip_drives[id].f = plat_fopen(fn, L"rb"); - read_only = 1; - } - if (zip_drives[id].f) { - fseek(zip_drives[id].f, 0, SEEK_END); - size = ftell(zip_drives[id].f); + zip_drives[id].f = plat_fopen(fn, zip_drives[id].ui_writeprot ? L"rb" : L"rb+"); + if (!zip_drives[id].ui_writeprot && !zip_drives[id].f) { + zip_drives[id].f = plat_fopen(fn, L"rb"); + read_only = 1; + } + if (zip_drives[id].f) { + fseek(zip_drives[id].f, 0, SEEK_END); + size = ftell(zip_drives[id].f); - if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { - /* This is a ZDI image. */ - size -= 0x1000; - zip_drives[id].base = 0x1000; - } else - zip_drives[id].base = 0; + if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { + /* This is a ZDI image. */ + size -= 0x1000; + zip_drives[id].base = 0x1000; + } else + zip_drives[id].base = 0; - if (zip_drives[id].is_250) { - if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); - fclose(zip_drives[id].f); - zip_drives[id].f = NULL; - zip_drives[id].medium_size = 0; - zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ - return 0; - } - } else { - if (size != (ZIP_SECTORS << 9)) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", ZIP_SECTORS << 9); - fclose(zip_drives[id].f); - zip_drives[id].f = NULL; - zip_drives[id].medium_size = 0; - zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ - return 0; - } - } - - zip_drives[id].medium_size = size >> 9; - - fseek(zip_drives[id].f, zip_drives[id].base, SEEK_SET); - - memcpy(zip_drives[id].image_path, fn, sizeof(zip_drives[id].image_path)); - - zip_drives[id].read_only = read_only; - - return 1; - } - - return 0; -} - -void zip_disk_reload(uint8_t id) -{ - int ret = 0; - - if (wcslen(zip_drives[id].prev_image_path) == 0) - return; - else - ret = zip_load(id, zip_drives[id].prev_image_path); - - if (ret) - zip[id].unit_attention = 1; -} - -void zip_close(uint8_t id) -{ - if (zip_drives[id].f) { - fclose(zip_drives[id].f); - zip_drives[id].f = NULL; - - memcpy(zip_drives[id].prev_image_path, zip_drives[id].image_path, sizeof(zip_drives[id].prev_image_path)); - memset(zip_drives[id].image_path, 0, sizeof(zip_drives[id].image_path)); - - zip_drives[id].medium_size = 0; - } -} - -void build_atapi_zip_map() -{ - uint8_t i = 0; - - memset(atapi_zip_drives, 0xff, 8); - - for (i = 0; i < 8; i++) { - atapi_zip_drives[i] = find_zip_for_channel(i); - if (atapi_zip_drives[i] != 0xff) - zip_init(atapi_zip_drives[i], 12); - } -} - -int find_zip_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) -{ - uint8_t i = 0; - - for (i = 0; i < ZIP_NUM; i++) { - if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && (zip_drives[i].scsi_device_id == scsi_id) && (zip_drives[i].scsi_device_lun == scsi_lun)) - return i; - } - return 0xff; -} - -void build_scsi_zip_map() -{ - uint8_t i = 0; - uint8_t j = 0; - - for (i = 0; i < 16; i++) - memset(scsi_zip_drives[i], 0xff, 8); - - for (i = 0; i < 16; i++) { - for (j = 0; j < 8; j++) { - scsi_zip_drives[i][j] = find_zip_for_scsi_id(i, j); - if (scsi_zip_drives[i][j] != 0xff) - zip_init(scsi_zip_drives[i][j], 12); - } - } -} - -void zip_set_callback(uint8_t id) -{ - if (zip_drives[id].bus_type != ZIP_BUS_SCSI) - ide_set_callback(zip_drives[id].ide_channel, zip[id].callback); -} - -void zip_set_cdb_len(int id, int cdb_len) -{ - zip[id].cdb_len = cdb_len; -} - -void zip_reset_cdb_len(int id) -{ - zip[id].cdb_len = zip[id].cdb_len_setting ? 16 : 12; -} - -void zip_set_signature(int id) -{ - if (id >= ZIP_NUM) - return; - zip[id].phase = 1; - zip[id].request_length = 0xEB14; -} - -void zip_init(int id, int cdb_len_setting) -{ - if (id >= ZIP_NUM) - return; - memset(&(zip[id]), 0, sizeof(zip_t)); - zip[id].requested_blocks = 1; - if (cdb_len_setting <= 1) - zip[id].cdb_len_setting = cdb_len_setting; - zip_reset_cdb_len(id); - zip[id].sense[0] = 0xf0; - zip[id].sense[7] = 10; - zip_drives[id].bus_mode = 0; - if (zip_drives[id].bus_type >= ZIP_BUS_ATAPI_PIO_AND_DMA) - zip_drives[id].bus_mode |= 2; - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) - zip_drives[id].bus_mode |= 1; - zip_log("ZIP %i: Bus type %i, bus mode %i\n", id, zip_drives[id].bus_type, zip_drives[id].bus_mode); - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) - zip_set_signature(id); - zip[id].status = READY_STAT | DSC_STAT; - zip[id].pos = 0; - zip[id].packet_status = 0xff; - zip_sense_key = zip_asc = zip_ascq = zip[id].unit_attention = 0; - zip[id].cdb_len_setting = 0; - zip[id].cdb_len = 12; -} - -int zip_supports_pio(int id) -{ - return (zip_drives[id].bus_mode & 1); -} - -int zip_supports_dma(int id) -{ - return (zip_drives[id].bus_mode & 2); -} - -/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ -int zip_current_mode(int id) -{ - if (!zip_supports_pio(id) && !zip_supports_dma(id)) - return 0; - if (zip_supports_pio(id) && !zip_supports_dma(id)) { - zip_log("ZIP %i: Drive does not support DMA, setting to PIO\n", id); - return 1; - } - if (!zip_supports_pio(id) && zip_supports_dma(id)) - return 2; - if (zip_supports_pio(id) && zip_supports_dma(id)) { - zip_log("ZIP %i: Drive supports both, setting to %s\n", id, (zip[id].features & 1) ? "DMA" : "PIO", id); - return (zip[id].features & 1) ? 2 : 1; - } - - return 0; -} - -/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int zip_ZIP_PHASE_to_scsi(uint8_t id) -{ - if (zip[id].status & ERR_STAT) - return SCSI_STATUS_CHECK_CONDITION; - else - return SCSI_STATUS_OK; -} - -/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ -int zip_atapi_phase_to_scsi(uint8_t id) -{ - if (zip[id].status & 8) { - switch (zip[id].phase & 3) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 1; - case 3: - return 7; + if (zip_drives[id].is_250) { + if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", + ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + zip_drives[id].medium_size = 0; + zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; } } else { - if ((zip[id].phase & 3) == 3) - return 3; - else - return 4; - } - - return 0; -} - -int zip_lba_to_msf_accurate(int lba) -{ - int temp_pos; - int m, s, f; - - temp_pos = lba + 150; - f = temp_pos % 75; - temp_pos -= f; - temp_pos /= 75; - s = temp_pos % 60; - temp_pos -= s; - temp_pos /= 60; - m = temp_pos; - - return ((m << 16) | (s << 8) | f); -} - -void zip_mode_sense_load(uint8_t id) -{ - FILE *f; - wchar_t file_name[512]; - int i; - memset(&zip_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); - for (i = 0; i < 0x3f; i++) { - if (zip_drives[id].is_250) { - if (zip_250_mode_sense_pages_default.pages[i][1] != 0) { - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default_scsi.pages[i], zip_250_mode_sense_pages_default_scsi.pages[i][1] + 2); - else - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default.pages[i], zip_250_mode_sense_pages_default.pages[i][1] + 2); - } - } else { - if (zip_mode_sense_pages_default.pages[i][1] != 0) { - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default_scsi.pages[i], zip_mode_sense_pages_default_scsi.pages[i][1] + 2); - else - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default.pages[i], zip_mode_sense_pages_default.pages[i][1] + 2); - } + if (size != (ZIP_SECTORS << 9)) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", + ZIP_SECTORS << 9); + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + zip_drives[id].medium_size = 0; + zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; } } - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); - else - swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); - f = plat_fopen(nvr_path(file_name), L"rb"); - if (f) - fclose(f); -} -void zip_mode_sense_save(uint8_t id) -{ - FILE *f; - wchar_t file_name[512]; - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); - else - swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); - f = plat_fopen(nvr_path(file_name), L"wb"); - if (f) - fclose(f); -} + zip_drives[id].medium_size = size >> 9; -static void zip_command_complete(uint8_t id); + fseek(zip_drives[id].f, zip_drives[id].base, SEEK_SET); -uint8_t zip_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + memcpy(zip_drives[id].image_path, fn, sizeof(zip_drives[id].image_path)); -int zip_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - int size = 0; - - if (zip_drives[id].is_250) - size = zip_drives[id].medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ - else - size = ZIP_SECTORS - 1; /* IMPORTANT: What's returned is the last LBA block. */ - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 2; /* 512 = 0x0200 */ - *len = 8; + zip_drives[id].read_only = read_only; return 1; + } + + return 0; } + +void +zip_disk_reload(uint8_t id) +{ + zip_t *dev = zip[id]; + int ret = 0; + + if (wcslen(zip_drives[id].prev_image_path) == 0) + return; + else + ret = zip_load(id, zip_drives[id].prev_image_path); + + if (ret) + dev->unit_attention = 1; +} + + +void +zip_close(uint8_t id) +{ + if (zip_drives[id].f) { + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + + memcpy(zip_drives[id].prev_image_path, zip_drives[id].image_path, sizeof(zip_drives[id].prev_image_path)); + memset(zip_drives[id].image_path, 0, sizeof(zip_drives[id].image_path)); + + zip_drives[id].medium_size = 0; + } +} + + +void +build_atapi_zip_map() +{ + uint8_t i = 0; + + memset(atapi_zip_drives, 0xff, 8); + + for (i = 0; i < 8; i++) { + atapi_zip_drives[i] = find_zip_for_channel(i); + if (atapi_zip_drives[i] != 0xff) + zip_init(atapi_zip_drives[i], 12); + } +} + + +int +find_zip_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t i = 0; + + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && (zip_drives[i].scsi_device_id == scsi_id) && (zip_drives[i].scsi_device_lun == scsi_lun)) + return i; + } + return 0xff; +} + + +void +build_scsi_zip_map() +{ + uint8_t i = 0; + uint8_t j = 0; + + for (i = 0; i < 16; i++) + memset(scsi_zip_drives[i], 0xff, 8); + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) { + scsi_zip_drives[i][j] = find_zip_for_scsi_id(i, j); + if (scsi_zip_drives[i][j] != 0xff) + zip_init(scsi_zip_drives[i][j], 12); + } + } +} + + +static void +zip_set_callback(uint8_t id) +{ + zip_t *dev = zip[id]; + + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) + ide_set_callback(zip_drives[id].ide_channel >> 1, dev->callback); +} + + +static void +zip_reset_cdb_len(int id) +{ + zip_t *dev = zip[id]; + + dev->cdb_len = dev->cdb_len_setting ? 16 : 12; +} + + +void +zip_set_signature(int id) +{ + zip_t *dev = zip[id]; + + if (id >= ZIP_NUM) + return; + dev->phase = 1; + dev->request_length = 0xEB14; +} + + +void +zip_init(int id, int cdb_len_setting) +{ + zip_t *dev = zip[id]; + + if (id >= ZIP_NUM) + return; + + memset(dev, 0, sizeof(zip_t)); + dev->requested_blocks = 1; + if (cdb_len_setting <= 1) + dev->cdb_len_setting = cdb_len_setting; + zip_reset_cdb_len(id); + dev->sense[0] = 0xf0; + dev->sense[7] = 10; + zip_drives[id].bus_mode = 0; + if (zip_drives[id].bus_type >= ZIP_BUS_ATAPI) + zip_drives[id].bus_mode |= 2; + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + zip_drives[id].bus_mode |= 1; + zip_log("ZIP %i: Bus type %i, bus mode %i\n", id, zip_drives[id].bus_type, zip_drives[id].bus_mode); + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + zip_set_signature(id); + dev->status = READY_STAT | DSC_STAT; + dev->pos = 0; + dev->packet_status = 0xff; + zip_sense_key = zip_asc = zip_ascq = dev->unit_attention = 0; + dev->cdb_len_setting = 0; + dev->cdb_len = 12; +} + + +static int +zip_supports_pio(int id) +{ + return (zip_drives[id].bus_mode & 1); +} + + +static int +zip_supports_dma(int id) +{ + return (zip_drives[id].bus_mode & 2); +} + + +/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ +static int +zip_current_mode(int id) +{ + zip_t *dev = zip[id]; + + if (!zip_supports_pio(id) && !zip_supports_dma(id)) + return 0; + if (zip_supports_pio(id) && !zip_supports_dma(id)) { + zip_log("ZIP %i: Drive does not support DMA, setting to PIO\n", id); + return 1; + } + if (!zip_supports_pio(id) && zip_supports_dma(id)) + return 2; + if (zip_supports_pio(id) && zip_supports_dma(id)) { + zip_log("ZIP %i: Drive supports both, setting to %s\n", id, (dev->features & 1) ? "DMA" : "PIO", id); + return (dev->features & 1) ? 2 : 1; + } + + return 0; +} + + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int +zip_ZIP_PHASE_to_scsi(uint8_t id) +{ + zip_t *dev = zip[id]; + + if (dev->status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; +} + + +/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ +int +zip_atapi_phase_to_scsi(uint8_t id) +{ + zip_t *dev = zip[id]; + + if (dev->status & 8) { + switch (dev->phase & 3) { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + case 3: + return 7; + } + } else { + if ((dev->phase & 3) == 3) + return 3; + else + return 4; + } + + return 0; +} + + +static void +zip_mode_sense_load(uint8_t id) +{ + FILE *f; + wchar_t file_name[512]; + int i; + + memset(&zip_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (zip_drives[id].is_250) { + if (zip_250_mode_sense_pages_default.pages[i][1] != 0) { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default_scsi.pages[i], zip_250_mode_sense_pages_default_scsi.pages[i][1] + 2); + else + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default.pages[i], zip_250_mode_sense_pages_default.pages[i][1] + 2); + } + } else { + if (zip_mode_sense_pages_default.pages[i][1] != 0) { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default_scsi.pages[i], zip_mode_sense_pages_default_scsi.pages[i][1] + 2); + else + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default.pages[i], zip_mode_sense_pages_default.pages[i][1] + 2); + } + } + } + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); + else + swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) + fclose(f); +} + + +static void +zip_mode_sense_save(uint8_t id) +{ + FILE *f; + wchar_t file_name[512]; + + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); + else + swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) + fclose(f); +} + + +int +zip_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int size = 0; + + if (zip_drives[id].is_250) + size = zip_drives[id].medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ + else + size = ZIP_SECTORS - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 2; /* 512 = 0x0200 */ + *len = 8; + + return 1; +} + + /*SCSI Mode Sense 6/10*/ -uint8_t zip_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) +static uint8_t +zip_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) { - switch (page_control) { - case 0: - case 3: - if (zip_drives[id].is_250 && (page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) - return 0x60; - return zip_mode_sense_pages_saved[id].pages[page][pos]; - break; - case 1: - if (zip_drives[id].is_250) - return zip_250_mode_sense_pages_changeable.pages[page][pos]; - else - return zip_mode_sense_pages_changeable.pages[page][pos]; - break; - case 2: - if (zip_drives[id].is_250) { - if ((page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) - return 0x60; - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - return zip_250_mode_sense_pages_default_scsi.pages[page][pos]; - else - return zip_250_mode_sense_pages_default.pages[page][pos]; - } else { - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - return zip_mode_sense_pages_default_scsi.pages[page][pos]; - else - return zip_mode_sense_pages_default.pages[page][pos]; - } - break; - } - - return 0; -} - -uint32_t zip_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) -{ - uint64_t page_flags; - uint8_t page_control = (type >> 6) & 3; - - if (zip_drives[id].is_250) - page_flags = zip_250_mode_sense_page_flags; - else - page_flags = zip_mode_sense_page_flags; - - int i = 0; - int j = 0; - - uint8_t msplen; - - type &= 0x3f; - - if (block_descriptor_len) { + switch (page_control) { + case 0: + case 3: + if (zip_drives[id].is_250 && (page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) + return 0x60; + return zip_mode_sense_pages_saved[id].pages[page][pos]; + break; + case 1: + if (zip_drives[id].is_250) + return zip_250_mode_sense_pages_changeable.pages[page][pos]; + else + return zip_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: if (zip_drives[id].is_250) { - buf[pos++] = ((zip_drives[id].medium_size >> 24) & 0xff); - buf[pos++] = ((zip_drives[id].medium_size >> 16) & 0xff); - buf[pos++] = ((zip_drives[id].medium_size >> 8) & 0xff); - buf[pos++] = ( zip_drives[id].medium_size & 0xff); + if ((page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) + return 0x60; + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + return zip_250_mode_sense_pages_default_scsi.pages[page][pos]; + else + return zip_250_mode_sense_pages_default.pages[page][pos]; } else { - buf[pos++] = ((ZIP_SECTORS >> 24) & 0xff); - buf[pos++] = ((ZIP_SECTORS >> 16) & 0xff); - buf[pos++] = ((ZIP_SECTORS >> 8) & 0xff); - buf[pos++] = ( ZIP_SECTORS & 0xff); + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + return zip_mode_sense_pages_default_scsi.pages[page][pos]; + else + return zip_mode_sense_pages_default.pages[page][pos]; } - buf[pos++] = 0; /* Reserved. */ - buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ - buf[pos++] = 2; - buf[pos++] = 0; - } + break; + } - for (i = 0; i < 0x40; i++) { - if ((type == GPMODE_ALL_PAGES) || (type == i)) { - if (page_flags & (1LL << zip[id].current_page_code)) { - buf[pos++] = zip_mode_sense_read(id, page_control, i, 0); - msplen = zip_mode_sense_read(id, page_control, i, 1); - buf[pos++] = msplen; - zip_log("ZIP %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); - for (j = 0; j < msplen; j++) - buf[pos++] = zip_mode_sense_read(id, page_control, i, 2 + j); + return 0; +} + + +static uint32_t +zip_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +{ + zip_t *dev = zip[id]; + + uint64_t page_flags; + uint8_t page_control = (type >> 6) & 3; + + if (zip_drives[id].is_250) + page_flags = zip_250_mode_sense_page_flags; + else + page_flags = zip_mode_sense_page_flags; + + int i = 0; + int j = 0; + + uint8_t msplen; + + type &= 0x3f; + + if (block_descriptor_len) { + if (zip_drives[id].is_250) { + buf[pos++] = ((zip_drives[id].medium_size >> 24) & 0xff); + buf[pos++] = ((zip_drives[id].medium_size >> 16) & 0xff); + buf[pos++] = ((zip_drives[id].medium_size >> 8) & 0xff); + buf[pos++] = ( zip_drives[id].medium_size & 0xff); + } else { + buf[pos++] = ((ZIP_SECTORS >> 24) & 0xff); + buf[pos++] = ((ZIP_SECTORS >> 16) & 0xff); + buf[pos++] = ((ZIP_SECTORS >> 8) & 0xff); + buf[pos++] = ( ZIP_SECTORS & 0xff); + } + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ + buf[pos++] = 2; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (page_flags & (1LL << dev->current_page_code)) { + buf[pos++] = zip_mode_sense_read(id, page_control, i, 0); + msplen = zip_mode_sense_read(id, page_control, i, 1); + buf[pos++] = msplen; + zip_log("ZIP %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); + for (j = 0; j < msplen; j++) + buf[pos++] = zip_mode_sense_read(id, page_control, i, 2 + j); + } + } + } + + return pos; +} + + +static void +zip_update_request_length(uint8_t id, int len, int block_len) +{ + zip_t *dev = zip[id]; + uint32_t bt, min_len = 0; + + dev->max_transfer_len = dev->request_length; + + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (dev->current_cdb[0]) { + case 0x08: + case 0x28: + case 0xa8: + /* Make sure total length is not bigger than sum of the lengths of + all the requested blocks. */ + bt = (dev->requested_blocks * block_len); + if (len > bt) + len = bt; + + min_len = block_len; + + if (len <= block_len) { + /* Total length is less or equal to block length. */ + if (dev->max_transfer_len < block_len) { + /* Transfer a minimum of (block size) bytes. */ + dev->max_transfer_len = block_len; + dev->packet_len = block_len; + break; } } - } + default: + dev->packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) + dev->max_transfer_len &= 0xfffe; + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (!dev->max_transfer_len) + dev->max_transfer_len = 65534; - return pos; + if ((len <= dev->max_transfer_len) && (len >= min_len)) + dev->request_length = dev->max_transfer_len = len; + + return; } -void zip_update_request_length(uint8_t id, int len, int block_len) -{ - uint32_t bt; - if (!zip[id].request_length) - zip[id].max_transfer_len = 65534; - else - zip[id].max_transfer_len = zip[id].request_length; - /* For media access commands, make sure the requested DRQ length matches the block length. */ - switch (zip[id].current_cdb[0]) { - case 0x08: - case 0x28: - case 0xa8: - if (zip[id].max_transfer_len < block_len) - zip[id].max_transfer_len = block_len; - bt = (zip[id].requested_blocks * block_len); - if (len > bt) - len = bt; - default: - zip[id].packet_len = len; - break; - } - /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ - if ((zip[id].max_transfer_len & 1) && (zip[id].max_transfer_len < len)) - zip[id].max_transfer_len &= 0xfffe; - /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ - if (len <= zip[id].max_transfer_len) - zip[id].max_transfer_len = len; - return; +static void +zip_command_bus(uint8_t id) +{ + zip_t *dev = zip[id]; + + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + dev->callback = 1LL * ZIP_TIME; + zip_set_callback(id); } -static void zip_command_common(uint8_t id) -{ - double bytes_per_second, period; - double dusec; - zip[id].status = BUSY_STAT; - zip[id].phase = 1; - zip[id].pos = 0; - if (zip[id].packet_status == ZIP_PHASE_COMPLETE) { - zip_phase_callback(id); - zip[id].callback = 0LL; +static void +zip_command_common(uint8_t id) +{ + zip_t *dev = zip[id]; + + double bytes_per_second, period; + double dusec; + + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + if (dev->packet_status == ZIP_PHASE_COMPLETE) { + zip_phase_callback(id); + dev->callback = 0LL; + } else { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + dev->callback = -1LL; /* Speed depends on SCSI controller */ + return; } else { - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - zip[id].callback = -1LL; /* Speed depends on SCSI controller */ - return; - } else if (zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA) { - if (zip_current_mode(id) == 2) - bytes_per_second = 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ - else - bytes_per_second = 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ - } else - bytes_per_second = 3333333.333333333333333; /* 3.3 MB/s PIO-0 speed */ - - period = 1000000.0 / bytes_per_second; - dusec = (double) TIMER_USEC; - dusec = dusec * period * (double) (zip[id].packet_len); - zip[id].callback = ((int64_t) dusec); + if (zip_current_mode(id) == 2) + bytes_per_second = 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ + else + bytes_per_second = 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ } - zip_set_callback(id); + period = 1000000.0 / bytes_per_second; + dusec = (double) TIMER_USEC; + dusec = dusec * period * (double) (dev->packet_len); + dev->callback = ((int64_t) dusec); + } + + zip_set_callback(id); } -static void zip_command_complete(uint8_t id) + +static void +zip_command_complete(uint8_t id) { - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip_command_common(id); + zip_t *dev = zip[id]; + + dev->packet_status = ZIP_PHASE_COMPLETE; + zip_command_common(id); } -static void zip_command_read(uint8_t id) + +static void +zip_command_read(uint8_t id) { - zip[id].packet_status = ZIP_PHASE_DATA_IN; - zip_command_common(id); - zip[id].total_read = 0; + zip_t *dev = zip[id]; + + dev->packet_status = ZIP_PHASE_DATA_IN; + zip_command_common(id); + dev->total_read = 0; } -static void zip_command_read_dma(uint8_t id) + +static void +zip_command_read_dma(uint8_t id) { - zip[id].packet_status = ZIP_PHASE_DATA_IN_DMA; - zip_command_common(id); - zip[id].total_read = 0; + zip_t *dev = zip[id]; + + dev->packet_status = ZIP_PHASE_DATA_IN_DMA; + zip_command_common(id); + dev->total_read = 0; } -static void zip_command_write(uint8_t id) +static void +zip_command_write(uint8_t id) { - zip[id].packet_status = ZIP_PHASE_DATA_OUT; - zip_command_common(id); + zip_t *dev = zip[id]; + + dev->packet_status = ZIP_PHASE_DATA_OUT; + zip_command_common(id); } -static void zip_command_write_dma(uint8_t id) + +static void +zip_command_write_dma(uint8_t id) { - zip[id].packet_status = ZIP_PHASE_DATA_OUT_DMA; - zip_command_common(id); + zip_t *dev = zip[id]; + + dev->packet_status = ZIP_PHASE_DATA_OUT_DMA; + zip_command_common(id); } + /* id = Current ZIP device ID; len = Total transfer length; block_len = Length of a single block (why does it matter?!); alloc_len = Allocated transfer length; direction = Transfer direction (0 = read from host, 1 = write to host). */ -static void zip_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +static void +zip_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) { - zip_log("ZIP %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, zip[id].current_cdb[0], len, block_len, alloc_len, direction, zip[id].request_length); - zip[id].pos=0; - if (alloc_len >= 0) { - if (alloc_len < len) { - len = alloc_len; - } - } - if ((len == 0) || (zip_current_mode(id) == 0)) { - if (zip_drives[id].bus_type != ZIP_BUS_SCSI) { - zip[id].packet_len = 0; - } - zip_command_complete(id); - } - else { - if (zip_current_mode(id) == 2) { - if (zip_drives[id].bus_type != ZIP_BUS_SCSI) { - zip[id].packet_len = alloc_len; - } - - if (direction == 0) - zip_command_read_dma(id); - else - zip_command_write_dma(id); - } - else { - zip_update_request_length(id, len, block_len); - if (direction == 0) - zip_command_read(id); - else - zip_command_write(id); - } - } - - zip_log("ZIP %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", id, zip[id].packet_status, zip[id].request_length, zip[id].packet_len, zip[id].pos, zip[id].phase); -} - -static void zip_sense_clear(int id, int command) -{ - zip[id].previous_command = command; - zip_sense_key = zip_asc = zip_ascq = 0; -} - -static void zip_set_phase(uint8_t id, uint8_t phase) -{ - uint8_t scsi_id = zip_drives[id].scsi_device_id; - uint8_t scsi_lun = zip_drives[id].scsi_device_lun; + zip_t *dev = zip[id]; + zip_log("ZIP %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); + dev->pos=0; + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if ((len == 0) || (zip_current_mode(id) == 0)) { if (zip_drives[id].bus_type != ZIP_BUS_SCSI) - return; + dev->packet_len = 0; - SCSIDevices[scsi_id][scsi_lun].Phase = phase; -} + zip_command_complete(id); + } else { + if (zip_current_mode(id) == 2) { + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) + dev->packet_len = alloc_len; -static void zip_cmd_error(uint8_t id) -{ - zip_set_phase(id, SCSI_PHASE_STATUS); - zip[id].error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR; - if (zip[id].unit_attention) - zip[id].error |= MCR_ERR; - zip[id].status = READY_STAT | ERR_STAT; - zip[id].phase = 3; - zip[id].pos = 0; - zip[id].packet_status = 0x80; - zip[id].callback = 50LL * ZIP_TIME; - zip_set_callback(id); - zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", id, zip[id].current_cdb[0], zip_sense_key, zip_asc, zip_ascq); -} - -static void zip_unit_attention(uint8_t id) -{ - zip_set_phase(id, SCSI_PHASE_STATUS); - zip[id].error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; - if (zip[id].unit_attention) - zip[id].error |= MCR_ERR; - zip[id].status = READY_STAT | ERR_STAT; - zip[id].phase = 3; - zip[id].pos = 0; - zip[id].packet_status = 0x80; - zip[id].callback = 50LL * ZIP_TIME; - zip_set_callback(id); - zip_log("ZIP %i: UNIT ATTENTION\n", id); -} - -static void zip_not_ready(uint8_t id) -{ - zip_sense_key = SENSE_NOT_READY; - zip_asc = ASC_MEDIUM_NOT_PRESENT; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_write_protected(uint8_t id) -{ - zip_sense_key = SENSE_UNIT_ATTENTION; - zip_asc = ASC_WRITE_PROTECTED; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_invalid_lun(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_INV_LUN; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_illegal_opcode(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_ILLEGAL_OPCODE; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_lba_out_of_range(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_LBA_OUT_OF_RANGE; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_invalid_field(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_INV_FIELD_IN_CMD_PACKET; - zip_ascq = 0; - zip_cmd_error(id); - zip[id].status = 0x53; -} - -static void zip_invalid_field_pl(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; - zip_ascq = 0; - zip_cmd_error(id); - zip[id].status = 0x53; -} - -static void zip_data_phase_error(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_DATA_PHASE_ERROR; - zip_ascq = 0; - zip_cmd_error(id); -} - -#define zipbufferb zip[id].buffer - -int zip_blocks(uint8_t id, uint32_t *len, int first_batch, int out) -{ - zip[id].data_pos = 0; - - *len = 0; - - if (!zip[id].sector_len) { - zip_command_complete(id); - return -1; + if (direction == 0) + zip_command_read_dma(id); + else + zip_command_write_dma(id); + } else { + zip_update_request_length(id, len, block_len); + if (direction == 0) + zip_command_read(id); + else + zip_command_write(id); } + } - zip_log("%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", zip[id].requested_blocks, zip[id].sector_pos); - - if (zip[id].sector_pos >= zip_drives[id].medium_size) { - zip_log("ZIP %i: Trying to %s beyond the end of disk\n", id, out ? "write" : "read"); - zip_lba_out_of_range(id); - return 0; - } - - *len = zip[id].requested_blocks << 9; - - fseek(zip_drives[id].f, zip_drives[id].base + (zip[id].sector_pos << 9), SEEK_SET); - if (out) - fwrite(zipbufferb, 1, *len, zip_drives[id].f); - else - fread(zipbufferb, 1, *len, zip_drives[id].f); - - zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); - - zip[id].sector_pos += zip[id].requested_blocks; - zip[id].sector_len -= zip[id].requested_blocks; - - return 1; + zip_log("ZIP %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", + id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); } -void zip_insert(uint8_t id) + +static void +zip_sense_clear(int id, int command) { - zip[id].unit_attention = 1; + zip_t *dev = zip[id]; + + dev->previous_command = command; + zip_sense_key = zip_asc = zip_ascq = 0; } + +static void +zip_set_phase(uint8_t id, uint8_t phase) +{ + uint8_t scsi_id = zip_drives[id].scsi_device_id; + uint8_t scsi_lun = zip_drives[id].scsi_device_lun; + + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) + return; + + SCSIDevices[scsi_id][scsi_lun].Phase = phase; +} + + +static void +zip_cmd_error(uint8_t id) +{ + zip_t *dev = zip[id]; + + zip_set_phase(id, SCSI_PHASE_STATUS); + dev->error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * ZIP_TIME; + zip_set_callback(id); + zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", id, dev->current_cdb[0], zip_sense_key, zip_asc, zip_ascq); +} + + +static void +zip_unit_attention(uint8_t id) +{ + zip_t *dev = zip[id]; + + zip_set_phase(id, SCSI_PHASE_STATUS); + dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * ZIP_TIME; + zip_set_callback(id); + zip_log("ZIP %i: UNIT ATTENTION\n", id); +} + + +static void +zip_bus_master_error(uint8_t id) +{ + zip_sense_key = zip_asc = zip_ascq = 0; + zip_cmd_error(id); +} + + +static void +zip_not_ready(uint8_t id) +{ + zip_sense_key = SENSE_NOT_READY; + zip_asc = ASC_MEDIUM_NOT_PRESENT; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static void +zip_write_protected(uint8_t id) +{ + zip_sense_key = SENSE_UNIT_ATTENTION; + zip_asc = ASC_WRITE_PROTECTED; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static void +zip_invalid_lun(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_LUN; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static void +zip_illegal_opcode(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_ILLEGAL_OPCODE; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static void +zip_lba_out_of_range(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_LBA_OUT_OF_RANGE; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static void +zip_invalid_field(uint8_t id) +{ + zip_t *dev = zip[id]; + + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_FIELD_IN_CMD_PACKET; + zip_ascq = 0; + zip_cmd_error(id); + dev->status = 0x53; +} + + +static void +zip_invalid_field_pl(uint8_t id) +{ + zip_t *dev = zip[id]; + + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + zip_ascq = 0; + zip_cmd_error(id); + dev->status = 0x53; +} + + +static void +zip_data_phase_error(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_DATA_PHASE_ERROR; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static int +zip_blocks(uint8_t id, uint32_t *len, int first_batch, int out) +{ + zip_t *dev = zip[id]; + + dev->data_pos = 0; + + *len = 0; + + if (!dev->sector_len) { + zip_command_complete(id); + return -1; + } + + zip_log("%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); + + if (dev->sector_pos >= zip_drives[id].medium_size) { + zip_log("ZIP %i: Trying to %s beyond the end of disk\n", id, out ? "write" : "read"); + zip_lba_out_of_range(id); + return 0; + } + + *len = dev->requested_blocks << 9; + + fseek(zip_drives[id].f, zip_drives[id].base + (dev->sector_pos << 9), SEEK_SET); + if (out) + fwrite(zipbufferb, 1, *len, zip_drives[id].f); + else + fread(zipbufferb, 1, *len, zip_drives[id].f); + + zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); + + dev->sector_pos += dev->requested_blocks; + dev->sector_len -= dev->requested_blocks; + + return 1; +} + + +void +zip_insert(uint8_t id) +{ + zip_t *dev = zip[id]; + + dev->unit_attention = 1; +} + + /*SCSI Sense Initialization*/ -void zip_sense_code_ok(uint8_t id) +void +zip_sense_code_ok(uint8_t id) { - zip_sense_key = SENSE_NONE; - zip_asc = 0; - zip_ascq = 0; + zip_sense_key = SENSE_NONE; + zip_asc = 0; + zip_ascq = 0; } -int zip_pre_execution_check(uint8_t id, uint8_t *cdb) + +static int +zip_pre_execution_check(uint8_t id, uint8_t *cdb) { - int ready = 0; + zip_t *dev = zip[id]; + int ready = 0; - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - if (((zip[id].request_length >> 5) & 7) != zip_drives[id].scsi_device_lun) { - zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((zip[id].request_length >> 5) & 7)); - zip_invalid_lun(id); - return 0; - } - } - - if (!(zip_command_flags[cdb[0]] & IMPLEMENTED)) { - zip_log("ZIP %i: Attempting to execute unknown command %02X over %s\n", id, cdb[0], (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? "SCSI" : ((zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA) ? "ATAPI PIO/DMA" : "ATAPI PIO")); - - zip_illegal_opcode(id); + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + if (((dev->request_length >> 5) & 7) != zip_drives[id].scsi_device_lun) { + zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((dev->request_length >> 5) & 7)); + zip_invalid_lun(id); return 0; } + } - if ((zip_drives[id].bus_type < ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & SCSI_ONLY)) { - zip_log("ZIP %i: Attempting to execute SCSI-only command %02X over ATAPI\n", id, cdb[0]); - zip_illegal_opcode(id); + if (!(zip_command_flags[cdb[0]] & IMPLEMENTED)) { + zip_log("ZIP %i: Attempting to execute unknown command %02X over %s\n", id, cdb[0], + (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? "SCSI" : "ATAPI"); + + zip_illegal_opcode(id); + return 0; + } + + if ((zip_drives[id].bus_type < ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & SCSI_ONLY)) { + zip_log("ZIP %i: Attempting to execute SCSI-only command %02X over ATAPI\n", id, cdb[0]); + zip_illegal_opcode(id); + return 0; + } + + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & ATAPI_ONLY)) { + zip_log("ZIP %i: Attempting to execute ATAPI-only command %02X over SCSI\n", id, cdb[0]); + zip_illegal_opcode(id); + return 0; + } + + ready = (zip_drives[id].f != NULL); + + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + if (!ready && dev->unit_attention) + dev->unit_attention = 0; + + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (dev->unit_attention == 1) { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(zip_command_flags[cdb[0]] & ALLOW_UA)) { + /* zip_log("ZIP %i: Unit attention now 2\n", id); */ + dev->unit_attention = 2; + zip_log("ZIP %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); + zip_unit_attention(id); return 0; } - - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & ATAPI_ONLY)) { - zip_log("ZIP %i: Attempting to execute ATAPI-only command %02X over SCSI\n", id, cdb[0]); - zip_illegal_opcode(id); - return 0; + } else if (dev->unit_attention == 2) { + if (cdb[0] != GPCMD_REQUEST_SENSE) { + /* zip_log("ZIP %i: Unit attention now 0\n", id); */ + dev->unit_attention = 0; } + } - ready = (zip_drives[id].f != NULL); + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + zip_sense_clear(id, cdb[0]); + /* Next it's time for NOT READY. */ + if (!ready) + dev->media_status = MEC_MEDIA_REMOVAL; + else + dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; + + if ((zip_command_flags[cdb[0]] & CHECK_READY) && !ready) { + zip_log("ZIP %i: Not ready (%02X)\n", id, cdb[0]); + zip_not_ready(id); + return 0; + } + + zip_log("ZIP %i: Continuing with command %02X\n", id, cdb[0]); + + return 1; +} + + +static void +zip_seek(uint8_t id, uint32_t pos) +{ + zip_t *dev = zip[id]; + + /* zip_log("ZIP %i: Seek %08X\n", id, pos); */ + dev->sector_pos = pos; +} + + +static void +zip_rezero(uint8_t id) +{ + zip_t *dev = zip[id]; + + dev->sector_pos = dev->sector_len = 0; + zip_seek(id, 0); +} + + +void +zip_reset(uint8_t id) +{ + zip_t *dev = zip[id]; + + zip_rezero(id); + dev->status = 0; + dev->callback = 0LL; + zip_set_callback(id); + dev->packet_status = 0xff; + dev->unit_attention = 0; +} + + +static void +zip_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) +{ + zip_t *dev = zip[id]; + + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + if (!desc) + memcpy(buffer, dev->sense, alloc_length); + else { + buffer[1] = zip_sense_key; + buffer[2] = zip_asc; + buffer[3] = zip_ascq; + } + } + + buffer[0] = desc ? 0x72 : 0x70; + + if (dev->unit_attention && (zip_sense_key == 0)) { + buffer[desc ? 1 : 2]=SENSE_UNIT_ATTENTION; + buffer[desc ? 2 : 12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[desc ? 3 : 13]=0; + } + + zip_log("ZIP %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); + + if (buffer[desc ? 1 : 2] == SENSE_UNIT_ATTENTION) { + /* If the last remaining sense is unit attention, clear + that condition. */ + dev->unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + zip_sense_clear(id, GPCMD_REQUEST_SENSE); +} + + +void +zip_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) +{ + zip_t *dev = zip[id]; + int ready = 0; + + ready = (zip_drives[id].f != NULL); + + if (!ready && dev->unit_attention) { /* If the drive is not ready, there is no reason to keep the UNIT ATTENTION condition present, as we only use it to mark disc changes. */ - if (!ready && zip[id].unit_attention) - zip[id].unit_attention = 0; + dev->unit_attention = 0; + } - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ - if (zip[id].unit_attention == 1) { - /* Only increment the unit attention phase if the command can not pass through it. */ - if (!(zip_command_flags[cdb[0]] & ALLOW_UA)) { - /* zip_log("ZIP %i: Unit attention now 2\n", id); */ - zip[id].unit_attention = 2; - zip_log("ZIP %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); - zip_unit_attention(id); - return 0; + /* Do *NOT* advance the unit attention phase. */ + + zip_request_sense(id, buffer, alloc_length, 0); +} + + +static void +zip_set_buf_len(uint8_t id, int32_t *BufLen, uint32_t *src_len) +{ + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + zip_log("ZIP %i: Actual transfer length: %i\n", id, *BufLen); + } +} + + +static void +zip_buf_alloc(uint8_t id, uint32_t len) +{ + zip_t *dev = zip[id]; + + zip_log("ZIP %i: Allocated buffer length: %i\n", id, len); + zipbufferb = (uint8_t *) malloc(len); +} + + +static void +zip_buf_free(uint8_t id) +{ + zip_t *dev = zip[id]; + + if (zipbufferb) { + zip_log("ZIP %i: Freeing buffer...\n", id); + free(zipbufferb); + zipbufferb = NULL; + } +} + + +void +zip_command(uint8_t id, uint8_t *cdb) +{ + int pos = 0, block_desc = 0; + int ret; + uint32_t len, max_len; + uint32_t alloc_length, i = 0; + unsigned size_idx, idx = 0; + unsigned preamble_len; + int32_t blen = 0; + int32_t *BufLen; + + zip_t *dev = zip[id]; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; + dev->status &= ~ERR_STAT; + } else { + BufLen = &blen; + dev->error = 0; + } + + dev->packet_len = 0; + dev->request_pos = 0; + + dev->data_pos = 0; + + memcpy(dev->current_cdb, cdb, dev->cdb_len); + + if (cdb[0] != 0) { + zip_log("ZIP %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", id, cdb[0], zip_sense_key, zip_asc, zip_ascq, dev->unit_attention); + zip_log("ZIP %i: Request length: %04X\n", id, dev->request_length); + + zip_log("ZIP %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + dev->sector_len = 0; + + zip_set_phase(id, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (zip_pre_execution_check(id, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_SEND_DIAGNOSTIC: + if (!(cdb[1] & (1 << 2))) { + zip_invalid_field(id); + return; } - } - else if (zip[id].unit_attention == 2) { - if (cdb[0] != GPCMD_REQUEST_SENSE) { - /* zip_log("ZIP %i: Unit attention now 0\n", id); */ - zip[id].unit_attention = 0; + case GPCMD_SCSI_RESERVE: + case GPCMD_SCSI_RELEASE: + case GPCMD_TEST_UNIT_READY: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_FORMAT_UNIT: + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) + { + zip_write_protected(id); + return; } - } - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ - if (cdb[0] != GPCMD_REQUEST_SENSE) - zip_sense_clear(id, cdb[0]); + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; - /* Next it's time for NOT READY. */ - if (!ready) - zip[id].media_status = MEC_MEDIA_REMOVAL; - else - zip[id].media_status = (zip[id].unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; - - if ((zip_command_flags[cdb[0]] & CHECK_READY) && !ready) { - zip_log("ZIP %i: Not ready (%02X)\n", id, cdb[0]); - zip_not_ready(id); - return 0; - } - - zip_log("ZIP %i: Continuing with command %02X\n", id, cdb[0]); - - return 1; -} - -void zip_clear_callback(uint8_t channel) -{ - uint8_t id = atapi_zip_drives[channel]; - - if (id < ZIP_NUM) - { - zip[id].callback = 0LL; - zip_set_callback(id); - } -} - -static void zip_seek(uint8_t id, uint32_t pos) -{ - /* zip_log("ZIP %i: Seek %08X\n", id, pos); */ - zip[id].sector_pos = pos; -} - -static void zip_rezero(uint8_t id) -{ - zip[id].sector_pos = zip[id].sector_len = 0; - zip_seek(id, 0); -} - -void zip_reset(uint8_t id) -{ - zip_rezero(id); - zip[id].status = 0; - zip[id].callback = 0LL; - zip_set_callback(id); - zip[id].packet_status = 0xff; - zip[id].unit_attention = 0; -} - -void zip_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) -{ - /*Will return 18 bytes of 0*/ - if (alloc_length != 0) { - memset(buffer, 0, alloc_length); - if (!desc) - memcpy(buffer, zip[id].sense, alloc_length); - else { - buffer[1] = zip_sense_key; - buffer[2] = zip_asc; - buffer[3] = zip_ascq; + case GPCMD_IOMEGA_SENSE: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + zip_buf_alloc(id, 256); + zip_set_buf_len(id, BufLen, &max_len); + memset(zipbufferb, 0, 256); + if (cdb[2] == 1) { + /* This page is related to disk health status - setting + this page to 0 makes disk health read as "marginal". */ + zipbufferb[0] = 0x58; + zipbufferb[1] = 0x00; + for (i = 0x00; i < 0x58; i++) + zipbufferb[i + 0x02] = 0xff; + } else if (cdb[2] == 2) { + zipbufferb[0] = 0x3d; + zipbufferb[1] = 0x00; + for (i = 0x00; i < 0x13; i++) + zipbufferb[i + 0x02] = 0x00; + zipbufferb[0x15] = 0x00; + if (zip_drives[id].read_only) + zipbufferb[0x15] |= 0x02; + for (i = 0x00; i < 0x27; i++) + zipbufferb[i + 0x16] = 0x00; + } else { + zip_invalid_field(id); + zip_buf_free(id); + return; } - } + zip_data_command_finish(id, 18, 18, cdb[4], 0); + break; - buffer[0] = desc ? 0x72 : 0x70; + case GPCMD_REZERO_UNIT: + dev->sector_pos = dev->sector_len = 0; + zip_seek(id, 0); + zip_set_phase(id, SCSI_PHASE_STATUS); + break; - if (zip[id].unit_attention && (zip_sense_key == 0)) { - buffer[desc ? 1 : 2]=SENSE_UNIT_ATTENTION; - buffer[desc ? 2 : 12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - buffer[desc ? 3 : 13]=0; - } + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + zip_set_phase(id, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + zip_buf_alloc(id, 256); + zip_set_buf_len(id, BufLen, &max_len); + len = (cdb[1] & 1) ? 8 : 18; + zip_request_sense(id, zipbufferb, max_len, cdb[1] & 1); + zip_data_command_finish(id, len, len, cdb[4], 0); + break; - zip_log("ZIP %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); + case GPCMD_MECHANISM_STATUS: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - if (buffer[desc ? 1 : 2] == SENSE_UNIT_ATTENTION) { - /* If the last remaining sense is unit attention, clear - that condition. */ - zip[id].unit_attention = 0; - } + zip_buf_alloc(id, 8); - /* Clear the sense stuff as per the spec. */ - zip_sense_clear(id, GPCMD_REQUEST_SENSE); -} + zip_set_buf_len(id, BufLen, &len); -void zip_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) -{ - int ready = 0; + memset(zipbufferb, 0, 8); + zipbufferb[5] = 1; - ready = (zip_drives[id].f != NULL); + zip_data_command_finish(id, 8, 8, len, 0); + break; - if (!ready && zip[id].unit_attention) { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - zip[id].unit_attention = 0; - } + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + alloc_length = 512; - /* Do *NOT* advance the unit attention phase. */ - - zip_request_sense(id, buffer, alloc_length, 0); -} - -void zip_set_buf_len(uint8_t id, int32_t *BufLen, uint32_t *src_len) -{ - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - if (*BufLen == -1) - *BufLen = *src_len; - else { - *BufLen = MIN(*src_len, *BufLen); - *src_len = *BufLen; + switch(cdb[0]) { + case GPCMD_READ_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + zip_log("ZIP %i: Length: %i, LBA: %i\n", id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_READ_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + zip_log("ZIP %i: Length: %i, LBA: %i\n", id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_READ_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; } - zip_log("ZIP %i: Actual transfer length: %i\n", id, *BufLen); - } -} -void zip_buf_alloc(uint8_t id, uint32_t len) -{ - zip_log("ZIP %i: Allocated buffer length: %i\n", id, len); - zipbufferb = (uint8_t *) malloc(len); -} + if (!dev->sector_len) { + zip_set_phase(id, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + dev->packet_status = ZIP_PHASE_COMPLETE; + dev->callback = 20LL * ZIP_TIME; + zip_set_callback(id); + break; + } -void zip_buf_free(uint8_t id) -{ - if (zipbufferb) { - zip_log("ZIP %i: Freeing buffer...\n", id); - free(zipbufferb); - zipbufferb = NULL; - } -} + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ -void zip_command(uint8_t id, uint8_t *cdb) -{ - uint32_t len; - int pos=0; - uint32_t max_len; - unsigned idx = 0; - unsigned size_idx; - unsigned preamble_len; - uint32_t alloc_length; - int block_desc = 0; - int ret; - int32_t blen = 0; - int32_t *BufLen; - uint32_t i = 0; + dev->packet_len = max_len * alloc_length; + zip_buf_alloc(id, dev->packet_len); - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; - zip[id].status &= ~ERR_STAT; - } else { - BufLen = &blen; - zip[id].error = 0; - } + ret = zip_blocks(id, &alloc_length, 1, 0); + if (ret <= 0) { + zip_buf_free(id); + return; + } - zip[id].packet_len = 0; - zip[id].request_pos = 0; + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; - zip[id].data_pos = 0; + zip_set_buf_len(id, BufLen, &dev->packet_len); - memcpy(zip[id].current_cdb, cdb, zip[id].cdb_len); + zip_data_command_finish(id, alloc_length, 512, alloc_length, 0); - if (cdb[0] != 0) { - zip_log("ZIP %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", id, cdb[0], zip_sense_key, zip_asc, zip_ascq, zip[id].unit_attention); - zip_log("ZIP %i: Request length: %04X\n", id, zip[id].request_length); - - zip_log("ZIP %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", id, - cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], - cdb[8], cdb[9], cdb[10], cdb[11]); - } - - zip[id].sector_len = 0; - - zip_set_phase(id, SCSI_PHASE_STATUS); - - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ - if (zip_pre_execution_check(id, cdb) == 0) + dev->all_blocks_total = dev->block_total; + if (dev->packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); return; - switch (cdb[0]) { - case GPCMD_SEND_DIAGNOSTIC: - if (!(cdb[1] & (1 << 2))) { - zip_invalid_field(id); - return; - } - case GPCMD_SCSI_RESERVE: - case GPCMD_SCSI_RELEASE: - case GPCMD_TEST_UNIT_READY: + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + if (!(cdb[1] & 2)) { zip_set_phase(id, SCSI_PHASE_STATUS); zip_command_complete(id); break; + } + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + alloc_length = 512; - case GPCMD_FORMAT_UNIT: - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) - { - zip_write_protected(id); + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) { + zip_write_protected(id); + return; + } + + switch(cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_WRITE_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + break; + case GPCMD_VERIFY_10: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + zip_log("ZIP %i: Length: %i, LBA: %i\n", id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_VERIFY_12: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if (zip_drives[id].is_250) { + if ((dev->sector_pos >= zip_drives[id].medium_size) || + ((dev->sector_pos + dev->sector_len - 1) >= zip_drives[id].medium_size)) { + zip_lba_out_of_range(id); return; } + } else { + if ((dev->sector_pos >= ZIP_SECTORS) || + ((dev->sector_pos + dev->sector_len - 1) >= ZIP_SECTORS)) { + zip_lba_out_of_range(id); + return; + } + } + if (!dev->sector_len) { zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + dev->packet_status = ZIP_PHASE_COMPLETE; + dev->callback = 20LL * ZIP_TIME; + zip_set_callback(id); break; + } - case GPCMD_IOMEGA_SENSE: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - max_len = cdb[4]; + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + zip_buf_alloc(id, dev->packet_len); + + dev->requested_blocks = max_len; + dev->packet_len = max_len << 9; + + zip_set_buf_len(id, BufLen, &dev->packet_len); + + zip_data_command_finish(id, dev->packet_len, 512, dev->packet_len, 1); + + dev->all_blocks_total = dev->block_total; + if (dev->packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); + return; + + case GPCMD_WRITE_SAME_10: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + + if ((cdb[1] & 6) == 6) { + zip_invalid_field(id); + return; + } + + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) { + zip_write_protected(id); + return; + } + + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + if (zip_drives[id].is_250) { + if ((dev->sector_pos >= zip_drives[id].medium_size) || + ((dev->sector_pos + dev->sector_len - 1) >= zip_drives[id].medium_size)) { + zip_lba_out_of_range(id); + return; + } + } else { + if ((dev->sector_pos >= ZIP_SECTORS) || + ((dev->sector_pos + dev->sector_len - 1) >= ZIP_SECTORS)) { + zip_lba_out_of_range(id); + return; + } + } + + if (!dev->sector_len) { + zip_set_phase(id, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + dev->packet_status = ZIP_PHASE_COMPLETE; + dev->callback = 20LL * ZIP_TIME; + zip_set_callback(id); + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + zip_buf_alloc(id, dev->packet_len); + + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + zip_set_buf_len(id, BufLen, &dev->packet_len); + + zip_data_command_finish(id, dev->packet_len, 512, dev->packet_len, 1); + + dev->all_blocks_total = dev->block_total; + if (dev->packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + else + block_desc = 0; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = cdb[4]; zip_buf_alloc(id, 256); - zip_set_buf_len(id, BufLen, &max_len); - memset(zipbufferb, 0, 256); - if (cdb[2] == 1) { - /* This page is related to disk health status - setting - this page to 0 makes disk health read as "marginal". */ - zipbufferb[0] = 0x58; - zipbufferb[1] = 0x00; - for (i = 0x00; i < 0x58; i++) - zipbufferb[i + 0x02] = 0xff; - } else if (cdb[2] == 2) { - zipbufferb[0] = 0x3d; - zipbufferb[1] = 0x00; - for (i = 0x00; i < 0x13; i++) - zipbufferb[i + 0x02] = 0x00; - zipbufferb[0x15] = 0x00; - if (zip_drives[id].read_only) - zipbufferb[0x15] |= 0x02; - for (i = 0x00; i < 0x27; i++) - zipbufferb[i + 0x16] = 0x00; - } else { - zip_invalid_field(id); - zip_buf_free(id); - return; - } - zip_data_command_finish(id, 18, 18, cdb[4], 0); - break; - - case GPCMD_REZERO_UNIT: - zip[id].sector_pos = zip[id].sector_len = 0; - zip_seek(id, 0); - zip_set_phase(id, SCSI_PHASE_STATUS); - break; - - case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE - should forget about the not ready, and report unit attention straight away. */ - zip_set_phase(id, SCSI_PHASE_DATA_IN); - max_len = cdb[4]; - zip_buf_alloc(id, 256); - zip_set_buf_len(id, BufLen, &max_len); - len = (cdb[1] & 1) ? 8 : 18; - zip_request_sense(id, zipbufferb, max_len, cdb[1] & 1); - zip_data_command_finish(id, len, len, cdb[4], 0); - break; - - case GPCMD_SET_SPEED: - case GPCMD_SET_SPEED_ALT: - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - - case GPCMD_MECHANISM_STATUS: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - zip_buf_alloc(id, 8); - - zip_set_buf_len(id, BufLen, &len); - - memset(zipbufferb, 0, 8); - zipbufferb[5] = 1; - - zip_data_command_finish(id, 8, 8, len, 0); - break; - - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - alloc_length = 512; - - switch(cdb[0]) { - case GPCMD_READ_6: - zip[id].sector_len = cdb[4]; - zip[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); - break; - case GPCMD_READ_10: - zip[id].sector_len = (cdb[7] << 8) | cdb[8]; - zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); - break; - case GPCMD_READ_12: - zip[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - zip[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - break; - } - - if (!zip[id].sector_len) { - zip_set_phase(id, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", id); */ - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].callback = 20LL * ZIP_TIME; - zip_set_callback(id); - break; - } - - max_len = zip[id].sector_len; - zip[id].requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ - - zip[id].packet_len = max_len * alloc_length; - zip_buf_alloc(id, zip[id].packet_len); - - ret = zip_blocks(id, &alloc_length, 1, 0); - if (ret <= 0) { - zip_buf_free(id); - return; - } - - zip[id].requested_blocks = max_len; - zip[id].packet_len = alloc_length; - - zip_set_buf_len(id, BufLen, &zip[id].packet_len); - - zip_data_command_finish(id, alloc_length, 512, alloc_length, 0); - - zip[id].all_blocks_total = zip[id].block_total; - if (zip[id].packet_status != ZIP_PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | id, 1); - else - ui_sb_update_icon(SB_ZIP | id, 0); - return; - - case GPCMD_VERIFY_6: - case GPCMD_VERIFY_10: - case GPCMD_VERIFY_12: - if (!(cdb[1] & 2)) { - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - } - case GPCMD_WRITE_6: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - zip_set_phase(id, SCSI_PHASE_DATA_OUT); - alloc_length = 512; - - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) - { - zip_write_protected(id); - return; - } - - switch(cdb[0]) { - case GPCMD_VERIFY_6: - case GPCMD_WRITE_6: - zip[id].sector_len = cdb[4]; - zip[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - break; - case GPCMD_VERIFY_10: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - zip[id].sector_len = (cdb[7] << 8) | cdb[8]; - zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); - break; - case GPCMD_VERIFY_12: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - zip[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - zip[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - break; - } - - if (zip_drives[id].is_250) { - if ((zip[id].sector_pos >= zip_drives[id].medium_size) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= zip_drives[id].medium_size)) - { - zip_lba_out_of_range(id); - return; - } - } else { - if ((zip[id].sector_pos >= ZIP_SECTORS) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= ZIP_SECTORS)) - { - zip_lba_out_of_range(id); - return; - } - } - - if (!zip[id].sector_len) { - zip_set_phase(id, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", id); */ - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].callback = 20LL * ZIP_TIME; - zip_set_callback(id); - break; - } - - max_len = zip[id].sector_len; - zip[id].requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ - - zip[id].packet_len = max_len * alloc_length; - zip_buf_alloc(id, zip[id].packet_len); - - zip[id].requested_blocks = max_len; - zip[id].packet_len = max_len << 9; - - zip_set_buf_len(id, BufLen, &zip[id].packet_len); - - zip_data_command_finish(id, zip[id].packet_len, 512, zip[id].packet_len, 1); - - zip[id].all_blocks_total = zip[id].block_total; - if (zip[id].packet_status != ZIP_PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | id, 1); - else - ui_sb_update_icon(SB_ZIP | id, 0); - return; - - case GPCMD_WRITE_SAME_10: - zip_set_phase(id, SCSI_PHASE_DATA_OUT); - alloc_length = 512; - - if ((cdb[1] & 6) == 6) - { - zip_invalid_field(id); - return; - } - - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) - { - zip_write_protected(id); - return; - } - - zip[id].sector_len = (cdb[7] << 8) | cdb[8]; - zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - - if (zip_drives[id].is_250) { - if ((zip[id].sector_pos >= zip_drives[id].medium_size) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= zip_drives[id].medium_size)) - { - zip_lba_out_of_range(id); - return; - } - } else { - if ((zip[id].sector_pos >= ZIP_SECTORS) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= ZIP_SECTORS)) - { - zip_lba_out_of_range(id); - return; - } - } - - if (!zip[id].sector_len) { - zip_set_phase(id, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", id); */ - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].callback = 20LL * ZIP_TIME; - zip_set_callback(id); - break; - } - - max_len = zip[id].sector_len; - zip[id].requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ - - zip[id].packet_len = max_len * alloc_length; - zip_buf_alloc(id, zip[id].packet_len); - - zip[id].requested_blocks = max_len; - zip[id].packet_len = alloc_length; - - zip_set_buf_len(id, BufLen, &zip[id].packet_len); - - zip_data_command_finish(id, zip[id].packet_len, 512, zip[id].packet_len, 1); - - zip[id].all_blocks_total = zip[id].block_total; - if (zip[id].packet_status != ZIP_PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | id, 1); - else - ui_sb_update_icon(SB_ZIP | id, 0); - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - else - block_desc = 0; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = cdb[4]; - zip_buf_alloc(id, 256); - } else { - len = (cdb[8] | (cdb[7] << 8)); - zip_buf_alloc(id, 65536); - } - - zip[id].current_page_code = cdb[2] & 0x3F; - zip_log("Mode sense page: %02X\n", zip[id].current_page_code); - - if (!(zip_mode_sense_page_flags & (1LL << zip[id].current_page_code))) { - zip_invalid_field(id); - zip_buf_free(id); - return; - } - - memset(zipbufferb, 0, len); - alloc_length = len; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = zip_mode_sense(id, zipbufferb, 4, cdb[2], block_desc); - len = MIN(len, alloc_length); - zipbufferb[0] = len - 1; - zipbufferb[1] = 0; - if (block_desc) - zipbufferb[3] = 8; - } else { - len = zip_mode_sense(id, zipbufferb, 8, cdb[2], block_desc); - len = MIN(len, alloc_length); - zipbufferb[0]=(len - 2) >> 8; - zipbufferb[1]=(len - 2) & 255; - zipbufferb[2] = 0; - if (block_desc) { - zipbufferb[6] = 0; - zipbufferb[7] = 8; - } - } - - zip_set_buf_len(id, BufLen, &len); - - zip_log("ZIP %i: Reading mode page: %02X...\n", id, cdb[2]); - - zip_data_command_finish(id, len, len, alloc_length, 0); - return; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - zip_set_phase(id, SCSI_PHASE_DATA_OUT); - - if (cdb[0] == GPCMD_MODE_SELECT_6) { - len = cdb[4]; - zip_buf_alloc(id, 256); - } else { - len = (cdb[7] << 8) | cdb[8]; - zip_buf_alloc(id, 65536); - } - - zip_set_buf_len(id, BufLen, &len); - - zip[id].total_length = len; - zip[id].do_page_save = cdb[1] & 1; - - zip[id].current_page_pos = 0; - - zip_data_command_finish(id, len, len, len, 1); - return; - - case GPCMD_START_STOP_UNIT: - zip_set_phase(id, SCSI_PHASE_STATUS); - - switch(cdb[4] & 3) { - case 0: /* Stop the disc. */ - zip_eject(id); /* The Iomega Windows 9x drivers require this. */ - break; - case 1: /* Start the disc and read the TOC. */ - break; - case 2: /* Eject the disc if possible. */ - /* zip_eject(id); */ - break; - case 3: /* Load the disc (close tray). */ - zip_reload(id); - break; - } - - zip_command_complete(id); - break; - - case GPCMD_INQUIRY: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - - max_len = cdb[3]; - max_len <<= 8; - max_len |= cdb[4]; - + } else { + len = (cdb[8] | (cdb[7] << 8)); zip_buf_alloc(id, 65536); + } - if (cdb[1] & 1) { - preamble_len = 4; - size_idx = 3; - - zipbufferb[idx++] = 05; - zipbufferb[idx++] = cdb[2]; - zipbufferb[idx++] = 0; + dev->current_page_code = cdb[2] & 0x3F; + zip_log("Mode sense page: %02X\n", dev->current_page_code); - idx++; + if (!(zip_mode_sense_page_flags & (1LL << dev->current_page_code))) { + zip_invalid_field(id); + zip_buf_free(id); + return; + } - switch (cdb[2]) { - case 0x00: - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 0x83; - break; - case 0x83: - if (idx + 24 > max_len) { - zip_data_phase_error(id); - zip_buf_free(id); - return; - } + memset(zipbufferb, 0, len); + alloc_length = len; - zipbufferb[idx++] = 0x02; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 20; - ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Serial */ - idx += 20; + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = zip_mode_sense(id, zipbufferb, 4, cdb[2], block_desc); + len = MIN(len, alloc_length); + zipbufferb[0] = len - 1; + zipbufferb[1] = 0; + if (block_desc) + zipbufferb[3] = 8; + } else { + len = zip_mode_sense(id, zipbufferb, 8, cdb[2], block_desc); + len = MIN(len, alloc_length); + zipbufferb[0]=(len - 2) >> 8; + zipbufferb[1]=(len - 2) & 255; + zipbufferb[2] = 0; + if (block_desc) { + zipbufferb[6] = 0; + zipbufferb[7] = 8; + } + } - if (idx + 72 > cdb[4]) - goto atapi_out; - zipbufferb[idx++] = 0x02; - zipbufferb[idx++] = 0x01; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 68; - ide_padstr8(zipbufferb + idx, 8, "IOMEGA "); /* Vendor */ - idx += 8; - if (zip_drives[id].is_250) - ide_padstr8(zipbufferb + idx, 40, "ZIP 250 "); /* Product */ - else - ide_padstr8(zipbufferb + idx, 40, "ZIP 100 "); /* Product */ - idx += 40; - ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Product */ - idx += 20; - break; - default: - zip_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - zip_invalid_field(id); + zip_set_buf_len(id, BufLen, &len); + + zip_log("ZIP %i: Reading mode page: %02X...\n", id, cdb[2]); + + zip_data_command_finish(id, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) { + len = cdb[4]; + zip_buf_alloc(id, 256); + } else { + len = (cdb[7] << 8) | cdb[8]; + zip_buf_alloc(id, 65536); + } + + zip_set_buf_len(id, BufLen, &len); + + dev->total_length = len; + dev->do_page_save = cdb[1] & 1; + + dev->current_page_pos = 0; + + zip_data_command_finish(id, len, len, len, 1); + return; + + case GPCMD_START_STOP_UNIT: + zip_set_phase(id, SCSI_PHASE_STATUS); + + switch(cdb[4] & 3) { + case 0: /* Stop the disc. */ + zip_eject(id); /* The Iomega Windows 9x drivers require this. */ + break; + case 1: /* Start the disc and read the TOC. */ + break; + case 2: /* Eject the disc if possible. */ + /* zip_eject(id); */ + break; + case 3: /* Load the disc (close tray). */ + zip_reload(id); + break; + } + + zip_command_complete(id); + break; + + case GPCMD_INQUIRY: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + zip_buf_alloc(id, 65536); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + zipbufferb[idx++] = 05; + zipbufferb[idx++] = cdb[2]; + zipbufferb[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + zip_data_phase_error(id); zip_buf_free(id); return; - } - } else { - preamble_len = 5; - size_idx = 4; + } - memset(zipbufferb, 0, 8); - if (cdb[1] & 0xe0) - zipbufferb[0] = 0x60; /*No physical device on this LUN*/ - else - zipbufferb[0] = 0x00; /*Hard disk*/ - zipbufferb[1] = 0x80; /*Removable*/ - if (zip_drives[id].is_250) { - zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; - } else { - zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; - } - zipbufferb[4] = 31; - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - zipbufferb[6] = 1; /* 16-bit transfers supported */ - zipbufferb[7] = 0x20; /* Wide bus supported */ - } + zipbufferb[idx++] = 0x02; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 20; + ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; - ide_padstr8(zipbufferb + 8, 8, "IOMEGA "); /* Vendor */ - if (zip_drives[id].is_250) { - ide_padstr8(zipbufferb + 16, 16, "ZIP 250 "); /* Product */ - ide_padstr8(zipbufferb + 32, 4, "42.S"); /* Revision */ - if (max_len >= 44) - ide_padstr8(zipbufferb + 36, 8, "08/08/01"); /* Date? */ - if (max_len >= 122) - ide_padstr8(zipbufferb + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */ - - } else { - ide_padstr8(zipbufferb + 16, 16, "ZIP 100 "); /* Product */ - ide_padstr8(zipbufferb + 32, 4, "E.08"); /* Revision */ - } - idx = 36; - - if (max_len == 96) { - zipbufferb[4] = 91; - idx = 96; - } else if (max_len == 128) { - zipbufferb[4] = 0x75; - idx = 128; - } + if (idx + 72 > cdb[4]) + goto atapi_out; + zipbufferb[idx++] = 0x02; + zipbufferb[idx++] = 0x01; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 68; + ide_padstr8(zipbufferb + idx, 8, "IOMEGA "); /* Vendor */ + idx += 8; + if (zip_drives[id].is_250) + ide_padstr8(zipbufferb + idx, 40, "ZIP 250 "); /* Product */ + else + ide_padstr8(zipbufferb + idx, 40, "ZIP 100 "); /* Product */ + idx += 40; + ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + zip_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + zip_invalid_field(id); + zip_buf_free(id); + return; } + } else { + preamble_len = 5; + size_idx = 4; + + memset(zipbufferb, 0, 8); + if (cdb[1] & 0xe0) + zipbufferb[0] = 0x60; /*No physical device on this LUN*/ + else + zipbufferb[0] = 0x00; /*Hard disk*/ + zipbufferb[1] = 0x80; /*Removable*/ + if (zip_drives[id].is_250) { + zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; + } else { + zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; + } + zipbufferb[4] = 31; + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + zipbufferb[6] = 1; /* 16-bit transfers supported */ + zipbufferb[7] = 0x20; /* Wide bus supported */ + } + + ide_padstr8(zipbufferb + 8, 8, "IOMEGA "); /* Vendor */ + if (zip_drives[id].is_250) { + ide_padstr8(zipbufferb + 16, 16, "ZIP 250 "); /* Product */ + ide_padstr8(zipbufferb + 32, 4, "42.S"); /* Revision */ + if (max_len >= 44) + ide_padstr8(zipbufferb + 36, 8, "08/08/01"); /* Date? */ + if (max_len >= 122) + ide_padstr8(zipbufferb + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */ + } else { + ide_padstr8(zipbufferb + 16, 16, "ZIP 100 "); /* Product */ + ide_padstr8(zipbufferb + 32, 4, "E.08"); /* Revision */ + } + idx = 36; + + if (max_len == 96) { + zipbufferb[4] = 91; + idx = 96; + } else if (max_len == 128) { + zipbufferb[4] = 0x75; + idx = 128; + } + } atapi_out: - zipbufferb[size_idx] = idx - preamble_len; - len=idx; + zipbufferb[size_idx] = idx - preamble_len; + len=idx; - len = MIN(len, max_len); - zip_set_buf_len(id, BufLen, &len); + len = MIN(len, max_len); + zip_set_buf_len(id, BufLen, &len); - zip_data_command_finish(id, len, len, max_len, 0); - break; + zip_data_command_finish(id, len, len, max_len, 0); + break; - case GPCMD_PREVENT_REMOVAL: - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; + case GPCMD_PREVENT_REMOVAL: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; - case GPCMD_SEEK_6: - case GPCMD_SEEK_10: - zip_set_phase(id, SCSI_PHASE_STATUS); - - switch(cdb[0]) { - case GPCMD_SEEK_6: - pos = (cdb[2] << 8) | cdb[3]; - break; - case GPCMD_SEEK_10: - pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; - break; - } - zip_seek(id, pos); - zip_command_complete(id); - break; + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + zip_set_phase(id, SCSI_PHASE_STATUS); - case GPCMD_READ_CDROM_CAPACITY: - zip_set_phase(id, SCSI_PHASE_DATA_IN); + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + zip_seek(id, pos); + zip_command_complete(id); + break; - zip_buf_alloc(id, 8); + case GPCMD_READ_CDROM_CAPACITY: + zip_set_phase(id, SCSI_PHASE_DATA_IN); - if (zip_read_capacity(id, zip[id].current_cdb, zipbufferb, &len) == 0) { - zip_buf_free(id); - return; - } + zip_buf_alloc(id, 8); - zip_set_buf_len(id, BufLen, &len); + if (zip_read_capacity(id, dev->current_cdb, zipbufferb, &len) == 0) { + zip_buf_free(id); + return; + } - zip_data_command_finish(id, len, len, len, 0); - break; + zip_set_buf_len(id, BufLen, &len); - case GPCMD_IOMEGA_EJECT: - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_eject(id); - zip_command_complete(id); - break; + zip_data_command_finish(id, len, len, len, 0); + break; - case GPCMD_READ_FORMAT_CAPACITIES: - len = (cdb[7] << 8) | cdb[8]; + case GPCMD_IOMEGA_EJECT: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_eject(id); + zip_command_complete(id); + break; - zip_buf_alloc(id, len); - memset(zipbufferb, 0, len); + case GPCMD_READ_FORMAT_CAPACITIES: + len = (cdb[7] << 8) | cdb[8]; - pos = 0; + zip_buf_alloc(id, len); + memset(zipbufferb, 0, len); - /* List header */ - zipbufferb[pos++] = 0; - zipbufferb[pos++] = 0; - zipbufferb[pos++] = 0; - if (zip_drives[id].f != NULL) - zipbufferb[pos++] = 16; - else - zipbufferb[pos++] = 8; + pos = 0; - /* Current/Maximum capacity header */ - if (zip_drives[id].is_250) { - if (zip_drives[id].f != NULL) { - zipbufferb[pos++] = (zip_drives[id].medium_size >> 24) & 0xff; - zipbufferb[pos++] = (zip_drives[id].medium_size >> 16) & 0xff; - zipbufferb[pos++] = (zip_drives[id].medium_size >> 8) & 0xff; - zipbufferb[pos++] = zip_drives[id].medium_size & 0xff; - zipbufferb[pos++] = 2; /* Current medium capacity */ - } else { - zipbufferb[pos++] = (ZIP_250_SECTORS >> 24) & 0xff; - zipbufferb[pos++] = (ZIP_250_SECTORS >> 16) & 0xff; - zipbufferb[pos++] = (ZIP_250_SECTORS >> 8) & 0xff; - zipbufferb[pos++] = ZIP_250_SECTORS & 0xff; - zipbufferb[pos++] = 3; /* Maximum medium capacity */ - } - } else { - zipbufferb[pos++] = (ZIP_SECTORS >> 24) & 0xff; - zipbufferb[pos++] = (ZIP_SECTORS >> 16) & 0xff; - zipbufferb[pos++] = (ZIP_SECTORS >> 8) & 0xff; - zipbufferb[pos++] = ZIP_SECTORS & 0xff; - if (zip_drives[id].f != NULL) - zipbufferb[pos++] = 2; - else - zipbufferb[pos++] = 3; - } - - zipbufferb[pos++] = 512 >> 16; - zipbufferb[pos++] = 512 >> 8; - zipbufferb[pos++] = 512 & 0xff; + /* List header */ + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 0; + if (zip_drives[id].f != NULL) + zipbufferb[pos++] = 16; + else + zipbufferb[pos++] = 8; + /* Current/Maximum capacity header */ + if (zip_drives[id].is_250) { if (zip_drives[id].f != NULL) { - /* Formattable capacity descriptor */ zipbufferb[pos++] = (zip_drives[id].medium_size >> 24) & 0xff; zipbufferb[pos++] = (zip_drives[id].medium_size >> 16) & 0xff; zipbufferb[pos++] = (zip_drives[id].medium_size >> 8) & 0xff; zipbufferb[pos++] = zip_drives[id].medium_size & 0xff; - zipbufferb[pos++] = 0; - zipbufferb[pos++] = 512 >> 16; - zipbufferb[pos++] = 512 >> 8; - zipbufferb[pos++] = 512 & 0xff; + zipbufferb[pos++] = 2; /* Current medium capacity */ + } else { + zipbufferb[pos++] = (ZIP_250_SECTORS >> 24) & 0xff; + zipbufferb[pos++] = (ZIP_250_SECTORS >> 16) & 0xff; + zipbufferb[pos++] = (ZIP_250_SECTORS >> 8) & 0xff; + zipbufferb[pos++] = ZIP_250_SECTORS & 0xff; + zipbufferb[pos++] = 3; /* Maximum medium capacity */ } + } else { + zipbufferb[pos++] = (ZIP_SECTORS >> 24) & 0xff; + zipbufferb[pos++] = (ZIP_SECTORS >> 16) & 0xff; + zipbufferb[pos++] = (ZIP_SECTORS >> 8) & 0xff; + zipbufferb[pos++] = ZIP_SECTORS & 0xff; + if (zip_drives[id].f != NULL) + zipbufferb[pos++] = 2; + else + zipbufferb[pos++] = 3; + } - zip_set_buf_len(id, BufLen, &len); + zipbufferb[pos++] = 512 >> 16; + zipbufferb[pos++] = 512 >> 8; + zipbufferb[pos++] = 512 & 0xff; - zip_data_command_finish(id, len, len, len, 0); - break; + if (zip_drives[id].f != NULL) { + /* Formattable capacity descriptor */ + zipbufferb[pos++] = (zip_drives[id].medium_size >> 24) & 0xff; + zipbufferb[pos++] = (zip_drives[id].medium_size >> 16) & 0xff; + zipbufferb[pos++] = (zip_drives[id].medium_size >> 8) & 0xff; + zipbufferb[pos++] = zip_drives[id].medium_size & 0xff; + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 512 >> 16; + zipbufferb[pos++] = 512 >> 8; + zipbufferb[pos++] = 512 & 0xff; + } - default: - zip_illegal_opcode(id); - break; - } + zip_set_buf_len(id, BufLen, &len); - /* zip_log("ZIP %i: Phase: %02X, request length: %i\n", zip[id].phase, zip[id].request_length); */ + zip_data_command_finish(id, len, len, len, 0); + break; - if (zip_atapi_phase_to_scsi(id) == SCSI_PHASE_STATUS) - zip_buf_free(id); + default: + zip_illegal_opcode(id); + break; + } + + /* zip_log("ZIP %i: Phase: %02X, request length: %i\n", dev->phase, dev->request_length); */ + + if (zip_atapi_phase_to_scsi(id) == SCSI_PHASE_STATUS) + zip_buf_free(id); } + /* The command second phase function, needed for Mode Select. */ -uint8_t zip_phase_data_out(uint8_t id) +static uint8_t +zip_phase_data_out(uint8_t id) { - uint16_t block_desc_len; - uint16_t pos; + zip_t *dev = zip[id]; - uint8_t error = 0; - uint8_t page, page_len; + uint16_t block_desc_len; + uint16_t pos; - uint16_t i = 0; + uint8_t error = 0; + uint8_t page, page_len; - uint8_t hdr_len, val, old_val, ch; + uint16_t i = 0; - uint32_t last_to_write = 0, len = 0; - uint32_t c, h, s; + uint8_t hdr_len, val, old_val, ch; - switch(zip[id].current_cdb[0]) { - case GPCMD_VERIFY_6: - case GPCMD_VERIFY_10: - case GPCMD_VERIFY_12: - break; - case GPCMD_WRITE_6: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - if (zip[id].requested_blocks > 0) - zip_blocks(id, &len, 1, 1); - break; - case GPCMD_WRITE_SAME_10: - if (!zip[id].current_cdb[7] && !zip[id].current_cdb[8]) { - if (zip_drives[id].is_250) - last_to_write = (zip_drives[id].medium_size - 1); - else - last_to_write = (ZIP_SECTORS - 1); - } else - last_to_write = zip[id].sector_pos + zip[id].sector_len - 1; + uint32_t last_to_write = 0, len = 0; + uint32_t c, h, s; - for (i = zip[id].sector_pos; i <= last_to_write; i++) { - if (zip[id].current_cdb[1] & 2) { - zipbufferb[0] = (i >> 24) & 0xff; - zipbufferb[1] = (i >> 16) & 0xff; - zipbufferb[2] = (i >> 8) & 0xff; - zipbufferb[3] = i & 0xff; - } else if (zip[id].current_cdb[1] & 4) { - /* CHS are 96,1,2048 (ZIP 100) and 239,1,2048 (ZIP 250) */ - s = (i % 2048); - h = ((i - s) / 2048) % 1; - c = ((i - s) / 2048) / 1; - zipbufferb[0] = (c >> 16) & 0xff; - zipbufferb[1] = (c >> 8) & 0xff; - zipbufferb[2] = c & 0xff; - zipbufferb[3] = h & 0xff; - zipbufferb[4] = (s >> 24) & 0xff; - zipbufferb[5] = (s >> 16) & 0xff; - zipbufferb[6] = (s >> 8) & 0xff; - zipbufferb[7] = s & 0xff; - } - fseek(zip_drives[id].f, zip_drives[id].base + (i << 9), SEEK_SET); - fwrite(zipbufferb, 1, 512, zip_drives[id].f); - } - break; - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - if (zip[id].current_cdb[0] == GPCMD_MODE_SELECT_10) - hdr_len = 8; + switch(dev->current_cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + break; + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + if (dev->requested_blocks > 0) + zip_blocks(id, &len, 1, 1); + break; + case GPCMD_WRITE_SAME_10: + if (!dev->current_cdb[7] && !dev->current_cdb[8]) { + if (zip_drives[id].is_250) + last_to_write = (zip_drives[id].medium_size - 1); else - hdr_len = 4; + last_to_write = (ZIP_SECTORS - 1); + } else + last_to_write = dev->sector_pos + dev->sector_len - 1; - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - if (zip[id].current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = zipbufferb[2]; - block_desc_len <<= 8; - block_desc_len |= zipbufferb[3]; - } else { - block_desc_len = zipbufferb[6]; - block_desc_len <<= 8; - block_desc_len |= zipbufferb[7]; - } - } else - block_desc_len = 0; + for (i = dev->sector_pos; i <= last_to_write; i++) { + if (dev->current_cdb[1] & 2) { + zipbufferb[0] = (i >> 24) & 0xff; + zipbufferb[1] = (i >> 16) & 0xff; + zipbufferb[2] = (i >> 8) & 0xff; + zipbufferb[3] = i & 0xff; + } else if (dev->current_cdb[1] & 4) { + /* CHS are 96,1,2048 (ZIP 100) and 239,1,2048 (ZIP 250) */ + s = (i % 2048); + h = ((i - s) / 2048) % 1; + c = ((i - s) / 2048) / 1; + zipbufferb[0] = (c >> 16) & 0xff; + zipbufferb[1] = (c >> 8) & 0xff; + zipbufferb[2] = c & 0xff; + zipbufferb[3] = h & 0xff; + zipbufferb[4] = (s >> 24) & 0xff; + zipbufferb[5] = (s >> 16) & 0xff; + zipbufferb[6] = (s >> 8) & 0xff; + zipbufferb[7] = s & 0xff; + } + fseek(zip_drives[id].f, zip_drives[id].base + (i << 9), SEEK_SET); + fwrite(zipbufferb, 1, 512, zip_drives[id].f); + } + break; + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; - pos = hdr_len + block_desc_len; + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = zipbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= zipbufferb[3]; + } else { + block_desc_len = zipbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= zipbufferb[7]; + } + } else + block_desc_len = 0; - while(1) { - page = zipbufferb[pos] & 0x3F; - page_len = zipbufferb[pos + 1]; + pos = hdr_len + block_desc_len; - pos += 2; + while(1) { + page = zipbufferb[pos] & 0x3F; + page_len = zipbufferb[pos + 1]; - if (!(zip_mode_sense_page_flags & (1LL << ((uint64_t) page)))) - error |= 1; - else { - for (i = 0; i < page_len; i++) { - ch = zip_mode_sense_pages_changeable.pages[page][i + 2]; - val = zipbufferb[pos + i]; - old_val = zip_mode_sense_pages_saved[id].pages[page][i + 2]; - if (val != old_val) { - if (ch) - zip_mode_sense_pages_saved[id].pages[page][i + 2] = val; - else - error |= 1; - } + pos += 2; + + if (!(zip_mode_sense_page_flags & (1LL << ((uint64_t) page)))) + error |= 1; + else { + for (i = 0; i < page_len; i++) { + ch = zip_mode_sense_pages_changeable.pages[page][i + 2]; + val = zipbufferb[pos + i]; + old_val = zip_mode_sense_pages_saved[id].pages[page][i + 2]; + if (val != old_val) { + if (ch) + zip_mode_sense_pages_saved[id].pages[page][i + 2] = val; + else + error |= 1; } } - - pos += page_len; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - val = zip_mode_sense_pages_default_scsi.pages[page][0] & 0x80; - else - val = zip_mode_sense_pages_default.pages[page][0] & 0x80; - if (zip[id].do_page_save && val) - zip_mode_sense_save(id); - - if (pos >= zip[id].total_length) - break; } - if (error) { - zip_invalid_field_pl(id); - return 0; - } - break; - } + pos += page_len; - return 1; + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + val = zip_mode_sense_pages_default_scsi.pages[page][0] & 0x80; + else + val = zip_mode_sense_pages_default.pages[page][0] & 0x80; + if (dev->do_page_save && val) + zip_mode_sense_save(id); + + if (pos >= dev->total_length) + break; + } + + if (error) { + zip_invalid_field_pl(id); + return 0; + } + break; + } + + return 1; } + /* This is the general ATAPI PIO request function. */ -void zip_pio_request(uint8_t id, uint8_t out) +static void +zip_pio_request(uint8_t id, uint8_t out) { - int old_pos = 0; - int ret = 0; + zip_t *dev = zip[id]; - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) { - zip_log("ZIP %i: Lowering IDE IRQ\n", id); - ide_irq_lower(&(ide_drives[zip_drives[id].ide_channel])); - } - - zip[id].status = BUSY_STAT; + int old_pos = 0; + int ret = 0; - if (zip[id].pos >= zip[id].packet_len) { - zip_log("ZIP %i: %i bytes %s, command done\n", id, zip[id].pos, out ? "written" : "read"); + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) { + zip_log("ZIP %i: Lowering IDE IRQ\n", id); + ide_irq_lower(ide_drives[zip_drives[id].ide_channel]); + } - zip[id].pos = zip[id].request_pos = 0; - if (out) { - ret = zip_phase_data_out(id); - /* If ret = 0 (phase 1 error), then we do not do anything else other than - free the buffer, as the phase and callback have already been set by the - error function. */ - if (ret) - zip_command_complete(id); - } else + dev->status = BUSY_STAT; + + if (dev->pos >= dev->packet_len) { + zip_log("ZIP %i: %i bytes %s, command done\n", id, dev->pos, out ? "written" : "read"); + + dev->pos = dev->request_pos = 0; + if (out) { + ret = zip_phase_data_out(id); + /* If ret = 0 (phase 1 error), then we do not do anything else other than + free the buffer, as the phase and callback have already been set by the + error function. */ + if (ret) zip_command_complete(id); - ui_sb_update_icon(SB_ZIP | id, 0); - zip_buf_free(id); - } else { - zip_log("ZIP %i: %i bytes %s, %i bytes are still left\n", id, zip[id].pos, out ? "written" : "read", zip[id].packet_len - zip[id].pos); - - /* Make sure to keep pos, and reset request_pos to 0. */ - /* Also make sure to not reset total_read. */ - - /* If less than (packet length) bytes are remaining, update packet length - accordingly. */ - if ((zip[id].packet_len - zip[id].pos) < (zip[id].max_transfer_len)) - zip[id].max_transfer_len = zip[id].packet_len - zip[id].pos; - - old_pos = zip[id].pos; - zip[id].packet_status = out ? ZIP_PHASE_DATA_OUT : ZIP_PHASE_DATA_IN; - zip_command_common(id); - zip[id].pos = old_pos; - zip[id].request_pos = 0; - } -} - -void zip_phase_callback(uint8_t id); - -int zip_read_from_ide_dma(uint8_t channel) -{ - uint8_t id = atapi_zip_drives[channel]; - - if (id > ZIP_NUM) - return 0; - - if (ide_bus_master_write) { - if (ide_bus_master_write(channel >> 1, zipbufferb, zip[id].packet_len)) - return 0; - else - return 1; } else - return 0; + zip_command_complete(id); + zip_buf_free(id); + } else { + zip_log("ZIP %i: %i bytes %s, %i bytes are still left\n", id, dev->pos, out ? "written" : "read", dev->packet_len - dev->pos); + + /* If less than (packet length) bytes are remaining, update packet length + accordingly. */ + if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) + dev->max_transfer_len = dev->packet_len - dev->pos; + zip_log("ZIP %i: Packet length %i, request length %i\n", id, dev->packet_len, dev->max_transfer_len); + + old_pos = dev->pos; + dev->packet_status = out ? ZIP_PHASE_DATA_OUT : ZIP_PHASE_DATA_IN; + zip_command_common(id); + dev->pos = old_pos; + + dev->request_pos = 0; + } } -int zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) + +static int +zip_read_from_ide_dma(uint8_t channel) { - uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; - int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + zip_t *dev; - if (id > ZIP_NUM) + uint8_t id = atapi_zip_drives[channel]; + int ret; + + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + if (ide_bus_master_write) { + ret = ide_bus_master_write(channel >> 1, + zipbufferb, dev->packet_len, + ide_bus_master_priv[channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + zip_bus_master_error(id); return 0; + } else + return 1; + } else + return 0; +} - zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(zipbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, *BufLen); + +static int +zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + zip_t *dev; + + uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(zipbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, *BufLen); + return 1; +} + + +static void +zip_irq_raise(uint8_t id) +{ + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + ide_irq_raise(ide_drives[zip_drives[id].ide_channel]); +} + + +static int +zip_read_from_dma(uint8_t id) +{ + zip_t *dev = zip[id]; + + int32_t *BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; + int ret = 0; + + int in_data_length = 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + ret = zip_read_from_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + else + ret = zip_read_from_ide_dma(zip_drives[id].ide_channel); + + if (ret != 1) + return ret; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + in_data_length = *BufLen; + zip_log("ZIP %i: SCSI Input data length: %i\n", id, in_data_length); + } else { + in_data_length = dev->max_transfer_len; + zip_log("ZIP %i: ATAPI Input data length: %i\n", id, in_data_length); + } + + ret = zip_phase_data_out(id); + + if (ret) return 1; + else + return 0; } -void zip_irq_raise(uint8_t id) + +static int +zip_write_to_ide_dma(uint8_t channel) { - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) - ide_irq_raise(&(ide_drives[zip_drives[id].ide_channel])); -} + zip_t *dev; -int zip_read_from_dma(uint8_t id) -{ - int32_t *BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; + uint8_t id = atapi_zip_drives[channel]; + int ret; - int ret = 0; + if (id > ZIP_NUM) { + zip_log("ZIP %i: Drive not found\n", id); + return 0; + } - int in_data_length = 0; + dev = zip[id]; - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - ret = zip_read_from_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); - else - ret = zip_read_from_ide_dma(zip_drives[id].ide_channel); - - if (!ret) + if (ide_bus_master_read) { + ret = ide_bus_master_read(channel >> 1, + zipbufferb, dev->packet_len, + ide_bus_master_priv[channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + zip_bus_master_error(id); return 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - in_data_length = *BufLen; - zip_log("ZIP %i: SCSI Input data length: %i\n", id, in_data_length); - } else { - in_data_length = zip[id].max_transfer_len; - zip_log("ZIP %i: ATAPI Input data length: %i\n", id, in_data_length); - } - - ret = zip_phase_data_out(id); - - if (ret || (zip_drives[id].bus_type == ZIP_BUS_SCSI)) { - zip_buf_free(id); - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].status = READY_STAT; - zip[id].phase = 3; - ui_sb_update_icon(SB_ZIP | id, 0); - zip_irq_raise(id); - if (ret) - return 1; - else - return 0; } else - return 0; + return 1; + } else + return 0; } -int zip_write_to_ide_dma(uint8_t channel) + +static int +zip_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) { - uint8_t id = atapi_zip_drives[channel]; + zip_t *dev; - if (id > ZIP_NUM) { - zip_log("ZIP %i: Drive not found\n", id); - return 0; - } + uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; - if (ide_bus_master_read) { - if (ide_bus_master_read(channel >> 1, zipbufferb, zip[id].packet_len)) - return 0; - else - return 1; - } else - return 0; + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, zipbufferb, *BufLen); + zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, zipbufferb[0], zipbufferb[1], zipbufferb[2], zipbufferb[3], zipbufferb[4], zipbufferb[5], zipbufferb[6], zipbufferb[7]); + zip_log("ZIP %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); + return 1; } -int zip_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) + +static int +zip_write_to_dma(uint8_t id) { - uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; - int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + zip_t *dev = zip[id]; - if (id > ZIP_NUM) - return 0; + int32_t *BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; + int ret = 0; - zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, zipbufferb, *BufLen); - zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, zipbufferb[0], zipbufferb[1], zipbufferb[2], zipbufferb[3], zipbufferb[4], zipbufferb[5], zipbufferb[6], zipbufferb[7]); - zip_log("ZIP %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); - return 1; + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + zip_log("Write to SCSI DMA: (%02X:%02X)\n", zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + ret = zip_write_to_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + } else + ret = zip_write_to_ide_dma(zip_drives[id].ide_channel); + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + zip_log("ZIP %i: SCSI Output data length: %i\n", id, *BufLen); + else + zip_log("ZIP %i: ATAPI Output data length: %i\n", id, dev->packet_len); + + return ret; } -int zip_write_to_dma(uint8_t id) -{ - int ret = 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - zip_log("Write to SCSI DMA: (%02X:%02X)\n", zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); - ret = zip_write_to_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); - } else - ret = zip_write_to_ide_dma(zip_drives[id].ide_channel); - - if (ret || (zip_drives[id].bus_type == ZIP_BUS_SCSI)) { - zip_buf_free(id); - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].status = READY_STAT; - zip[id].phase = 3; - ui_sb_update_icon(SB_ZIP | id, 0); - zip_irq_raise(id); - if (ret) - return 1; - else - return 0; - } else - return 0; -} /* If the result is 1, issue an IRQ, otherwise not. */ -void zip_phase_callback(uint8_t id) +void +zip_phase_callback(uint8_t id) { - switch(zip[id].packet_status) { - case ZIP_PHASE_IDLE: - zip_log("ZIP %i: ZIP_PHASE_IDLE\n", id); - zip[id].pos=0; - zip[id].phase = 1; - zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); - return; - case ZIP_PHASE_COMMAND: - zip_log("ZIP %i: ZIP_PHASE_COMMAND\n", id); - zip[id].status = BUSY_STAT | (zip[id].status &ERR_STAT); - memcpy(zip[id].atapi_cdb, zipbufferb, zip[id].cdb_len); - zip_command(id, zip[id].atapi_cdb); - return; - case ZIP_PHASE_COMPLETE: - zip_log("ZIP %i: ZIP_PHASE_COMPLETE\n", id); - zip[id].status = READY_STAT; - zip[id].phase = 3; - zip[id].packet_status = 0xFF; - ui_sb_update_icon(SB_ZIP | id, 0); - zip_irq_raise(id); - return; - case ZIP_PHASE_DATA_OUT: - zip_log("ZIP %i: ZIP_PHASE_DATA_OUT\n", id); - zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); - zip[id].phase = 0; - zip_irq_raise(id); - return; - case ZIP_PHASE_DATA_OUT_DMA: - zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", id); - zip_read_from_dma(id); - return; - case ZIP_PHASE_DATA_IN: - zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", id); - zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); - zip[id].phase = 2; - zip_irq_raise(id); - return; - case ZIP_PHASE_DATA_IN_DMA: - zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", id); - zip_write_to_dma(id); - return; - case ZIP_PHASE_ERROR: - zip_log("ZIP %i: ZIP_PHASE_ERROR\n", id); - zip[id].status = READY_STAT | ERR_STAT; - zip[id].phase = 3; - zip[id].packet_status = 0xFF; - zip_irq_raise(id); - ui_sb_update_icon(SB_ZIP | id, 0); - return; - } + zip_t *dev = zip[id]; + int ret; + + switch(dev->packet_status) { + case ZIP_PHASE_IDLE: + zip_log("ZIP %i: ZIP_PHASE_IDLE\n", id); + dev->pos=0; + dev->phase = 1; + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + return; + case ZIP_PHASE_COMMAND: + zip_log("ZIP %i: ZIP_PHASE_COMMAND\n", id); + dev->status = BUSY_STAT | (dev->status &ERR_STAT); + memcpy(dev->atapi_cdb, zipbufferb, dev->cdb_len); + zip_command(id, dev->atapi_cdb); + return; + case ZIP_PHASE_COMPLETE: + zip_log("ZIP %i: ZIP_PHASE_COMPLETE\n", id); + dev->status = READY_STAT; + dev->phase = 3; + dev->packet_status = 0xFF; + ui_sb_update_icon(SB_ZIP | id, 0); + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_OUT: + zip_log("ZIP %i: ZIP_PHASE_DATA_OUT\n", id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 0; + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_OUT_DMA: + zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", id); + ret = zip_read_from_dma(id); + + if ((ret == 1) || (zip_drives[id].bus_type == ZIP_BUS_SCSI)) { + zip_log("ZIP %i: DMA data out phase done\n"); + zip_buf_free(id); + zip_command_complete(id); + } else if (ret == 2) { + zip_log("ZIP %i: DMA out not enabled, wait\n"); + zip_command_bus(id); + } else { + zip_log("ZIP %i: DMA data out phase failure\n"); + zip_buf_free(id); + } + return; + case ZIP_PHASE_DATA_IN: + zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 2; + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_IN_DMA: + zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", id); + ret = zip_write_to_dma(id); + + if ((ret == 1) || (zip_drives[id].bus_type == ZIP_BUS_SCSI)) { + zip_log("ZIP %i: DMA data in phase done\n"); + zip_buf_free(id); + zip_command_complete(id); + } else if (ret == 2) { + zip_log("ZIP %i: DMA in not enabled, wait\n"); + zip_command_bus(id); + } else { + zip_log("ZIP %i: DMA data in phase failure\n"); + zip_buf_free(id); + } + return; + case ZIP_PHASE_ERROR: + zip_log("ZIP %i: ZIP_PHASE_ERROR\n", id); + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->packet_status = 0xFF; + zip_irq_raise(id); + ui_sb_update_icon(SB_ZIP | id, 0); + return; + } } -/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ -uint32_t zip_read(uint8_t channel, int length) + +uint32_t +zip_read(uint8_t channel, int length) { - uint16_t *zipbufferw; - uint32_t *zipbufferl; + zip_t *dev; - uint8_t id = atapi_zip_drives[channel]; + uint16_t *zipbufferw; + uint32_t *zipbufferl; - uint32_t temp = 0; + uint8_t id = atapi_zip_drives[channel]; - if (id > ZIP_NUM) + uint32_t temp = 0; + + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + zipbufferw = (uint16_t *) zipbufferb; + zipbufferl = (uint32_t *) zipbufferb; + + if (!zipbufferb) + return 0; + + /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, + which can happen when issuing media access commands with an allocated length below minimum request length + (which is 1 sector = 512 bytes). */ + switch(length) { + case 1: + temp = (dev->pos < dev->packet_len) ? zipbufferb[dev->pos] : 0; + dev->pos++; + dev->request_pos++; + break; + case 2: + temp = (dev->pos < dev->packet_len) ? zipbufferw[dev->pos >> 1] : 0; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + temp = (dev->pos < dev->packet_len) ? zipbufferl[dev->pos >> 2] : 0; + dev->pos += 4; + dev->request_pos += 4; + break; + default: return 0; + } - zipbufferw = (uint16_t *) zipbufferb; - zipbufferl = (uint32_t *) zipbufferb; + if (dev->packet_status == ZIP_PHASE_DATA_IN) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + zip_log("ZIP %i: Issuing read callback\n", id); + zip_pio_request(id, 0); + } + zip_log("ZIP %i: Returning: %02X (buffer position: %i, request position: %i)\n", id, temp, dev->pos, dev->request_pos); + return temp; + } else { + zip_log("ZIP %i: Returning zero (buffer position: %i, request position: %i)\n", id, dev->pos, dev->request_pos); + return 0; + } +} + +void +zip_write(uint8_t channel, uint32_t val, int length) +{ + zip_t *dev; + + uint16_t *zipbufferw; + uint32_t *zipbufferl; + + uint8_t id = atapi_zip_drives[channel]; + + if (id > ZIP_NUM) + return; + + dev = zip[id]; + + if (dev->packet_status == ZIP_PHASE_IDLE) { if (!zipbufferb) - return 0; + zip_buf_alloc(id, dev->cdb_len); + } - /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, - which can happen when issuing media access commands with an allocated length below minimum request length - (which is 1 sector = 512 bytes). */ - switch(length) { - case 1: - temp = (zip[id].pos < zip[id].packet_len) ? zipbufferb[zip[id].pos] : 0; - zip[id].pos++; - zip[id].request_pos++; - break; - case 2: - temp = (zip[id].pos < zip[id].packet_len) ? zipbufferw[zip[id].pos >> 1] : 0; - zip[id].pos += 2; - zip[id].request_pos += 2; - break; - case 4: - temp = (zip[id].pos < zip[id].packet_len) ? zipbufferl[zip[id].pos >> 2] : 0; - zip[id].pos += 4; - zip[id].request_pos += 4; - break; - default: - return 0; - } + zipbufferw = (uint16_t *) zipbufferb; + zipbufferl = (uint32_t *) zipbufferb; - if (zip[id].packet_status == ZIP_PHASE_DATA_IN) { - if ((zip[id].request_pos >= zip[id].max_transfer_len) || (zip[id].pos >= zip[id].packet_len)) { - /* Time for a DRQ. */ - // zip_log("ZIP %i: Issuing read callback\n", id); - zip_pio_request(id, 0); - } - // zip_log("ZIP %i: Returning: %02X (buffer position: %i, request position: %i)\n", id, temp, zip[id].pos, zip[id].request_pos); - return temp; - } else { - // zip_log("ZIP %i: Returning zero (buffer position: %i, request position: %i)\n", id, zip[id].pos, zip[id].request_pos); - return 0; + if (!zipbufferb) + return; + + switch(length) { + case 1: + zipbufferb[dev->pos] = val & 0xff; + dev->pos++; + dev->request_pos++; + break; + case 2: + zipbufferw[dev->pos >> 1] = val & 0xffff; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + zipbufferl[dev->pos >> 2] = val; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return; + } + + if (dev->packet_status == ZIP_PHASE_DATA_OUT) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + zip_pio_request(id, 1); } + return; + } else if (dev->packet_status == ZIP_PHASE_IDLE) { + if (dev->pos >= dev->cdb_len) { + dev->pos=0; + dev->status = BUSY_STAT; + dev->packet_status = ZIP_PHASE_COMMAND; + timer_process(); + zip_phase_callback(id); + timer_update_outstanding(); + } + return; + } } -/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ -void zip_write(uint8_t channel, uint32_t val, int length) -{ - uint16_t *zipbufferw; - uint32_t *zipbufferl; - - uint8_t id = atapi_zip_drives[channel]; - - if (id > ZIP_NUM) - return; - - if (zip[id].packet_status == ZIP_PHASE_IDLE) { - if (!zipbufferb) - zip_buf_alloc(id, zip[id].cdb_len); - } - - zipbufferw = (uint16_t *) zipbufferb; - zipbufferl = (uint32_t *) zipbufferb; - - if (!zipbufferb) - return; - - switch(length) { - case 1: - zipbufferb[zip[id].pos] = val & 0xff; - zip[id].pos++; - zip[id].request_pos++; - break; - case 2: - zipbufferw[zip[id].pos >> 1] = val & 0xffff; - zip[id].pos += 2; - zip[id].request_pos += 2; - break; - case 4: - zipbufferl[zip[id].pos >> 2] = val; - zip[id].pos += 4; - zip[id].request_pos += 4; - break; - default: - return; - } - - if (zip[id].packet_status == ZIP_PHASE_DATA_OUT) { - if ((zip[id].request_pos >= zip[id].max_transfer_len) || (zip[id].pos >= zip[id].packet_len)) { - /* Time for a DRQ. */ - zip_pio_request(id, 1); - } - return; - } else if (zip[id].packet_status == ZIP_PHASE_IDLE) { - if (zip[id].pos >= zip[id].cdb_len) { - zip[id].pos=0; - zip[id].status = BUSY_STAT; - zip[id].packet_status = ZIP_PHASE_COMMAND; - timer_process(); - zip_phase_callback(id); - timer_update_outstanding(); - } - return; - } -} /* Peform a master init on the entire module. */ void @@ -2576,14 +2828,23 @@ zip_hard_reset(void) { int c; + zip_destroy_drives(); + for (c=0; c * @@ -19,15 +19,15 @@ #define EMU_ZIP_H -#define ZIP_NUM 4 +#define ZIP_NUM 4 -#define ZIP_PHASE_IDLE 0 -#define ZIP_PHASE_COMMAND 1 -#define ZIP_PHASE_COMPLETE 2 -#define ZIP_PHASE_DATA_IN 3 -#define ZIP_PHASE_DATA_IN_DMA 4 -#define ZIP_PHASE_DATA_OUT 5 -#define ZIP_PHASE_DATA_OUT_DMA 6 +#define ZIP_PHASE_IDLE 0x00 +#define ZIP_PHASE_COMMAND 0x01 +#define ZIP_PHASE_COMPLETE 0x02 +#define ZIP_PHASE_DATA_IN 0x03 +#define ZIP_PHASE_DATA_IN_DMA 0x04 +#define ZIP_PHASE_DATA_OUT 0x05 +#define ZIP_PHASE_DATA_OUT_DMA 0x06 #define ZIP_PHASE_ERROR 0x80 #define BUF_SIZE 32768 @@ -42,134 +42,81 @@ enum { ZIP_BUS_DISABLED = 0, - ZIP_BUS_ATAPI_PIO_ONLY = 4, - ZIP_BUS_ATAPI_PIO_AND_DMA, + ZIP_BUS_ATAPI = 4, ZIP_BUS_SCSI, - ZIP_BUS_USB = 8 + ZIP_BUS_USB }; typedef struct { - uint8_t previous_command; + uint8_t previous_command, error, + features, status, + phase, *buffer, + atapi_cdb[16], + current_cdb[16], + sense[256]; - int toctimes; - int media_status; + uint16_t request_length, max_transfer_len; - int is_dma; + int toctimes, media_status, + is_dma, requested_blocks, + current_page_len, current_page_pos, + total_length, written_length, + mode_select_phase, do_page_save, + callback, data_pos, + packet_status, unit_attention, + cdb_len_setting, cdb_len, + request_pos, total_read, + block_total, all_blocks_total, + old_len, block_descriptor_len, + init_length; - int requested_blocks; /* This will be set to something other than 1 when block reads are implemented. */ + uint32_t sector_pos, sector_len, + packet_len, pos, + seek_pos; - uint64_t current_page_code; - int current_page_len; - - int current_page_pos; - - int mode_select_phase; - - int total_length; - int written_length; - - int do_page_save; - - uint8_t error; - uint8_t features; - uint16_t request_length; - uint16_t max_transfer_len; - uint8_t status; - uint8_t phase; - - uint32_t sector_pos; - uint32_t sector_len; - - uint32_t packet_len; - int packet_status; - - uint8_t atapi_cdb[16]; - uint8_t current_cdb[16]; - - uint32_t pos; - - int callback; - - int data_pos; - - int cdb_len_setting; - int cdb_len; - - int cd_status; - int prev_status; - - int unit_attention; - uint8_t sense[256]; - - int request_pos; - - uint8_t *buffer; - - int times; - - uint32_t seek_pos; - - int total_read; - - int block_total; - int all_blocks_total; - - int old_len; - int block_descriptor_len; - - int init_length; + uint64_t current_page_code; } zip_t; typedef struct { - int host_drive; - int prev_host_drive; + unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ + uint8_t ide_channel, + bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ - unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ - uint8_t bus_mode; /* Bit 0 = PIO suported; - Bit 1 = DMA supportd. */ + unsigned int scsi_device_id, scsi_device_lun, + is_250; - uint8_t ide_channel; + wchar_t image_path[1024], + prev_image_path[1024]; - unsigned int scsi_device_id; - unsigned int scsi_device_lun; - - unsigned int is_250; - unsigned int atapi_dma; + int read_only, ui_writeprot; - wchar_t image_path[1024]; - wchar_t prev_image_path[1024]; + uint32_t medium_size, base; - uint32_t medium_size; - - int read_only; - int ui_writeprot; - - uint32_t base; - - FILE *f; + FILE *f; } zip_drive_t; -extern zip_t zip[ZIP_NUM]; +extern zip_t *zip[ZIP_NUM]; extern zip_drive_t zip_drives[ZIP_NUM]; extern uint8_t atapi_zip_drives[8]; extern uint8_t scsi_zip_drives[16][8]; -#define zip_sense_error zip[id].sense[0] -#define zip_sense_key zip[id].sense[2] -#define zip_asc zip[id].sense[12] -#define zip_ascq zip[id].sense[13] -#define zip_drive zip_drives[id].host_drive +#define zip_sense_error zip[id]->sense[0] +#define zip_sense_key zip[id]->sense[2] +#define zip_asc zip[id]->sense[12] +#define zip_ascq zip[id]->sense[13] #ifdef __cplusplus extern "C" { #endif -extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length); -extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length); -extern void (*ide_bus_master_set_irq)(int channel); +extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +extern void (*ide_bus_master_set_irq)(int channel, void *priv); +extern void *ide_bus_master_priv[2]; extern void ioctl_close(uint8_t id); extern uint32_t zip_mode_sense_get_channel(uint8_t id, int channel); @@ -183,8 +130,6 @@ extern void zip_phase_callback(uint8_t id); extern uint32_t zip_read(uint8_t channel, int length); extern void zip_write(uint8_t channel, uint32_t val, int length); -extern int zip_lba_to_msf_accurate(int lba); - extern void zip_close(uint8_t id); extern void zip_disk_reload(uint8_t id); extern void zip_reset(uint8_t id); @@ -200,6 +145,8 @@ extern void zip_global_init(void); extern void zip_hard_reset(void); extern int zip_load(uint8_t id, wchar_t *fn); + +extern void zip_destroy_drives(void); extern void zip_close(uint8_t id); #ifdef __cplusplus diff --git a/src/dma.c b/src/dma.c index 89fcb9c8a..ef07c6137 100644 --- a/src/dma.c +++ b/src/dma.c @@ -1,20 +1,40 @@ /* - * 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. + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. * - * This file is part of the 86Box distribution. + * This file is part of the VARCem Project. * * Implementation of the Intel DMA controllers. * - * Version: @(#)dma.c 1.0.8 2018/03/11 + * Version: @(#)dma.c 1.0.3 2018/03/13 * - * Authors: Sarah Walker, + * Authors: Fred N. van Kempen, * Miran Grca, + * Sarah Walker, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. */ #include #include @@ -30,824 +50,868 @@ #include "dma.h" -static uint8_t dmaregs[16]; -static uint8_t dma16regs[16]; -static uint8_t dmapages[16]; +dma_t dma[8]; -dma_t dma[8]; -static int dma_wp, dma16_wp; -static uint8_t dma_m; -static uint8_t dma_stat; -static uint8_t dma_stat_rq; -static uint8_t dma_command, dma16_command; +static uint8_t dmaregs[16]; +static uint8_t dma16regs[16]; +static uint8_t dmapages[16]; +static int dma_wp, + dma16_wp; +static uint8_t dma_m; +static uint8_t dma_stat; +static uint8_t dma_stat_rq; +static uint8_t dma_command, + dma16_command; +static struct { + int xfr_command, + xfr_channel; + int byte_ptr; -static struct -{ - int xfr_command, xfr_channel; - int byte_ptr; - - int is_ps2; + int is_ps2; } dma_ps2; -#define DMA_PS2_IOA (1 << 0) -#define DMA_PS2_XFER_MEM_TO_IO (1 << 2) -#define DMA_PS2_XFER_IO_TO_MEM (3 << 2) -#define DMA_PS2_XFER_MASK (3 << 2) -#define DMA_PS2_DEC2 (1 << 4) -#define DMA_PS2_SIZE16 (1 << 6) + +#define DMA_PS2_IOA (1 << 0) +#define DMA_PS2_XFER_MEM_TO_IO (1 << 2) +#define DMA_PS2_XFER_IO_TO_MEM (3 << 2) +#define DMA_PS2_XFER_MASK (3 << 2) +#define DMA_PS2_DEC2 (1 << 4) +#define DMA_PS2_SIZE16 (1 << 6) + static void dma_ps2_run(int channel); -void dma_reset(void) + +static uint8_t +dma_read(uint16_t addr, void *priv) { - int c; - - dma_wp = dma16_wp = 0; - dma_m = 0; - - for (c = 0; c < 16; c++) - dmaregs[c] = 0; - for (c = 0; c < 8; c++) - { - dma[c].mode = 0; - dma[c].ac = 0; - dma[c].cc = 0; - dma[c].ab = 0; - dma[c].cb = 0; - dma[c].size = (c & 4) ? 1 : 0; + int channel = (addr >> 1) & 3; + uint8_t temp; + + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma_wp ^= 1; + if (dma_wp) + return(dma[channel].ac & 0xff); + return((dma[channel].ac >> 8) & 0xff); + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma_wp ^= 1; + if (dma_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; + return(temp); + + case 8: /*Status register*/ + temp = dma_stat & 0xf; + dma_stat &= ~0xf; + return(temp); + + case 0xd: + return(0); + } + + return(dmaregs[addr & 0xf]); +} + + +static void +dma_write(uint16_t addr, uint8_t val, void *priv) +{ + int channel = (addr >> 1) & 3; + + dmaregs[addr & 0xf] = val; + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma_wp ^= 1; + if (dma_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + dma[channel].ac = dma[channel].ab; + return; + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma_wp ^= 1; + if (dma_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; + return; + + case 8: /*Control register*/ + dma_command = val; + return; + + case 0xa: /*Mask*/ + if (val & 4) + dma_m |= (1 << (val & 3)); + else + dma_m &= ~(1 << (val & 3)); + return; + + case 0xb: /*Mode*/ + channel = (val & 3); + dma[channel].mode = val; + if (dma_ps2.is_ps2) { + dma[channel].ps2_mode &= ~0x1c; + if (val & 0x20) + dma[channel].ps2_mode |= 0x10; + if ((val & 0xc) == 8) + dma[channel].ps2_mode |= 4; + else if ((val & 0xc) == 4) + dma[channel].ps2_mode |= 0xc; + } + return; + + case 0xc: /*Clear FF*/ + dma_wp = 0; + return; + + case 0xd: /*Master clear*/ + dma_wp = 0; + dma_m |= 0xf; + return; + + case 0xf: /*Mask write*/ + dma_m = (dma_m & 0xf0) | (val & 0xf); + return; + } +} + + +static uint8_t +dma_ps2_read(uint16_t addr, void *priv) +{ + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; + uint8_t temp = 0xff; + + switch (addr) { + case 0x1a: + switch (dma_ps2.xfr_command) { + case 2: /*Address*/ + case 3: + switch (dma_ps2.byte_ptr) { + case 0: + temp = dma_c->ac & 0xff; + dma_ps2.byte_ptr = 1; + break; + case 1: + temp = (dma_c->ac >> 8) & 0xff; + dma_ps2.byte_ptr = 2; + break; + case 2: + temp = (dma_c->ac >> 16) & 0xff; + dma_ps2.byte_ptr = 0; + break; + } + break; + + case 4: /*Count*/ + case 5: + if (dma_ps2.byte_ptr) + temp = dma_c->cc >> 8; + else + temp = dma_c->cc & 0xff; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + + case 6: /*Read DMA status*/ + if (dma_ps2.byte_ptr) { + temp = ((dma_stat_rq & 0xf0) >> 4) | (dma_stat & 0xf0); + dma_stat &= ~0xf0; + dma_stat_rq &= ~0xf0; + } else { + temp = (dma_stat_rq & 0xf) | ((dma_stat & 0xf) << 4); + dma_stat &= ~0xf; + dma_stat_rq &= ~0xf; + } + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + + case 7: /*Mode*/ + temp = dma_c->ps2_mode; + break; + + case 8: /*Arbitration Level*/ + temp = dma_c->arb_level; + break; + + default: + fatal("Bad XFR Read command %i channel %i\n", dma_ps2.xfr_command, dma_ps2.xfr_channel); + } + break; + } + + return(temp); +} + + +static void +dma_ps2_write(uint16_t addr, uint8_t val, void *priv) +{ + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; + uint8_t mode; + + switch (addr) { + case 0x18: + dma_ps2.xfr_channel = val & 0x7; + dma_ps2.xfr_command = val >> 4; + dma_ps2.byte_ptr = 0; + switch (dma_ps2.xfr_command) { + case 9: /*Set DMA mask*/ + dma_m |= (1 << dma_ps2.xfr_channel); + break; + + case 0xa: /*Reset DMA mask*/ + dma_m &= ~(1 << dma_ps2.xfr_channel); + break; + + case 0xb: + if (!(dma_m & (1 << dma_ps2.xfr_channel))) + dma_ps2_run(dma_ps2.xfr_channel); + break; + } + break; + + case 0x1a: + switch (dma_ps2.xfr_command) { + case 0: /*I/O address*/ + if (dma_ps2.byte_ptr) + dma_c->io_addr = (dma_c->io_addr & 0x00ff) | (val << 8); + else + dma_c->io_addr = (dma_c->io_addr & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + + case 2: /*Address*/ + switch (dma_ps2.byte_ptr) { + case 0: + dma_c->ac = (dma_c->ac & 0xffff00) | val; + dma_ps2.byte_ptr = 1; + break; + + case 1: + dma_c->ac = (dma_c->ac & 0xff00ff) | (val << 8); + dma_ps2.byte_ptr = 2; + break; + + case 2: + dma_c->ac = (dma_c->ac & 0x00ffff) | (val << 16); + dma_ps2.byte_ptr = 0; + break; + } + dma_c->ab = dma_c->ac; + break; + + case 4: /*Count*/ + if (dma_ps2.byte_ptr) + dma_c->cc = (dma_c->cc & 0xff) | (val << 8); + else + dma_c->cc = (dma_c->cc & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + dma_c->cb = dma_c->cc; + break; + + case 7: /*Mode register*/ + mode = 0; + if (val & DMA_PS2_DEC2) + mode |= 0x20; + if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_MEM_TO_IO) + mode |= 8; + else if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_IO_TO_MEM) + mode |= 4; + dma_c->mode = (dma_c->mode & ~0x2c) | mode; + dma_c->ps2_mode = val; + dma_c->size = val & DMA_PS2_SIZE16; + break; + + case 8: /*Arbitration Level*/ + dma_c->arb_level = val; + break; + + default: + fatal("Bad XFR command %i channel %i val %02x\n", dma_ps2.xfr_command, dma_ps2.xfr_channel, val); + } + break; + } +} + + +static uint8_t +dma16_read(uint16_t addr, void *priv) +{ + int channel = ((addr >> 2) & 3) + 4; + uint8_t temp; + + addr >>= 1; + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { + if (dma16_wp) + return(dma[channel].ac); + return((dma[channel].ac >> 8) & 0xff); + } + if (dma16_wp) + return((dma[channel].ac >> 1) & 0xff); + return((dma[channel].ac >> 9) & 0xff); + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma16_wp ^= 1; + if (dma16_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; + return(temp); + + case 8: /*Status register*/ + temp = dma_stat >> 4; + dma_stat &= ~0xf0; + return(temp); + } + + return(dma16regs[addr & 0xf]); +} + + +static void +dma16_write(uint16_t addr, uint8_t val, void *priv) +{ + int channel = ((addr >> 2) & 3) + 4; + addr >>= 1; + + dma16regs[addr & 0xf] = val; + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + } else { + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xfffe00) | (val << 1); + else + dma[channel].ab = (dma[channel].ab & 0xfe01ff) | (val << 9); + } + dma[channel].ac = dma[channel].ab; + return; + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma16_wp ^= 1; + if (dma16_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; + return; + + case 8: /*Control register*/ + return; + + case 0xa: /*Mask*/ + if (val & 4) + dma_m |= (0x10 << (val & 3)); + else + dma_m &= ~(0x10 << (val & 3)); + return; + + case 0xb: /*Mode*/ + channel = (val & 3) + 4; + dma[channel].mode = val; + if (dma_ps2.is_ps2) { + dma[channel].ps2_mode &= ~0x1c; + if (val & 0x20) + dma[channel].ps2_mode |= 0x10; + if ((val & 0xc) == 8) + dma[channel].ps2_mode |= 4; + else if ((val & 0xc) == 4) + dma[channel].ps2_mode |= 0xc; + } + return; + + case 0xc: /*Clear FF*/ + dma16_wp = 0; + return; + + case 0xd: /*Master clear*/ + dma16_wp = 0; + dma_m |= 0xf0; + return; + + case 0xf: /*Mask write*/ + dma_m = (dma_m & 0x0f) | ((val & 0xf) << 4); + return; + } +} + + +static void +dma_page_write(uint16_t addr, uint8_t val, void *priv) +{ + dmapages[addr & 0xf] = val; + + switch (addr & 0xf) { + case 1: + dma[2].page = (AT) ? val : val & 0xf; + dma[2].ab = (dma[2].ab & 0xffff) | (dma[2].page << 16); + dma[2].ac = (dma[2].ac & 0xffff) | (dma[2].page << 16); + break; + + case 2: + dma[3].page = (AT) ? val : val & 0xf; + dma[3].ab = (dma[3].ab & 0xffff) | (dma[3].page << 16); + dma[3].ac = (dma[3].ac & 0xffff) | (dma[3].page << 16); + break; + + case 3: + dma[1].page = (AT) ? val : val & 0xf; + dma[1].ab = (dma[1].ab & 0xffff) | (dma[1].page << 16); + dma[1].ac = (dma[1].ac & 0xffff) | (dma[1].page << 16); + break; + + case 7: + dma[0].page = (AT) ? val : val & 0xf; + dma[0].ab = (dma[0].ab & 0xffff) | (dma[0].page << 16); + dma[0].ac = (dma[0].ac & 0xffff) | (dma[0].page << 16); + break; + + case 0x9: + dma[6].page = val & 0xfe; + dma[6].ab = (dma[6].ab & 0x1ffff) | (dma[6].page << 16); + dma[6].ac = (dma[6].ac & 0x1ffff) | (dma[6].page << 16); + break; + + case 0xa: + dma[7].page = val & 0xfe; + dma[7].ab = (dma[7].ab & 0x1ffff) | (dma[7].page << 16); + dma[7].ac = (dma[7].ac & 0x1ffff) | (dma[7].page << 16); + break; + + case 0xb: + dma[5].page = val & 0xfe; + dma[5].ab = (dma[5].ab & 0x1ffff) | (dma[5].page << 16); + dma[5].ac = (dma[5].ac & 0x1ffff) | (dma[5].page << 16); + break; + + case 0xf: + dma[4].page = val & 0xfe; + dma[4].ab = (dma[4].ab & 0x1ffff) | (dma[4].page << 16); + dma[4].ac = (dma[4].ac & 0x1ffff) | (dma[4].page << 16); + break; + } +} + + +static uint8_t +dma_page_read(uint16_t addr, void *priv) +{ + return(dmapages[addr & 0xf]); +} + + +void +dma_reset(void) +{ + int c; + + dma_wp = dma16_wp = 0; + dma_m = 0; + + for (c = 0; c < 16; c++) + dmaregs[c] = 0; + for (c = 0; c < 8; c++) { + dma[c].mode = 0; + dma[c].ac = 0; + dma[c].cc = 0; + dma[c].ab = 0; + dma[c].cb = 0; + dma[c].size = (c & 4) ? 1 : 0; + } +} + + +void +dma_init(void) +{ + io_sethandler(0x0000, 16, + dma_read,NULL,NULL, dma_write,NULL,NULL, NULL); + io_sethandler(0x0080, 8, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + dma_ps2.is_ps2 = 0; +} + + +void +dma16_init(void) +{ + io_sethandler(0x00C0, 32, + dma16_read,NULL,NULL, dma16_write,NULL,NULL, NULL); + io_sethandler(0x0088, 8, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + +void +dma_alias_set(void) +{ + io_sethandler(0x0090, 16, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + +void +dma_alias_remove(void) +{ + io_removehandler(0x0090, 16, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + +void +dma_alias_remove_piix(void) +{ + io_removehandler(0x0090, 1, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_removehandler(0x0094, 3, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_removehandler(0x0098, 1, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_removehandler(0x009C, 3, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + +void +ps2_dma_init(void) +{ + io_sethandler(0x0018, 1, + dma_ps2_read,NULL,NULL, dma_ps2_write,NULL,NULL, NULL); + io_sethandler(0x001a, 1, + dma_ps2_read,NULL,NULL, dma_ps2_write,NULL,NULL, NULL); + dma_ps2.is_ps2 = 1; +} + + +uint8_t +_dma_read(uint32_t addr) +{ + uint8_t temp = mem_readb_phys_dma(addr); + + return(temp); +} + + +void +_dma_write(uint32_t addr, uint8_t val) +{ + mem_writeb_phys_dma(addr, val); + mem_invalidate_range(addr, addr); +} + + +int +dma_channel_read(int channel) +{ + dma_t *dma_c = &dma[channel]; + uint16_t temp; + int tc = 0; + + if (channel < 4) { + if (dma_command & 0x04) + return(DMA_NODATA); + } else { + if (dma16_command & 0x04) + return(DMA_NODATA); + } + + if (! AT) + refreshread(); + + if (dma_m & (1 << channel)) + return(DMA_NODATA); + if ((dma_c->mode & 0xC) != 8) + return(DMA_NODATA); + + if (! dma_c->size) { + temp = _dma_read(dma_c->ac); + + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac--; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac++; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); } -} + } else { + temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); -uint8_t dma_read(uint16_t addr, void *priv) -{ - int channel = (addr >> 1) & 3; - uint8_t temp; - switch (addr & 0xf) - { - case 0: case 2: case 4: case 6: /*Address registers*/ - dma_wp ^= 1; - if (dma_wp) - return dma[channel].ac & 0xff; - return (dma[channel].ac >> 8) & 0xff; - - case 1: case 3: case 5: case 7: /*Count registers*/ - dma_wp ^= 1; - if (dma_wp) - temp = dma[channel].cc & 0xff; - else - temp = dma[channel].cc >> 8; - return temp; - - case 8: /*Status register*/ - temp = dma_stat & 0xf; - dma_stat &= ~0xf; - return temp; - - case 0xd: - return 0; - } - return dmaregs[addr & 0xf]; -} - -void dma_write(uint16_t addr, uint8_t val, void *priv) -{ - int channel = (addr >> 1) & 3; - dmaregs[addr & 0xf] = val; - switch (addr & 0xf) - { - case 0: case 2: case 4: case 6: /*Address registers*/ - dma_wp ^= 1; - if (dma_wp) - dma[channel].ab = (dma[channel].ab & 0xffff00) | val; - else - dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); - dma[channel].ac = dma[channel].ab; - return; - - case 1: case 3: case 5: case 7: /*Count registers*/ - dma_wp ^= 1; - if (dma_wp) - dma[channel].cb = (dma[channel].cb & 0xff00) | val; - else - dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); - dma[channel].cc = dma[channel].cb; - return; - - case 8: /*Control register*/ - dma_command = val; - return; - - case 0xa: /*Mask*/ - if (val & 4) - dma_m |= (1 << (val & 3)); - else - dma_m &= ~(1 << (val & 3)); - return; - - case 0xb: /*Mode*/ - channel = (val & 3); - dma[channel].mode = val; - if (dma_ps2.is_ps2) - { - dma[channel].ps2_mode &= ~0x1c; - if (val & 0x20) - dma[channel].ps2_mode |= 0x10; - if ((val & 0xc) == 8) - dma[channel].ps2_mode |= 4; - else if ((val & 0xc) == 4) - dma[channel].ps2_mode |= 0xc; - } - return; - - case 0xc: /*Clear FF*/ - dma_wp = 0; - return; - - case 0xd: /*Master clear*/ - dma_wp = 0; - dma_m |= 0xf; - return; - - case 0xf: /*Mask write*/ - dma_m = (dma_m & 0xf0) | (val & 0xf); - return; - } -} - -static uint8_t dma_ps2_read(uint16_t addr, void *priv) -{ - dma_t *dma_c = &dma[dma_ps2.xfr_channel]; - uint8_t temp = 0xff; - - switch (addr) - { - case 0x1a: - switch (dma_ps2.xfr_command) - { - case 2: /*Address*/ - case 3: - switch (dma_ps2.byte_ptr) - { - case 0: - temp = dma_c->ac & 0xff; - dma_ps2.byte_ptr = 1; - break; - case 1: - temp = (dma_c->ac >> 8) & 0xff; - dma_ps2.byte_ptr = 2; - break; - case 2: - temp = (dma_c->ac >> 16) & 0xff; - dma_ps2.byte_ptr = 0; - break; - } - break; - case 4: /*Count*/ - case 5: - if (dma_ps2.byte_ptr) - temp = dma_c->cc >> 8; - else - temp = dma_c->cc & 0xff; - dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; - break; - case 6: /*Read DMA status*/ - if (dma_ps2.byte_ptr) - { - temp = ((dma_stat_rq & 0xf0) >> 4) | (dma_stat & 0xf0); - dma_stat &= ~0xf0; - dma_stat_rq &= ~0xf0; - } - else - { - temp = (dma_stat_rq & 0xf) | ((dma_stat & 0xf) << 4); - dma_stat &= ~0xf; - dma_stat_rq &= ~0xf; - } - dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; - break; - case 7: /*Mode*/ - temp = dma_c->ps2_mode; - break; - case 8: /*Arbitration Level*/ - temp = dma_c->arb_level; - break; - - default: - fatal("Bad XFR Read command %i channel %i\n", dma_ps2.xfr_command, dma_ps2.xfr_channel); - } - break; - } - - return temp; -} - -static void dma_ps2_write(uint16_t addr, uint8_t val, void *priv) -{ - dma_t *dma_c = &dma[dma_ps2.xfr_channel]; - uint8_t mode; - - switch (addr) - { - case 0x18: - dma_ps2.xfr_channel = val & 0x7; - dma_ps2.xfr_command = val >> 4; - dma_ps2.byte_ptr = 0; - switch (dma_ps2.xfr_command) - { - case 9: /*Set DMA mask*/ - dma_m |= (1 << dma_ps2.xfr_channel); - break; - case 0xa: /*Reset DMA mask*/ - dma_m &= ~(1 << dma_ps2.xfr_channel); - break; - case 0xb: - if (!(dma_m & (1 << dma_ps2.xfr_channel))) - dma_ps2_run(dma_ps2.xfr_channel); - break; - } - break; - case 0x1a: - switch (dma_ps2.xfr_command) - { - case 0: /*I/O address*/ - if (dma_ps2.byte_ptr) - dma_c->io_addr = (dma_c->io_addr & 0x00ff) | (val << 8); - else - dma_c->io_addr = (dma_c->io_addr & 0xff00) | val; - dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; - break; - - case 2: /*Address*/ - switch (dma_ps2.byte_ptr) - { - case 0: - dma_c->ac = (dma_c->ac & 0xffff00) | val; - dma_ps2.byte_ptr = 1; - break; - case 1: - dma_c->ac = (dma_c->ac & 0xff00ff) | (val << 8); - dma_ps2.byte_ptr = 2; - break; - case 2: - dma_c->ac = (dma_c->ac & 0x00ffff) | (val << 16); - dma_ps2.byte_ptr = 0; - break; - } - dma_c->ab = dma_c->ac; - break; - - case 4: /*Count*/ - if (dma_ps2.byte_ptr) - dma_c->cc = (dma_c->cc & 0xff) | (val << 8); - else - dma_c->cc = (dma_c->cc & 0xff00) | val; - dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; - dma_c->cb = dma_c->cc; - break; - - case 7: /*Mode register*/ - mode = 0; - if (val & DMA_PS2_DEC2) - mode |= 0x20; - if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_MEM_TO_IO) - mode |= 8; - else if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_IO_TO_MEM) - mode |= 4; - dma_c->mode = (dma_c->mode & ~0x2c) | mode; - dma_c->ps2_mode = val; - dma_c->size = val & DMA_PS2_SIZE16; - break; - - case 8: /*Arbitration Level*/ - dma_c->arb_level = val; - break; - - default: - fatal("Bad XFR command %i channel %i val %02x\n", dma_ps2.xfr_command, dma_ps2.xfr_channel, val); - } - break; - } -} - -uint8_t dma16_read(uint16_t addr, void *priv) -{ - int channel = ((addr >> 2) & 3) + 4; - uint8_t temp; - addr >>= 1; - switch (addr & 0xf) - { - case 0: case 2: case 4: case 6: /*Address registers*/ - dma16_wp ^= 1; - if (dma_ps2.is_ps2) - { - if (dma16_wp) - return dma[channel].ac; - return (dma[channel].ac >> 8) & 0xff; - } - if (dma16_wp) - return (dma[channel].ac >> 1) & 0xff; - return (dma[channel].ac >> 9) & 0xff; - - case 1: case 3: case 5: case 7: /*Count registers*/ - dma16_wp ^= 1; - if (dma16_wp) - temp = dma[channel].cc & 0xff; - else - temp = dma[channel].cc >> 8; - return temp; - - case 8: /*Status register*/ - temp = dma_stat >> 4; - dma_stat &= ~0xf0; - return temp; - } - return dma16regs[addr & 0xf]; -} - -void dma16_write(uint16_t addr, uint8_t val, void *priv) -{ - int channel = ((addr >> 2) & 3) + 4; - addr >>= 1; - dma16regs[addr & 0xf] = val; - switch (addr & 0xf) - { - case 0: case 2: case 4: case 6: /*Address registers*/ - dma16_wp ^= 1; - if (dma_ps2.is_ps2) - { - if (dma16_wp) - dma[channel].ab = (dma[channel].ab & 0xffff00) | val; - else - dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); - } - else - { - if (dma16_wp) - dma[channel].ab = (dma[channel].ab & 0xfffe00) | (val << 1); - else - dma[channel].ab = (dma[channel].ab & 0xfe01ff) | (val << 9); - } - dma[channel].ac = dma[channel].ab; - return; - - case 1: case 3: case 5: case 7: /*Count registers*/ - dma16_wp ^= 1; - if (dma16_wp) - dma[channel].cb = (dma[channel].cb & 0xff00) | val; - else - dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); - dma[channel].cc = dma[channel].cb; - return; - - case 8: /*Control register*/ - return; - - case 0xa: /*Mask*/ - if (val & 4) - dma_m |= (0x10 << (val & 3)); - else - dma_m &= ~(0x10 << (val & 3)); - return; - - case 0xb: /*Mode*/ - channel = (val & 3) + 4; - dma[channel].mode = val; - if (dma_ps2.is_ps2) - { - dma[channel].ps2_mode &= ~0x1c; - if (val & 0x20) - dma[channel].ps2_mode |= 0x10; - if ((val & 0xc) == 8) - dma[channel].ps2_mode |= 4; - else if ((val & 0xc) == 4) - dma[channel].ps2_mode |= 0xc; - } - return; - - case 0xc: /*Clear FF*/ - dma16_wp = 0; - return; - - case 0xd: /*Master clear*/ - dma16_wp = 0; - dma_m |= 0xf0; - return; - - case 0xf: /*Mask write*/ - dma_m = (dma_m & 0x0f) | ((val & 0xf) << 4); - return; - } -} - - -void dma_page_write(uint16_t addr, uint8_t val, void *priv) -{ - dmapages[addr & 0xf] = val; - switch (addr & 0xf) - { - case 1: - dma[2].page = (AT) ? val : val & 0xf; - dma[2].ab = (dma[2].ab & 0xffff) | (dma[2].page << 16); - dma[2].ac = (dma[2].ac & 0xffff) | (dma[2].page << 16); - break; - case 2: - dma[3].page = (AT) ? val : val & 0xf; - dma[3].ab = (dma[3].ab & 0xffff) | (dma[3].page << 16); - dma[3].ac = (dma[3].ac & 0xffff) | (dma[3].page << 16); - break; - case 3: - dma[1].page = (AT) ? val : val & 0xf; - dma[1].ab = (dma[1].ab & 0xffff) | (dma[1].page << 16); - dma[1].ac = (dma[1].ac & 0xffff) | (dma[1].page << 16); - break; - case 7: - dma[0].page = (AT) ? val : val & 0xf; - dma[0].ab = (dma[0].ab & 0xffff) | (dma[0].page << 16); - dma[0].ac = (dma[0].ac & 0xffff) | (dma[0].page << 16); - break; - case 0x9: - dma[6].page = val & 0xfe; - dma[6].ab = (dma[6].ab & 0x1ffff) | (dma[6].page << 16); - dma[6].ac = (dma[6].ac & 0x1ffff) | (dma[6].page << 16); - break; - case 0xa: - dma[7].page = val & 0xfe; - dma[7].ab = (dma[7].ab & 0x1ffff) | (dma[7].page << 16); - dma[7].ac = (dma[7].ac & 0x1ffff) | (dma[7].page << 16); - break; - case 0xb: - dma[5].page = val & 0xfe; - dma[5].ab = (dma[5].ab & 0x1ffff) | (dma[5].page << 16); - dma[5].ac = (dma[5].ac & 0x1ffff) | (dma[5].page << 16); - break; - case 0xf: - dma[4].page = val & 0xfe; - dma[4].ab = (dma[4].ab & 0x1ffff) | (dma[4].page << 16); - dma[4].ac = (dma[4].ac & 0x1ffff) | (dma[4].page << 16); - break; - } -} - -uint8_t dma_page_read(uint16_t addr, void *priv) -{ - return dmapages[addr & 0xf]; -} - -void dma_init(void) -{ - io_sethandler(0x0000, 0x0010, dma_read, NULL, NULL, dma_write, NULL, NULL, NULL); - io_sethandler(0x0080, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); - dma_ps2.is_ps2 = 0; -} - -void dma16_init(void) -{ - io_sethandler(0x00C0, 0x0020, dma16_read, NULL, NULL, dma16_write, NULL, NULL, NULL); - io_sethandler(0x0088, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); -} - -void dma_alias_set(void) -{ - io_sethandler(0x0090, 0x0010, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); -} - -void dma_alias_remove(void) -{ - io_removehandler(0x0090, 0x0010, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); -} - -void dma_alias_remove_piix(void) -{ - io_removehandler(0x0090, 0x0001, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); - io_removehandler(0x0094, 0x0003, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); - io_removehandler(0x0098, 0x0001, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); - io_removehandler(0x009C, 0x0003, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); -} - -void ps2_dma_init(void) -{ - io_sethandler(0x0018, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); - io_sethandler(0x001a, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); - dma_ps2.is_ps2 = 1; -} - - -uint8_t _dma_read(uint32_t addr) -{ - uint8_t temp = mem_readb_phys_dma(addr); - return temp; -} - -void _dma_write(uint32_t addr, uint8_t val) -{ - mem_writeb_phys_dma(addr, val); - mem_invalidate_range(addr, addr); -} - -int dma_channel_read(int channel) -{ - dma_t *dma_c = &dma[channel]; - uint16_t temp; - int tc = 0; - - if (channel < 4) - { - if (dma_command & 0x04) - return DMA_NODATA; - } - else - { - if (dma16_command & 0x04) - return DMA_NODATA; - } - - if (!AT) - refreshread(); - - if (dma_m & (1 << channel)) - return DMA_NODATA; - if ((dma_c->mode & 0xC) != 8) - return DMA_NODATA; - - if (!dma_c->size) - { - temp = _dma_read(dma_c->ac); - - if (dma_c->mode & 0x20) - { - if (dma_ps2.is_ps2) - dma_c->ac--; - else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); - } - else - { - if (dma_ps2.is_ps2) - dma_c->ac++; - else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); - } - } - else - { - temp = _dma_read(dma_c->ac) | - (_dma_read(dma_c->ac + 1) << 8); - - if (dma_c->mode & 0x20) - { - if (dma_ps2.is_ps2) - dma_c->ac -= 2; - else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); - } - else - { - if (dma_ps2.is_ps2) - dma_c->ac += 2; - else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); - } - } - - dma_stat_rq |= (1 << channel); - - dma_c->cc--; - if (dma_c->cc < 0) - { - tc = 1; - if (dma_c->mode & 0x10) /*Auto-init*/ - { - dma_c->cc = dma_c->cb; - dma_c->ac = dma_c->ab; - } - else - dma_m |= (1 << channel); - dma_stat |= (1 << channel); - } - - if (tc) - return temp | DMA_OVER; - return temp; -} - -int dma_channel_write(int channel, uint16_t val) -{ - dma_t *dma_c = &dma[channel]; - - if (channel < 4) - { - if (dma_command & 0x04) - return DMA_NODATA; - } - else - { - if (dma16_command & 0x04) - return DMA_NODATA; - } - - if (!AT) - refreshread(); - - if (dma_m & (1 << channel)) - return DMA_NODATA; - if ((dma_c->mode & 0xC) != 4) - return DMA_NODATA; - - if (!dma_c->size) - { - _dma_write(dma_c->ac, val); - - if (dma_c->mode & 0x20) - { - if (dma_ps2.is_ps2) - dma_c->ac--; - else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); - } - else - { - if (dma_ps2.is_ps2) - dma_c->ac++; - else - dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); - } - } - else - { - _dma_write(dma_c->ac, val); - _dma_write(dma_c->ac + 1, val >> 8); - - if (dma_c->mode & 0x20) - { - if (dma_ps2.is_ps2) - dma_c->ac -= 2; - else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); - } - else - { - if (dma_ps2.is_ps2) - dma_c->ac += 2; - else - dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); - } - } - - dma_stat_rq |= (1 << channel); - - dma_c->cc--; - if (dma_c->cc < 0) - { - if (dma_c->mode & 0x10) /*Auto-init*/ - { - dma_c->cc = dma_c->cb; - dma_c->ac = dma_c->ab; - } - else - dma_m |= (1 << channel); - dma_stat |= (1 << channel); - } - - if (dma_m & (1 << channel)) - return DMA_OVER; - - return 0; -} - -static void dma_ps2_run(int channel) -{ - dma_t *dma_c = &dma[channel]; - - switch (dma_c->ps2_mode & DMA_PS2_XFER_MASK) - { - case DMA_PS2_XFER_MEM_TO_IO: - do - { - if (!dma_c->size) - { - uint8_t temp = _dma_read(dma_c->ac); - outb(dma_c->io_addr, temp); - - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac--; - else - dma_c->ac++; - } - else - { - uint16_t temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); - outw(dma_c->io_addr, temp); - - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac -= 2; - else - dma_c->ac += 2; - } - - dma_stat_rq |= (1 << channel); - dma_c->cc--; - } while (dma_c->cc > 0); - - dma_stat |= (1 << channel); - break; - - case DMA_PS2_XFER_IO_TO_MEM: - do - { - if (!dma_c->size) - { - uint8_t temp = inb(dma_c->io_addr); - _dma_write(dma_c->ac, temp); - - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac--; - else - dma_c->ac++; - } - else - { - uint16_t temp = inw(dma_c->io_addr); - _dma_write(dma_c->ac, temp & 0xff); - _dma_write(dma_c->ac + 1, temp >> 8); - - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac -= 2; - else - dma_c->ac += 2; - } - - dma_stat_rq |= (1 << channel); - dma_c->cc--; - } while (dma_c->cc > 0); - - ps2_cache_clean(); - dma_stat |= (1 << channel); - break; - - default: /*Memory verify*/ - do - { - if (!dma_c->size) - { - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac--; - else - dma_c->ac++; - } - else - { - if (dma_c->ps2_mode & DMA_PS2_DEC2) - dma_c->ac -= 2; - else - dma_c->ac += 2; - } - - dma_stat_rq |= (1 << channel); - dma->cc--; - } while (dma->cc > 0); - - dma_stat |= (1 << channel); - break; - } -} - -int dma_mode(int channel) -{ - if (channel < 4) - { - return dma[channel].mode; - } - else - { - return dma[channel & 3].mode; + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac -= 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac += 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); } + } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) { + tc = 1; + if (dma_c->mode & 0x10) { /*Auto-init*/ + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } + + if (tc) + return(temp | DMA_OVER); + + return(temp); } + +int +dma_channel_write(int channel, uint16_t val) +{ + dma_t *dma_c = &dma[channel]; + + if (channel < 4) { + if (dma_command & 0x04) + return(DMA_NODATA); + } else { + if (dma16_command & 0x04) + return(DMA_NODATA); + } + + if (! AT) + refreshread(); + + if (dma_m & (1 << channel)) + return(DMA_NODATA); + if ((dma_c->mode & 0xC) != 4) + return(DMA_NODATA); + + if (! dma_c->size) { + _dma_write(dma_c->ac, val & 0xff); + + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac--; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac++; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); + } + } else { + _dma_write(dma_c->ac, val & 0xff); + _dma_write(dma_c->ac + 1, val >> 8); + + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac -= 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac += 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); + } + } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) { + if (dma_c->mode & 0x10) { /*Auto-init*/ + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } + + if (dma_m & (1 << channel)) + return(DMA_OVER); + + return(0); +} + + +static void +dma_ps2_run(int channel) +{ + dma_t *dma_c = &dma[channel]; + + switch (dma_c->ps2_mode & DMA_PS2_XFER_MASK) { + case DMA_PS2_XFER_MEM_TO_IO: + do { + if (! dma_c->size) { + uint8_t temp = _dma_read(dma_c->ac); + + outb(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } else { + uint16_t temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); + + outw(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + dma_stat |= (1 << channel); + break; + + case DMA_PS2_XFER_IO_TO_MEM: + do { + if (! dma_c->size) { + uint8_t temp = inb(dma_c->io_addr); + + _dma_write(dma_c->ac, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } else { + uint16_t temp = inw(dma_c->io_addr); + + _dma_write(dma_c->ac, temp & 0xff); + _dma_write(dma_c->ac + 1, temp >> 8); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + ps2_cache_clean(); + dma_stat |= (1 << channel); + break; + + default: /*Memory verify*/ + do { + if (! dma_c->size) { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } else { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma->cc--; + } while (dma->cc > 0); + + dma_stat |= (1 << channel); + break; + + } +} + + +int +dma_mode(int channel) +{ + if (channel < 4) + return(dma[channel].mode); + else + return(dma[channel & 3].mode); +} + + /* DMA Bus Master Page Read/Write */ -void DMAPageRead(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize) +void +DMAPageRead(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize) { - int i = 0; + uint32_t i = 0; #if 0 - memcpy(DataRead, &ram[PhysAddress], TotalSize); + memcpy(DataRead, &ram[PhysAddress], TotalSize); #else - for (i = 0; i < TotalSize; i++) - DataRead[i] = mem_readb_phys_dma(PhysAddress + i); + for (i = 0; i < TotalSize; i++) + DataRead[i] = mem_readb_phys_dma(PhysAddress + i); #endif } -void DMAPageWrite(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize) + +void +DMAPageWrite(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize) { - int i = 0; + uint32_t i = 0; #if 0 - mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); - memcpy(&ram[PhysAddress], DataWrite, TotalSize); + mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); + memcpy(&ram[PhysAddress], DataWrite, TotalSize); #else - for (i = 0; i < TotalSize; i++) - mem_writeb_phys_dma(PhysAddress + i, DataWrite[i]); + for (i = 0; i < TotalSize; i++) + mem_writeb_phys_dma(PhysAddress + i, DataWrite[i]); - mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); + mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); #endif } diff --git a/src/dma.h b/src/dma.h index 223994a17..32f90c4e7 100644 --- a/src/dma.h +++ b/src/dma.h @@ -1,20 +1,40 @@ /* - * 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. + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. * - * This file is part of the 86Box distribution. + * This file is part of the VARCem Project. * - * Implementation of the Intel DMA controllers. + * Definitions for the Intel DMA controller. * - * Version: @(#)dma.h 1.0.5 2018/03/11 + * Version: @(#)dma.h 1.0.2 2018/03/12 * - * Authors: Sarah Walker, + * Authors: Fred N. van Kempen, * Miran Grca, + * Sarah Walker, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. */ #ifndef EMU_DMA_H # define EMU_DMA_H @@ -25,25 +45,25 @@ #define DMA_VERIFY 0x20000 -/*DMA*/ -typedef struct dma_t -{ - uint32_t ab, ac; - uint16_t cb; - int cc; - int wp; - uint8_t m, mode; - uint8_t page; - uint8_t stat, stat_rq; - uint8_t command; - int size; - - uint8_t ps2_mode; - uint8_t arb_level; - uint16_t io_addr; +typedef struct { + uint32_t ab, ac; + uint16_t cb; + int cc; + int wp; + uint8_t m, mode; + uint8_t page; + uint8_t stat, stat_rq; + uint8_t command; + int size; + + uint8_t ps2_mode; + uint8_t arb_level; + uint16_t io_addr; } dma_t; -extern dma_t dma[8]; + +extern dma_t dma[8]; + extern void dma_init(void); extern void dma16_init(void); diff --git a/src/floppy/fdc.c b/src/floppy/fdc.c index ab4e8c4ef..372d0fbbb 100644 --- a/src/floppy/fdc.c +++ b/src/floppy/fdc.c @@ -9,7 +9,7 @@ * Implementation of the NEC uPD-765 and compatible floppy disk * controller. * - * Version: @(#)fdc.c 1.0.5 2018/03/16 + * Version: @(#)fdc.c 1.0.6 2018/04/12 * * Authors: Miran Grca, * Sarah Walker, @@ -133,10 +133,14 @@ fdc_log(const char *fmt, ...) uint8_t fdc_ps1_525(void) { - if ((romset == ROM_IBMPS1_2011) && fdd_is_525(current_drive)) - return 0x40; - else - return 0; + switch (romset) { + case ROM_IBMPS1_2011: + case ROM_IBMPS1_2121: + case ROM_IBMPS1_2121_ISA: + return fdd_is_525(current_drive) ? 0x40 : 0x00; + default: + return 0x00; + } } @@ -151,6 +155,7 @@ fdc_ctrl_reset(void *p) fdc->lock = 0; fdc->head = 0; fdc->abort = 0; + fdc->step = 0; if (!(fdc->flags & FDC_FLAG_AT)) fdc->rate = 2; } @@ -214,7 +219,7 @@ static void fdc_rate(fdc_t *fdc, int drive); int fdc_get_perp(fdc_t *fdc) { - if (!(fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_PCJR) || (fdc->flags & FDC_FLAG_PS1)) + if (!(fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_PCJR)) return 0; return fdc->perp; @@ -226,7 +231,7 @@ fdc_get_gap2(fdc_t *fdc, int drive) { int auto_gap2 = 22; - if (!(fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_PCJR) || (fdc->flags & FDC_FLAG_PS1)) + if (!(fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_PCJR)) return 22; if (fdc->perp & 3) @@ -715,7 +720,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) case 1: return; case 2: /*DOR*/ - if ((fdc->flags & FDC_FLAG_PCJR)) { + if (fdc->flags & FDC_FLAG_PCJR) { if ((fdc->dor & 0x40) && !(val & 0x40)) { fdc->watchdog_timer = 1000LL * TIMER_USEC; fdc->watchdog_count = 1000LL; @@ -728,6 +733,10 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->interrupt = -1; ui_sb_update_icon(SB_FLOPPY | 0, 0); fdc_ctrl_reset(fdc); + fdd_changed[0] = 1; + fdd_changed[1] = 1; + fdd_changed[2] = 1; + fdd_changed[3] = 1; } if (!fdd_get_flags(0)) val &= 0xfe; @@ -793,6 +802,8 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc->perp &= 0xfc; fdc_ctrl_reset(fdc); } + /* if (fdc->flags & FDC_FLAG_PS1) + fdc->rate = val & 0x03; */ return; case 5: /*Command register*/ if ((fdc->stat & 0xf0) == 0xb0) { @@ -935,7 +946,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_callback(fdc); break; case 0x12: /*Set perpendicular mode*/ - if ((fdc->flags & FDC_FLAG_AT) && !(fdc->flags & FDC_FLAG_PCJR) && !(fdc->flags & FDC_FLAG_PS1)) { + if ((fdc->flags & FDC_FLAG_AT) && !(fdc->flags & FDC_FLAG_PCJR)) { fdc->pnum=0; fdc->ptot=1; fdc->stat |= 0x90; @@ -1055,6 +1066,7 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) fdc_seek(fdc, fdc->drive, -fdc->max_track); fdc_log("Recalibrating...\n"); fdc->time = 5000LL; + fdc->step = fdc->seek_dir = 1; break; case 0x0d: /*Format*/ fdc_rate(fdc, fdc->drive); @@ -1098,14 +1110,17 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) if (fdc->params[1]) { if (fdc->command & 0x40) { /* Relative seek inwards. */ + fdc->seek_dir = 0; fdc_seek(fdc, fdc->drive, fdc->params[1]); fdc->pcn[fdc->params[0] & 3] += fdc->params[1]; } else { /* Relative seek outwards. */ + fdc->seek_dir = 1; fdc_seek(fdc, fdc->drive, -fdc->params[1]); fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; } fdc->time = 5000LL; + fdc->step = 1; } else { fdc->st0 = 0x20 | (fdc->params[0] & 7); fdc->interrupt = -3; @@ -1125,9 +1140,14 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) timer_update_outstanding(); break; } + if (fdc->params[1] > fdc->pcn[fdc->params[0] & 3]) + fdc->seek_dir = 0; + else + fdc->seek_dir = 1; fdc_seek(fdc, fdc->drive, fdc->params[1] - fdc->pcn[fdc->params[0] & 3]); fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; fdc->time = 5000LL; + fdc->step = 1; fdc_log("fdc->time = %i\n", fdc->time); } break; @@ -1154,7 +1174,9 @@ fdc_write(uint16_t addr, uint8_t val, void *priv) case 7: if (!(fdc->flags & FDC_FLAG_AT)) return; - fdc->rate=val&3; + fdc->rate = val & 0x03; + if (fdc->flags & FDC_FLAG_PS1) + fdc->noprec = !!(val & 0x04); return; } } @@ -1171,24 +1193,58 @@ fdc_read(uint16_t addr, void *priv) switch (addr&7) { case 0: /* STA */ - ret = 0xff; + if (fdc->flags & FDC_FLAG_PS1) { + drive = real_drive(fdc, fdc->dor & 3); + ret = 0x00; + /* TODO: + Bit 2: INDEX (best return always 0 as it goes by very fast) + Bit 6: DRQ + */ + if (writeprot[drive]) /* WRITEPROT */ + ret |= 0x01; + if (fdc->seek_dir) /* nDIRECTION */ + ret |= 0x02; + if (!fdd_get_head(drive)) /* nHDSEL */ + ret |= 0x08; + if (fdd_track0(drive)) /* TRK0 */ + ret |= 0x10; + if (fdc->step) /* STEP */ + ret |= 0x20; + if (fdc->fintr || fdc->reset_stat) /* INTR */ + ret |= 0x80; + } else + ret = 0xff; break; case 1: /* STB */ - if (is486) - return 0xff; - drive = real_drive(fdc, fdc->dor & 3); - if (!fdc->enable_3f1) - ret = 0xff; - ret = 0x70; - if (drive) - ret &= ~0x40; - else - ret &= ~0x20; + if (fdc->flags & FDC_FLAG_PS1) { + drive = real_drive(fdc, fdc->dor & 3); + ret = 0x00; + /* -Drive 2 Installed */ + if (!fdd_get_type(1)) + ret |= 80; + /* -Drive Select 1,0 */ + if (drive) + ret |= 0x20; + else + ret |= 0x40; + } else { + if (is486) + return 0xff; + drive = real_drive(fdc, fdc->dor & 3); + if (!fdc->enable_3f1) + ret = 0xff; - if (fdc->dor & 0x10) - ret |= 1; - if (fdc->dor & 0x20) - ret |= 2; + ret = 0x70; + if (drive) + ret &= ~0x40; + else + ret &= ~0x20; + + if (fdc->dor & 0x10) + ret |= 1; + if (fdc->dor & 0x20) + ret |= 2; + } break; case 2: ret = fdc->dor; @@ -1252,13 +1308,27 @@ fdc_read(uint16_t addr, void *priv) break; case 7: /*Disk change*/ drive = real_drive(fdc, fdc->dor & 3); - if (fdc->dor & (0x10 << drive)) - ret = (fdd_changed[drive] || drive_empty[drive])?0x80:0; - else - ret = 0; - if (fdc->flags & FDC_FLAG_DISKCHG_ACTLOW) /*PC2086/3086 seem to reverse this bit*/ - ret ^= 0x80; - ret |= 0x01; + + if (fdc->flags & FDC_FLAG_PS1) { + if (fdc->dor & (0x10 << drive)) { + ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x00 : 0x80; + ret |= (fdc->dor & 0x08); + ret |= (fdc->noprec << 2); + ret |= (fdc->rate & 0x03); + } else + ret = 0x00; + } else { + if (fdc->dor & (0x10 << drive)) + ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x80 : 0x00; + else + ret = 0x00; + if (fdc->flags & FDC_FLAG_DISKCHG_ACTLOW) /*PC2086/3086 seem to reverse this bit*/ + ret ^= 0x80; + + ret |= 0x01; + } + + fdc->step = 0; break; default: ret = 0xFF; @@ -1271,7 +1341,8 @@ static void fdc_poll_common_finish(fdc_t *fdc, int compare, int st5) { fdc_int(fdc); - fdc->fintr = 0; + if (!(fdc->flags & FDC_FLAG_PS1)) + fdc->fintr = 0; fdc->stat = 0xD0; fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->rw_drive; fdc->res[5] = st5; @@ -1530,7 +1601,8 @@ fdc_callback(void *priv) } else { fdc->interrupt = -2; fdc_int(fdc); - fdc->fintr = 0; + if (!(fdc->flags & FDC_FLAG_PS1)) + fdc->fintr = 0; fdc->stat = 0xD0; fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->drive; fdc->res[5] = fdc->res[6] = 0; @@ -1612,7 +1684,8 @@ fdc_error(fdc_t *fdc, int st5, int st6) fdc->time = 0LL; fdc_int(fdc); - fdc->fintr = 0; + if (!(fdc->flags & FDC_FLAG_PS1)) + fdc->fintr = 0; fdc->stat = 0xD0; fdc->st0 = fdc->res[4] = 0x40 | (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->rw_drive; fdc->res[5] = st5; @@ -1977,7 +2050,10 @@ fdc_reset(void *priv) fdc_update_is_nsc(fdc, 0); fdc_update_enh_mode(fdc, 0); - fdc_update_densel_polarity(fdc, 1); + if (fdc->flags & FDC_FLAG_PS1) + fdc_update_densel_polarity(fdc, 0); + else + fdc_update_densel_polarity(fdc, 1); fdc_update_densel_force(fdc, 0); fdc_update_rwc(fdc, 0, default_rwc); fdc_update_rwc(fdc, 1, default_rwc); @@ -1992,7 +2068,7 @@ fdc_reset(void *priv) fdc->fifo = 0; fdc->tfifo = 1; - if ((fdc->flags & FDC_FLAG_PCJR)) { + if (fdc->flags & FDC_FLAG_PCJR) { fdc->dma = 0; fdc->specify[1] = 1; } else { diff --git a/src/floppy/fdc.h b/src/floppy/fdc.h index 0d540e918..dbc3fdd0a 100644 --- a/src/floppy/fdc.h +++ b/src/floppy/fdc.h @@ -9,7 +9,7 @@ * Implementation of the NEC uPD-765 and compatible floppy disk * controller. * - * Version: @(#)fdc.h 1.0.3 2018/03/17 + * Version: @(#)fdc.h 1.0.4 2018/04/12 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -70,6 +70,8 @@ typedef struct { int abort; int format_state, format_n; int tc, written; + int step, seek_dir; + int noprec; int data_ready, inread; int bitcell_period, enh_mode; diff --git a/src/floppy/fdd.c b/src/floppy/fdd.c index 006a6ed87..61e445243 100644 --- a/src/floppy/fdd.c +++ b/src/floppy/fdd.c @@ -8,7 +8,7 @@ * * Implementation of the floppy drive emulation. * - * Version: @(#)fdd.c 1.0.5 2018/03/16 + * Version: @(#)fdd.c 1.0.6 2018/04/10 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -495,7 +495,6 @@ void fdd_close(int drive) drive_empty[drive] = 1; fdd_set_head(drive, 0); floppyfns[drive][0] = 0; - d86f_destroy(drive); drives[drive].hole = NULL; drives[drive].poll = NULL; drives[drive].seek = NULL; @@ -506,6 +505,7 @@ void fdd_close(int drive) drives[drive].format = NULL; drives[drive].byteperiod = NULL; drives[drive].stop = NULL; + d86f_destroy(drive); ui_sb_update_icon_state(drive, 1); } diff --git a/src/floppy/fdd.h b/src/floppy/fdd.h index 7610cee46..70414804f 100644 --- a/src/floppy/fdd.h +++ b/src/floppy/fdd.h @@ -8,7 +8,7 @@ * * Definitions for the floppy drive emulation. * - * Version: @(#)fdd.h 1.0.3 2018/03/17 + * Version: @(#)fdd.h 1.0.4 2018/04/12 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -135,7 +135,6 @@ extern void fdd_format(int drive, int side, int density, uint8_t fill); extern int fdd_hole(int drive); extern double fdd_byteperiod(int drive); extern void fdd_stop(int drive); -extern int fdd_empty(int drive); extern void fdd_set_rate(int drive, int drvden, int rate); extern int motorspin; diff --git a/src/floppy/fdd_86f.c b/src/floppy/fdd_86f.c index ded25f291..13c7c4c54 100644 --- a/src/floppy/fdd_86f.c +++ b/src/floppy/fdd_86f.c @@ -10,7 +10,7 @@ * data in the form of FM/MFM-encoded transitions) which also * forms the core of the emulator's floppy disk emulation. * - * Version: @(#)fdd_86f.c 1.0.7 2018/03/19 + * Version: @(#)fdd_86f.c 1.0.8 2018/04/11 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -46,6 +46,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../config.h" +#include "../device.h" #include "../dma.h" #include "../nvr.h" #include "../random.h" diff --git a/src/intel_piix.c b/src/intel_piix.c index 369d4166b..d57d3d82e 100644 --- a/src/intel_piix.c +++ b/src/intel_piix.c @@ -10,7 +10,7 @@ * word 0 - base address * word 1 - bits 1-15 = byte count, bit 31 = end of transfer * - * Version: @(#)intel_piix.c 1.0.13 2018/02/23 + * Version: @(#)intel_piix.c 1.0.14 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, @@ -18,768 +18,871 @@ * Copyright 2008-2018 Sarah Walker. * Copyright 2016-2018 Miran Grca. */ -#include +#include #include +#include +#include #include #include +#define HAVE_STDARG_H #include "86box.h" +#include "scsi/scsi.h" +#include "cdrom/cdrom.h" #include "dma.h" #include "io.h" #include "device.h" #include "keyboard.h" #include "mem.h" #include "pci.h" +#include "pic.h" #include "disk/hdc.h" #include "disk/hdc_ide.h" +#include "disk/zip.h" #include "piix.h" -uint8_t piix_33 = 0; - -static uint8_t piix_type = 1; -static uint8_t card_piix[256], card_piix_ide[256]; - - -uint8_t piix_bus_master_read(uint16_t port, void *priv); -void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); - - -void piix_write(int func, int addr, uint8_t val, void *priv) +typedef struct { - uint16_t old_base = (card_piix_ide[0x20] & 0xf0) | (card_piix_ide[0x21] << 8); - if (func > 1) - return; - - if (func == 1) /*IDE*/ - { - /* pclog("PIIX IDE write: %02X %02X\n", addr, val); */ + uint8_t command, status, + ptr0; + uint32_t ptr, ptr_cur, + addr; + int count, eot; +} piix_busmaster_t; - switch (addr) - { - case 0x04: - card_piix_ide[0x04] = (val & 5) | 2; - break; - case 0x07: - card_piix_ide[0x07] = val & 0x3e; - break; - case 0x0d: - card_piix_ide[0x0d] = val; - break; - - case 0x20: - card_piix_ide[0x20] = (val & ~0x0f) | 1; - break; - case 0x21: - card_piix_ide[0x21] = val; - break; - - case 0x40: - card_piix_ide[0x40] = val; - break; - case 0x41: - card_piix_ide[0x41] = val; - break; - case 0x42: - card_piix_ide[0x42] = val; - break; - case 0x43: - card_piix_ide[0x43] = val; - break; - case 0x44: - if (piix_type >= 3) card_piix_ide[0x44] = val; - break; - } - if (addr == 4 || (addr & ~3) == 0x20) /*Bus master base address*/ - { - uint16_t base = (card_piix_ide[0x20] & 0xf0) | (card_piix_ide[0x21] << 8); - if (old_base) - io_removehandler(old_base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); - if ((card_piix_ide[0x04] & 1) && base) - io_sethandler(base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); - } - if (addr == 4 || addr == 0x41 || addr == 0x43) - { - ide_pri_disable(); - ide_sec_disable(); - if (card_piix_ide[0x04] & 1) - { - if (card_piix_ide[0x41] & 0x80) - ide_pri_enable(); - if (card_piix_ide[0x43] & 0x80) - ide_sec_enable(); - } - } - } - else - { - /* pclog("PIIX writing value %02X to register %02X\n", val, addr); */ - if ((addr >= 0x0f) && (addr < 0x4c)) - return; +typedef struct +{ + uint8_t type, + regs[256], regs_ide[256]; + piix_busmaster_t bm[2]; +} piix_t; - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: - return; - - case 0x60: - /* pclog("Set IRQ routing: INT A -> %02X\n", val); */ - if (val & 0x80) - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTA, val & 0xf); - break; - case 0x61: - /* pclog("Set IRQ routing: INT B -> %02X\n", val); */ - if (val & 0x80) - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTB, val & 0xf); - break; - case 0x62: - /* pclog("Set IRQ routing: INT C -> %02X\n", val); */ - if (val & 0x80) - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTC, val & 0xf); - break; - case 0x63: - /* pclog("Set IRQ routing: INT D -> %02X\n", val); */ - if (val & 0x80) - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTD, val & 0xf); - break; - case 0x70: - /* pclog("Set MIRQ routing: MIRQ0 -> %02X\n", val); */ - if (val & 0x80) - pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); - else - pci_set_mirq_routing(PCI_MIRQ0, val & 0xf); - break; - /* pclog("MIRQ0 is %s\n", (val & 0x20) ? "disabled" : "enabled"); */ - case 0x71: - if (piix_type == 1) - { - /* pclog("Set MIRQ routing: MIRQ1 -> %02X\n", val); */ - if (val & 0x80) - pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); - else - pci_set_mirq_routing(PCI_MIRQ1, val & 0xf); - } -#if 0 - else - { - pclog("Set unused MIRQ routing: MIRQ1 -> %02X\n", val); - } + +static uint8_t piix_bus_master_read(uint16_t port, void *priv); +static uint16_t piix_bus_master_readw(uint16_t port, void *priv); +static uint32_t piix_bus_master_readl(uint16_t port, void *priv); +static void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); +static void piix_bus_master_writew(uint16_t port, uint16_t val, void *priv); +static void piix_bus_master_writel(uint16_t port, uint32_t val, void *priv); + + +#ifdef ENABLE_PIIX_LOG +int piix_do_log = ENABLE_PIIX_LOG; #endif - break; - } - if (addr == 0x4C) - { - if (!((val ^ card_piix[addr]) & 0x80)) - { - card_piix[addr] = val; - return; - } - card_piix[addr] = val; - if (val & 0x80) - { - if (piix_type == 3) - { - dma_alias_remove(); - } - else - { - dma_alias_remove_piix(); - } - } - else - { - dma_alias_set(); - } - } - else if (addr == 0x4E) - { - keyboard_at_set_mouse_scan((val & 0x10) ? 1 : 0); - card_piix[addr] = val; - } - else if (addr == 0x6A) - { - if (piix_type == 1) - card_piix[addr] = (val & 0xFC) | (card_piix[addr] | 3); - else if (piix_type == 3) - card_piix[addr] = (val & 0xFD) | (card_piix[addr] | 2); - } - else - card_piix[addr] = val; - } + +static void +piix_log(const char *format, ...) +{ +#ifdef ENABLE_PIIX_LOG + va_list ap; + + if (piix_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif } -uint8_t piix_read(int func, int addr, void *priv) -{ - if (func > 1) - return 0xff; - if (func == 1) /*IDE*/ - { - if (addr == 4) - { - return (card_piix_ide[addr] & 5) | 2; - } - else if (addr == 5) - { - return 0; - } - else if (addr == 6) - { - return 0x80; - } - else if (addr == 7) - { - return card_piix_ide[addr] & 0x3E; - } - else if (addr == 0xD) - { - return card_piix_ide[addr] & 0xF0; - } - else if (addr == 0x20) - { - return (card_piix_ide[addr] & 0xF0) | 1; - } - else if (addr == 0x22) - { - return 0; - } - else if (addr == 0x23) - { - return 0; - } - else if (addr == 0x41) - { - if (piix_type == 1) - return card_piix_ide[addr] & 0xB3; - else if (piix_type == 3) - return card_piix_ide[addr] & 0xF3; - } - else if (addr == 0x43) - { - if (piix_type == 1) - return card_piix_ide[addr] & 0xB3; - else if (piix_type == 3) - return card_piix_ide[addr] & 0xF3; - } - else - { - return card_piix_ide[addr]; - } - } - else - { - if ((addr & 0xFC) == 0x60) - { - return card_piix[addr] & 0x8F; - } - if (addr == 4) - { - return (card_piix[addr] & 0x80) | 7; - } - else if (addr == 5) - { - if (piix_type == 1) - return 0; - else if (piix_type == 3) - return card_piix[addr] & 1; - } - else if (addr == 6) - { - return card_piix[addr] & 0x80; - } - else if (addr == 7) - { - if (piix_type == 1) - return card_piix[addr] & 0x3E; - else if (piix_type == 3) - return card_piix[addr]; - } - else if (addr == 0x4E) - { - return (card_piix[addr] & 0xEF) | keyboard_at_get_mouse_scan(); - } - else if (addr == 0x69) - { - return card_piix[addr] & 0xFE; - } - else if (addr == 0x6A) - { - if (piix_type == 1) - return card_piix[addr] & 0x07; - else if (piix_type == 3) - return card_piix[addr] & 0xD1; - } - else if (addr == 0x6B) - { - if (piix_type == 1) - return 0; - else if (piix_type == 3) - return card_piix[addr] & 0x80; - } - else if (addr == 0x70) - { - if (piix_type == 1) - return card_piix[addr] & 0xCF; - else if (piix_type == 3) - return card_piix[addr] & 0xEF; - } - else if (addr == 0x71) - { - if (piix_type == 1) - return card_piix[addr] & 0xCF; - else if (piix_type == 3) - return 0; - } - else if (addr == 0x76) - { - if (piix_type == 1) - return card_piix[addr] & 0x8F; - else if (piix_type == 3) - return card_piix[addr] & 0x87; - } - else if (addr == 0x77) - { - if (piix_type == 1) - return card_piix[addr] & 0x8F; - else if (piix_type == 3) - return card_piix[addr] & 0x87; - } - else if (addr == 0x80) - { - if (piix_type == 1) - return 0; - else if (piix_type == 3) - return card_piix[addr] & 0x7F; - } - else if (addr == 0x82) - { - if (piix_type == 1) - return 0; - else if (piix_type == 3) - return card_piix[addr] & 0x0F; - } - else if (addr == 0xA0) - { - return card_piix[addr] & 0x1F; - } - else if (addr == 0xA3) - { - if (piix_type == 1) - return 0; - else if (piix_type == 3) - return card_piix[addr] & 1; - } - else if (addr == 0xA7) - { - if (piix_type == 1) - return card_piix[addr] & 0xEF; - else if (piix_type == 3) - return card_piix[addr]; - } - else if (addr == 0xAB) - { - if (piix_type == 1) - return card_piix[addr] & 0xFE; - else if (piix_type == 3) - return card_piix[addr]; - } - else - return card_piix[addr]; +static void +piix_bus_master_handlers(piix_t *dev, uint16_t old_base) +{ + uint16_t base; + + base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); + io_removehandler(old_base, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[0]); + io_removehandler(old_base + 8, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[1]); + + if ((dev->regs_ide[0x04] & 1) && base) { + io_sethandler(base, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[0]); + io_sethandler(base + 8, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[1]); + } +} + + +static void +piix_write(int func, int addr, uint8_t val, void *priv) +{ + piix_t *dev = (piix_t *) priv; + uint8_t valxor; + + uint16_t old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); + if (func > 1) + return; + + if (func == 1) { /*IDE*/ + piix_log("PIIX IDE write: %02X %02X\n", addr, val); + valxor = val ^ dev->regs_ide[addr]; + + switch (addr) { + case 0x04: + dev->regs_ide[0x04] = (val & 5) | 2; + if (valxor & 0x01) { + ide_pri_disable(); + ide_sec_disable(); + if (val & 0x01) { + if (dev->regs_ide[0x41] & 0x80) + ide_pri_enable(); + if (dev->regs_ide[0x43] & 0x80) + ide_sec_enable(); + } + + piix_bus_master_handlers(dev, old_base); + } + break; + case 0x07: + dev->regs_ide[0x07] = val & 0x3e; + break; + case 0x0d: + dev->regs_ide[0x0d] = val; + break; + + case 0x20: + dev->regs_ide[0x20] = (val & ~0x0f) | 1; + if (valxor) + piix_bus_master_handlers(dev, old_base); + break; + case 0x21: + dev->regs_ide[0x21] = val; + if (valxor) + piix_bus_master_handlers(dev, old_base); + break; + + case 0x40: + dev->regs_ide[0x40] = val; + break; + case 0x41: + dev->regs_ide[0x41] = val; + if (valxor & 0x80) { + ide_pri_disable(); + if ((val & 0x80) && (dev->regs_ide[0x04] & 0x01)) + ide_pri_enable(); + } + break; + case 0x42: + dev->regs_ide[0x42] = val; + break; + case 0x43: + dev->regs_ide[0x43] = val; + if (valxor & 0x80) { + ide_sec_disable(); + if ((val & 0x80) && (dev->regs_ide[0x04] & 0x01)) + ide_sec_enable(); + } + break; + case 0x44: + if (dev->type >= 3) dev->regs_ide[0x44] = val; + break; + } + } else { + piix_log("PIIX writing value %02X to register %02X\n", val, addr); + valxor = val ^ dev->regs[addr]; + + if ((addr >= 0x0f) && (addr < 0x4c)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x4c: + if (valxor) { + if (val & 0x80) { + if (dev->type == 3) + dma_alias_remove(); + else + dma_alias_remove_piix(); + } else + dma_alias_set(); + } + break; + case 0x4e: + keyboard_at_set_mouse_scan((val & 0x10) ? 1 : 0); + break; + case 0x60: + piix_log("Set IRQ routing: INT A -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x61: + piix_log("Set IRQ routing: INT B -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x62: + piix_log("Set IRQ routing: INT C -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x63: + piix_log("Set IRQ routing: INT D -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; + case 0x6a: + if (dev->type == 1) + dev->regs[addr] = (val & 0xFC) | (dev->regs[addr] | 3); + else if (dev->type == 3) + dev->regs[addr] = (val & 0xFD) | (dev->regs[addr] | 2); + return; + case 0x70: + piix_log("Set MIRQ routing: MIRQ0 -> %02X\n", val); + if (val & 0x80) + pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); + else + pci_set_mirq_routing(PCI_MIRQ0, val & 0xf); + break; + piix_log("MIRQ0 is %s\n", (val & 0x20) ? "disabled" : "enabled"); + case 0x71: + if (dev->type == 1) { + piix_log("Set MIRQ routing: MIRQ1 -> %02X\n", val); + if (val & 0x80) + pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); + else + pci_set_mirq_routing(PCI_MIRQ1, val & 0xf); + } + break; } - return 0; + dev->regs[addr] = val; + } } -struct -{ - uint8_t command; - uint8_t status; - uint32_t ptr, ptr_cur; - int count; - uint32_t addr; - int eot; - uint8_t ptr0; -} piix_busmaster[2]; -static void piix_bus_master_next_addr(int channel) +static uint8_t +piix_read(int func, int addr, void *priv) { - DMAPageRead(piix_busmaster[channel].ptr_cur, (uint8_t *)&(piix_busmaster[channel].addr), 4); - DMAPageRead(piix_busmaster[channel].ptr_cur + 4, (uint8_t *)&(piix_busmaster[channel].count), 4); -#if 0 - pclog("PIIX Bus master DWORDs: %08X %08X\n", piix_busmaster[channel].addr, piix_busmaster[channel].count); -#endif - piix_busmaster[channel].eot = piix_busmaster[channel].count >> 31; - piix_busmaster[channel].count &= 0xfffe; - if (!piix_busmaster[channel].count) - piix_busmaster[channel].count = 65536; - piix_busmaster[channel].addr &= 0xfffffffe; - piix_busmaster[channel].ptr_cur += 8; + piix_t *dev = (piix_t *) priv; + + if (func > 1) + return 0xff; + + if (func == 1) { /*IDE*/ + if (addr == 4) + return (dev->regs_ide[addr] & 5) | 2; + else if (addr == 5) + return 0; + else if (addr == 6) + return 0x80; + else if (addr == 7) + return dev->regs_ide[addr] & 0x3E; + else if (addr == 0xD) + return dev->regs_ide[addr] & 0xF0; + else if (addr == 0x20) + return (dev->regs_ide[addr] & 0xF0) | 1; + else if (addr == 0x22) + return 0; + else if (addr == 0x23) + return 0; + else if (addr == 0x41) { + if (dev->type == 1) + return dev->regs_ide[addr] & 0xB3; + else if (dev->type == 3) + return dev->regs_ide[addr] & 0xF3; + } else if (addr == 0x43) { + if (dev->type == 1) + return dev->regs_ide[addr] & 0xB3; + else if (dev->type == 3) + return dev->regs_ide[addr] & 0xF3; + } else + return dev->regs_ide[addr]; + } else { + if ((addr & 0xFC) == 0x60) + return dev->regs[addr] & 0x8F; + + if (addr == 4) + return (dev->regs[addr] & 0x80) | 7; + else if (addr == 5) { + if (dev->type == 1) + return 0; + else if (dev->type == 3) + return dev->regs[addr] & 1; + } else if (addr == 6) + return dev->regs[addr] & 0x80; + else if (addr == 7) { + if (dev->type == 1) + return dev->regs[addr] & 0x3E; + else if (dev->type == 3) + return dev->regs[addr]; + } else if (addr == 0x4E) + return (dev->regs[addr] & 0xEF) | keyboard_at_get_mouse_scan(); + else if (addr == 0x69) + return dev->regs[addr] & 0xFE; + else if (addr == 0x6A) { + if (dev->type == 1) + return dev->regs[addr] & 0x07; + else if (dev->type == 3) + return dev->regs[addr] & 0xD1; + } else if (addr == 0x6B) { + if (dev->type == 1) + return 0; + else if (dev->type == 3) + return dev->regs[addr] & 0x80; + } + else if (addr == 0x70) { + if (dev->type == 1) + return dev->regs[addr] & 0xCF; + else if (dev->type == 3) + return dev->regs[addr] & 0xEF; + } else if (addr == 0x71) { + if (dev->type == 1) + return dev->regs[addr] & 0xCF; + else if (dev->type == 3) + return 0; + } else if (addr == 0x76) { + if (dev->type == 1) + return dev->regs[addr] & 0x8F; + else if (dev->type == 3) + return dev->regs[addr] & 0x87; + } else if (addr == 0x77) { + if (dev->type == 1) + return dev->regs[addr] & 0x8F; + else if (dev->type == 3) + return dev->regs[addr] & 0x87; + } else if (addr == 0x80) { + if (dev->type == 1) + return 0; + else if (dev->type == 3) + return dev->regs[addr] & 0x7F; + } else if (addr == 0x82) { + if (dev->type == 1) + return 0; + else if (dev->type == 3) + return dev->regs[addr] & 0x0F; + } else if (addr == 0xA0) + return dev->regs[addr] & 0x1F; + else if (addr == 0xA3) { + if (dev->type == 1) + return 0; + else if (dev->type == 3) + return dev->regs[addr] & 1; + } else if (addr == 0xA7) { + if (dev->type == 1) + return dev->regs[addr] & 0xEF; + else if (dev->type == 3) + return dev->regs[addr]; + } else if (addr == 0xAB) { + if (dev->type == 1) + return dev->regs[addr] & 0xFE; + else if (dev->type == 3) + return dev->regs[addr]; + } else + return dev->regs[addr]; + } + + return 0; } -void piix_bus_master_write(uint16_t port, uint8_t val, void *priv) + +static void +piix_bus_master_next_addr(piix_busmaster_t *dev) { - /* pclog("PIIX Bus master write: %04X %02X\n", port, val); */ - int channel = (port & 8) ? 1 : 0; - switch (port & 7) { - case 0: - if ((val & 1) && !(piix_busmaster[channel].command & 1)) { /*Start*/ - piix_busmaster[channel].ptr_cur = piix_busmaster[channel].ptr; - piix_bus_master_next_addr(channel); - piix_busmaster[channel].status |= 1; - } - if (!(val & 1) && (piix_busmaster[channel].command & 1)) /*Stop*/ - piix_busmaster[channel].status &= ~1; - - piix_busmaster[channel].command = val; - break; - case 2: - piix_busmaster[channel].status &= 0x07; - piix_busmaster[channel].status |= (val & 0x60); + DMAPageRead(dev->ptr_cur, (uint8_t *)&(dev->addr), 4); + DMAPageRead(dev->ptr_cur + 4, (uint8_t *)&(dev->count), 4); + piix_log("PIIX Bus master DWORDs: %08X %08X\n", dev->addr, dev->count); + dev->eot = dev->count >> 31; + dev->count &= 0xfffe; + if (!dev->count) + dev->count = 65536; + dev->addr &= 0xfffffffe; + dev->ptr_cur += 8; +} + + +static void +piix_bus_master_write(uint16_t port, uint8_t val, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + int channel = (port & 8) ? 1 : 0; + + piix_log("PIIX Bus master BYTE write: %04X %02X\n", port, val); + + switch (port & 7) { + case 0: + piix_log("PIIX Cmd : val = %02X, old = %02X\n", val, dev->command); + if ((val & 1) && !(dev->command & 1)) { /*Start*/ + piix_log("PIIX Bus Master start on channel %i\n", channel); + dev->ptr_cur = dev->ptr; + piix_bus_master_next_addr(dev); + dev->status |= 1; + } + if (!(val & 1) && (dev->command & 1)) { /*Stop*/ + piix_log("PIIX Bus Master stop on channel %i\n", channel); + dev->status &= ~1; + } + + dev->command = val; + break; + case 2: + piix_log("PIIX Status: val = %02X, old = %02X\n", val, dev->status); + dev->status &= 0x07; + dev->status |= (val & 0x60); if (val & 0x04) - piix_busmaster[channel].status &= ~0x04; + dev->status &= ~0x04; if (val & 0x02) - piix_busmaster[channel].status &= ~0x02; - /* piix_busmaster[channel].status = (val & 0x60) | ((piix_busmaster[channel].status & ~val) & 6) | (piix_busmaster[channel].status & 1); */ - break; - case 4: - piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xffffff00) | (val & 0xfc); - piix_busmaster[channel].ptr %= (mem_size * 1024); - piix_busmaster[channel].ptr0 = val; - break; - case 5: - piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xffff00fc) | (val << 8); - piix_busmaster[channel].ptr %= (mem_size * 1024); - break; - case 6: - piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xff00fffc) | (val << 16); - piix_busmaster[channel].ptr %= (mem_size * 1024); - break; - case 7: - piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0x00fffffc) | (val << 24); - piix_busmaster[channel].ptr %= (mem_size * 1024); - break; - - } -} - -uint8_t piix_bus_master_read(uint16_t port, void *priv) -{ - /* pclog("PIIX Bus master read: %04X\n", port); */ - int channel = (port & 8) ? 1 : 0; - switch (port & 7) { - case 0: - return piix_busmaster[channel].command; - case 2: - return piix_busmaster[channel].status & 0x67; - case 4: - return piix_busmaster[channel].ptr0; - case 5: - return piix_busmaster[channel].ptr >> 8; - case 6: - return piix_busmaster[channel].ptr >> 16; - case 7: - return piix_busmaster[channel].ptr >> 24; - } - return 0xff; + dev->status &= ~0x02; + break; + case 4: + dev->ptr = (dev->ptr & 0xffffff00) | (val & 0xfc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val; + break; + case 5: + dev->ptr = (dev->ptr & 0xffff00fc) | (val << 8); + dev->ptr %= (mem_size * 1024); + break; + case 6: + dev->ptr = (dev->ptr & 0xff00fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + case 7: + dev->ptr = (dev->ptr & 0x00fffffc) | (val << 24); + dev->ptr %= (mem_size * 1024); + break; + } } -int piix_bus_master_get_count(int channel) + +static void +piix_bus_master_writew(uint16_t port, uint16_t val, void *priv) { - return piix_busmaster[channel].count; + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + piix_log("PIIX Bus master WORD write: %04X %04X\n", port, val); + + switch (port & 7) { + case 0: + case 2: + piix_bus_master_write(port, val & 0xff, priv); + break; + case 4: + dev->ptr = (dev->ptr & 0xffff0000) | (val & 0xfffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + case 6: + dev->ptr = (dev->ptr & 0x0000fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + } } -int piix_bus_master_get_eot(int channel) + +static void +piix_bus_master_writel(uint16_t port, uint32_t val, void *priv) { - return piix_busmaster[channel].eot; + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + piix_log("PIIX Bus master DWORD write: %04X %08X\n", port, val); + + switch (port & 7) { + case 0: + case 2: + piix_bus_master_write(port, val & 0xff, priv); + break; + case 4: + dev->ptr = (val & 0xfffffffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + } } -int piix_bus_master_dma_read(int channel, uint8_t *data, int transfer_length) + +static uint8_t +piix_bus_master_read(uint16_t port, void *priv) { - int force_end = 0; - int buffer_pos = 0; - - if (!(piix_busmaster[channel].status & 1)) - return 1; /*DMA disabled*/ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; -#if 0 - pclog("PIIX Bus master read: %i bytes\n", transfer_length); -#endif + uint8_t ret = 0xff; - while (1) { - if (piix_busmaster[channel].count <= transfer_length) { -#if 0 - pclog("Writing %i bytes to %08X\n", piix_busmaster[channel].count, piix_busmaster[channel].addr); -#endif - DMAPageWrite(piix_busmaster[channel].addr, (uint8_t *)(data + buffer_pos), piix_busmaster[channel].count); - transfer_length -= piix_busmaster[channel].count; - buffer_pos += piix_busmaster[channel].count; - } else { -#if 0 - pclog("Writing %i bytes to %08X\n", piix_busmaster[channel].count, piix_busmaster[channel].addr); -#endif - DMAPageWrite(piix_busmaster[channel].addr, (uint8_t *)(data + buffer_pos), transfer_length); - transfer_length = 0; - force_end = 1; - } + switch (port & 7) { + case 0: + ret = dev->command; + break; + case 2: + ret = dev->status & 0x67; + break; + case 4: + ret = dev->ptr0; + break; + case 5: + ret = dev->ptr >> 8; + break; + case 6: + ret = dev->ptr >> 16; + break; + case 7: + ret = dev->ptr >> 24; + break; + } - if (force_end) { -#if 0 - pclog("Total transfer length smaller than sum of all blocks, partial block\n"); -#endif - piix_busmaster[channel].status &= ~2; - return 0; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ + piix_log("PIIX Bus master BYTE read : %04X %02X\n", port, ret); + + return ret; +} + + +static uint16_t +piix_bus_master_readw(uint16_t port, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + uint16_t ret = 0xffff; + + switch (port & 7) { + case 0: + case 2: + ret = (uint16_t) piix_bus_master_read(port, priv); + break; + case 4: + ret = dev->ptr0 | (dev->ptr & 0xff00); + break; + case 6: + ret = dev->ptr >> 16; + break; + } + + piix_log("PIIX Bus master WORD read : %04X %04X\n", port, ret); + + return ret; +} + + +static uint32_t +piix_bus_master_readl(uint16_t port, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + uint32_t ret = 0xffffffff; + + switch (port & 7) { + case 0: + case 2: + ret = (uint32_t) piix_bus_master_read(port, priv); + break; + case 4: + ret = dev->ptr0 | (dev->ptr & 0xffffff00); + break; + } + + piix_log("PIIX Bus master DWORD read : %04X %08X\n", port, ret); + + return ret; +} + + +static int +piix_bus_master_dma_op(int channel, uint8_t *data, int transfer_length, int out, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + char *sop; + + int force_end = 0, buffer_pos = 0; + + sop = out ? "Writ" : "Read"; + + if (!(dev->status & 1)) + return 2; /*DMA disabled*/ + + piix_log("PIIX Bus master %s: %i bytes\n", out ? "read" : "write", transfer_length); + + while (1) { + if (dev->count <= transfer_length) { + piix_log("%sing %i bytes to %08X\n", sop, dev->count, dev->addr); + if (out) + DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); + else + DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); + transfer_length -= dev->count; + buffer_pos += dev->count; + } else { + piix_log("%sing %i bytes to %08X\n", sop, transfer_length, dev->addr); + if (out) + DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); + else + DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); + /* Increase addr and decrease count so that resumed transfers do not mess up. */ + dev->addr += transfer_length; + dev->count -= transfer_length; + transfer_length = 0; + force_end = 1; + } + + if (force_end) { + piix_log("Total transfer length smaller than sum of all blocks, partial block\n"); + dev->status &= ~2; + return 0; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ + } else { + if (!transfer_length && !dev->eot) { + piix_log("Total transfer length smaller than sum of all blocks, full block\n"); + dev->status &= ~2; + return 0; /* We have exhausted the data to transfer but there's more blocks left, break. */ + } else if (transfer_length && dev->eot) { + piix_log("Total transfer length greater than sum of all blocks\n"); + dev->status |= 2; + return 1; /* There is data left to transfer but we have reached EOT - return with error. */ + } else if (dev->eot) { + piix_log("Regular EOT\n"); + dev->status &= ~3; + return 0; /* We have regularly reached EOT - clear status and break. */ } else { - if (!transfer_length && !piix_busmaster[channel].eot) { -#if 0 - pclog("Total transfer length smaller than sum of all blocks, full block\n"); -#endif - piix_busmaster[channel].status &= ~2; - return 0; /* We have exhausted the data to transfer but there's more blocks left, break. */ - } else if (transfer_length && piix_busmaster[channel].eot) { -#if 0 - pclog("Total transfer length greater than sum of all blocks\n"); -#endif - piix_busmaster[channel].status |= 2; - return 1; /* There is data left to transfer but we have reached EOT - return with error. */ - } else if (piix_busmaster[channel].eot) { -#if 0 - pclog("Regular EOT\n"); -#endif - piix_busmaster[channel].status &= ~3; - return 0; /* We have regularly reached EOT - clear status and break. */ - } else { - /* We have more to transfer and there are blocks left, get next block. */ - piix_bus_master_next_addr(channel); - } + /* We have more to transfer and there are blocks left, get next block. */ + piix_bus_master_next_addr(dev); } - } - return 0; -} - -int piix_bus_master_dma_write(int channel, uint8_t *data, int transfer_length) -{ - int force_end = 0; - int buffer_pos = 0; - - if (!(piix_busmaster[channel].status & 1)) - return 1; /*DMA disabled*/ - -#if 0 - pclog("PIIX Bus master write: %i bytes\n", transfer_length); -#endif - - while (1) { - if (piix_busmaster[channel].count <= transfer_length) { -#if 0 - pclog("Reading %i bytes from %08X\n", piix_busmaster[channel].count, piix_busmaster[channel].addr); -#endif - DMAPageRead(piix_busmaster[channel].addr, (uint8_t *)(data + buffer_pos), piix_busmaster[channel].count); - transfer_length -= piix_busmaster[channel].count; - buffer_pos += piix_busmaster[channel].count; - } else { -#if 0 - pclog("Reading %i bytes from %08X\n", piix_busmaster[channel].count, piix_busmaster[channel].addr); -#endif - DMAPageRead(piix_busmaster[channel].addr, (uint8_t *)(data + buffer_pos), transfer_length); - transfer_length = 0; - force_end = 1; - } - - if (force_end) { -#if 0 - pclog("Total transfer length smaller than sum of all blocks, partial block\n"); -#endif - piix_busmaster[channel].status &= ~2; - return 0; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ - } else { - if (!transfer_length && !piix_busmaster[channel].eot) { -#if 0 - pclog("Total transfer length smaller than sum of all blocks, full block\n"); -#endif - piix_busmaster[channel].status &= ~2; - return 0; /* We have exhausted the data to transfer but there's more blocks left, break. */ - } else if (transfer_length && piix_busmaster[channel].eot) { -#if 0 - pclog("Total transfer length greater than sum of all blocks\n"); -#endif - piix_busmaster[channel].status |= 2; - return 1; /* There is data left to transfer but we have reached EOT - return with error. */ - } else if (piix_busmaster[channel].eot) { -#if 0 - pclog("Regular EOT\n"); -#endif - piix_busmaster[channel].status &= ~3; - return 0; /* We have regularly reached EOT - clear status and break. */ - } else { - /* We have more to transfer and there are blocks left, get next block. */ - piix_bus_master_next_addr(channel); - } - } - } - return 0; -} - -void piix_bus_master_set_irq(int channel) -{ - // piix_busmaster[channel].status |= 4; - piix_busmaster[channel & 0x0F].status &= ~4; - piix_busmaster[channel & 0x0F].status |= (channel >> 4); + } + } + return 0; } -static void piix_bus_master_reset(void) +int +piix_bus_master_dma_read(int channel, uint8_t *data, int transfer_length, void *priv) { - uint16_t old_base = (card_piix_ide[0x20] & 0xf0) | (card_piix_ide[0x21] << 8); - if (old_base) - io_removehandler(old_base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + return piix_bus_master_dma_op(channel, data, transfer_length, 1, priv); } -void piix_reset(void) +int +piix_bus_master_dma_write(int channel, uint8_t *data, int transfer_length, void *priv) { - piix_bus_master_reset(); - memset(card_piix, 0, 256); - card_piix[0x00] = 0x86; card_piix[0x01] = 0x80; /*Intel*/ - card_piix[0x02] = 0x2e; card_piix[0x03] = 0x12; /*82371FB (PIIX)*/ - card_piix[0x04] = 0x07; card_piix[0x05] = 0x00; - card_piix[0x06] = 0x80; card_piix[0x07] = 0x02; - card_piix[0x08] = 0x00; /*A0 stepping*/ - card_piix[0x09] = 0x00; card_piix[0x0a] = 0x01; card_piix[0x0b] = 0x06; - card_piix[0x0e] = 0x80; /*Multi-function device*/ - card_piix[0x4c] = 0x4d; - card_piix[0x4e] = 0x03; - card_piix[0x60] = card_piix[0x61] = card_piix[0x62] = card_piix[0x63] = 0x80; - card_piix[0x69] = 0x02; - card_piix[0x70] = card_piix[0x71] = 0xc0; - card_piix[0x76] = card_piix[0x77] = 0x0c; - card_piix[0x78] = 0x02; card_piix[0x79] = 0x00; - card_piix[0xa0] = 0x08; - card_piix[0xa2] = card_piix[0xa3] = 0x00; - card_piix[0xa4] = card_piix[0xa5] = card_piix[0xa6] = card_piix[0xa7] = 0x00; - card_piix[0xa8] = 0x0f; - card_piix[0xaa] = card_piix[0xab] = 0x00; - card_piix[0xac] = 0x00; - card_piix[0xae] = 0x00; + return piix_bus_master_dma_op(channel, data, transfer_length, 0, priv); +} - card_piix_ide[0x00] = 0x86; card_piix_ide[0x01] = 0x80; /*Intel*/ - card_piix_ide[0x02] = 0x30; card_piix_ide[0x03] = 0x12; /*82371FB (PIIX)*/ - card_piix_ide[0x04] = 0x02; card_piix_ide[0x05] = 0x00; - card_piix_ide[0x06] = 0x80; card_piix_ide[0x07] = 0x02; - card_piix_ide[0x08] = 0x00; - card_piix_ide[0x09] = 0x80; card_piix_ide[0x0a] = 0x01; card_piix_ide[0x0b] = 0x01; - card_piix_ide[0x0d] = 0x00; - card_piix_ide[0x0e] = 0x00; - card_piix_ide[0x20] = 0x01; card_piix_ide[0x21] = card_piix_ide[0x22] = card_piix_ide[0x23] = 0x00; /*Bus master interface base address*/ - card_piix_ide[0x40] = card_piix_ide[0x42] = 0x00; - card_piix_ide[0x41] = card_piix_ide[0x43] = 0x80; - pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); +void +piix_bus_master_set_irq(int channel, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + dev->status &= ~4; + dev->status |= (channel >> 4); + + channel &= 0x01; + if (dev->status & 0x04) { + if (channel && pci_use_mirq(0)) + pci_set_mirq(0); + else + picint(1 << (14 + channel)); + } else { + if ((channel & 1) && pci_use_mirq(0)) + pci_clear_mirq(0); + else + picintc(1 << (14 + channel)); + } +} + + +static void +piix_bus_master_reset(piix_t *dev) +{ + uint8_t i; + + uint16_t old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); + if (old_base) { + io_removehandler(old_base, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[0]); + io_removehandler(old_base + 8, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[1]); + } + + for (i = 0; i < 2; i++) { + dev->bm[i].command = 0x00; + dev->bm[i].status = 0x00; + dev->bm[i].ptr = dev->bm[i].ptr_cur = 0x00000000; + dev->bm[i].addr = 0x00000000; + dev->bm[i].ptr0 = 0x00; + dev->bm[i].count = dev->bm[i].eot = 0x00000000; + } +} + + +static void +piix_reset_hard(void *priv) +{ + piix_t *piix = (piix_t *) priv; + + piix_bus_master_reset(piix); + + memset(piix->regs, 0, 256); + memset(piix->regs_ide, 0, 256); + + piix->regs[0x00] = 0x86; piix->regs[0x01] = 0x80; /*Intel*/ + if (piix->type == 3) { + piix->regs[0x02] = 0x00; piix->regs[0x03] = 0x70; /*82371SB (PIIX3)*/ + } else { + piix->regs[0x02] = 0x2e; piix->regs[0x03] = 0x12; /*82371FB (PIIX)*/ + } + piix->regs[0x04] = 0x07; piix->regs[0x05] = 0x00; + piix->regs[0x06] = 0x80; piix->regs[0x07] = 0x02; + piix->regs[0x08] = 0x00; /*A0 stepping*/ + piix->regs[0x09] = 0x00; piix->regs[0x0a] = 0x01; piix->regs[0x0b] = 0x06; + piix->regs[0x0e] = 0x80; /*Multi-function device*/ + piix->regs[0x4c] = 0x4d; + piix->regs[0x4e] = 0x03; + if (piix->type == 3) + piix->regs[0x4f] = 0x00; + piix->regs[0x60] = piix->regs[0x61] = piix->regs[0x62] = piix->regs[0x63] = 0x80; + piix->regs[0x69] = 0x02; + piix->regs[0x70] = 0xc0; + if (piix->type != 3) + piix->regs[0x71] = 0xc0; + piix->regs[0x76] = piix->regs[0x77] = 0x0c; + piix->regs[0x78] = 0x02; piix->regs[0x79] = 0x00; + if (piix->type == 3) { + piix->regs[0x80] = piix->regs[0x82] = 0x00; + } + piix->regs[0xa0] = 0x08; + piix->regs[0xa2] = piix->regs[0xa3] = 0x00; + piix->regs[0xa4] = piix->regs[0xa5] = piix->regs[0xa6] = piix->regs[0xa7] = 0x00; + piix->regs[0xa8] = 0x0f; + piix->regs[0xaa] = piix->regs[0xab] = 0x00; + piix->regs[0xac] = 0x00; + piix->regs[0xae] = 0x00; + + piix->regs_ide[0x00] = 0x86; piix->regs_ide[0x01] = 0x80; /*Intel*/ + if (piix->type == 3) { + piix->regs_ide[0x02] = 0x10; piix->regs_ide[0x03] = 0x70; /*82371SB (PIIX3)*/ + } else { + piix->regs_ide[0x02] = 0x30; piix->regs_ide[0x03] = 0x12; /*82371FB (PIIX)*/ + } + piix->regs_ide[0x04] = 0x03; piix->regs_ide[0x05] = 0x00; + piix->regs_ide[0x06] = 0x80; piix->regs_ide[0x07] = 0x02; + piix->regs_ide[0x08] = 0x00; + piix->regs_ide[0x09] = 0x80; piix->regs_ide[0x0a] = 0x01; piix->regs_ide[0x0b] = 0x01; + piix->regs_ide[0x0d] = 0x00; + piix->regs_ide[0x0e] = 0x00; + piix->regs_ide[0x20] = 0x01; piix->regs_ide[0x21] = piix->regs_ide[0x22] = piix->regs_ide[0x23] = 0x00; /*Bus master interface base address*/ + piix->regs_ide[0x40] = piix->regs_ide[0x42] = 0x00; + piix->regs_ide[0x41] = piix->regs_ide[0x43] = 0x80; + if (piix->type == 3) + piix->regs_ide[0x44] = 0x00; + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); + if (piix->type != 3) pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); - ide_pri_disable(); - ide_sec_disable(); + ide_pri_disable(); + ide_sec_disable(); + + ide_pri_enable(); + ide_sec_enable(); } -void piix3_reset(void) + +static void +piix_reset(void *p) { - piix_bus_master_reset(); - memset(card_piix, 0, 256); - card_piix[0x00] = 0x86; card_piix[0x01] = 0x80; /*Intel*/ - card_piix[0x02] = 0x00; card_piix[0x03] = 0x70; /*82371SB (PIIX3)*/ - card_piix[0x04] = 0x07; card_piix[0x05] = 0x00; - card_piix[0x06] = 0x80; card_piix[0x07] = 0x02; - card_piix[0x08] = 0x00; /*A0 stepping*/ - card_piix[0x09] = 0x00; card_piix[0x0a] = 0x01; card_piix[0x0b] = 0x06; - card_piix[0x0e] = 0x80; /*Multi-function device*/ - card_piix[0x4c] = 0x4d; - card_piix[0x4e] = 0x03; - card_piix[0x4f] = 0x00; - card_piix[0x60] = card_piix[0x61] = card_piix[0x62] = card_piix[0x63] = 0x80; - card_piix[0x69] = 0x02; - card_piix[0x70] = 0xc0; - card_piix[0x76] = card_piix[0x77] = 0x0c; - card_piix[0x78] = 0x02; card_piix[0x79] = 0x00; - card_piix[0x80] = card_piix[0x82] = 0x00; - card_piix[0xa0] = 0x08; - card_piix[0xa2] = card_piix[0xa3] = 0x00; - card_piix[0xa4] = card_piix[0xa5] = card_piix[0xa6] = card_piix[0xa7] = 0x00; - card_piix[0xa8] = 0x0f; - card_piix[0xaa] = card_piix[0xab] = 0x00; - card_piix[0xac] = 0x00; - card_piix[0xae] = 0x00; + int i = 0; - card_piix_ide[0x00] = 0x86; card_piix_ide[0x01] = 0x80; /*Intel*/ - card_piix_ide[0x02] = 0x10; card_piix_ide[0x03] = 0x70; /*82371SB (PIIX3)*/ - card_piix_ide[0x04] = 0x02; card_piix_ide[0x05] = 0x00; - card_piix_ide[0x06] = 0x80; card_piix_ide[0x07] = 0x02; - card_piix_ide[0x08] = 0x00; - card_piix_ide[0x09] = 0x80; card_piix_ide[0x0a] = 0x01; card_piix_ide[0x0b] = 0x01; - card_piix_ide[0x0d] = 0x00; - card_piix_ide[0x0e] = 0x00; - card_piix_ide[0x20] = 0x01; card_piix_ide[0x21] = card_piix_ide[0x22] = card_piix_ide[0x23] = 0x00; /*Bus master interface base address*/ - card_piix_ide[0x40] = card_piix_ide[0x42] = 0x00; - card_piix_ide[0x41] = card_piix_ide[0x43] = 0x80; - card_piix_ide[0x44] = 0x00; - - pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); - - ide_pri_disable(); - ide_sec_disable(); + for (i = 0; i < CDROM_NUM; i++) { + if (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) + cdrom_reset(cdrom[i]); + } + for (i = 0; i < ZIP_NUM; i++) { + if (zip_drives[i].bus_type == ZIP_BUS_ATAPI) + zip_reset(i); + } } -void piix_init(int card) + +static void +piix_close(void *p) { - device_add(&ide_pci_2ch_device); + piix_t *piix = (piix_t *)p; - pci_add_card(card, piix_read, piix_write, NULL); - - piix_reset(); - - piix_type = 1; - - ide_set_bus_master(piix_bus_master_dma_read, piix_bus_master_dma_write, piix_bus_master_set_irq); - - port_92_reset(); - - port_92_add(); - - dma_alias_set(); - - pci_reset_handler.pci_set_reset = piix_reset; - - pci_enable_mirq(0); - pci_enable_mirq(1); + free(piix); } -void piix3_init(int card) + +static void +*piix_init(const device_t *info) { - device_add(&ide_pci_2ch_device); + piix_t *piix = (piix_t *) malloc(sizeof(piix_t)); + memset(piix, 0, sizeof(piix_t)); - pci_add_card(card, piix_read, piix_write, NULL); - - piix3_reset(); + device_add(&ide_pci_2ch_device); - piix_type = 3; - - ide_set_bus_master(piix_bus_master_dma_read, piix_bus_master_dma_write, piix_bus_master_set_irq); + pci_add_card(7, piix_read, piix_write, piix); - port_92_reset(); + piix->type = info->local; + piix_reset_hard(piix); - port_92_add(); + ide_set_bus_master(piix_bus_master_dma_read, piix_bus_master_dma_write, + piix_bus_master_set_irq, + &piix->bm[0], &piix->bm[1]); - dma_alias_set(); + port_92_reset(); - pci_reset_handler.pci_set_reset = piix3_reset; + port_92_add(); - pci_enable_mirq(0); + dma_alias_set(); + + pci_enable_mirq(0); + pci_enable_mirq(1); + + return piix; } + + +const device_t piix_device = +{ + "Intel 82371FB (PIIX)", + DEVICE_PCI, + 1, + piix_init, + piix_close, + piix_reset, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +const device_t piix3_device = +{ + "Intel 82371SB (PIIX3)", + DEVICE_PCI, + 1, + piix_init, + piix_close, + piix_reset, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/intel_sio.c b/src/intel_sio.c index cb37a2d48..fcf74ceff 100644 --- a/src/intel_sio.c +++ b/src/intel_sio.c @@ -6,18 +6,20 @@ * * Emulation of Intel System I/O PCI chip. * - * Version: @(#)intel_sio.c 1.0.7 2017/11/04 + * Version: @(#)intel_sio.c 1.0.7 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ -#include #include +#include +#include #include #include +#include "device.h" #include "cpu/cpu.h" #include "io.h" #include "dma.h" @@ -26,144 +28,181 @@ #include "intel_sio.h" -static uint8_t card_sio[256]; - - -static void sio_write(int func, int addr, uint8_t val, void *priv) +typedef struct { - if (func > 0) - return; - - if (addr >= 0x0f && addr < 0x4c) + uint8_t regs[256]; +} sio_t; + + +static void +sio_write(int func, int addr, uint8_t val, void *priv) +{ + sio_t *dev = (sio_t *) priv; + + if (func > 0) + return; + + if (addr >= 0x0f && addr < 0x4c) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: return; - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: - return; - - case 0x04: /*Command register*/ - val &= 0x08; - val |= 0x07; - break; - case 0x05: - val = 0; - break; - - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - val = 0x02; - break; - - case 0x40: - if (!((val ^ card_sio[addr]) & 0x40)) - { - return; - } - - if (val & 0x40) - { - dma_alias_remove(); - } - else - { - dma_alias_set(); - } + case 0x04: /*Command register*/ + val &= 0x08; + val |= 0x07; + break; + case 0x05: + val = 0; break; - case 0x4f: - if (!((val ^ card_sio[addr]) & 0x40)) - { + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x40: + if (!((val ^ dev->regs[addr]) & 0x40)) return; - } if (val & 0x40) - { - port_92_add(); - } + dma_alias_remove(); + else + dma_alias_set(); + break; + + case 0x4f: + if (!((val ^ dev->regs[addr]) & 0x40)) + return; + + if (val & 0x40) + port_92_add(); else - { port_92_remove(); - } - case 0x60: - if (val & 0x80) - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTA, val & 0xf); - break; - case 0x61: - if (val & 0x80) - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTC, val & 0xf); - break; - case 0x62: - if (val & 0x80) - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTB, val & 0xf); - break; - case 0x63: - if (val & 0x80) - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - else - pci_set_irq_routing(PCI_INTD, val & 0xf); - break; - } - card_sio[addr] = val; + case 0x60: + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x61: + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x62: + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x63: + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; + } + dev->regs[addr] = val; } -static uint8_t sio_read(int func, int addr, void *priv) +static uint8_t +sio_read(int func, int addr, void *priv) { - if (func > 0) - return 0xff; + sio_t *dev = (sio_t *) priv; + uint8_t ret; - return card_sio[addr]; + ret = 0xff; + + if (func == 0) + ret = dev->regs[addr]; + + return ret; } -static void sio_reset(void) +static void +sio_reset(void *priv) { - memset(card_sio, 0, 256); - card_sio[0x00] = 0x86; card_sio[0x01] = 0x80; /*Intel*/ - card_sio[0x02] = 0x84; card_sio[0x03] = 0x04; /*82378IB (SIO)*/ - card_sio[0x04] = 0x07; card_sio[0x05] = 0x00; - card_sio[0x06] = 0x00; card_sio[0x07] = 0x02; - card_sio[0x08] = 0x03; /*A0 stepping*/ + sio_t *dev = (sio_t *) priv; - card_sio[0x40] = 0x20; card_sio[0x41] = 0x00; - card_sio[0x42] = 0x04; card_sio[0x43] = 0x00; - card_sio[0x44] = 0x20; card_sio[0x45] = 0x10; - card_sio[0x46] = 0x0f; card_sio[0x47] = 0x00; - card_sio[0x48] = 0x01; card_sio[0x49] = 0x10; - card_sio[0x4a] = 0x10; card_sio[0x4b] = 0x0f; - card_sio[0x4c] = 0x56; card_sio[0x4d] = 0x40; - card_sio[0x4e] = 0x07; card_sio[0x4f] = 0x4f; - card_sio[0x54] = 0x00; card_sio[0x55] = 0x00; card_sio[0x56] = 0x00; - card_sio[0x60] = 0x80; card_sio[0x61] = 0x80; card_sio[0x62] = 0x80; card_sio[0x63] = 0x80; - card_sio[0x80] = 0x78; card_sio[0x81] = 0x00; - card_sio[0xa0] = 0x08; - card_sio[0xa8] = 0x0f; + memset(dev->regs, 0, 256); + + dev->regs[0x00] = 0x86; dev->regs[0x01] = 0x80; /*Intel*/ + dev->regs[0x02] = 0x84; dev->regs[0x03] = 0x04; /*82378IB (SIO)*/ + dev->regs[0x04] = 0x07; dev->regs[0x05] = 0x00; + dev->regs[0x06] = 0x00; dev->regs[0x07] = 0x02; + dev->regs[0x08] = 0x03; /*A0 stepping*/ + + dev->regs[0x40] = 0x20; dev->regs[0x41] = 0x00; + dev->regs[0x42] = 0x04; dev->regs[0x43] = 0x00; + dev->regs[0x44] = 0x20; dev->regs[0x45] = 0x10; + dev->regs[0x46] = 0x0f; dev->regs[0x47] = 0x00; + dev->regs[0x48] = 0x01; dev->regs[0x49] = 0x10; + dev->regs[0x4a] = 0x10; dev->regs[0x4b] = 0x0f; + dev->regs[0x4c] = 0x56; dev->regs[0x4d] = 0x40; + dev->regs[0x4e] = 0x07; dev->regs[0x4f] = 0x4f; + dev->regs[0x54] = 0x00; dev->regs[0x55] = 0x00; dev->regs[0x56] = 0x00; + dev->regs[0x60] = 0x80; dev->regs[0x61] = 0x80; dev->regs[0x62] = 0x80; dev->regs[0x63] = 0x80; + dev->regs[0x80] = 0x78; dev->regs[0x81] = 0x00; + dev->regs[0xa0] = 0x08; + dev->regs[0xa8] = 0x0f; + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); } -void sio_init(int card) +static void +sio_close(void *p) { - pci_add_card(card, sio_read, sio_write, NULL); + sio_t *sio = (sio_t *)p; + + free(sio); +} + + +static void +*sio_init(const device_t *info) +{ + sio_t *sio = (sio_t *) malloc(sizeof(sio_t)); + memset(sio, 0, sizeof(sio_t)); + + pci_add_card(2, sio_read, sio_write, sio); - sio_reset(); + sio_reset(sio); - port_92_reset(); + port_92_reset(); - port_92_add(); + port_92_add(); - dma_alias_set(); + dma_alias_set(); - pci_reset_handler.pci_set_reset = sio_reset; + return sio; } + + +const device_t sio_device = +{ + "Intel 82378IB (SIO)", + DEVICE_PCI, + 0, + sio_init, + sio_close, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/intel_sio.h b/src/intel_sio.h index 6ac704d82..b1976b9b2 100644 --- a/src/intel_sio.h +++ b/src/intel_sio.h @@ -6,12 +6,12 @@ * * Emulation of Intel System I/O PCI chip. * - * Version: @(#)sio.h 1.0.2 2017/08/23 + * Version: @(#)sio.h 1.0.3 2018/03/26 * * Author: Sarah Walker, * Miran Grca, - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ -void sio_init(int card); +extern const device_t sio_device; diff --git a/src/keyboard.h b/src/keyboard.h index 289b1a40c..e4c846b7d 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -8,7 +8,7 @@ * * Definitions for the keyboard interface. * - * Version: @(#)keyboard.h 1.0.14 2018/03/22 + * Version: @(#)keyboard.h 1.0.15 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, @@ -70,6 +70,8 @@ extern const device_t keyboard_ps2_ami_device; extern const device_t keyboard_ps2_mca_device; extern const device_t keyboard_ps2_mca_2_device; extern const device_t keyboard_ps2_quadtel_device; +extern const device_t keyboard_ps2_pci_device; +extern const device_t keyboard_ps2_ami_pci_device; #endif extern void keyboard_init(void); @@ -87,7 +89,6 @@ extern int keyboard_recv(uint16_t key); extern int keyboard_isfsexit(void); extern int keyboard_ismsexit(void); -extern void keyboard_at_reset(void); extern void keyboard_at_adddata_keyboard_raw(uint8_t val); extern void keyboard_at_adddata_mouse(uint8_t val); extern void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val,void *), void *); diff --git a/src/keyboard_at.c b/src/keyboard_at.c index 2a78ef62c..9cf927080 100644 --- a/src/keyboard_at.c +++ b/src/keyboard_at.c @@ -8,7 +8,7 @@ * * Intel 8042 (AT keyboard controller) emulation. * - * Version: @(#)keyboard_at.c 1.0.33 2018/03/22 + * Version: @(#)keyboard_at.c 1.0.34 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, @@ -2044,15 +2044,25 @@ const device_t keyboard_ps2_quadtel_device = { NULL, NULL, NULL, NULL }; +const device_t keyboard_ps2_pci_device = { + "PS/2 Keyboard", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL, NULL +}; -void -keyboard_at_reset(void) -{ - atkbd_t *kbd = CurrentKbd; - - if (kbd != NULL) - kbd_reset(kbd); -} +const device_t keyboard_ps2_ami_pci_device = { + "PS/2 Keyboard (AMI)", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL, NULL +}; void diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index 108a7b638..72466d540 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -32,7 +32,7 @@ * in alpha mode, but in highres ("ECD350") mode, it displays * some semi-random junk. Video-memory pointer maybe? * - * Version: @(#)m_amstrad.c 1.0.11 2018/03/18 + * Version: @(#)m_amstrad.c 1.0.12 2018/04/11 * * Authors: Sarah Walker, * Miran Grca, @@ -1205,7 +1205,7 @@ machine_amstrad_init(const machine_t *model) ams = (amstrad_t *)malloc(sizeof(amstrad_t)); memset(ams, 0x00, sizeof(amstrad_t)); - nvr_at_init(1); + device_add(&amstrad_nvr_device); machine_common_init(model); diff --git a/src/machine/m_at.c b/src/machine/m_at.c index edbec78a2..d4bf80adb 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -30,7 +30,7 @@ machine_at_common_init(const machine_t *model) if (lpt_enabled) lpt2_remove(); - nvr_at_init(8); + device_add(&at_nvr_device); if (joystick_type != 7) device_add(&gameport_device); diff --git a/src/machine/m_at_430fx.c b/src/machine/m_at_430fx.c index 31c63d74a..8621fb5ce 100644 --- a/src/machine/m_at_430fx.c +++ b/src/machine/m_at_430fx.c @@ -8,16 +8,17 @@ * * Implementation of the Intel 430FX PCISet chip. * - * Version: @(#)m_at_430fx.c 1.0.14 2018/03/18 + * Version: @(#)m_at_430fx.c 1.0.16 2018/04/04 * * Authors: Sarah Walker, * Miran Grca, * * Copyright 2008-2018 Sarah Walker. - * Copyright 2016,2018 Miran Grca. + * Copyright 2016-2018 Miran Grca. */ #include #include +#include #include #include #include "../86box.h" @@ -36,220 +37,231 @@ #include "machine.h" -static uint8_t card_i430fx[256]; - - -static void i430fx_map(uint32_t addr, uint32_t size, int state) +typedef struct { - switch (state & 3) - { - case 0: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 1: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - flushmmucache_nopc(); -} + uint8_t regs[256]; +} i430fx_t; -static void i430fx_write(int func, int addr, uint8_t val, void *priv) +static void +i430fx_map(uint32_t addr, uint32_t size, int state) { - if (func) - return; - - if (addr >= 0x10 && addr < 0x4f) - return; - - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0e: - return; - - case 0x04: /*Command register*/ - val &= 0x02; - val |= 0x04; - break; - case 0x05: - val = 0; - break; - - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - val = 0x02; - break; - - case 0x59: /*PAM0*/ - if ((card_i430fx[0x59] ^ val) & 0xf0) - { - i430fx_map(0xf0000, 0x10000, val >> 4); - shadowbios = (val & 0x10); - } - pclog("i430fx_write : PAM0 write %02X\n", val); - break; - case 0x5a: /*PAM1*/ - if ((card_i430fx[0x5a] ^ val) & 0x0f) - i430fx_map(0xc0000, 0x04000, val & 0xf); - if ((card_i430fx[0x5a] ^ val) & 0xf0) - i430fx_map(0xc4000, 0x04000, val >> 4); - break; - case 0x5b: /*PAM2*/ - if ((card_i430fx[0x5b] ^ val) & 0x0f) - i430fx_map(0xc8000, 0x04000, val & 0xf); - if ((card_i430fx[0x5b] ^ val) & 0xf0) - i430fx_map(0xcc000, 0x04000, val >> 4); - break; - case 0x5c: /*PAM3*/ - if ((card_i430fx[0x5c] ^ val) & 0x0f) - i430fx_map(0xd0000, 0x04000, val & 0xf); - if ((card_i430fx[0x5c] ^ val) & 0xf0) - i430fx_map(0xd4000, 0x04000, val >> 4); - break; - case 0x5d: /*PAM4*/ - if ((card_i430fx[0x5d] ^ val) & 0x0f) - i430fx_map(0xd8000, 0x04000, val & 0xf); - if ((card_i430fx[0x5d] ^ val) & 0xf0) - i430fx_map(0xdc000, 0x04000, val >> 4); - break; - case 0x5e: /*PAM5*/ - if ((card_i430fx[0x5e] ^ val) & 0x0f) - i430fx_map(0xe0000, 0x04000, val & 0xf); - if ((card_i430fx[0x5e] ^ val) & 0xf0) - i430fx_map(0xe4000, 0x04000, val >> 4); - pclog("i430fx_write : PAM5 write %02X\n", val); - break; - case 0x5f: /*PAM6*/ - if ((card_i430fx[0x5f] ^ val) & 0x0f) - i430fx_map(0xe8000, 0x04000, val & 0xf); - if ((card_i430fx[0x5f] ^ val) & 0xf0) - i430fx_map(0xec000, 0x04000, val >> 4); - pclog("i430fx_write : PAM6 write %02X\n", val); - break; - case 0x72: /*SMRAM*/ - if ((card_i430fx[0x72] ^ val) & 0x48) - i430fx_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); + switch (state & 3) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); break; - } - - card_i430fx[addr] = val; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); } -static uint8_t i430fx_read(int func, int addr, void *priv) +static void +i430fx_write(int func, int addr, uint8_t val, void *priv) { - if (func) - return 0xff; + i430fx_t *dev = (i430fx_t *) priv; - return card_i430fx[addr]; + if (func) + return; + + if ((addr >= 0x10) && (addr < 0x4f)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x59: /*PAM0*/ + if ((dev->regs[0x59] ^ val) & 0xf0) { + i430fx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + break; + case 0x5a: /*PAM1*/ + if ((dev->regs[0x5a] ^ val) & 0x0f) + i430fx_map(0xc0000, 0x04000, val & 0xf); + if ((dev->regs[0x5a] ^ val) & 0xf0) + i430fx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((dev->regs[0x5b] ^ val) & 0x0f) + i430fx_map(0xc8000, 0x04000, val & 0xf); + if ((dev->regs[0x5b] ^ val) & 0xf0) + i430fx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((dev->regs[0x5c] ^ val) & 0x0f) + i430fx_map(0xd0000, 0x04000, val & 0xf); + if ((dev->regs[0x5c] ^ val) & 0xf0) + i430fx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((dev->regs[0x5d] ^ val) & 0x0f) + i430fx_map(0xd8000, 0x04000, val & 0xf); + if ((dev->regs[0x5d] ^ val) & 0xf0) + i430fx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((dev->regs[0x5e] ^ val) & 0x0f) + i430fx_map(0xe0000, 0x04000, val & 0xf); + if ((dev->regs[0x5e] ^ val) & 0xf0) + i430fx_map(0xe4000, 0x04000, val >> 4); + break; + case 0x5f: /*PAM6*/ + if ((dev->regs[0x5f] ^ val) & 0x0f) + i430fx_map(0xe8000, 0x04000, val & 0xf); + if ((dev->regs[0x5f] ^ val) & 0xf0) + i430fx_map(0xec000, 0x04000, val >> 4); + break; + case 0x72: /*SMRAM*/ + if ((dev->regs[0x72] ^ val) & 0x48) + i430fx_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); + break; + } + + dev->regs[addr] = val; } -static void i430fx_reset(void) +static uint8_t +i430fx_read(int func, int addr, void *priv) { - memset(card_i430fx, 0, 256); - card_i430fx[0x00] = 0x86; card_i430fx[0x01] = 0x80; /*Intel*/ - card_i430fx[0x02] = 0x2d; card_i430fx[0x03] = 0x16; /*SB82437FX-66*/ - card_i430fx[0x04] = 0x06; card_i430fx[0x05] = 0x00; - card_i430fx[0x06] = 0x00; card_i430fx[0x07] = 0x82; - if (romset == ROM_MB500N) card_i430fx[0x07] = 0x02; - card_i430fx[0x08] = 0x00; /*A0 stepping*/ - card_i430fx[0x09] = 0x00; card_i430fx[0x0a] = 0x00; card_i430fx[0x0b] = 0x06; - card_i430fx[0x52] = 0x40; /*256kb PLB cache*/ - if (romset == ROM_MB500N) - { - card_i430fx[0x52] = 0x42; - card_i430fx[0x53] = 0x14; - card_i430fx[0x56] = 0x52; /*DRAM control*/ - } - card_i430fx[0x57] = 0x01; - card_i430fx[0x60] = card_i430fx[0x61] = card_i430fx[0x62] = card_i430fx[0x63] = card_i430fx[0x64] = 0x02; - if (romset == ROM_MB500N) - { - card_i430fx[0x67] = 0x11; - card_i430fx[0x69] = 0x03; - card_i430fx[0x70] = 0x20; - } - card_i430fx[0x72] = 0x02; - if (romset == ROM_MB500N) - { - card_i430fx[0x74] = 0x0e; - card_i430fx[0x78] = 0x23; - } + i430fx_t *dev = (i430fx_t *) priv; + + if (func) + return 0xff; + + return dev->regs[addr]; } -static void i430fx_pci_reset(void) +static void +i430fx_reset(void *priv) { - i430fx_write(0, 0x59, 0x00, NULL); - i430fx_write(0, 0x72, 0x02, NULL); + i430fx_write(0, 0x59, 0x00, priv); + i430fx_write(0, 0x72, 0x02, priv); } -static void i430fx_init(void) +static void +i430fx_close(void *p) { - pci_add_card(0, i430fx_read, i430fx_write, NULL); + i430fx_t *i430fx = (i430fx_t *)p; - i430fx_reset(); - - pci_reset_handler.pci_master_reset = i430fx_pci_reset; + free(i430fx); } +static void +*i430fx_init(const device_t *info) +{ + i430fx_t *i430fx = (i430fx_t *) malloc(sizeof(i430fx_t)); + memset(i430fx, 0, sizeof(i430fx_t)); + + i430fx->regs[0x00] = 0x86; i430fx->regs[0x01] = 0x80; /*Intel*/ + i430fx->regs[0x02] = 0x2d; i430fx->regs[0x03] = 0x12; /*SB82437FX-66*/ + i430fx->regs[0x04] = 0x06; i430fx->regs[0x05] = 0x00; + i430fx->regs[0x06] = 0x00; i430fx->regs[0x07] = 0x82; + i430fx->regs[0x08] = 0x00; /*A0 stepping*/ + i430fx->regs[0x09] = 0x00; i430fx->regs[0x0a] = 0x00; i430fx->regs[0x0b] = 0x06; + i430fx->regs[0x52] = 0x40; /*256kb PLB cache*/ + i430fx->regs[0x57] = 0x01; + i430fx->regs[0x60] = i430fx->regs[0x61] = i430fx->regs[0x62] = i430fx->regs[0x63] = 0x02; + i430fx->regs[0x64] = 0x02; + i430fx->regs[0x72] = 0x02; + + pci_add_card(0, i430fx_read, i430fx_write, i430fx); + + return i430fx; +} + + +const device_t i430fx_device = +{ + "Intel SB82437FX-66", + DEVICE_PCI, + 0, + i430fx_init, + i430fx_close, + i430fx_reset, + NULL, + NULL, + NULL, + NULL, + NULL +}; + + void machine_at_p54tp4xe_init(const machine_t *model) { - machine_at_ps2_init(model); + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - 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(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i430fx_init(); - piix3_init(7); - fdc37c665_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + 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(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + fdc37c665_init(); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); } void machine_at_endeavor_init(const machine_t *model) { - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_device); + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i430fx_init(); - piix_init(7); - pc87306_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + pc87306_init(); - device_add(&intel_flash_bxt_ami_device); + device_add(&intel_flash_bxt_ami_device); - if (gfxcard == GFX_INTERNAL) - device_add(&s3_phoenix_trio64_onboard_pci_device); + if (gfxcard == GFX_INTERNAL) + device_add(&s3_phoenix_trio64_onboard_pci_device); } @@ -263,83 +275,85 @@ at_endeavor_get_device(void) void machine_at_zappa_init(const machine_t *model) { - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_device); + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i430fx_init(); - piix_init(7); - pc87306_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + pc87306_init(); - device_add(&intel_flash_bxt_ami_device); + device_add(&intel_flash_bxt_ami_device); } void machine_at_mb500n_init(const machine_t *model) { - machine_at_ps2_init(model); + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i430fx_init(); - piix_init(7); - fdc37c665_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + fdc37c665_init(); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); } void machine_at_president_init(const machine_t *model) { - machine_at_ps2_init(model); + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i430fx_init(); - piix_init(7); - w83877f_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + w83877f_init(); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); } void machine_at_thor_init(const machine_t *model) { - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_device); + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 2, 1); - pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i430fx_init(); - piix_init(7); - pc87306_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + pc87306_init(); - device_add(&intel_flash_bxt_ami_device); + device_add(&intel_flash_bxt_ami_device); } diff --git a/src/machine/m_at_430hx.c b/src/machine/m_at_430hx.c index 74f735a28..75af65316 100644 --- a/src/machine/m_at_430hx.c +++ b/src/machine/m_at_430hx.c @@ -8,7 +8,7 @@ * * Implementation of the Intel 430HX PCISet chip. * - * Version: @(#)m_at_430hx.c 1.0.11 2018/03/18 + * Version: @(#)m_at_430hx.c 1.0.12 2018/04/04 * * Authors: Sarah Walker, * Miran Grca, @@ -18,6 +18,7 @@ */ #include #include +#include #include #include #include "../86box.h" @@ -33,297 +34,372 @@ #include "machine.h" -static uint8_t card_i430hx[256]; +typedef struct +{ + uint8_t regs[256]; +} i430hx_t; + + +typedef struct +{ + int index; +} acerm3a_t; static void i430hx_map(uint32_t addr, uint32_t size, int state) { - switch (state & 3) - { - case 0: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 1: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - flushmmucache_nopc(); -} - - -static void i430hx_write(int func, int addr, uint8_t val, void *priv) -{ - if (func) - return; - - if ((addr >= 0x10) && (addr < 0x4f)) - return; - - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0e: - return; - - case 0x04: /*Command register*/ - val &= 0x02; - val |= 0x04; - break; - case 0x05: - val = 0; - break; - - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - val &= 0x80; - val |= 0x02; - break; - - case 0x59: /*PAM0*/ - if ((card_i430hx[0x59] ^ val) & 0xf0) - { - i430hx_map(0xf0000, 0x10000, val >> 4); - shadowbios = (val & 0x10); - } - break; - case 0x5a: /*PAM1*/ - if ((card_i430hx[0x5a] ^ val) & 0x0f) - i430hx_map(0xc0000, 0x04000, val & 0xf); - if ((card_i430hx[0x5a] ^ val) & 0xf0) - i430hx_map(0xc4000, 0x04000, val >> 4); - break; - case 0x5b: /*PAM2*/ - if ((card_i430hx[0x5b] ^ val) & 0x0f) - i430hx_map(0xc8000, 0x04000, val & 0xf); - if ((card_i430hx[0x5b] ^ val) & 0xf0) - i430hx_map(0xcc000, 0x04000, val >> 4); - break; - case 0x5c: /*PAM3*/ - if ((card_i430hx[0x5c] ^ val) & 0x0f) - i430hx_map(0xd0000, 0x04000, val & 0xf); - if ((card_i430hx[0x5c] ^ val) & 0xf0) - i430hx_map(0xd4000, 0x04000, val >> 4); - break; - case 0x5d: /*PAM4*/ - if ((card_i430hx[0x5d] ^ val) & 0x0f) - i430hx_map(0xd8000, 0x04000, val & 0xf); - if ((card_i430hx[0x5d] ^ val) & 0xf0) - i430hx_map(0xdc000, 0x04000, val >> 4); - break; - case 0x5e: /*PAM5*/ - if ((card_i430hx[0x5e] ^ val) & 0x0f) - i430hx_map(0xe0000, 0x04000, val & 0xf); - if ((card_i430hx[0x5e] ^ val) & 0xf0) - i430hx_map(0xe4000, 0x04000, val >> 4); - break; - case 0x5f: /*PAM6*/ - if ((card_i430hx[0x5f] ^ val) & 0x0f) - i430hx_map(0xe8000, 0x04000, val & 0xf); - if ((card_i430hx[0x5f] ^ val) & 0xf0) - i430hx_map(0xec000, 0x04000, val >> 4); - break; - case 0x72: /*SMRAM*/ - if ((card_i430hx[0x72] ^ val) & 0x48) - i430hx_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); + switch (state & 3) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); break; - } - - card_i430hx[addr] = val; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); } -static uint8_t i430hx_read(int func, int addr, void *priv) +static void +i430hx_write(int func, int addr, uint8_t val, void *priv) { - if (func) - return 0xff; + i430hx_t *dev = (i430hx_t *) priv; - return card_i430hx[addr]; + if (func) + return; + + if ((addr >= 0x10) && (addr < 0x4f)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val &= 0x80; + val |= 0x02; + break; + + case 0x59: /*PAM0*/ + if ((dev->regs[0x59] ^ val) & 0xf0) { + i430hx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + break; + case 0x5a: /*PAM1*/ + if ((dev->regs[0x5a] ^ val) & 0x0f) + i430hx_map(0xc0000, 0x04000, val & 0xf); + if ((dev->regs[0x5a] ^ val) & 0xf0) + i430hx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((dev->regs[0x5b] ^ val) & 0x0f) + i430hx_map(0xc8000, 0x04000, val & 0xf); + if ((dev->regs[0x5b] ^ val) & 0xf0) + i430hx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((dev->regs[0x5c] ^ val) & 0x0f) + i430hx_map(0xd0000, 0x04000, val & 0xf); + if ((dev->regs[0x5c] ^ val) & 0xf0) + i430hx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((dev->regs[0x5d] ^ val) & 0x0f) + i430hx_map(0xd8000, 0x04000, val & 0xf); + if ((dev->regs[0x5d] ^ val) & 0xf0) + i430hx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((dev->regs[0x5e] ^ val) & 0x0f) + i430hx_map(0xe0000, 0x04000, val & 0xf); + if ((dev->regs[0x5e] ^ val) & 0xf0) + i430hx_map(0xe4000, 0x04000, val >> 4); + break; + case 0x5f: /*PAM6*/ + if ((dev->regs[0x5f] ^ val) & 0x0f) + i430hx_map(0xe8000, 0x04000, val & 0xf); + if ((dev->regs[0x5f] ^ val) & 0xf0) + i430hx_map(0xec000, 0x04000, val >> 4); + break; + case 0x72: /*SMRAM*/ + if ((dev->regs[0x72] ^ val) & 0x48) + i430hx_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); + break; + } + + dev->regs[addr] = val; +} + + +static uint8_t +i430hx_read(int func, int addr, void *priv) +{ + i430hx_t *dev = (i430hx_t *) priv; + + if (func) + return 0xff; + + return dev->regs[addr]; } -static void i430hx_reset(void) +static void +i430hx_reset(void *priv) { - memset(card_i430hx, 0, 256); - card_i430hx[0x00] = 0x86; card_i430hx[0x01] = 0x80; /*Intel*/ - card_i430hx[0x02] = 0x50; card_i430hx[0x03] = 0x12; /*82439HX*/ - card_i430hx[0x04] = 0x06; card_i430hx[0x05] = 0x00; - card_i430hx[0x06] = 0x00; card_i430hx[0x07] = 0x02; - card_i430hx[0x08] = 0x00; /*A0 stepping*/ - card_i430hx[0x09] = 0x00; card_i430hx[0x0a] = 0x00; card_i430hx[0x0b] = 0x06; - card_i430hx[0x51] = 0x20; - card_i430hx[0x52] = 0xB5; /*512kb cache*/ - - card_i430hx[0x59] = 0x40; - card_i430hx[0x5A] = card_i430hx[0x5B] = card_i430hx[0x5C] = card_i430hx[0x5D] = card_i430hx[0x5E] = card_i430hx[0x5F] = 0x44; - - card_i430hx[0x56] = 0x52; /*DRAM control*/ - card_i430hx[0x57] = 0x01; - card_i430hx[0x60] = card_i430hx[0x61] = card_i430hx[0x62] = card_i430hx[0x63] = card_i430hx[0x64] = card_i430hx[0x65] = card_i430hx[0x66] = card_i430hx[0x67] = 0x02; - card_i430hx[0x68] = 0x11; - card_i430hx[0x72] = 0x02; -} - - -static void i430hx_pci_reset(void) -{ - i430hx_write(0, 0x59, 0x00, NULL); - i430hx_write(0, 0x72, 0x02, NULL); + i430hx_write(0, 0x59, 0x00, priv); + i430hx_write(0, 0x72, 0x02, priv); } -static void i430hx_init(void) +static void +i430hx_close(void *p) { - pci_add_card(0, i430hx_read, i430hx_write, NULL); + i430hx_t *i430hx = (i430hx_t *)p; - i430hx_reset(); - - pci_reset_handler.pci_master_reset = i430hx_pci_reset; + free(i430hx); } -static int acerm3a_index; +static void +*i430hx_init(const device_t *info) +{ + i430hx_t *i430hx = (i430hx_t *) malloc(sizeof(i430hx_t)); + memset(i430hx, 0, sizeof(i430hx_t)); + + i430hx->regs[0x00] = 0x86; i430hx->regs[0x01] = 0x80; /*Intel*/ + i430hx->regs[0x02] = 0x50; i430hx->regs[0x03] = 0x12; /*82439HX*/ + i430hx->regs[0x04] = 0x06; i430hx->regs[0x05] = 0x00; + i430hx->regs[0x06] = 0x00; i430hx->regs[0x07] = 0x02; + i430hx->regs[0x08] = 0x00; /*A0 stepping*/ + i430hx->regs[0x09] = 0x00; i430hx->regs[0x0a] = 0x00; i430hx->regs[0x0b] = 0x06; + i430hx->regs[0x51] = 0x20; + i430hx->regs[0x52] = 0xB5; /*512kb cache*/ + i430hx->regs[0x59] = 0x40; + i430hx->regs[0x5A] = i430hx->regs[0x5B] = i430hx->regs[0x5C] = i430hx->regs[0x5D] = 0x44; + i430hx->regs[0x5E] = i430hx->regs[0x5F] = 0x44; + i430hx->regs[0x56] = 0x52; /*DRAM control*/ + i430hx->regs[0x57] = 0x01; + i430hx->regs[0x60] = i430hx->regs[0x61] = i430hx->regs[0x62] = i430hx->regs[0x63] = 0x02; + i430hx->regs[0x64] = i430hx->regs[0x65] = i430hx->regs[0x66] = i430hx->regs[0x67] = 0x02; + i430hx->regs[0x68] = 0x11; + i430hx->regs[0x72] = 0x02; + + pci_add_card(0, i430hx_read, i430hx_write, i430hx); + + return i430hx; +} + + +const device_t i430hx_device = +{ + "Intel 82439HX", + DEVICE_PCI, + 0, + i430hx_init, + i430hx_close, + i430hx_reset, + NULL, + NULL, + NULL, + NULL, + NULL +}; static void acerm3a_out(uint16_t port, uint8_t val, void *p) { - if (port == 0xea) - acerm3a_index = val; + acerm3a_t *dev = (acerm3a_t *) p; + + if (port == 0xea) + dev->index = val; } + static uint8_t acerm3a_in(uint16_t port, void *p) { - if (port == 0xeb) - { - switch (acerm3a_index) - { - case 2: - return 0xfd; - } - } - return 0xff; + acerm3a_t *dev = (acerm3a_t *) p; + + if (port == 0xeb) { + switch (dev->index) { + case 2: + return 0xfd; + } + } + return 0xff; } +static void +acerm3a_close(void *p) +{ + acerm3a_t *dev = (acerm3a_t *)p; + + free(dev); +} + + +static void +*acerm3a_init(const device_t *info) +{ + acerm3a_t *acerm3a = (acerm3a_t *) malloc(sizeof(acerm3a_t)); + memset(acerm3a, 0, sizeof(acerm3a_t)); + + io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, acerm3a); + + return acerm3a; +} + + +const device_t acerm3a_device = +{ + "Acer M3A Register", + 0, + 0, + acerm3a_init, + acerm3a_close, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; + + void machine_at_acerm3a_init(const machine_t *model) { - machine_at_ps2_init(model); + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x1F, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x10, PCI_CARD_ONBOARD, 4, 0, 0, 0); - i430hx_init(); - piix3_init(7); - fdc37c932fr_init(); - io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, NULL); + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x1F, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x10, PCI_CARD_ONBOARD, 4, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + fdc37c932fr_init(); + device_add(&acerm3a_device); - device_add(&intel_flash_bxb_device); + device_add(&intel_flash_bxb_device); } void machine_at_acerv35n_init(const machine_t *model) { - machine_at_ps2_init(model); + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); - i430hx_init(); - piix3_init(7); - fdc37c932fr_init(); - io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, NULL); + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + fdc37c932fr_init(); + device_add(&acerm3a_device); - device_add(&intel_flash_bxb_device); + device_add(&intel_flash_bxb_device); } void machine_at_ap53_init(const machine_t *model) { - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_device); + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); - memregs_init(); - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x06, PCI_CARD_ONBOARD, 1, 2, 3, 4); - i430hx_init(); - piix3_init(7); - fdc37c669_init(); + memregs_init(); + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_ONBOARD, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + fdc37c669_init(); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); } void machine_at_p55t2p4_init(const machine_t *model) { - machine_at_ps2_init(model); + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - 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(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i430hx_init(); - piix3_init(7); - w83877f_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + 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(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + w83877f_init(); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); } void machine_at_p55t2s_init(const machine_t *model) { - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_device); + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); - memregs_init(); - powermate_memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i430hx_init(); - piix3_init(7); - pc87306_init(); + memregs_init(); + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + pc87306_init(); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); } diff --git a/src/machine/m_at_430lx_nx.c b/src/machine/m_at_430lx_nx.c index c2c80483e..773454cb0 100644 --- a/src/machine/m_at_430lx_nx.c +++ b/src/machine/m_at_430lx_nx.c @@ -8,7 +8,7 @@ * * Implementation of the Intel 430LX and 430NX PCISet chips. * - * Version: @(#)m_at_430lx_nx.c 1.0.10 2018/03/18 + * Version: @(#)m_at_430lx_nx.c 1.0.11 2018/04/04 * * Authors: Sarah Walker, * Miran Grca, @@ -18,6 +18,7 @@ */ #include #include +#include #include #include #include "../86box.h" @@ -34,217 +35,240 @@ #include "machine.h" -static uint8_t card_i430_lx_nx[256]; - - -static void i430lx_nx_map(uint32_t addr, uint32_t size, int state) +typedef struct { - switch (state & 3) - { - case 0: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 1: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - flushmmucache_nopc(); + uint8_t regs[256]; +} i430lx_nx_t; + + +static void +i430lx_nx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); } -static void i430lx_nx_write(int func, int addr, uint8_t val, void *priv) +static void +i430lx_nx_write(int func, int addr, uint8_t val, void *priv) { - if (func) - return; + i430lx_nx_t *dev = (i430lx_nx_t *) priv; - if ((addr >= 0x10) && (addr < 0x4f)) - return; - - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0e: - return; - - case 0x04: /*Command register*/ - val &= 0x42; - val |= 0x04; - break; - case 0x05: - val &= 0x01; - break; - - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - val = 0x02; - break; - - case 0x59: /*PAM0*/ - if ((card_i430_lx_nx[0x59] ^ val) & 0xf0) - { - i430lx_nx_map(0xf0000, 0x10000, val >> 4); - shadowbios = (val & 0x10); - } - pclog("i430lx_write : PAM0 write %02X\n", val); - break; - case 0x5a: /*PAM1*/ - if ((card_i430_lx_nx[0x5a] ^ val) & 0x0f) - i430lx_nx_map(0xc0000, 0x04000, val & 0xf); - if ((card_i430_lx_nx[0x5a] ^ val) & 0xf0) - i430lx_nx_map(0xc4000, 0x04000, val >> 4); - break; - case 0x5b: /*PAM2*/ - if (romset == ROM_REVENGE) - { - if ((card_i430_lx_nx[0x5b] ^ val) & 0x0f) - i430lx_nx_map(0xc8000, 0x04000, val & 0xf); - if ((card_i430_lx_nx[0x5b] ^ val) & 0xf0) - i430lx_nx_map(0xcc000, 0x04000, val >> 4); + if (func) + return; + + if ((addr >= 0x10) && (addr < 0x4f)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x42; + val |= 0x04; + break; + case 0x05: + val &= 0x01; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x59: /*PAM0*/ + if ((dev->regs[0x59] ^ val) & 0xf0) { + i430lx_nx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); } - break; - case 0x5c: /*PAM3*/ - if ((card_i430_lx_nx[0x5c] ^ val) & 0x0f) - i430lx_nx_map(0xd0000, 0x04000, val & 0xf); - if ((card_i430_lx_nx[0x5c] ^ val) & 0xf0) - i430lx_nx_map(0xd4000, 0x04000, val >> 4); - break; - case 0x5d: /*PAM4*/ - if ((card_i430_lx_nx[0x5d] ^ val) & 0x0f) - i430lx_nx_map(0xd8000, 0x04000, val & 0xf); - if ((card_i430_lx_nx[0x5d] ^ val) & 0xf0) - i430lx_nx_map(0xdc000, 0x04000, val >> 4); - break; - case 0x5e: /*PAM5*/ - if ((card_i430_lx_nx[0x5e] ^ val) & 0x0f) - i430lx_nx_map(0xe0000, 0x04000, val & 0xf); - if ((card_i430_lx_nx[0x5e] ^ val) & 0xf0) - i430lx_nx_map(0xe4000, 0x04000, val >> 4); - pclog("i430lx_write : PAM5 write %02X\n", val); - break; - case 0x5f: /*PAM6*/ - if ((card_i430_lx_nx[0x5f] ^ val) & 0x0f) - i430lx_nx_map(0xe8000, 0x04000, val & 0xf); - if ((card_i430_lx_nx[0x5f] ^ val) & 0xf0) - i430lx_nx_map(0xec000, 0x04000, val >> 4); - pclog("i430lx_write : PAM6 write %02X\n", val); - break; - } - - card_i430_lx_nx[addr] = val; + break; + case 0x5a: /*PAM1*/ + if ((dev->regs[0x5a] ^ val) & 0x0f) + i430lx_nx_map(0xc0000, 0x04000, val & 0xf); + if ((dev->regs[0x5a] ^ val) & 0xf0) + i430lx_nx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((dev->regs[0x5b] ^ val) & 0x0f) + i430lx_nx_map(0xc8000, 0x04000, val & 0xf); + if ((dev->regs[0x5b] ^ val) & 0xf0) + i430lx_nx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((dev->regs[0x5c] ^ val) & 0x0f) + i430lx_nx_map(0xd0000, 0x04000, val & 0xf); + if ((dev->regs[0x5c] ^ val) & 0xf0) + i430lx_nx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((dev->regs[0x5d] ^ val) & 0x0f) + i430lx_nx_map(0xd8000, 0x04000, val & 0xf); + if ((dev->regs[0x5d] ^ val) & 0xf0) + i430lx_nx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((dev->regs[0x5e] ^ val) & 0x0f) + i430lx_nx_map(0xe0000, 0x04000, val & 0xf); + if ((dev->regs[0x5e] ^ val) & 0xf0) + i430lx_nx_map(0xe4000, 0x04000, val >> 4); + break; + case 0x5f: /*PAM6*/ + if ((dev->regs[0x5f] ^ val) & 0x0f) + i430lx_nx_map(0xe8000, 0x04000, val & 0xf); + if ((dev->regs[0x5f] ^ val) & 0xf0) + i430lx_nx_map(0xec000, 0x04000, val >> 4); + break; + } + + dev->regs[addr] = val; } -static uint8_t i430lx_nx_read(int func, int addr, void *priv) +static uint8_t +i430lx_nx_read(int func, int addr, void *priv) { - if (func) - return 0xff; + i430lx_nx_t *dev = (i430lx_nx_t *) priv; - return card_i430_lx_nx[addr]; + if (func) + return 0xff; + + return dev->regs[addr]; } -static void i430lx_nx_reset_common(void) +static void +i430lx_nx_reset(void *priv) { - memset(card_i430_lx_nx, 0, 256); - card_i430_lx_nx[0x00] = 0x86; card_i430_lx_nx[0x01] = 0x80; /*Intel*/ - card_i430_lx_nx[0x02] = 0xa3; card_i430_lx_nx[0x03] = 0x04; /*82434LX/NX*/ - card_i430_lx_nx[0x04] = 0x06; card_i430_lx_nx[0x05] = 0x00; - card_i430_lx_nx[0x06] = 0x00; card_i430_lx_nx[0x07] = 0x02; - card_i430_lx_nx[0x09] = 0x00; card_i430_lx_nx[0x0a] = 0x00; card_i430_lx_nx[0x0b] = 0x06; - card_i430_lx_nx[0x57] = 0x31; - card_i430_lx_nx[0x60] = card_i430_lx_nx[0x61] = card_i430_lx_nx[0x62] = card_i430_lx_nx[0x63] = card_i430_lx_nx[0x64] = 0x02; + i430lx_nx_write(0, 0x59, 0x00, priv); } -static void i430lx_reset(void) +static void +i430lx_nx_close(void *p) { - i430lx_nx_reset_common(); - card_i430_lx_nx[0x08] = 0x03; /*A3 stepping*/ - card_i430_lx_nx[0x50] = 0x80; - card_i430_lx_nx[0x52] = 0x40; /*256kb PLB cache*/ + i430lx_nx_t *i430lx_nx = (i430lx_nx_t *)p; + + free(i430lx_nx); } -static void i430nx_reset(void) +static void +*i430lx_nx_init(const device_t *info) { - i430lx_nx_reset_common(); - card_i430_lx_nx[0x08] = 0x10; /*A0 stepping*/ - card_i430_lx_nx[0x50] = 0xA0; - card_i430_lx_nx[0x52] = 0x44; /*256kb PLB cache*/ - card_i430_lx_nx[0x66] = card_i430_lx_nx[0x67] = 0x02; + i430lx_nx_t *i430lx_nx = (i430lx_nx_t *) malloc(sizeof(i430lx_nx_t)); + memset(i430lx_nx, 0, sizeof(i430lx_nx_t)); + + i430lx_nx->regs[0x00] = 0x86; i430lx_nx->regs[0x01] = 0x80; /*Intel*/ + i430lx_nx->regs[0x02] = 0xa3; i430lx_nx->regs[0x03] = 0x04; /*82434LX/NX*/ + i430lx_nx->regs[0x04] = 0x06; i430lx_nx->regs[0x05] = 0x00; + i430lx_nx->regs[0x06] = 0x00; i430lx_nx->regs[0x07] = 0x02; + i430lx_nx->regs[0x09] = 0x00; i430lx_nx->regs[0x0a] = 0x00; i430lx_nx->regs[0x0b] = 0x06; + i430lx_nx->regs[0x57] = 0x31; + i430lx_nx->regs[0x60] = i430lx_nx->regs[0x61] = i430lx_nx->regs[0x62] = i430lx_nx->regs[0x63] = 0x02; + i430lx_nx->regs[0x64] = 0x02; + + if (info->local == 1) { + i430lx_nx->regs[0x08] = 0x10; /*A0 stepping*/ + i430lx_nx->regs[0x50] = 0xA0; + i430lx_nx->regs[0x52] = 0x44; /*256kb PLB cache*/ + i430lx_nx->regs[0x66] = i430lx_nx->regs[0x67] = 0x02; + } else { + i430lx_nx->regs[0x08] = 0x03; /*A3 stepping*/ + i430lx_nx->regs[0x50] = 0x80; + i430lx_nx->regs[0x52] = 0x40; /*256kb PLB cache*/ + } + + pci_add_card(0, i430lx_nx_read, i430lx_nx_write, i430lx_nx); + + return i430lx_nx; } -static void i430lx_nx_pci_reset(void) +const device_t i430lx_device = { - i430lx_nx_write(0, 0x59, 0x00, NULL); -} + "Intel 82434LX", + DEVICE_PCI, + 0, + i430lx_nx_init, + i430lx_nx_close, + i430lx_nx_reset, + NULL, + NULL, + NULL, + NULL, + NULL +}; -static void i430lx_init(void) +const device_t i430nx_device = { - pci_add_card(0, i430lx_nx_read, i430lx_nx_write, NULL); - - i430lx_reset(); - - pci_reset_handler.pci_master_reset = i430lx_nx_pci_reset; -} - - -static void i430nx_init(void) -{ - pci_add_card(0, i430lx_nx_read, i430lx_nx_write, NULL); - - i430nx_reset(); - - pci_reset_handler.pci_master_reset = i430lx_nx_pci_reset; -} + "Intel 82434NX", + DEVICE_PCI, + 1, + i430lx_nx_init, + i430lx_nx_close, + i430lx_nx_reset, + NULL, + NULL, + NULL, + NULL, + NULL +}; static void machine_at_premiere_common_init(const machine_t *model) { - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_device); + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_2); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); - pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); - sio_init(2); - fdc37c665_init(); - intel_batman_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&sio_device); + fdc37c665_init(); + intel_batman_init(); - device_add(&intel_flash_bxt_ami_device); + device_add(&intel_flash_bxt_ami_device); } void machine_at_batman_init(const machine_t *model) { - machine_at_premiere_common_init(model); + machine_at_premiere_common_init(model); - i430lx_init(); + device_add(&i430lx_device); } void machine_at_plato_init(const machine_t *model) { - machine_at_premiere_common_init(model); + machine_at_premiere_common_init(model); - i430nx_init(); + device_add(&i430nx_device); } diff --git a/src/machine/m_at_430vx.c b/src/machine/m_at_430vx.c index 9165dd203..817be98e8 100644 --- a/src/machine/m_at_430vx.c +++ b/src/machine/m_at_430vx.c @@ -8,7 +8,7 @@ * * Implementation of the Intel 430VX PCISet chip. * - * Version: @(#)m_at_430vx.c 1.0.11 2018/03/18 + * Version: @(#)m_at_430vx.c 1.0.12 2018/04/04 * * Authors: Sarah Walker, * Miran Grca, @@ -18,237 +18,269 @@ */ #include #include +#include #include #include #include "../86box.h" +#include "../device.h" +#include "../keyboard.h" #include "../io.h" #include "../pci.h" #include "../mem.h" #include "../memregs.h" -#include "../device.h" #include "../piix.h" #include "../intel_flash.h" #include "../sio.h" #include "machine.h" -static uint8_t card_i430vx[256]; - - -static void i430vx_map(uint32_t addr, uint32_t size, int state) +typedef struct { - switch (state & 3) - { - case 0: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 1: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - flushmmucache_nopc(); + uint8_t regs[256]; +} i430vx_t; + + +static void +i430vx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); } -static void i430vx_write(int func, int addr, uint8_t val, void *priv) +static void +i430vx_write(int func, int addr, uint8_t val, void *priv) { - if (func) - return; - - if ((addr >= 0x10) && (addr < 0x4f)) - return; - - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0e: - return; - - case 0x04: /*Command register*/ - val &= 0x02; - val |= 0x04; - break; - case 0x05: - val = 0; - break; - - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - val &= 0x80; - val |= 0x02; - break; - - case 0x59: /*PAM0*/ - if ((card_i430vx[0x59] ^ val) & 0xf0) - { - i430vx_map(0xf0000, 0x10000, val >> 4); - shadowbios = (val & 0x10); - } - /* pclog("i430vx_write : PAM0 write %02X\n", val); */ - break; - case 0x5a: /*PAM1*/ - if ((card_i430vx[0x5a] ^ val) & 0x0f) - i430vx_map(0xc0000, 0x04000, val & 0xf); - if ((card_i430vx[0x5a] ^ val) & 0xf0) - i430vx_map(0xc4000, 0x04000, val >> 4); - break; - case 0x5b: /*PAM2*/ - if ((card_i430vx[0x5b] ^ val) & 0x0f) - i430vx_map(0xc8000, 0x04000, val & 0xf); - if ((card_i430vx[0x5b] ^ val) & 0xf0) - i430vx_map(0xcc000, 0x04000, val >> 4); - break; - case 0x5c: /*PAM3*/ - if ((card_i430vx[0x5c] ^ val) & 0x0f) - i430vx_map(0xd0000, 0x04000, val & 0xf); - if ((card_i430vx[0x5c] ^ val) & 0xf0) - i430vx_map(0xd4000, 0x04000, val >> 4); - break; - case 0x5d: /*PAM4*/ - if ((card_i430vx[0x5d] ^ val) & 0x0f) - i430vx_map(0xd8000, 0x04000, val & 0xf); - if ((card_i430vx[0x5d] ^ val) & 0xf0) - i430vx_map(0xdc000, 0x04000, val >> 4); - break; - case 0x5e: /*PAM5*/ - if ((card_i430vx[0x5e] ^ val) & 0x0f) - i430vx_map(0xe0000, 0x04000, val & 0xf); - if ((card_i430vx[0x5e] ^ val) & 0xf0) - i430vx_map(0xe4000, 0x04000, val >> 4); - /* pclog("i430vx_write : PAM5 write %02X\n", val); */ - break; - case 0x5f: /*PAM6*/ - if ((card_i430vx[0x5f] ^ val) & 0x0f) - i430vx_map(0xe8000, 0x04000, val & 0xf); - if ((card_i430vx[0x5f] ^ val) & 0xf0) - i430vx_map(0xec000, 0x04000, val >> 4); - /* pclog("i430vx_write : PAM6 write %02X\n", val); */ - break; - case 0x72: /*SMRAM*/ - if ((card_i430vx[0x72] ^ val) & 0x48) - i430vx_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); + i430vx_t *dev = (i430vx_t *) priv; + + if (func) + return; + + if ((addr >= 0x10) && (addr < 0x4f)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; break; - } - - card_i430vx[addr] = val; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val &= 0x80; + val |= 0x02; + break; + + case 0x59: /*PAM0*/ + if ((dev->regs[0x59] ^ val) & 0xf0) { + i430vx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + break; + case 0x5a: /*PAM1*/ + if ((dev->regs[0x5a] ^ val) & 0x0f) + i430vx_map(0xc0000, 0x04000, val & 0xf); + if ((dev->regs[0x5a] ^ val) & 0xf0) + i430vx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((dev->regs[0x5b] ^ val) & 0x0f) + i430vx_map(0xc8000, 0x04000, val & 0xf); + if ((dev->regs[0x5b] ^ val) & 0xf0) + i430vx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((dev->regs[0x5c] ^ val) & 0x0f) + i430vx_map(0xd0000, 0x04000, val & 0xf); + if ((dev->regs[0x5c] ^ val) & 0xf0) + i430vx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((dev->regs[0x5d] ^ val) & 0x0f) + i430vx_map(0xd8000, 0x04000, val & 0xf); + if ((dev->regs[0x5d] ^ val) & 0xf0) + i430vx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((dev->regs[0x5e] ^ val) & 0x0f) + i430vx_map(0xe0000, 0x04000, val & 0xf); + if ((dev->regs[0x5e] ^ val) & 0xf0) + i430vx_map(0xe4000, 0x04000, val >> 4); + break; + case 0x5f: /*PAM6*/ + if ((dev->regs[0x5f] ^ val) & 0x0f) + i430vx_map(0xe8000, 0x04000, val & 0xf); + if ((dev->regs[0x5f] ^ val) & 0xf0) + i430vx_map(0xec000, 0x04000, val >> 4); + break; + case 0x72: /*SMRAM*/ + if ((dev->regs[0x72] ^ val) & 0x48) + i430vx_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); + break; + } + + dev->regs[addr] = val; } static uint8_t i430vx_read(int func, int addr, void *priv) { - if (func) - return 0xff; + i430vx_t *dev = (i430vx_t *) priv; - return card_i430vx[addr]; + if (func) + return 0xff; + + return dev->regs[addr]; } - -static void i430vx_reset(void) + +static void +i430vx_reset(void *priv) { - memset(card_i430vx, 0, 256); - card_i430vx[0x00] = 0x86; card_i430vx[0x01] = 0x80; /*Intel*/ - card_i430vx[0x02] = 0x30; card_i430vx[0x03] = 0x70; /*82437VX*/ - card_i430vx[0x04] = 0x06; card_i430vx[0x05] = 0x00; - card_i430vx[0x06] = 0x00; card_i430vx[0x07] = 0x02; - card_i430vx[0x08] = 0x00; /*A0 stepping*/ - card_i430vx[0x09] = 0x00; card_i430vx[0x0a] = 0x00; card_i430vx[0x0b] = 0x06; - card_i430vx[0x52] = 0x42; /*256kb PLB cache*/ - card_i430vx[0x53] = 0x14; - card_i430vx[0x56] = 0x52; /*DRAM control*/ - card_i430vx[0x57] = 0x01; - card_i430vx[0x60] = card_i430vx[0x61] = card_i430vx[0x62] = card_i430vx[0x63] = card_i430vx[0x64] = 0x02; - card_i430vx[0x67] = 0x11; - card_i430vx[0x69] = 0x03; - card_i430vx[0x70] = 0x20; - card_i430vx[0x72] = 0x02; - card_i430vx[0x74] = 0x0e; - card_i430vx[0x78] = 0x23; + i430vx_write(0, 0x59, 0x00, priv); + i430vx_write(0, 0x72, 0x02, priv); } - -static void i430vx_pci_reset(void) + +static void +i430vx_close(void *p) { - i430vx_write(0, 0x59, 0x00, NULL); - i430vx_write(0, 0x72, 0x02, NULL); + i430vx_t *i430vx = (i430vx_t *)p; + + free(i430vx); } -void i430vx_init(void) +static void +*i430vx_init(const device_t *info) { - pci_add_card(0, i430vx_read, i430vx_write, NULL); - - i430vx_reset(); + i430vx_t *i430vx = (i430vx_t *) malloc(sizeof(i430vx_t)); + memset(i430vx, 0, sizeof(i430vx_t)); - pci_reset_handler.pci_master_reset = i430vx_pci_reset; + i430vx->regs[0x00] = 0x86; i430vx->regs[0x01] = 0x80; /*Intel*/ + i430vx->regs[0x02] = 0x30; i430vx->regs[0x03] = 0x70; /*82437VX*/ + i430vx->regs[0x04] = 0x06; i430vx->regs[0x05] = 0x00; + i430vx->regs[0x06] = 0x00; i430vx->regs[0x07] = 0x02; + i430vx->regs[0x08] = 0x00; /*A0 stepping*/ + i430vx->regs[0x09] = 0x00; i430vx->regs[0x0a] = 0x00; i430vx->regs[0x0b] = 0x06; + i430vx->regs[0x52] = 0x42; /*256kb PLB cache*/ + i430vx->regs[0x53] = 0x14; + i430vx->regs[0x56] = 0x52; /*DRAM control*/ + i430vx->regs[0x57] = 0x01; + i430vx->regs[0x60] = i430vx->regs[0x61] = i430vx->regs[0x62] = i430vx->regs[0x63] = 0x02; + i430vx->regs[0x64] = 0x02; + i430vx->regs[0x67] = 0x11; + i430vx->regs[0x69] = 0x03; + i430vx->regs[0x70] = 0x20; + i430vx->regs[0x72] = 0x02; + i430vx->regs[0x74] = 0x0e; + i430vx->regs[0x78] = 0x23; + + pci_add_card(0, i430vx_read, i430vx_write, i430vx); + + return i430vx; } +const device_t i430vx_device = +{ + "Intel 82437VX", + DEVICE_PCI, + 0, + i430vx_init, + i430vx_close, + i430vx_reset, + NULL, + NULL, + NULL, + NULL, + NULL +}; + + void machine_at_p55tvp4_init(const machine_t *model) { - machine_at_ps2_init(model); + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - 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(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i430vx_init(); - piix3_init(7); - w83877f_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + 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(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + w83877f_init(); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); } void machine_at_i430vx_init(const machine_t *model) { - machine_at_ps2_init(model); + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i430vx_init(); - piix3_init(7); - um8669f_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + um8669f_init(); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); } void machine_at_p55va_init(const machine_t *model) { - machine_at_ps2_init(model); + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i430vx_init(); - piix3_init(7); - fdc37c932fr_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + fdc37c932fr_init(); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); } diff --git a/src/machine/m_at_440fx.c b/src/machine/m_at_440fx.c index 6d3038048..eff026d9d 100644 --- a/src/machine/m_at_440fx.c +++ b/src/machine/m_at_440fx.c @@ -8,7 +8,7 @@ * * Implementation of the Intel 440FX PCISet chip. * - * Version: @(#)m_at_440fx.c 1.0.11 2018/03/18 + * Version: @(#)m_at_440fx.c 1.0.12 2018/04/04 * * Authors: Sarah Walker, * Miran Grca, @@ -18,6 +18,7 @@ */ #include #include +#include #include #include #include "../86box.h" @@ -33,207 +34,239 @@ #include "machine.h" -static uint8_t card_i440fx[256]; - - -static void i440fx_map(uint32_t addr, uint32_t size, int state) +typedef struct { - switch (state & 3) - { - case 0: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 1: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - flushmmucache_nopc(); -} + uint8_t regs[256]; +} i440fx_t; -static void i440fx_write(int func, int addr, uint8_t val, void *priv) +static void +i440fx_map(uint32_t addr, uint32_t size, int state) { - if (func) - return; - - if ((addr >= 0x10) && (addr < 0x4f)) - return; - - switch (addr) - { - case 0x00: case 0x01: case 0x02: case 0x03: - case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0c: case 0x0e: - return; - - case 0x04: /*Command register*/ - val &= 0x02; - val |= 0x04; - break; - case 0x05: - val = 0; - break; - - case 0x06: /*Status*/ - val = 0; - break; - case 0x07: - val &= 0x80; - val |= 0x02; - break; - - case 0x59: /*PAM0*/ - if ((card_i440fx[0x59] ^ val) & 0xf0) - { - i440fx_map(0xf0000, 0x10000, val >> 4); - shadowbios = (val & 0x10); - } - break; - case 0x5a: /*PAM1*/ - if ((card_i440fx[0x5a] ^ val) & 0x0f) - i440fx_map(0xc0000, 0x04000, val & 0xf); - if ((card_i440fx[0x5a] ^ val) & 0xf0) - i440fx_map(0xc4000, 0x04000, val >> 4); - break; - case 0x5b: /*PAM2*/ - if ((card_i440fx[0x5b] ^ val) & 0x0f) - i440fx_map(0xc8000, 0x04000, val & 0xf); - if ((card_i440fx[0x5b] ^ val) & 0xf0) - i440fx_map(0xcc000, 0x04000, val >> 4); - break; - case 0x5c: /*PAM3*/ - if ((card_i440fx[0x5c] ^ val) & 0x0f) - i440fx_map(0xd0000, 0x04000, val & 0xf); - if ((card_i440fx[0x5c] ^ val) & 0xf0) - i440fx_map(0xd4000, 0x04000, val >> 4); - break; - case 0x5d: /*PAM4*/ - if ((card_i440fx[0x5d] ^ val) & 0x0f) - i440fx_map(0xd8000, 0x04000, val & 0xf); - if ((card_i440fx[0x5d] ^ val) & 0xf0) - i440fx_map(0xdc000, 0x04000, val >> 4); - break; - case 0x5e: /*PAM5*/ - if ((card_i440fx[0x5e] ^ val) & 0x0f) - i440fx_map(0xe0000, 0x04000, val & 0xf); - if ((card_i440fx[0x5e] ^ val) & 0xf0) - i440fx_map(0xe4000, 0x04000, val >> 4); - break; - case 0x5f: /*PAM6*/ - if ((card_i440fx[0x5f] ^ val) & 0x0f) - i440fx_map(0xe8000, 0x04000, val & 0xf); - if ((card_i440fx[0x5f] ^ val) & 0xf0) - i440fx_map(0xec000, 0x04000, val >> 4); - break; - case 0x72: /*SMRAM*/ - if ((card_i440fx[0x72] ^ val) & 0x48) - i440fx_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); + switch (state & 3) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); break; - } - - card_i440fx[addr] = val; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); } -static uint8_t i440fx_read(int func, int addr, void *priv) +static void +i440fx_write(int func, int addr, uint8_t val, void *priv) { - if (func) - return 0xff; + i440fx_t *dev = (i440fx_t *) priv; - return card_i440fx[addr]; + if (func) + return; + + if ((addr >= 0x10) && (addr < 0x4f)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val &= 0x80; + val |= 0x02; + break; + + case 0x59: /*PAM0*/ + if ((dev->regs[0x59] ^ val) & 0xf0) { + i440fx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + break; + case 0x5a: /*PAM1*/ + if ((dev->regs[0x5a] ^ val) & 0x0f) + i440fx_map(0xc0000, 0x04000, val & 0xf); + if ((dev->regs[0x5a] ^ val) & 0xf0) + i440fx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((dev->regs[0x5b] ^ val) & 0x0f) + i440fx_map(0xc8000, 0x04000, val & 0xf); + if ((dev->regs[0x5b] ^ val) & 0xf0) + i440fx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((dev->regs[0x5c] ^ val) & 0x0f) + i440fx_map(0xd0000, 0x04000, val & 0xf); + if ((dev->regs[0x5c] ^ val) & 0xf0) + i440fx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((dev->regs[0x5d] ^ val) & 0x0f) + i440fx_map(0xd8000, 0x04000, val & 0xf); + if ((dev->regs[0x5d] ^ val) & 0xf0) + i440fx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((dev->regs[0x5e] ^ val) & 0x0f) + i440fx_map(0xe0000, 0x04000, val & 0xf); + if ((dev->regs[0x5e] ^ val) & 0xf0) + i440fx_map(0xe4000, 0x04000, val >> 4); + break; + case 0x5f: /*PAM6*/ + if ((dev->regs[0x5f] ^ val) & 0x0f) + i440fx_map(0xe8000, 0x04000, val & 0xf); + if ((dev->regs[0x5f] ^ val) & 0xf0) + i440fx_map(0xec000, 0x04000, val >> 4); + break; + case 0x72: /*SMRAM*/ + if ((dev->regs[0x72] ^ val) & 0x48) + i440fx_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); + break; + } + + dev->regs[addr] = val; +} + + +static uint8_t +i440fx_read(int func, int addr, void *priv) +{ + i440fx_t *dev = (i440fx_t *) priv; + + if (func) + return 0xff; + + return dev->regs[addr]; } -static void i440fx_reset(void) +static void +i440fx_reset(void *priv) { - memset(card_i440fx, 0, 256); - card_i440fx[0x00] = 0x86; card_i440fx[0x01] = 0x80; /*Intel*/ - card_i440fx[0x02] = 0x37; card_i440fx[0x03] = 0x12; /*82441FX*/ - card_i440fx[0x04] = 0x03; card_i440fx[0x05] = 0x01; - card_i440fx[0x06] = 0x80; card_i440fx[0x07] = 0x00; - card_i440fx[0x08] = 0x02; /*A0 stepping*/ - card_i440fx[0x09] = 0x00; card_i440fx[0x0a] = 0x00; card_i440fx[0x0b] = 0x06; - card_i440fx[0x0d] = 0x00; - card_i440fx[0x0f] = 0x00; - card_i440fx[0x2c] = 0xf4; - card_i440fx[0x2d] = 0x1a; - card_i440fx[0x2e] = 0x00; - card_i440fx[0x2f] = 0x11; - card_i440fx[0x50] = 0x00; - card_i440fx[0x51] = 0x01; - card_i440fx[0x52] = card_i440fx[0x54] = card_i440fx[0x55] = card_i440fx[0x56] = 0x00; - card_i440fx[0x53] = 0x80; - card_i440fx[0x57] = 0x01; - card_i440fx[0x58] = 0x10; - card_i440fx[0x5a] = card_i440fx[0x5b] = card_i440fx[0x5c] = card_i440fx[0x5d] = card_i440fx[0x5e] = 0x11; - card_i440fx[0x5f] = 0x31; - card_i440fx[0x72] = 0x02; -} - - -static void i440fx_pci_reset(void) -{ - i440fx_write(0, 0x59, 0x00, NULL); - i440fx_write(0, 0x72, 0x02, NULL); + i440fx_write(0, 0x59, 0x00, priv); + i440fx_write(0, 0x72, 0x02, priv); } -static void i440fx_init(void) +static void +i440fx_close(void *p) { - pci_add_card(0, i440fx_read, i440fx_write, NULL); - - i440fx_reset(); + i440fx_t *i440fx = (i440fx_t *)p; - pci_reset_handler.pci_master_reset = i440fx_pci_reset; + free(i440fx); } +static void +*i440fx_init(const device_t *info) +{ + i440fx_t *i440fx = (i440fx_t *) malloc(sizeof(i440fx_t)); + memset(i440fx, 0, sizeof(i440fx_t)); + + i440fx->regs[0x00] = 0x86; i440fx->regs[0x01] = 0x80; /*Intel*/ + i440fx->regs[0x02] = 0x37; i440fx->regs[0x03] = 0x12; /*82441FX*/ + i440fx->regs[0x04] = 0x03; i440fx->regs[0x05] = 0x01; + i440fx->regs[0x06] = 0x80; i440fx->regs[0x07] = 0x00; + i440fx->regs[0x08] = 0x02; /*A0 stepping*/ + i440fx->regs[0x09] = 0x00; i440fx->regs[0x0a] = 0x00; i440fx->regs[0x0b] = 0x06; + i440fx->regs[0x0d] = 0x00; + i440fx->regs[0x0f] = 0x00; + i440fx->regs[0x2c] = 0xf4; + i440fx->regs[0x2d] = 0x1a; + i440fx->regs[0x2e] = 0x00; + i440fx->regs[0x2f] = 0x11; + i440fx->regs[0x50] = 0x00; + i440fx->regs[0x51] = 0x01; + i440fx->regs[0x52] = i440fx->regs[0x54] = i440fx->regs[0x55] = i440fx->regs[0x56] = 0x00; + i440fx->regs[0x53] = 0x80; + i440fx->regs[0x57] = 0x01; + i440fx->regs[0x58] = 0x10; + i440fx->regs[0x5a] = i440fx->regs[0x5b] = i440fx->regs[0x5c] = i440fx->regs[0x5d] = 0x11; + i440fx->regs[0x5e] = 0x11; + i440fx->regs[0x5f] = 0x31; + i440fx->regs[0x72] = 0x02; + + pci_add_card(0, i440fx_read, i440fx_write, i440fx); + + return i440fx; +} + + +const device_t i440fx_device = +{ + "Intel 82441FX", + DEVICE_PCI, + 0, + i440fx_init, + i440fx_close, + i440fx_reset, + NULL, + NULL, + NULL, + NULL, + NULL +}; + + void machine_at_i440fx_init(const machine_t *model) { - machine_at_ps2_init(model); + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - i440fx_init(); - piix3_init(7); - fdc37c665_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i440fx_device); + device_add(&piix3_device); + fdc37c665_init(); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); } void machine_at_s1668_init(const machine_t *model) { - machine_at_common_init(model); - device_add(&keyboard_ps2_ami_device); + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); - pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); - i440fx_init(); - piix3_init(7); - fdc37c665_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i440fx_device); + device_add(&piix3_device); + fdc37c665_init(); - device_add(&intel_flash_bxt_device); + device_add(&intel_flash_bxt_device); } diff --git a/src/machine/m_at_sis_85c496.c b/src/machine/m_at_sis_85c496.c index 1705425cb..86bf2cc88 100644 --- a/src/machine/m_at_sis_85c496.c +++ b/src/machine/m_at_sis_85c496.c @@ -1,14 +1,30 @@ -/* Copyright holders: Sarah Walker - see COPYING for more details -*/ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Implementation of the SiS 85c496/85c497 chip. + * + * Version: @(#)m_at_sis_85c496.c 1.0.0 2018/04/17 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ #include #include -#include #include +#include #include #include "../86box.h" #include "../cpu/cpu.h" #include "../device.h" +#include "../keyboard.h" #include "../io.h" #include "../pci.h" #include "../mem.h" @@ -20,169 +36,196 @@ typedef struct sis_85c496_t { - uint8_t pci_conf[256]; + uint8_t pci_conf[256]; } sis_85c496_t; -sis_85c496_t sis496; - - -static void sis_85c496_recalcmapping(void) +static void +sis_85c496_recalcmapping(sis_85c496_t *dev) { - int c; - - for (c = 0; c < 8; c++) - { - uint32_t base = 0xc0000 + (c << 15); - if (sis496.pci_conf[0x44] & (1 << c)) - { - switch (sis496.pci_conf[0x45] & 3) - { - case 0: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 1: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - } - } - else - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } + int c; + uint32_t base; - flushmmucache(); - shadowbios = (sis496.pci_conf[0x44] & 0xf0); + for (c = 0; c < 8; c++) { + base = 0xc0000 + (c << 15); + if (dev->pci_conf[0x44] & (1 << c)) { + switch (dev->pci_conf[0x45] & 3) { + case 0: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 1: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + flushmmucache(); + shadowbios = (dev->pci_conf[0x44] & 0xf0); } -static void sis_85c496_write(int func, int addr, uint8_t val, void *p) +static void +sis_85c496_write(int func, int addr, uint8_t val, void *p) { - switch (addr) - { - case 0x44: /*Shadow configure*/ - if ((sis496.pci_conf[0x44] & val) ^ 0xf0) - { - sis496.pci_conf[0x44] = val; - sis_85c496_recalcmapping(); - } - break; - case 0x45: /*Shadow configure*/ - if ((sis496.pci_conf[0x45] & val) ^ 0x01) - { - sis496.pci_conf[0x45] = val; - sis_85c496_recalcmapping(); - } - break; - - case 0xc0: - if (val & 0x80) - pci_set_irq_routing(PCI_INTA, val & 0xf); - else - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - break; - case 0xc1: - if (val & 0x80) - pci_set_irq_routing(PCI_INTB, val & 0xf); - else - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - break; - case 0xc2: - if (val & 0x80) - pci_set_irq_routing(PCI_INTC, val & 0xf); - else - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - break; - case 0xc3:// pclog("IRQ routing %02x %02x\n", addr, val); - if (val & 0x80) - pci_set_irq_routing(PCI_INTD, val & 0xf); - else - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - break; - } + sis_85c496_t *dev = (sis_85c496_t *) p; + + switch (addr) { + case 0x44: /*Shadow configure*/ + if ((dev->pci_conf[0x44] & val) ^ 0xf0) { + dev->pci_conf[0x44] = val; + sis_85c496_recalcmapping(dev); + } + break; + case 0x45: /*Shadow configure*/ + if ((dev->pci_conf[0x45] & val) ^ 0x01) { + dev->pci_conf[0x45] = val; + sis_85c496_recalcmapping(dev); + } + break; + + case 0xc0: + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, val & 0xf); + else + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + break; + case 0xc1: + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, val & 0xf); + else + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + break; + case 0xc2: + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, val & 0xf); + else + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + break; + case 0xc3: + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, val & 0xf); + else + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + break; + } - if ((addr >= 4 && addr < 8) || addr >= 0x40) - sis496.pci_conf[addr] = val; + if ((addr >= 4 && addr < 8) || addr >= 0x40) + dev->pci_conf[addr] = val; } -static uint8_t sis_85c496_read(int func, int addr, void *p) +static uint8_t +sis_85c496_read(int func, int addr, void *p) { - return sis496.pci_conf[addr]; + sis_85c496_t *dev = (sis_85c496_t *) p; + + return dev->pci_conf[addr]; } -static void sis_85c496_reset(void) +static void +sis_85c496_reset(void *priv) { - memset(&sis496, 0, sizeof(sis_85c496_t)); - - sis496.pci_conf[0x00] = 0x39; /*SiS*/ - sis496.pci_conf[0x01] = 0x10; - sis496.pci_conf[0x02] = 0x96; /*496/497*/ - sis496.pci_conf[0x03] = 0x04; + uint8_t val = 0; - sis496.pci_conf[0x04] = 7; - sis496.pci_conf[0x05] = 0; - - sis496.pci_conf[0x06] = 0x80; - sis496.pci_conf[0x07] = 0x02; - - sis496.pci_conf[0x08] = 2; /*Device revision*/ - - sis496.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ - sis496.pci_conf[0x0a] = 0x00; - sis496.pci_conf[0x0b] = 0x06; - - sis496.pci_conf[0x0e] = 0x00; /*Single function device*/ + val = sis_85c496_read(0, 0x44, priv); /* Read current value of 0x44. */ + sis_85c496_write(0, 0x44, val & 0xf, priv); /* Turn off shadow BIOS but keep the lower 4 bits. */ } -static void sis_85c496_pci_reset(void) +static void +sis_85c496_close(void *p) { - uint8_t val = 0; + sis_85c496_t *sis_85c496 = (sis_85c496_t *)p; - val = sis_85c496_read(0, 0x44, NULL); /* Read current value of 0x44. */ - sis_85c496_write(0, 0x44, val & 0xf, NULL); /* Turn off shadow BIOS but keep the lower 4 bits. */ + free(sis_85c496); } -static void sis_85c496_init(void) +static void +*sis_85c496_init(const device_t *info) { - pci_add_card(5, sis_85c496_read, sis_85c496_write, NULL); + sis_85c496_t *sis496 = malloc(sizeof(sis_85c496_t)); + memset(sis496, 0, sizeof(sis_85c496_t)); - sis_85c496_reset(); + sis496->pci_conf[0x00] = 0x39; /*SiS*/ + sis496->pci_conf[0x01] = 0x10; + sis496->pci_conf[0x02] = 0x96; /*496/497*/ + sis496->pci_conf[0x03] = 0x04; - pci_reset_handler.pci_master_reset = sis_85c496_pci_reset; + sis496->pci_conf[0x04] = 7; + sis496->pci_conf[0x05] = 0; + + sis496->pci_conf[0x06] = 0x80; + sis496->pci_conf[0x07] = 0x02; + + sis496->pci_conf[0x08] = 2; /*Device revision*/ + + sis496->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis496->pci_conf[0x0a] = 0x00; + sis496->pci_conf[0x0b] = 0x06; + + sis496->pci_conf[0x0e] = 0x00; /*Single function device*/ + + pci_add_card(5, sis_85c496_read, sis_85c496_write, sis496); + + return sis496; } +const device_t sis_85c496_device = +{ + "SiS 85c496/85c497", + DEVICE_PCI, + 0, + sis_85c496_init, + sis_85c496_close, + sis_85c496_reset, + NULL, + NULL, + NULL, + NULL, + NULL +}; + + static void machine_at_sis_85c496_common_init(const machine_t *model) { - machine_at_ps2_init(model); - device_add(&ide_pci_device); + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x05, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); + device_add(&ide_pci_device); - sis_85c496_init(); + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x05, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + device_add(&sis_85c496_device); } void machine_at_r418_init(const machine_t *model) { - machine_at_sis_85c496_common_init(model); + machine_at_sis_85c496_common_init(model); - fdc37c665_init(); + fdc37c665_init(); } diff --git a/src/machine/m_europc.c b/src/machine/m_europc.c index 63d4b4b4d..4f0d7dd92 100644 --- a/src/machine/m_europc.c +++ b/src/machine/m_europc.c @@ -68,7 +68,7 @@ * * WARNING THIS IS A WORK-IN-PROGRESS MODULE. USE AT OWN RISK. * - * Version: @(#)europc.c 1.0.3 2018/03/18 + * Version: @(#)europc.c 1.0.4 2018/04/11 * * Author: Fred N. van Kempen, * @@ -120,8 +120,8 @@ #include "../nmi.h" #include "../mem.h" #include "../rom.h" -#include "../nvr.h" #include "../device.h" +#include "../nvr.h" #include "../keyboard.h" #include "../mouse.h" #include "../game/gameport.h" @@ -652,13 +652,16 @@ europc_boot(const device_t *info) /* Only after JIM has been initialized. */ (void)device_add(&keyboard_xt_device); - /* + /* Enable and set up the FDC. */ + (void)device_add(&fdc_xt_device); + + /* * Set up and enable the HD20 disk controller. * * We only do this if we have not configured another one. */ if (hdc_current == 1) - (void)device_add(&europc_hdc_device); + (void)device_add(&xta_hd20_device); return(sys); } @@ -715,12 +718,13 @@ const device_t europc_device = { void machine_europc_init(const machine_t *model) { + machine_common_init(model); + nmi_init(); + /* Clear the machine state. */ memset(&europc, 0x00, sizeof(europc_t)); europc.jim = 0x0250; - machine_common_init(model); - nmi_init(); mem_add_bios(); /* This is machine specific. */ @@ -735,9 +739,6 @@ machine_europc_init(const machine_t *model) /* Initialize the actual NVR. */ nvr_init(&europc.nvr); - /* Enable and set up the FDC. */ - (void)device_add(&fdc_xt_device); - /* Enable and set up the mainboard device. */ device_add(&europc_device); } diff --git a/src/machine/m_europc_hdc.c b/src/machine/m_europc_hdc.c deleted file mode 100644 index 315f0f85c..000000000 --- a/src/machine/m_europc_hdc.c +++ /dev/null @@ -1,987 +0,0 @@ -/* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. - * - * This file is part of the VARCem Project. - * - * Implementation of the EuroPC HD20 internal controller. - * - * The HD20 was an externally-connected drive, very often a - * 8425XT (20MB, 615/4/17) from Miniscribe. These drives used - * an 8-bit version of IDE called X-IDE, also known as XTA. - * Some older units had a 8225XT drive (20MB, 771/2/17.) - * - * To access the HD disk formatter, enter the "debug" program - * in DOS, and type "g=f000:a000" to start that utility, which - * is hidden in the PC's ROM BIOS. - * - * This driver is based on the information found in the IBM-PC - * Technical Reference manual, pp 187 and on. - * - * Based on the original "xebec.c" from Sarah Walker. - * - * Version: @(#)m_europc_hdc.c 1.0.3 2018/03/18 - * - * Authors: Fred N. van Kempen, - * Sarah Walker, - * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2008-2017 Sarah Walker. - * - * Redistribution and use in source and binary forms, with - * or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#define __USE_LARGEFILE64 -#define _LARGEFILE_SOURCE -#define _LARGEFILE64_SOURCE -#include -#include -#include -#include -#include -#include "../86box.h" -#include "../io.h" -#include "../dma.h" -#include "../pic.h" -#include "../device.h" -#include "../timer.h" -#include "../disk/hdc.h" -#include "../disk/hdd.h" -#include "../plat.h" -#include "../ui.h" -#include "machine.h" - - -#define HDC_DEBUG 0 -#define HDC_NEWPARAMS 1 /* use NEW parameter block */ - -#define HDD_IOADDR 0x0320 -#define HDD_IRQCHAN 5 -#define HDD_DMACHAN 3 - - -#define HDC_TIME (200*TIMER_USEC) - - -enum { - STATE_IDLE, - STATE_CMD, - STATE_RUN, - STATE_RXDTA, - STATE_RDATA, - STATE_TXDTA, - STATE_TDATA, - STATE_COMPL -}; - - -/* Command values. */ -#define CMD_TEST_DRV_RDY 0x00 -#define CMD_RECALIBRATE 0x01 - /* unused 0x02 */ -#define CMD_READ_SENSE 0x03 -#define CMD_FORMAT_DRIVE 0x04 -#define CMD_READY_VERIFY 0x05 -#define CMD_FORMAT_TRACK 0x06 -#define CMD_FORMAT_BAD_TRACK 0x07 -#define CMD_READ_SECTORS 0x08 - /* unused 0x09 */ -#define CMD_WRITE_SECTORS 0x0a -#define CMD_SEEK 0x0b -#define CMD_SET_DRIVE_PARAMS 0x0c -#define CMD_READ_ECC_BURST 0x0d -#define CMD_READ_SECTOR_BUFFER 0x0e -#define CMD_WRITE_SECTOR_BUFFER 0x0f -#define CMD_RAM_DIAGS 0xe0 - /* unused 0xe1 */ - /* unused 0xe2 */ -#define CMD_DRIVE_DIAGS 0xe3 -#define CMD_CTRL_DIAGS 0xe4 -#define CMD_READ_LONG 0xe5 -#define CMD_WRITE_LONG 0xe6 - -/* STATUS register values. */ -#define STAT_REQ 0x01 -#define STAT_IO 0x02 -#define STAT_CD 0x04 -#define STAT_BSY 0x08 -#define STAT_DRQ 0x10 -#define STAT_IRQ 0x20 - -/* Sense Error codes. */ -#define ERR_NOERROR 0x00 /* no error detected */ -#define ERR_NOINDEX 0x01 /* drive did not detect IDX pulse */ -#define ERR_NOSEEK 0x02 /* drive did not complete SEEK */ -#define ERR_WRFAULT 0x03 /* write fault during last cmd */ -#define ERR_NOTRDY 0x04 /* drive did not go READY after cmd */ -#define ERR_NOTRK000 0x06 /* drive did not see TRK0 signal */ -#define ERR_LONGSEEK 0x08 /* long seek in progress */ -#define ERR_IDREAD 0x10 /* ECC error during ID field */ -#define ERR_DATA 0x11 /* uncorrectable ECC err in data */ -#define ERR_NOMARK 0x12 /* no address mark detected */ -#define ERR_NOSECT 0x14 /* sector not found */ -#define ERR_SEEK 0x15 /* seek error */ -#define ERR_ECCDATA 0x18 /* ECC corrected data */ -#define ERR_BADTRK 0x19 /* bad track detected */ -#define ERR_ILLCMD 0x20 /* invalid command received */ -#define ERR_ILLADDR 0x21 /* invalid disk address received */ -#define ERR_BADRAM 0x30 /* bad RAM in sector data buffer */ -#define ERR_BADROM 0x31 /* bad checksum in ROM test */ -#define ERR_BADECC 0x32 /* ECC polynomial generator bad */ - -/* Completion Byte fields. */ -#define COMP_DRIVE 0x20 -#define COMP_ERR 0x02 - -#define IRQ_ENA 0x02 -#define DMA_ENA 0x01 - - -/* The device control block (6 bytes) */ -#pragma pack(push,1) -struct dcb { - uint8_t cmd; /* [7:5] class, [4:0] opcode */ - uint8_t head:5, /* [4:0] head number */ - drvsel:1, /* [5] drive select */ - unused:2; /* [7:6] unused MBZ */ - uint8_t sector:6, /* [5:0] sector number 0-63 */ - cylh:2; /* [7:6] cylinder [9:8] bits */ - uint8_t cyl; /* [7:0] cylinder [7:0] bits */ - uint8_t count; /* [7:0] blk count / interleave */ - uint8_t ctrl; /* [7:0] control field */ -}; -#pragma pack(pop) - -/* - * The (configured) Drive Parameters. - * - * Although the IBM specification calls for a total of 8 bytes - * in the Paramater Block, the EuroPC uses a 16-byte block. It - * looks like it has extended (translated?) information there, - * as well as the actual data we need. - * - * [ 03 ac 04 01 f4 02 67 0b 11 04 67 02 00 00 01 00] - * - * is what was sent for a standard 615/4/17 disk with rdwrcyl - * set to 500, and precomp to 615. - * - * For now, we will just look at the rest of the data. - */ -#pragma pack(push,1) -struct dprm { -#if HDC_NEWPARAMS - uint16_t tracks; /* total number of sectors on drive */ - uint8_t heads; /* number of heads per cylinder */ - uint16_t rwcurrent; /* (MSB) reduced write current cylinder */ - uint16_t wprecomp; /* (MSB) write precompensation cylinder */ - uint8_t maxecc; /* max ECC data burst length */ -#else - uint16_t tracks; /* (MSB) max number of cylinders */ - uint8_t heads; /* number of heads per cylinder */ - uint16_t rwcurrent; /* (MSB) reduced write current cylinder */ - uint16_t wprecomp; /* (MSB) write precompensation cylinder */ - uint8_t maxecc; /* max ECC data burst length */ -#endif -}; - -typedef struct { - uint8_t spt, - hpc; - uint16_t tracks; - - struct dprm params; - uint8_t cfg_spt, - cfg_hpc; - uint16_t cfg_tracks; - - uint16_t cur_cyl; - - int8_t present, - hdd_num; -} drive_t; -#pragma pack(pop) - - -typedef struct { - uint16_t base; - int8_t irq; - int8_t dma; - uint8_t mask; - - int8_t state; - int64_t callback; - - uint8_t sense; /* current SENSE ERROR value */ - uint8_t status; /* current operational status */ - - /* Current operation parameters. */ - int16_t buf_idx, /* command buffer index and pointer */ - buf_len; - uint8_t *buf_ptr; - uint16_t track; /* requested track# */ - uint8_t head, /* requested head# */ - sector, /* requested sector# */ - comp; /* operation completion byte */ - int count; /* requested sector count */ - - struct dcb dcb; /* device control block */ - - drive_t drives[MFM_NUM]; - - uint8_t data[512]; /* data buffer */ - uint8_t sector_buf[512]; -} hd20_t; - - -static void -hd20_intr(hd20_t *dev) -{ - dev->status = STAT_REQ|STAT_CD|STAT_IO|STAT_BSY; - dev->state = STATE_COMPL; - if (dev->mask & IRQ_ENA) { - dev->status |= STAT_IRQ; - picint(1<irq); - } -} - - -static int -get_sector(hd20_t *dev, drive_t *drive, off64_t *addr) -{ - int heads = drive->cfg_hpc; - - if (drive->cur_cyl != dev->track) { - pclog("HD20: get_sector: wrong cylinder %d/%d\n", - drive->cur_cyl, dev->track); - dev->sense = ERR_ILLADDR; - return(1); - } - - if (dev->head > heads) { - pclog("HD20: get_sector: past end of configured heads\n"); - dev->sense = ERR_ILLADDR; - return(1); - } - - if (dev->head > drive->hpc) { - pclog("HD20: get_sector: past end of heads\n"); - dev->sense = ERR_ILLADDR; - return(1); - } - - if (dev->sector >= 17) { - pclog("HD20: get_sector: past end of sectors\n"); - dev->sense = ERR_ILLADDR; - return(1); - } - - *addr = ((((off64_t) dev->track*heads) + dev->head)*17) + dev->sector; - - return(0); -} - - -static void -next_sector(hd20_t *dev, drive_t *drive) -{ - if (++dev->sector >= 17) { - dev->sector = 0; - if (++dev->head >= drive->cfg_hpc) { - dev->head = 0; - dev->track++; - drive->cur_cyl++; - if (drive->cur_cyl >= drive->cfg_tracks) - drive->cur_cyl = drive->cfg_tracks-1; - } - } -} - - -/* Execute the DCB we just received. */ -static void -hd20_callback(void *priv) -{ - hd20_t *dev = (hd20_t *)priv; - struct dcb *dcb = &dev->dcb; - drive_t *drive; - off64_t addr; - int val; - - dev->callback = 0; - - drive = &dev->drives[dcb->drvsel]; - dev->comp = (dcb->drvsel) ? COMP_DRIVE : 0x00; - - switch (dcb->cmd) { - case CMD_TEST_DRV_RDY: -#if HDC_DEBUG - if (dcb->drvsel == 0) - pclog("HD20: test_rdy(%d) ready=%d\n", - dcb->drvsel, drive->present); -#endif - if (! drive->present) { - dev->comp |= COMP_ERR; - dev->sense = ERR_NOTRDY; - } - hd20_intr(dev); - break; - - case CMD_RECALIBRATE: -#if HDC_DEBUG - if (dcb->drvsel == 0) - pclog("HD20: recalibrate(%d) ready=%d\n", - dcb->drvsel, drive->present); -#endif - if (! drive->present) { - dev->comp |= COMP_ERR; - dev->sense = ERR_NOTRDY; - } else { - dev->track = drive->cur_cyl = 0; - } - hd20_intr(dev); - break; - - case CMD_READ_SENSE: - if (dev->state == STATE_RUN) { -#if HDC_DEBUG - if (dcb->drvsel == 0) - pclog("HD20: sense(%d)\n", dcb->drvsel); -#endif - dev->buf_idx = 0; - dev->buf_len = 4; - dev->buf_ptr = dev->data; - dev->data[0] = dev->sense; - dev->data[1] = dcb->drvsel ? 0x20 : 0x00; - dev->data[2] = dev->data[3] = 0x00; - dev->sense = ERR_NOERROR; - dev->status = STAT_BSY|STAT_IO|STAT_REQ; - dev->state = STATE_TXDTA; - } else if (dev->state == STATE_TDATA) { - hd20_intr(dev); - } - break; - - case CMD_READY_VERIFY: - if (dev->state == STATE_RUN) { - /* Seek to cylinder. */ - dev->track = dcb->cyl | (dcb->cylh<<2); - if (dev->track >= drive->cfg_tracks) - drive->cur_cyl = drive->cfg_tracks-1; - else - drive->cur_cyl = dev->track; - dev->head = dcb->head; - dev->sector = dcb->sector; -#if HDC_DEBUG - pclog("HD20: verify_sector(%d) %d,%d,%d\n", - dcb->drvsel, dev->track, dev->head,dev->sector); -#endif - - /* Get sector count; count=0 means 256. */ - dev->count = (int)dcb->count; - if (dev->count == 0) dev->count = 256; - while (dev->count-- > 0) { - if (get_sector(dev, drive, &addr)) { - pclog("HD20: get_sector failed\n"); - dev->comp |= COMP_ERR; - hd20_intr(dev); - return; - } - - next_sector(dev, drive); - } - - hd20_intr(dev); - - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - } - break; - - case CMD_FORMAT_DRIVE: -#if HDC_DEBUG - pclog("HD20: format_drive(%d)\n", dcb->drvsel); -#endif - for (dev->track=0; dev->tracktracks; dev->track++) { - drive->cur_cyl = dev->track; - for (dev->head=0; dev->headhpc; dev->head++) { - dev->sector = 0; - - if (get_sector(dev, drive, &addr)) { - pclog("HD20: get_sector failed\n"); - dev->comp |= COMP_ERR; - hd20_intr(dev); - return; - } - - hdd_image_zero(drive->hdd_num,addr,drive->spt); - - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - } - } - hd20_intr(dev); - break; - - case CMD_FORMAT_TRACK: - /* Seek to cylinder. */ - dev->track = dcb->cyl | (dcb->cylh<<2); - if (dev->track >= drive->cfg_tracks) - drive->cur_cyl = drive->cfg_tracks-1; - else - drive->cur_cyl = dev->track; - dev->head = dcb->head; - dev->sector = 0; -#if HDC_DEBUG - pclog("HD20: format_track(%d) %d,%d\n", - dcb->drvsel, dev->track, dev->head); -#endif - - if (get_sector(dev, drive, &addr)) { - pclog("HD20: get_sector failed\n"); - dev->comp |= COMP_ERR; - hd20_intr(dev); - return; - } - - hdd_image_zero(drive->hdd_num, addr, drive->spt); - - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - - hd20_intr(dev); - break; - - case CMD_READ_SECTORS: - switch (dev->state) { - case STATE_RUN: - /* Seek to cylinder. */ - dev->track = dcb->cyl | (dcb->cylh<<2); - if (dev->track >= drive->cfg_tracks) - drive->cur_cyl = drive->cfg_tracks-1; - else - drive->cur_cyl = dev->track; - dev->head = dcb->head; - dev->sector = dcb->sector; - - /* Get sector count; count=0 means 256. */ - dev->count = (int)dcb->count; - if (dev->count == 0) dev->count = 256; -#if HDC_DEBUG - pclog("HD20: read_sector(%d) %d,%d,%d cnt=%d\n", - dcb->drvsel, dev->track, dev->head, - dev->sector, dev->count); -#endif - - if (get_sector(dev, drive, &addr)) { - dev->comp |= COMP_ERR; - hd20_intr(dev); - return; - } - - hdd_image_read(drive->hdd_num, addr, 1, - (uint8_t *)dev->sector_buf); - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - - /* Ready to transfer the data out. */ - dev->buf_idx = 0; - dev->buf_len = 512; - dev->state = STATE_TXDTA; - - if (! (dev->mask & DMA_ENA)) { - memcpy(dev->data, dev->sector_buf, 512); - dev->buf_ptr = dev->data; - dev->status = STAT_BSY|STAT_IO|STAT_REQ; - } else { - dev->callback = HDC_TIME; - dev->buf_ptr = dev->sector_buf; - } - break; - - case STATE_TXDTA: - dev->status = STAT_BSY; - while (dev->buf_idx < dev->buf_len) { - val = dma_channel_write(dev->dma, - *dev->buf_ptr++); - if (val == DMA_NODATA) { - pclog("CMD_READ_SECTORS out of data!\n"); - dev->status = STAT_BSY|STAT_CD|STAT_IO|STAT_REQ; - dev->callback = HDC_TIME; - return; - } - dev->buf_idx++; - } - dev->state = STATE_TDATA; - dev->callback = HDC_TIME; - break; - - case STATE_TDATA: - next_sector(dev, drive); - - dev->buf_idx = 0; - if (--dev->count == 0) { - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); - hd20_intr(dev); - return; - } - - if (get_sector(dev, drive, &addr)) { - dev->comp |= COMP_ERR; - hd20_intr(dev); - return; - } - - hdd_image_read(drive->hdd_num, addr, 1, - (uint8_t *)dev->sector_buf); - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - - dev->state = STATE_TXDTA; - - if (! (dev->mask & DMA_ENA)) { - memcpy(dev->data, dev->sector_buf, 512); - dev->buf_ptr = dev->data; - dev->status = STAT_BSY|STAT_IO|STAT_REQ; - } else { - dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; - } - break; - } - break; - - case CMD_WRITE_SECTORS: - switch (dev->state) { - case STATE_RUN: - /* Seek to cylinder. */ - dev->track = dcb->cyl | (dcb->cylh<<2); - if (dev->track >= drive->cfg_tracks) - drive->cur_cyl = drive->cfg_tracks-1; - else - drive->cur_cyl = dev->track; - dev->head = dcb->head; - dev->sector = dcb->sector; - - /* Get sector count; count=0 means 256. */ - dev->count = (int)dev->dcb.count; - if (dev->count == 0) dev->count = 256; -#if HDC_DEBUG - pclog("HD20: write_sector(%d) %d,%d,%d cnt=%d\n", - dcb->drvsel, dev->track, dev->head, - dev->sector, dev->count); -#endif - dev->buf_idx = 0; - dev->buf_len = 512; - dev->state = STATE_RXDTA; - if (! (dev->mask & DMA_ENA)) { - dev->buf_ptr = dev->data; - dev->status = STAT_BSY|STAT_REQ; - } else { - dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; - } - break; - - case STATE_RXDTA: - dev->status = STAT_BSY; - while (dev->buf_idx < dev->buf_len) { - val = dma_channel_read(dev->dma); - if (val == DMA_NODATA) { - pclog("CMD_WRITE_SECTORS out of data!\n"); - dev->status = STAT_BSY|STAT_CD|STAT_IO|STAT_REQ; - dev->callback = HDC_TIME; - return; - } - - *dev->buf_ptr++ = (val & 0xff); - dev->buf_idx++; - } - dev->state = STATE_RDATA; - dev->callback = HDC_TIME; - break; - - case STATE_RDATA: -#if 0 -/* If I enable this, we get data corruption.. ??? -FvK */ - if (! (dev->mask & DMA_ENA)) - memcpy(dev->sector_buf, dev->data, 512); -#endif - - if (get_sector(dev, drive, &addr)) { - dev->comp |= COMP_ERR; - hd20_intr(dev); - - return; - } - - hdd_image_write(drive->hdd_num, addr, 1, - (uint8_t *)dev->sector_buf); - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); - - next_sector(dev, drive); - - dev->buf_idx = 0; - if (--dev->count == 0) { - ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); - hd20_intr(dev); - break; - } - - dev->state = STATE_RXDTA; - if (! (dev->mask & DMA_ENA)) { - dev->buf_ptr = dev->data; - dev->status = STAT_BSY|STAT_REQ; - } else { - dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; - } - } - break; - - case CMD_SEEK: - if (! drive->present) { - dev->comp |= COMP_ERR; - dev->sense = ERR_NOTRDY; - hd20_intr(dev); - break; - } - - /* Seek to cylinder. */ - val = dcb->cyl | (dcb->cylh<<2); - if (val >= drive->cfg_tracks) - drive->cur_cyl = drive->cfg_tracks-1; - else - drive->cur_cyl = val; -#if HDC_DEBUG - pclog("HD20: seek(%d) %d/%d\n", - dcb->drvsel, val, drive->cur_cyl); -#endif - - if (val != drive->cur_cyl) { - dev->comp |= COMP_ERR; - dev->sense = ERR_SEEK; - } - hd20_intr(dev); - break; - - case CMD_SET_DRIVE_PARAMS: - if (dev->state == STATE_RUN) { - dev->state = STATE_RXDTA; - dev->buf_idx = 0; - dev->buf_len = sizeof(struct dprm); - dev->buf_ptr = (uint8_t *)&drive->params; - dev->status = STAT_BSY|STAT_REQ; - } else { -dev->buf_ptr=(uint8_t *)&drive->params; -pclog("HD20: PARAMS=["); -for(val=0;val<8;val++)pclog(" %02x",*dev->buf_ptr++); -pclog(" ]\n"); -#if 0 - drive->cfg_tracks = drive->params.tracks; - drive->cfg_hpc = drive->params.heads; - drive->cfg_spt = drive->spt; -#endif -#if HDC_DEBUG - pclog("HD20: set_params(%d) cyl=%d,hd=%d,spt=%d\n", - dcb->drvsel, drive->cfg_tracks, - drive->cfg_hpc, drive->cfg_spt); -#endif - hd20_intr(dev); - } - break; - - case CMD_WRITE_SECTOR_BUFFER: - switch (dev->state) { - case STATE_RUN: -#if HDC_DEBUG - pclog("HD20: write_sector_buffer(%d)\n", - dcb->drvsel); -#endif - dev->buf_idx = 0; - dev->buf_len = 512; - dev->state = STATE_RXDTA; - if (! (dev->mask & DMA_ENA)) { - dev->buf_ptr = dev->data; - dev->status = STAT_BSY|STAT_REQ; - } else { - dev->buf_ptr = dev->sector_buf; - dev->callback = HDC_TIME; - } - break; - - case STATE_RXDTA: - dev->status = STAT_BSY; - if (! (dev->mask & DMA_ENA)) break; - - while (dev->buf_idx++ < dev->buf_len) { - val = dma_channel_read(dev->dma); - if (val == DMA_NODATA) { - pclog("CMD_WRITE_SECTORS out of data!\n"); - dev->status = STAT_BSY|STAT_CD|STAT_IO|STAT_REQ; - dev->callback = HDC_TIME; - return; - } - - *dev->buf_ptr++ = (val & 0xff); - } - dev->state = STATE_RDATA; - dev->callback = HDC_TIME; - break; - - case STATE_RDATA: - if (! (dev->mask & DMA_ENA)) - memcpy(dev->sector_buf, dev->data, 512); - - hd20_intr(dev); - break; - } - break; - - case CMD_RAM_DIAGS: -#if HDC_DEBUG - pclog("HD20: ram_diags\n"); -#endif - dev->callback = 5*HDC_TIME; - hd20_intr(dev); - break; - - case CMD_DRIVE_DIAGS: -#if HDC_DEBUG - pclog("HD20: drive_diags(%d)\n", dcb->drvsel); -#endif - dev->callback = 5*HDC_TIME; - hd20_intr(dev); - break; - - case CMD_CTRL_DIAGS: -#if HDC_DEBUG - pclog("HD20: ctrl_diags\n"); -#endif - dev->callback = 5*HDC_TIME; - hd20_intr(dev); - break; - - default: - pclog("HD20: unknown command - %02x\n", dcb->cmd); - dev->comp |= COMP_ERR; - dev->sense = ERR_ILLCMD; - hd20_intr(dev); - } -} - - -/* Read one of the HD controller registers. */ -static uint8_t -hd20_read(uint16_t port, void *priv) -{ - hd20_t *dev = (hd20_t *)priv; - uint8_t ret = 0xff; - - switch (port-dev->base) { - case 0: /* read data */ - dev->status &= ~STAT_IRQ; - - if (dev->state == STATE_TXDTA) { - if ((dev->status & 0x0f) != - (STAT_IO|STAT_REQ|STAT_BSY)) - fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", dev->status); - if (dev->buf_idx > dev->buf_len) { - pclog("HD20: read with empty buffer!\n"); - dev->comp |= COMP_ERR; - dev->sense = ERR_ILLCMD; - break; - } - - ret = dev->data[dev->buf_idx++]; - if (dev->buf_idx == dev->buf_len) { - dev->status = STAT_BSY; - dev->state = STATE_TDATA; - dev->callback = HDC_TIME; - } - } else if (dev->state == STATE_COMPL) { - if ((dev->status & 0x0f) != - (STAT_CD|STAT_IO|STAT_REQ|STAT_BSY)) - fatal("Read data STATE_COMPL, status=%02x\n", dev->status); - ret = dev->comp; - dev->status = 0x00; - dev->state = STATE_IDLE; - } - break; - - case 1: /* read status */ - ret = dev->status; - break; - - case 2: /* read option jumpers */ - ret = 0x00; - break; - } - -#if HDC_DEBUG > 1 - pclog("HD20: read(%04x) = %02x\n", port, ret); -#endif - return(ret); -} - - -static void -hd20_write(uint16_t port, uint8_t val, void *priv) -{ - hd20_t *dev = (hd20_t *)priv; - -#if HDC_DEBUG > 1 - pclog("HD20: write(%04x,%02x)\n", port, val); -#endif - switch (port-dev->base) { - case 0: /* write command/data */ - if (! (dev->status & STAT_REQ)) { - pclog("HD20: not ready for command/data!\n"); - dev->comp |= COMP_ERR; - dev->sense = ERR_ILLCMD; - break; - } - - if (dev->buf_idx >= dev->buf_len) { - pclog("HD20: write with full buffer!\n"); - dev->comp |= COMP_ERR; - dev->sense = ERR_ILLCMD; - break; - } - - /* Store the data into the buffer. */ - *dev->buf_ptr++ = val; - if (++dev->buf_idx == dev->buf_len) { - /* We got all the data we need. */ - dev->status &= ~STAT_REQ; - dev->state = (dev->state==STATE_CMD) ? STATE_RUN : STATE_RDATA; - dev->callback = HDC_TIME; - } - break; - - case 1: /* controller reset */ - dev->sense = 0x00; - /*FALLTHROUGH*/ - - case 2: /* generate controller-select-pulse */ - dev->status = STAT_BSY|STAT_CD|STAT_REQ; - dev->buf_idx = 0; - dev->buf_len = sizeof(struct dcb); - dev->buf_ptr = (uint8_t *)&dev->dcb; - dev->state = STATE_CMD; - break; - - case 3: /* DMA/IRQ mask register */ - dev->mask = val; - break; - } -} - - -static void * -hd20_init(const device_t *info) -{ - drive_t *drive; - hd20_t *dev; - int c, i; - - pclog("EuroPC: initializing HD20 controller.\n"); - - dev = malloc(sizeof(hd20_t)); - memset(dev, 0x00, sizeof(hd20_t)); - dev->base = HDD_IOADDR; - dev->irq = HDD_IRQCHAN; - dev->dma = HDD_DMACHAN; - - for (c=0,i=0; idrives[hdd[i].mfm_channel]; - - if (! hdd_image_load(i)) { - drive->present = 0; - continue; - } - - /* These are the "hardware" parameters (from the image.) */ - drive->spt = hdd[i].spt; - drive->hpc = hdd[i].hpc; - drive->tracks = hdd[i].tracks; - - /* Use them as "configured" parameters until overwritten. */ - drive->cfg_spt = drive->spt; - drive->cfg_hpc = drive->hpc; - drive->cfg_tracks = drive->tracks; - - drive->hdd_num = i; - drive->present = 1; - - pclog("HD20: drive%d (cyl=%d,hd=%d,spt=%d), disk %d\n", - hdd[i].mfm_channel,drive->tracks,drive->hpc,drive->spt,i); - - if (++c > MFM_NUM) break; - } - } - - io_sethandler(dev->base, 4, - hd20_read, NULL, NULL, hd20_write, NULL, NULL, dev); - - timer_add(hd20_callback, &dev->callback, &dev->callback, dev); - - return(dev); -} - - -static void -hd20_close(void *priv) -{ - hd20_t *dev = (hd20_t *)priv; - drive_t *drive; - int d; - - for (d=0; d<2; d++) { - drive = &dev->drives[d]; - - hdd_image_close(drive->hdd_num); - } - - free(dev); -} - - -static int -hd20_available(void) -{ - return(1); -} - - -const device_t europc_hdc_device = { - "EuroPC HD20", - 0, 0, - hd20_init, hd20_close, NULL, - hd20_available, NULL, NULL, NULL, - NULL -}; diff --git a/src/machine/m_olivetti_m24.c b/src/machine/m_olivetti_m24.c index b8128f25b..2a3f2d1c7 100644 --- a/src/machine/m_olivetti_m24.c +++ b/src/machine/m_olivetti_m24.c @@ -8,7 +8,7 @@ * * Emulation of the Olivetti M24. * - * Version: @(#)m_olivetti_m24.c 1.0.12 2018/03/19 + * Version: @(#)m_olivetti_m24.c 1.0.13 2018/04/10 * * Authors: Sarah Walker, * Miran Grca, @@ -849,7 +849,7 @@ machine_olim24_init(const machine_t *model) device_add(&gameport_device); /* FIXME: make sure this is correct?? */ - nvr_at_init(8); + device_add(&at_nvr_device); nmi_init(); } diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 9be9cbd2c..eadce712d 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -28,7 +28,7 @@ * boot. Sometimes, they do, and then it shows an "Incorrect * DOS" error message?? --FvK * - * Version: @(#)m_ps1.c 1.0.7 2018/03/18 + * Version: @(#)m_ps1.c 1.0.8 2018/04/10 * * Authors: Sarah Walker, * Miran Grca, @@ -88,7 +88,8 @@ typedef struct { rom_t high_rom; - uint8_t ps1_92, + uint8_t ps1_91, + ps1_92, ps1_94, ps1_102, ps1_103, @@ -97,11 +98,6 @@ typedef struct { ps1_190; int ps1_e0_addr; uint8_t ps1_e0_regs[256]; - - struct { - uint8_t status, int_status; - uint8_t attention, ctrl; - } hd; } ps1_t; @@ -334,7 +330,7 @@ ps1_write(uint16_t port, uint8_t val, void *priv) lpt1_remove(); if (val & 0x04) serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - else + else serial_remove(1); if (val & 0x10) { switch ((val >> 5) & 3) { @@ -367,22 +363,6 @@ ps1_write(uint16_t port, uint8_t val, void *priv) case 0x0190: ps->ps1_190 = val; break; - - case 0x0322: - if (ps->model == 2011) { - ps->hd.ctrl = val; - if (val & 0x80) - ps->hd.status |= 0x02; - } - break; - - case 0x0324: - if (ps->model == 2011) { - ps->hd.attention = val & 0xf0; - if (ps->hd.attention) - ps->hd.status = 0x14; - } - break; } } @@ -395,7 +375,8 @@ ps1_read(uint16_t port, void *priv) switch (port) { case 0x0091: - ret = 0; + ret = ps->ps1_91; + ps->ps1_91 = 0; break; case 0x0092: @@ -438,19 +419,6 @@ ps1_read(uint16_t port, void *priv) ret = ps->ps1_190; break; - case 0x0322: - if (ps->model == 2011) { - ret = ps->hd.status; - } - break; - - case 0x0324: - if (ps->model == 2011) { - ret = ps->hd.int_status; - ps->hd.int_status &= ~0x02; - } - break; - default: break; } @@ -463,6 +431,7 @@ static void ps1_setup(int model) { ps1_t *ps; + void *priv; ps = (ps1_t *)malloc(sizeof(ps1_t)); memset(ps, 0x00, sizeof(ps1_t)); @@ -479,23 +448,15 @@ ps1_setup(int model) io_sethandler(0x0190, 1, ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + lpt1_remove(); + lpt1_init(0x3bc); + if (model == 2011) { - io_sethandler(0x0320, 1, - ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); - io_sethandler(0x0322, 1, - ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); - io_sethandler(0x0324, 1, - ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); - -#if 0 rom_init(&ps->high_rom, - L"roms/machines/ibmps1es/f80000_shell.bin", + L"roms/machines/ibmps1es/f80000.bin", 0xf80000, 0x80000, 0x7ffff, 0, MEM_MAPPING_EXTERNAL); -#endif - lpt1_remove(); lpt2_remove(); - lpt1_init(0x03bc); serial_remove(1); serial_remove(2); @@ -505,31 +466,44 @@ ps1_setup(int model) device_add(&ps1vga_device); else device_add(&ibm_ps1_2121_device); + + device_add(&snd_device); + + device_add(&fdc_at_actlow_device); + + /* Enable the builtin HDC. */ + if (hdc_current == 1) { + priv = device_add(&ps1_hdc_device); + + ps1_hdc_inform(priv, ps); + } } if (model == 2121) { io_sethandler(0x00e0, 2, ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); -#if 1 +#if 0 rom_init(&ps->high_rom, L"roms/machines/ibmps1_2121/fc0000.bin", 0xfc0000, 0x20000, 0x1ffff, 0, MEM_MAPPING_EXTERNAL); -#else - rom_init(&ps->high_rom, - L"roms/machines/ibmps1_2121/fc0000_shell.bin", - 0xfc0000, 0x40000, 0x3ffff, 0, MEM_MAPPING_EXTERNAL); #endif - lpt1_init(0x03bc); - /* Initialize the video controller. */ if (gfxcard == GFX_INTERNAL) device_add(&ibm_ps1_2121_device); + + device_add(&fdc_at_ps1_device); + + device_add(&ide_isa_device); + + device_add(&snd_device); } if (model == 2133) { - lpt1_init(0x03bc); + device_add(&fdc_at_device); + + device_add(&ide_isa_device); } } @@ -546,29 +520,26 @@ ps1_common_init(const machine_t *model) dma16_init(); pic2_init(); - nvr_at_init(8); - - if (romset != ROM_IBMPS1_2011) - device_add(&ide_isa_device); + device_add(&ps_nvr_device); device_add(&keyboard_ps2_device); - if (romset == ROM_IBMPS1_2133) - device_add(&fdc_at_device); - else { - if ((romset == ROM_IBMPS1_2121) || (romset == ROM_IBMPS1_2121_ISA)) - device_add(&fdc_at_ps1_device); - else - device_add(&fdc_at_actlow_device); - device_add(&snd_device); - } - /* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */ if (joystick_type != 7) device_add(&gameport_201_device); } +/* Set the Card Selected Flag */ +void +ps1_set_feedback(void *priv) +{ + ps1_t *ps = (ps1_t *)priv; + + ps->ps1_91 |= 0x01; +} + + void machine_ps1_m2011_init(const machine_t *model) { diff --git a/src/machine/m_ps1_hdc.c b/src/machine/m_ps1_hdc.c new file mode 100644 index 000000000..c89e19bee --- /dev/null +++ b/src/machine/m_ps1_hdc.c @@ -0,0 +1,1523 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the PS/1 Model 2011 disk controller. + * + * XTA is the acronym for 'XT-Attached', which was basically + * the XT-counterpart to what we know now as IDE (which is + * also named ATA - AT Attachment.) The basic ideas was to + * put the actual drive controller electronics onto the drive + * itself, and have the host machine just talk to that using + * a simpe, standardized I/O path- hence the name IDE, for + * Integrated Drive Electronics. + * + * In the ATA version of IDE, the programming interface of + * the IBM PC/AT (which used the Western Digitial 1002/1003 + * controllers) was kept, and, so, ATA-IDE assumes a 16bit + * data path: it reads and writes 16bit words of data. The + * disk drives for this bus commonly have an 'A' suffix to + * identify them as 'ATBUS'. + * + * In XTA-IDE, which is slightly older, the programming + * interface of the IBM PC/XT (which used the MFM controller + * from Xebec) was kept, and, so, it uses an 8bit data path. + * Disk drives for this bus commonly have the 'X' suffix to + * mark them as being for this XTBUS variant. + * + * So, XTA and ATA try to do the same thing, but they use + * different ways to achive their goal. + * + * Also, XTA is **not** the same as XTIDE. XTIDE is a modern + * variant of ATA-IDE, but retro-fitted for use on 8bit XT + * systems: an extra register is used to deal with the extra + * data byte per transfer. XTIDE uses regular IDE drives, + * and uses the regular ATA/IDE programming interface, just + * with the extra register. + * + * NOTE: We should probably find a nicer way to integrate our Disk + * Type table with the main code, so the user can only select + * items from that list... + * + * Version: @(#)m_ps1_hdc.c 1.0.3 2018/04/23 + * + * Author: Fred N. van Kempen, + * + * Based on my earlier HD20 driver for the EuroPC. + * Thanks to Marco Bortolin for the help and feedback !! + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../device.h" +#include "../timer.h" +#include "../disk/hdc.h" +#include "../disk/hdd.h" +#include "../plat.h" +#include "../ui.h" +#include "machine.h" + + +#define HDC_TIME (200*TIMER_USEC) +#define HDC_TYPE_USER 47 /* user drive type */ + + +enum { + STATE_IDLE = 0, + STATE_RECV, + STATE_RDATA, + STATE_RDONE, + STATE_SEND, + STATE_SDATA, + STATE_SDONE, + STATE_FINIT, + STATE_FDONE +}; + + +/* Command values. These deviate from the XTA ones. */ +#define CMD_READ_SECTORS 0x01 /* regular read-date */ +#define CMD_READ_VERIFY 0x02 /* read for verify, no data */ +#define CMD_READ_EXT 0x03 /* read extended (ecc) */ +#define CMD_READ_ID 0x05 /* read ID mark on cyl */ +#define CMD_RECALIBRATE 0x08 /* recalibrate to track0 */ +#define CMD_WRITE_SECTORS 0x09 /* regular write-data */ +#define CMD_WRITE_VERIFY 0x0a /* write-data with verify */ +#define CMD_WRITE_EXT 0x0b /* write extended (ecc) */ +#define CMD_FORMAT_DRIVE 0x0d /* format entire disk */ +#define CMD_SEEK 0x0e /* seek */ +#define CMD_FORMAT_TRACK 0x0f /* format one track */ + +/* Attachment Status register (reg 2R) values (IBM PS/1 2011.) */ +#define ASR_TX_EN 0x01 /* transfer enable */ +#define ASR_INT_REQ 0x02 /* interrupt request */ +#define ASR_BUSY 0x04 /* busy */ +#define ASR_DIR 0x08 /* direction */ +#define ASR_DATA_REQ 0x10 /* data request */ + +/* Attachment Control register (2W) values (IBM PS/1 2011.) */ +#define ACR_DMA_EN 0x01 /* DMA enable */ +#define ACR_INT_EN 0x02 /* interrupt enable */ +#define ACR_RESET 0x80 /* reset */ + +/* Interrupt Status register (4R) values (IBM PS/1 2011.) */ +#define ISR_EQUIP_CHECK 0x01 /* internal hardware error */ +#define ISR_ERP_INVOKED 0x02 /* error recovery invoked */ +#define ISR_CMD_REJECT 0x20 /* command reject */ +#define ISR_INVALID_CMD 0x40 /* invalid command */ +#define ISR_TERMINATION 0x80 /* termination error */ + +/* Attention register (4W) values (IBM PS/1 2011.) */ +#define ATT_DATA 0x10 /* data request */ +#define ATT_SSB 0x20 /* sense summary block */ +#define ATT_CSB 0x40 /* command specify block */ +#define ATT_CCB 0x80 /* command control block */ + + +/* + * Define the Sense Summary Block. + * + * The sense summary block contains the current status of the + * drive. The information in the summary block is updated after + * each command is completed, after an error, or before the + * block is transferred. + */ +#pragma pack(push,1) +typedef struct { + /* Status byte 0. */ + uint8_t track_0 :1, /* T0 */ + mbz1 :1, /* 0 */ + mbz2 :1, /* 0 */ + cylinder_err :1, /* CE */ + write_fault :1, /* WF */ + mbz3 :1, /* 0 */ + seek_end :1, /* SE */ + not_ready :1; /* NR */ + + /* Status byte 1. */ + uint8_t id_not_found :1, /* ID */ + mbz4 :1, /* 0 */ + mbz5 :1, /* 0 */ + wrong_cyl :1, /* WC */ + all_bit_set :1, /* BT */ + mark_not_found :1, /* AM */ + ecc_crc_err :1, /* ET */ + ecc_crc_field :1; /* EF */ + + /* Status byte 2. */ + uint8_t headsel_state :4, /* headsel state[4] */ + defective_sector:1, /* DS */ + retried_ok :1, /* RG */ + need_reset :1, /* RR */ +#if 1 + valid :1; /* 0 (abused as VALID) */ +#else + mbz6 :1; /* 0 */ +#endif + + /* Most recent ID field seen. */ + uint8_t last_cyl_low; /* Cyl_Low[8] */ + uint8_t last_head :4, /* HD[4] */ + mbz7 :1, /* 0 */ + last_cyl_high :2, /* Cyl_high[2] */ + last_def_sect :1; /* DS */ + uint8_t last_sect; /* Sect[8] */ + + uint8_t sect_size; /* Size[8] = 02 */ + + /* Current position. */ + uint8_t curr_cyl_high :2, /* Cyl_High_[2] */ + mbz8 :1, /* 0 */ + mbz9 :1, /* 0 */ + curr_head :4; /* HD_2[4] */ + uint8_t curr_cyl_low; /* Cyl_Low_2[8] */ + + uint8_t sect_corr; /* sectors corrected */ + + uint8_t retries; /* retries */ + + /* + * This byte shows the progress of the controller through the + * last command. It allows the system to monitor the controller + * and determine if a reset is needed. When the transfer of the + * control block is started, the value is set to hex 00. The + * progress indicated by this byte is: + * + * 1. Set to hex 01 after the control block is successfully + * transferred. + * + * 2. Set to hex 02 when the command is valid and the drive + * is ready. + * + * 3. Set to hex 03 when the head is in the correct track. + * The most-significant four bits (high nibble) are then + * used to indicate the successful stages of the data + * transfer: + * + * Bit 7 A sector was transferred between the system + * and the sector buffer. + * + * Bit 6 A sector was transferred between the controller + * and the sector buffer. + * + * Bit 5 An error was detected and error recovery + * procedures have been started. + * + * Bit 4 The controller has completed the operation + * and is now not busy. + * + * 4. When the transfer is complete, the low nibble equals hex 4 + * and the high nibble is unchanged. + */ + uint8_t cmd_syndrome; /* command syndrome */ + + uint8_t drive_type; /* drive type */ + + uint8_t rsvd; /* reserved byte */ +} ssb_t; +#pragma pack(pop) + +/* + * Define the Format Control Block. + * + * The format control block (FCB) specifies the ID data used + * in formatting the track. It is used by the Format Track + * and Format Disk commands and contains five bytes for each + * sector formatted on that track. + * + * When the Format Disk command is used, the control block + * contains the sector information of all sectors for head 0, + * cylinder 0. The drive will use the same block to format + * the rest of the disk and automatically increment the head + * number and cylinder number for the remaining tracks. The + * sector numbers, sector size, and the fill byte will be + * the same for each track. + * + * The drive formats the sector IDs on the disk in the same + * order as they are specified in the control block. + * Therefore, sector interleaving is accomplished by filling + * in the control block with the desired interleave. + * + * For example, when formatting 17 sectors per track with an + * interleave of 2, the control block has the first 5 bytes + * with a sector number of 1, the second with a sector number + * of 10, the third with a sector number of 2, and continuing + * until all 17 sectors for that track are defined. + * + * The format for the format control block is described in + * the following. The five bytes are repeated for each + * sector on the track. The control block must contain an + * even number of bytes. If an odd number of sectors are + * being formatted, an additional byte is sent with all + * bits 0. + */ +#pragma pack(push,1) +typedef struct { + uint8_t cyl_high :2, /* cylinder [9:8] bits */ + defective_sector:1, /* DS */ + mbz1 :1, /* 0 */ + head :4; /* head number */ + + uint8_t cyl_low; /* cylinder [7:0] bits */ + + uint8_t sector; /* sector number */ + + uint8_t mbz2 :1, /* 0 */ + mbo :1, /* 1 */ + mbz3 :6; /* 000000 */ + + uint8_t fill; /* filler byte */ +} fcb_t; +#pragma pack(pop) + +/* + * Define the Command Control Block. + * + * The system specifies the operation by sending the 6-byte + * command control block to the controller. It can be sent + * through a DMA or PIO operation. + */ +#pragma pack(push,1) +typedef struct { + uint8_t ec_p :1, /* EC/P (ecc/park) */ + mbz1 :1, /* 0 */ + auto_seek :1, /* AS (auto-seek) */ + no_data :1, /* ND (no data) */ + cmd :4; /* command code[4] */ + + uint8_t cyl_high :2, /* cylinder [9:8] bits */ + mbz2 :2, /* 00 */ + head :4; /* head number */ + + uint8_t cyl_low; /* cylinder [7:0] bits */ + + uint8_t sector; /* sector number */ + + uint8_t mbz3 :1, /* 0 */ + mbo1 :1, /* 1 */ + mbz4 :6; /* 000000 */ + + uint8_t count; /* blk count/interleave */ +} ccb_t; +#pragma pack(pop) + +/* Define the hard drive geometry table. */ +typedef struct { + uint16_t cyl; + uint8_t hpc; + uint8_t spt; + int16_t wpc; + int16_t lz; +} geom_t; + +/* Define an attached drive. */ +typedef struct { + int8_t id, /* drive ID on bus */ + present, /* drive is present */ + hdd_num, /* index to global disk table */ + type; /* drive type ID */ + + uint16_t cur_cyl; /* last known position of heads */ + + uint8_t spt, /* active drive parameters */ + hpc; + uint16_t tracks; + + uint8_t cfg_spt, /* configured drive parameters */ + cfg_hpc; + uint16_t cfg_tracks; +} drive_t; + + +typedef struct { + uint16_t base; /* controller base I/O address */ + int8_t irq; /* controller IRQ channel */ + int8_t dma; /* controller DMA channel */ + + /* Registers. */ + uint8_t attn, /* ATTENTION register */ + ctrl, /* Control register (ACR) */ + status, /* Status register (ASR) */ + intstat; /* Interrupt Status register (ISR) */ + + void *sys; /* handle to system board */ + + /* Controller state. */ + int64_t callback; + int8_t state, /* controller state */ + reset; /* reset state counter */ + + /* Data transfer. */ + int16_t buf_idx, /* buffer index and pointer */ + buf_len; + uint8_t *buf_ptr; + + /* Current operation parameters. */ + ssb_t ssb; /* sense block */ + ccb_t ccb; /* command control block */ + uint16_t track; /* requested track# */ + uint8_t head, /* requested head# */ + sector; /* requested sector# */ + int count; /* requested sector count */ + + drive_t drives[XTA_NUM]; /* the attached drive(s) */ + + uint8_t data[512]; /* data buffer */ + uint8_t sector_buf[512]; /* sector buffer */ +} hdc_t; + + +/* + * IBM hard drive types 1-44. + * + * We need these to translate the selected disk's + * geometry back to a valid type through the SSB. + * + * Cyl. Head Sect. Write Land + * p-comp Zone + */ +static const geom_t ibm_type_table[] = { + { 0, 0, 0, 0, 0 }, /* 0 (none) */ + { 306, 4, 17, 128, 305 }, /* 1 10 MB */ + { 615, 4, 17, 300, 615 }, /* 2 20 MB */ + { 615, 6, 17, 300, 615 }, /* 3 31 MB */ + { 940, 8, 17, 512, 940 }, /* 4 62 MB */ + { 940, 6, 17, 512, 940 }, /* 5 47 MB */ + { 615, 4, 17, -1, 615 }, /* 6 20 MB */ + { 462, 8, 17, 256, 511 }, /* 7 31 MB */ + { 733, 5, 17, -1, 733 }, /* 8 30 MB */ + { 900, 15, 17, -1, 901 }, /* 9 112 MB */ + { 820, 3, 17, -1, 820 }, /* 10 20 MB */ + { 855, 5, 17, -1, 855 }, /* 11 35 MB */ + { 855, 7, 17, -1, 855 }, /* 12 50 MB */ + { 306, 8, 17, 128, 319 }, /* 13 20 MB */ + { 733, 7, 17, -1, 733 }, /* 14 43 MB */ + { 0, 0, 0, 0, 0 }, /* 15 (rsvd) */ + { 612, 4, 17, 0, 663 }, /* 16 20 MB */ + { 977, 5, 17, 300, 977 }, /* 17 41 MB */ + { 977, 7, 17, -1, 977 }, /* 18 57 MB */ + { 1024, 7, 17, 512, 1023 }, /* 19 59 MB */ + { 733, 5, 17, 300, 732 }, /* 20 30 MB */ + { 733, 7, 17, 300, 732 }, /* 21 43 MB */ + { 733, 5, 17, 300, 733 }, /* 22 30 MB */ + { 306, 4, 17, 0, 336 }, /* 23 10 MB */ + { 612, 4, 17, 305, 663 }, /* 24 20 MB */ + { 306, 4, 17, -1, 340 }, /* 25 10 MB */ + { 612, 4, 17, -1, 670 }, /* 26 20 MB */ + { 698, 7, 17, 300, 732 }, /* 27 41 MB */ + { 976, 5, 17, 488, 977 }, /* 28 40 MB */ + { 306, 4, 17, 0, 340 }, /* 29 10 MB */ + { 611, 4, 17, 306, 663 }, /* 30 20 MB */ + { 732, 7, 17, 300, 732 }, /* 31 43 MB */ + { 1023, 5, 17, -1, 1023 }, /* 32 42 MB */ + { 614, 4, 25, -1, 663 }, /* 33 30 MB */ + { 775, 2, 27, -1, 900 }, /* 34 20 MB */ + { 921, 2, 33, -1, 1000 }, /* 35 30 MB * */ + { 402, 4, 26, -1, 460 }, /* 36 20 MB */ + { 580, 6, 26, -1, 640 }, /* 37 44 MB */ + { 845, 2, 36, -1, 1023 }, /* 38 30 MB * */ + { 769, 3, 36, -1, 1023 }, /* 39 41 MB * */ + { 531, 4, 39, -1, 532 }, /* 40 40 MB */ + { 577, 2, 36, -1, 1023 }, /* 41 20 MB */ + { 654, 2, 32, -1, 674 }, /* 42 20 MB */ + { 923, 5, 36, -1, 1023 }, /* 43 81 MB */ + { 531, 8, 39, -1, 532 } /* 44 81 MB */ +}; + + +/* FIXME: we should use the disk/hdd_table.c code with custom tables! */ +static int +ibm_drive_type(drive_t *drive) +{ + const geom_t *ptr; + int i; + + for (i = 0; i < (sizeof(ibm_type_table) / sizeof(geom_t)); i++) { + ptr = &ibm_type_table[i]; + if ((drive->tracks == ptr->cyl) && + (drive->hpc == ptr->hpc) && (drive->spt == ptr->spt)) return(i); + } + + return(HDC_TYPE_USER); +} + + +static void +set_intr(hdc_t *dev, int raise) +{ + if (raise) { + dev->status |= ASR_INT_REQ; + if (dev->ctrl & ACR_INT_EN) + picint(1 << dev->irq); + } else { + dev->status &= ~ASR_INT_REQ; + picintc(1 << dev->irq); + } +} + + +/* Get the logical (block) address of a CHS triplet. */ +static int +get_sector(hdc_t *dev, drive_t *drive, off64_t *addr) +{ + if (drive->cur_cyl != dev->track) { +#if 0 + pclog("HDC: get_sector: wrong cylinder %d/%d\n", + drive->cur_cyl, dev->track); +#endif + dev->ssb.wrong_cyl = 1; + return(1); + } + + if (dev->head >= drive->hpc) { +#if 0 + pclog("HDC: get_sector: past end of heads\n"); +#endif + dev->ssb.cylinder_err = 1; + return(1); + } + + if (dev->sector > drive->spt) { +#if 0 + pclog("HDC: get_sector: past end of sectors\n"); +#endif + dev->ssb.mark_not_found = 1; + return(1); + } + + /* Calculate logical address (block number) of desired sector. */ + *addr = ((((off64_t) dev->track*drive->hpc) + \ + dev->head)*drive->spt) + dev->sector - 1; + + return(0); +} + + +static void +next_sector(hdc_t *dev, drive_t *drive) +{ + if (++dev->sector > drive->spt) { + dev->sector = 1; + if (++dev->head >= drive->hpc) { + dev->head = 0; + dev->track++; + if (++drive->cur_cyl >= drive->tracks) { + drive->cur_cyl = drive->tracks-1; + dev->ssb.cylinder_err = 1; + } + } + } +} + + +#if defined(ENABLE_HDC_LOG) && defined(_DEBUG) +static void +dump_ssb(ssb_t *ssb) +{ + char temp[1024]; + char *sp = temp; + uint8_t *ptr = (uint8_t *)ssb; + int i; + + sprintf(temp, "Current SSB:\n ["); + sp += strlen(sp); + for (i = 0; i < sizeof(ssb_t); i++) { + sprintf(sp, " %02X", *ptr++); + sp += strlen(sp); + } + sprintf(sp, " ]\n"); sp += strlen(sp); + + sprintf(sp, " Status 0: T0=%d CE=%d WF=%d SE=%d NR=%d\n", + ssb->track_0, ssb->cylinder_err, ssb->write_fault, + ssb->seek_end, ssb->not_ready); + sp += strlen(sp); + + sprintf(sp, " Status 1: ID=%d WC=%d BT=%d AM=%d ET=%d EF=%d\n", + ssb->id_not_found, ssb->wrong_cyl, ssb->all_bit_set, + ssb->mark_not_found, ssb->ecc_crc_err, ssb->ecc_crc_field); + sp += strlen(sp); + + sprintf(sp, " Status 2: HEADSEL=%d DS=%d RG=%d RR=%d\n", + ssb->headsel_state, ssb->defective_sector, ssb->retried_ok, + ssb->need_reset); + sp += strlen(sp); + + sprintf(sp, " Last : CYL=%d HEAD=%d SECTOR=%d DS=%d SIZE=%d\n", + (ssb->last_cyl_high<<8)|ssb->last_cyl_low, ssb->last_head, + ssb->last_sect, ssb->last_def_sect, (128<sect_size)); + sp += strlen(sp); + + sprintf(sp, " Current : CYL=%d HEAD=%d CORR=%d RETR=%d\n", + (ssb->curr_cyl_high<<8)|ssb->curr_cyl_low, ssb->curr_head, + ssb->sect_corr, ssb->retries); + sp += strlen(sp); + + sprintf(sp, " Misc : Syndrome=%02X DRIVE_TYPE=%d\n", + ssb->cmd_syndrome, ssb->drive_type); + +#if 0 + pclog("HDC: %s\n", temp); +#endif +} + + +static void +dump_ccb(hdc_t *dev, ccb_t *ccb) +{ + char temp[1024]; + char *sp = temp; + + sprintf(temp, "Incoming CCB:\n"); + sp += strlen(sp); + sprintf(sp, " CMD=%02X EC/P=%d DS=%d AS=%d ND=%d\n", + ccb->cmd, ccb->ec_p, ccb->mbz1, ccb->auto_seek, ccb->no_data); + sp += strlen(sp); + sprintf(sp, " CYL=%d HEAD=%d SECTOR=%d COUNT=%d\n", + ((ccb->cyl_high<<8)|ccb->cyl_low), ccb->head, ccb->sector, ccb->count); + +#if 0 + pclog("HDC: %s\n", temp); +#endif +}; + + +static void +dump_fcb(fcb_t *fcb, int count) +{ + char temp[1024]; + char *sp = temp; + + sprintf(temp, "Incoming FCB:\n"); + + while (count--) { + sp += strlen(sp); + sprintf(sp, " CYL=%4d HEAD=%2d DS=%d", + ((fcb->cyl_high << 8) | fcb->cyl_low), + fcb->head, fcb->defective_sector); + sp += strlen(sp); + sprintf(sp, " SECTOR=%2d FILL=%02X\n", fcb->sector, fcb->fill); + fcb++; + } + +#if 0 + pclog("HDC: %s\n", temp); +#endif +} +#endif + + +/* Finish up. Repeated all over, so a function it is now. */ +static void +do_finish(hdc_t *dev) +{ + dev->state = STATE_IDLE; + + dev->attn &= ~(ATT_CCB | ATT_DATA); + + dev->status = 0x00; + + set_intr(dev, 1); +} + + +/* Seek to a cylinder. */ +static int +do_seek(hdc_t *dev, drive_t *drive, uint16_t cyl) +{ + if (cyl >= drive->tracks) { + dev->ssb.cylinder_err = 1; + return(1); + } + + dev->track = cyl; + drive->cur_cyl = dev->track; + + return(0); +} + + +/* Format a track or an entire drive. */ +static void +do_format(hdc_t *dev, drive_t *drive, ccb_t *ccb) +{ + int start_cyl, end_cyl; + int intr = 0, val; + off64_t addr; +#if 0 + fcb_t *fcb; +#endif + + /* Get the parameters from the CCB. */ + if (ccb->cmd == CMD_FORMAT_DRIVE) { + start_cyl = 0; + end_cyl = drive->tracks; + } else { + start_cyl = (ccb->cyl_low | (ccb->cyl_high << 8)); + end_cyl = start_cyl + 1; + } + + switch (dev->state) { + case STATE_IDLE: + /* Ready to transfer the FCB data in. */ + dev->state = STATE_RDATA; + dev->buf_idx = 0; + dev->buf_ptr = dev->data; + dev->buf_len = ccb->count * sizeof(fcb_t); + if (dev->buf_len & 1) + dev->buf_len++; /* must be even */ + + /* Enable for PIO or DMA, as needed. */ +#if NOT_USED + if (dev->ctrl & ACR_DMA_EN) + dev->callback = HDC_TIME; + else +#endif + dev->status |= ASR_DATA_REQ; + break; + + case STATE_RDATA: + /* Perform DMA. */ + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { +#if 0 + pclog("HDC: CMD_FORMAT out of data (idx=%d, len=%d)!\n", dev->buf_idx, dev->buf_len); +#endif + dev->intstat |= ISR_EQUIP_CHECK; + dev->ssb.need_reset = 1; + intr = 1; + break; + } + dev->buf_ptr[dev->buf_idx] = (val & 0xff); + dev->buf_idx++; + } + dev->state = STATE_RDONE; + dev->callback = HDC_TIME; + break; + + case STATE_RDONE: + if (! (dev->ctrl & ACR_DMA_EN)) + dev->status &= ~ASR_DATA_REQ; + + /* Point to the FCB we got. */ +#if 0 + fcb = (fcb_t *)dev->data; +#endif +#if defined(ENABLE_HDC_LOG) && defined(_DEBUG) + dump_fcb(fcb, ccb->count); +#endif + dev->state = STATE_FINIT; + /*FALLTHROUGH*/ + + case STATE_FINIT: +do_fmt: +#ifdef ENABLE_HDC_LOG + hdc_log("HDC: format_%s(%d) %d,%d\n", + (ccb->cmd==CMD_FORMAT_DRIVE)?"drive":"track", + drive->id, dev->track, dev->head); +#endif + + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); + + /* Seek to cylinder. */ + if (do_seek(dev, drive, start_cyl)) { + intr = 1; + break; + } + dev->head = ccb->head; + dev->sector = 1; + + /* Get address of sector to write. */ + if (get_sector(dev, drive, &addr)) { + intr = 1; + break; + } + + /* + * For now, we don't use the info from + * the FCB, although we should at least + * use it's "filler byte" value... + */ +#if 0 + hdd_image_zero_ex(drive->hdd_num, addr, fcb->fill, drive->spt); +#else + hdd_image_zero(drive->hdd_num, addr, drive->spt); +#endif + + /* Done with this track. */ + dev->state = STATE_FDONE; + /*FALLTHROUGH*/ + + case STATE_FDONE: + /* One more track done. */ + if (++start_cyl == end_cyl) { + intr = 1; + break; + } + + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + /* This saves us a LOT of code. */ + dev->state = STATE_FINIT; + goto do_fmt; + } + + /* If we errored out, go back idle. */ + if (intr) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + do_finish(dev); + } +} + + +/* Execute the CCB we just received. */ +static void +hdc_callback(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + ccb_t *ccb = &dev->ccb; + drive_t *drive; + off64_t addr; + int no_data = 0; + int val; + + /* Cancel timer. */ + dev->callback = 0; + + /* Clear the SSB error bits. */ + dev->ssb.track_0 = 0; + dev->ssb.cylinder_err = 0; + dev->ssb.write_fault = 0; + dev->ssb.seek_end = 0; + dev->ssb.not_ready = 0; + dev->ssb.id_not_found = 0; + dev->ssb.wrong_cyl = 0; + dev->ssb.all_bit_set = 0; + dev->ssb.mark_not_found = 0; + dev->ssb.ecc_crc_err = 0; + dev->ssb.ecc_crc_field = 0; + dev->ssb.valid = 1; + + /* We really only support one drive, but ohwell. */ + drive = &dev->drives[0]; + + switch (ccb->cmd) { + case CMD_READ_VERIFY: + no_data = 1; + /*FALLTHROUGH*/ + + case CMD_READ_SECTORS: +#if defined(ENABLE_HDC_LOG) && defined(_DEBUG) + if (dev->state == STATE_IDLE) dump_ccb(dev, ccb); +#endif + if (! drive->present) { + dev->ssb.not_ready = 1; + do_finish(dev); + return; + } + + switch (dev->state) { + case STATE_IDLE: + /* Seek to cylinder if requested. */ + if (ccb->auto_seek) { + if (do_seek(dev, drive, + (ccb->cyl_low|(ccb->cyl_high<<8)))) { + do_finish(dev); + return; + } + } + dev->head = ccb->head; + dev->sector = ccb->sector; + + /* Get sector count and size. */ + dev->count = (int)ccb->count; + dev->buf_len = (128 << dev->ssb.sect_size); + + dev->state = STATE_SEND; + /*FALLTHROUGH*/ + + case STATE_SEND: + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); + +do_send: +#ifdef ENABLE_HDC_LOG + pclog("HDC: read_%s(%d: %d,%d,%d) cnt=%d\n", + (no_data)?"verify":"sector", drive->id, + dev->track, dev->head, dev->sector, + dev->count); +#endif + + /* Get address of sector to load. */ + if (get_sector(dev, drive, &addr)) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + do_finish(dev); + return; + } + + /* Read the block from the image. */ + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)dev->sector_buf); + + /* Ready to transfer the data out. */ + dev->state = STATE_SDATA; + dev->buf_idx = 0; + if (no_data) { + /* Delay a bit, no actual transfer. */ + dev->callback = HDC_TIME; + } else { + if (dev->ctrl & ACR_DMA_EN) { + /* DMA enabled. */ + dev->buf_ptr = dev->sector_buf; + dev->callback = HDC_TIME; + } else { + /* No DMA, do PIO. */ + dev->status |= (ASR_DATA_REQ|ASR_DIR); + + /* Copy from sector to data. */ + memcpy(dev->data, + dev->sector_buf, + (128<ssb.sect_size)); + dev->buf_ptr = dev->data; + } + } + break; + + case STATE_SDATA: + if (! no_data) { + /* Perform DMA. */ + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_write(dev->dma, + *dev->buf_ptr++); + if (val == DMA_NODATA) { +#if 0 + pclog("HDC: CMD_READ_SECTORS out of data (idx=%d, len=%d)!\n", dev->buf_idx, dev->buf_len); +#endif + + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + dev->intstat |= ISR_EQUIP_CHECK; + dev->ssb.need_reset = 1; + do_finish(dev); + return; + } + dev->buf_idx++; + } + } + dev->state = STATE_SDONE; + dev->callback = HDC_TIME; + break; + + case STATE_SDONE: + dev->buf_idx = 0; + if (--dev->count == 0) { +#ifdef ENABLE_HDC_LOG + hdc_log("HDC: read_%s(%d) DONE\n", + (no_data)?"verify":"sector", + drive->id); +#endif + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + if (! (dev->ctrl & ACR_DMA_EN)) + dev->status &= ~(ASR_DATA_REQ|ASR_DIR); + dev->ssb.cmd_syndrome = 0xD4; + do_finish(dev); + return; + } + + /* Addvance to next sector. */ + next_sector(dev, drive); + + /* This saves us a LOT of code. */ + dev->state = STATE_SEND; + goto do_send; + } + break; + + case CMD_READ_EXT: /* READ_EXT */ + case CMD_READ_ID: /* READ_ID */ +#if defined(ENABLE_HDC_LOG) && defined(_DEBUG) + if (dev->state == STATE_IDLE) dump_ccb(dev, ccb); +#endif + if (! drive->present) { + dev->ssb.not_ready = 1; + do_finish(dev); + return; + } + + dev->intstat |= ISR_INVALID_CMD; + do_finish(dev); + break; + + case CMD_RECALIBRATE: /* RECALIBRATE */ +#if defined(ENABLE_HDC_LOG) && defined(_DEBUG) + dump_ccb(dev, ccb); +#endif +#ifdef ENABLE_HDC_LOG + hdc_log("HDC: recalibrate(%d) ready=%d\n", + drive->id, drive->present); +#endif + if (drive->present) { + dev->track = drive->cur_cyl = 0; + } else { + dev->ssb.not_ready = 1; + dev->intstat |= ISR_TERMINATION; + } + + do_finish(dev); + break; + + case CMD_WRITE_VERIFY: + no_data = 1; + /*FALLTHROUGH*/ + + case CMD_WRITE_SECTORS: +#if defined(ENABLE_HDC_LOG) && defined(_DEBUG) + dump_ccb(dev, ccb); +#endif + if (! drive->present) { + dev->ssb.not_ready = 1; + do_finish(dev); + return; + } + + switch (dev->state) { + case STATE_IDLE: + /* Seek to cylinder if requested. */ + if (ccb->auto_seek) { + if (do_seek(dev, drive, + (ccb->cyl_low|(ccb->cyl_high<<8)))) { + do_finish(dev); + return; + } + } + dev->head = ccb->head; + dev->sector = ccb->sector; + + /* Get sector count and size. */ + dev->count = (int)ccb->count; + dev->buf_len = (128 << dev->ssb.sect_size); + + dev->state = STATE_RECV; + /*FALLTHROUGH*/ + + case STATE_RECV: + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); +do_recv: +#ifdef ENABLE_HDC_LOG + hdc_log("HDC write_%s(%d: %d,%d,%d) cnt=%d\n", + (no_data)?"verify":"sector", drive->id, + dev->track, dev->head, dev->sector, + dev->count); +#endif + /* Ready to transfer the data in. */ + dev->state = STATE_RDATA; + dev->buf_idx = 0; + if (no_data) { + /* Delay a bit, no actual transfer. */ + dev->callback = HDC_TIME; + } else { + if (dev->ctrl & ACR_DMA_EN) { + /* DMA enabled. */ + dev->buf_ptr = dev->sector_buf; + dev->callback = HDC_TIME; + } else { + /* No DMA, do PIO. */ + dev->buf_ptr = dev->data; + dev->status |= ASR_DATA_REQ; + } + } + break; + + case STATE_RDATA: + if (! no_data) { + /* Perform DMA. */ + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { +#if 0 + pclog("HDC: CMD_WRITE_SECTORS out of data (idx=%d, len=%d)!\n", dev->buf_idx, dev->buf_len); +#endif + + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + dev->intstat |= ISR_EQUIP_CHECK; + dev->ssb.need_reset = 1; + do_finish(dev); + return; + } + dev->buf_ptr[dev->buf_idx] = (val & 0xff); + dev->buf_idx++; + } + } + dev->state = STATE_RDONE; + dev->callback = HDC_TIME; + break; + + case STATE_RDONE: + /* Copy from data to sector if PIO. */ + if (! (dev->ctrl & ACR_DMA_EN)) + memcpy(dev->sector_buf, dev->data, + (128<ssb.sect_size)); + + /* Get address of sector to write. */ + if (get_sector(dev, drive, &addr)) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + do_finish(dev); + return; + } + + /* Write the block to the image. */ + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *)dev->sector_buf); + + dev->buf_idx = 0; + if (--dev->count == 0) { +#ifdef ENABLE_HDC_LOG + hdc_log("HDC: write_%s(%d) DONE\n", + (no_data)?"verify":"sector", + drive->id); +#endif + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + if (! (dev->ctrl & ACR_DMA_EN)) + dev->status &= ~ASR_DATA_REQ; + dev->ssb.cmd_syndrome = 0xD4; + do_finish(dev); + return; + } + + /* Advance to next sector. */ + next_sector(dev, drive); + + /* This saves us a LOT of code. */ + dev->state = STATE_RECV; + goto do_recv; + } + break; + + case CMD_FORMAT_DRIVE: + case CMD_FORMAT_TRACK: +#if defined(ENABLE_HDC_LOG) && defined(_DEBUG) + if (dev->state == STATE_IDLE) dump_ccb(dev, ccb); +#endif + do_format(dev, drive, ccb); + break; + + case CMD_SEEK: +#if defined(ENABLE_HDC_LOG) && defined(_DEBUG) + dump_ccb(dev, ccb); +#endif + if (! drive->present) { + dev->ssb.not_ready = 1; + do_finish(dev); + return; + } + + if (ccb->ec_p == 1) { + /* Park the heads. */ + val = do_seek(dev, drive, drive->tracks-1); + } else { + /* Seek to cylinder. */ + val = do_seek(dev, drive, + (ccb->cyl_low|(ccb->cyl_high<<8))); + } +#ifdef ENABLE_HDC_LOG + hdc_log("HDC: %s(%d) cyl=%d, err=%d\n", + (ccb->ec_p)?"park":"seek", + drive->id, drive->cur_cyl, val); +#endif + if (! val) + dev->ssb.seek_end = 1; + do_finish(dev); + break; + + default: +#ifdef ENABLE_HDC_LOG + hdc_log("HDC: unknown command - %02x\n", ccb->cmd); +# ifdef _DEBUG + dump_ccb(dev, ccb); +# endif +#endif + dev->intstat |= ISR_INVALID_CMD; + do_finish(dev); + } +} + + +/* Prepare to send the SSB block. */ +static void +hdc_send_ssb(hdc_t *dev) +{ + drive_t *drive; + + /* We only support one drive, really, but ohwell. */ + drive = &dev->drives[0]; + + if (! dev->ssb.valid) { + /* Create a valid SSB. */ + memset(&dev->ssb, 0x00, sizeof(dev->ssb)); + dev->ssb.sect_size = 0x02; /* 512 bytes */ + dev->ssb.drive_type = drive->type; + } + + /* Update position fields. */ + dev->ssb.track_0 = !!(dev->track == 0); + dev->ssb.last_cyl_low = dev->ssb.curr_cyl_low; + dev->ssb.last_cyl_high = dev->ssb.curr_cyl_high; + dev->ssb.last_head = dev->ssb.curr_head; + dev->ssb.curr_cyl_high = ((dev->track >> 8) & 0x03); + dev->ssb.curr_cyl_low = (dev->track & 0xff); + dev->ssb.curr_head = (dev->head & 0x0f); + + dev->ssb.headsel_state = dev->ssb.curr_head; + dev->ssb.last_sect = dev->sector; + + /* We abuse an unused MBZ bit, so clear it. */ + dev->ssb.valid = 0; + + /* Set up the transfer buffer for the SSB. */ + dev->buf_idx = 0; + dev->buf_len = sizeof(dev->ssb); + dev->buf_ptr = (uint8_t *)&dev->ssb; + +#if defined(ENABLE_HDC_LOG) && defined(_DEBUG) + dump_ssb(&dev->ssb); +#endif + + /* Done with the SSB. */ + dev->attn &= ~ATT_SSB; +} + + +/* Read one of the controller registers. */ +static uint8_t +hdc_read(uint16_t port, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + uint8_t ret = 0xff; + + /* TRM: tell system board we are alive. */ + ps1_set_feedback(dev->sys); + + switch (port & 7) { + case 0: /* DATA register */ + if (dev->state == STATE_SDATA) { + if (dev->buf_idx > dev->buf_len) { +#if 0 + pclog("HDC: read with empty buffer!\n"); +#endif + dev->state = STATE_IDLE; + dev->intstat |= ISR_INVALID_CMD; + dev->status &= (ASR_TX_EN|ASR_DATA_REQ|ASR_DIR); + set_intr(dev, 1); + break; + } + + ret = dev->buf_ptr[dev->buf_idx]; + if (++dev->buf_idx == dev->buf_len) { + /* Data block sent OK. */ + dev->status &= ~(ASR_TX_EN|ASR_DATA_REQ|ASR_DIR); + dev->state = STATE_IDLE; + } + } + break; + + case 2: /* ASR */ + ret = dev->status; + break; + + case 4: /* ISR */ + ret = dev->intstat; + dev->intstat = 0x00; + break; + } + + return(ret); +} + + +static void +hdc_write(uint16_t port, uint8_t val, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + + /* TRM: tell system board we are alive. */ + ps1_set_feedback(dev->sys); + + switch (port & 7) { + case 0: /* DATA register */ + if (dev->state == STATE_RDATA) { + if (dev->buf_idx >= dev->buf_len) { +#if 0 + pclog("HDC: write with full buffer!\n"); +#endif + dev->intstat |= ISR_INVALID_CMD; + dev->status &= ~ASR_DATA_REQ; + set_intr(dev, 1); + break; + } + + /* Store the data into the buffer. */ + dev->buf_ptr[dev->buf_idx] = val; + if (++dev->buf_idx == dev->buf_len) { + /* We got all the data we need. */ + dev->status &= ~ASR_DATA_REQ; + dev->state = STATE_IDLE; + + /* If we were receiving a CCB, execute it. */ + if (dev->attn & ATT_CCB) { + /* + * If we were already busy with + * a CCB, then it must have had + * some new data using PIO. + */ + if (dev->status & ASR_BUSY) + dev->state = STATE_RDONE; + else + dev->status |= ASR_BUSY; + + /* Schedule command execution. */ + dev->callback = HDC_TIME; + } + } + } + break; + + case 2: /* ACR */ + dev->ctrl = val; + 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; + break; + + case 4: /* ATTN */ + dev->status &= ~ASR_INT_REQ; + if (val & ATT_DATA) { + /* Dunno. Start PIO/DMA now? */ + } + + if (val & ATT_SSB) { + if (dev->attn & ATT_CCB) { + /* Hey now, we're still busy for you! */ + dev->intstat |= ISR_INVALID_CMD; + set_intr(dev, 1); + break; + } + + /* OK, prepare for sending an SSB. */ + dev->attn |= ATT_SSB; + + /* Grab or initialize an SSB to send. */ + hdc_send_ssb(dev); + + dev->state = STATE_SDATA; + dev->status |= (ASR_TX_EN|ASR_DATA_REQ|ASR_DIR); + set_intr(dev, 1); + } + + if (val & ATT_CCB) { + dev->attn |= ATT_CCB; + + /* Set up the transfer buffer for a CCB. */ + dev->buf_idx = 0; + dev->buf_len = sizeof(dev->ccb); + dev->buf_ptr = (uint8_t *)&dev->ccb; + + dev->state = STATE_RDATA; + dev->status |= ASR_DATA_REQ; + set_intr(dev, 1); + } + break; + } +} + + +static void * +ps1_hdc_init(const device_t *info) +{ + drive_t *drive; + hdc_t *dev; + int c, i; + + /* Allocate and initialize device block. */ + dev = malloc(sizeof(hdc_t)); + memset(dev, 0x00, sizeof(hdc_t)); + + /* Set up controller parameters for PS/1 2011. */ + dev->base = 0x0320; + dev->irq = 14; + dev->dma = 3; + + pclog("HDC: initializing (I/O=%04X, IRQ=%d, DMA=%d)\n", + dev->base, dev->irq, dev->dma); + + /* Load any disks for this device class. */ + c = 0; + for (i = 0; i < HDD_NUM; i++) { + if ((hdd[i].bus == HDD_BUS_XTA) && (hdd[i].xta_channel < 1)) { + drive = &dev->drives[hdd[i].xta_channel]; + + if (! hdd_image_load(i)) { + drive->present = 0; + continue; + } + drive->id = c; + + /* These are the "hardware" parameters (from the image.) */ + drive->cfg_spt = (uint8_t)(hdd[i].spt & 0xff); + drive->cfg_hpc = (uint8_t)(hdd[i].hpc & 0xff); + drive->cfg_tracks = (uint16_t)hdd[i].tracks; + + /* Use them as "active" parameters until overwritten. */ + drive->spt = drive->cfg_spt; + drive->hpc = drive->cfg_hpc; + drive->tracks = drive->cfg_tracks; + + drive->type = ibm_drive_type(drive); + drive->hdd_num = i; + drive->present = 1; + + pclog("HDC: drive%d (type %d: cyl=%d,hd=%d,spt=%d), disk %d\n", + hdd[i].xta_channel, drive->type, + drive->tracks, drive->hpc, drive->spt, i); + + if (++c > 1) break; + } + } + + /* Sectors are 1-based. */ + dev->sector = 1; + + /* Enable the I/O block. */ + io_sethandler(dev->base, 5, + hdc_read,NULL,NULL, hdc_write,NULL,NULL, dev); + + /* Create a timer for command delays. */ + timer_add(hdc_callback, &dev->callback, &dev->callback, dev); + + return(dev); +} + + +static void +ps1_hdc_close(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + drive_t *drive; + int d; + + /* Remove the I/O handler. */ + io_removehandler(dev->base, 5, + hdc_read,NULL,NULL, hdc_write,NULL,NULL, dev); + + /* Close all disks and their images. */ + for (d = 0; d < XTA_NUM; d++) { + drive = &dev->drives[d]; + + if (drive->present) + hdd_image_close(drive->hdd_num); + } + + /* Release the device. */ + free(dev); +} + + +const device_t ps1_hdc_device = { + "PS/1 2011 Fixed Disk Controller", + DEVICE_ISA | DEVICE_PS2, + 0, + ps1_hdc_init, ps1_hdc_close, NULL, + NULL, NULL, NULL, NULL, + NULL +}; + + +/* + * Very nasty. + * + * The PS/1 systems employ a feedback system where external + * cards let the system know they were 'addressed' by setting + * their Card Selected Flag (CSF) in register 0x0091. Driver + * software can test this register to see if they are talking + * to hardware or not. + * + * This means, that we must somehow do the same, and yes, I + * agree that the current solution is nasty. + */ +void +ps1_hdc_inform(void *priv, void *arg) +{ + hdc_t *dev = (hdc_t *)priv; + + dev->sys = arg; +} diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index 60300adf0..213e06b50 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -156,7 +156,7 @@ machine_ps2_m30_286_init(const machine_t *model) pit_set_out_func(&pit, 1, pit_refresh_timer_at); dma16_init(); device_add(&keyboard_ps2_device); - nvr_at_init(8); + device_add(&ps_nvr_device); pic2_init(); ps2board_init(); device_add(&ps1vga_device); diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index 0aeed187a..9f495c4f7 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -1172,7 +1172,7 @@ machine_ps2_common_init(const machine_t *model) dma16_init(); ps2_dma_init(); device_add(&keyboard_ps2_mca_device); - nvr_at_init(8); + device_add(&ps_nvr_device); pic2_init(); pit_ps2_init(); diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c index 02d5e6c48..778f29caf 100644 --- a/src/machine/m_xt_t1000.c +++ b/src/machine/m_xt_t1000.c @@ -51,7 +51,7 @@ * NOTE: Still need to figure out a way to load/save ConfigSys and * HardRAM stuff. Needs to be linked in to the NVR code. * - * Version: @(#)m_xt_t1000.c 1.0.4 2018/03/19 + * Version: @(#)m_xt_t1000.c 1.0.5 2018/04/11 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -92,8 +92,8 @@ #include "../nmi.h" #include "../mem.h" #include "../rom.h" -#include "../nvr.h" #include "../device.h" +#include "../nvr.h" #include "../keyboard.h" #include "../lpt.h" #include "../mem.h" diff --git a/src/machine/m_xt_xi8088.c b/src/machine/m_xt_xi8088.c index f4137cfb0..f78bcb462 100644 --- a/src/machine/m_xt_xi8088.c +++ b/src/machine/m_xt_xi8088.c @@ -129,7 +129,7 @@ void machine_xt_xi8088_init(const machine_t *model) device_add(&fdc_xt_device); device_add(&keyboard_ps2_device); nmi_init(); - nvr_at_init(8); + device_add(&at_nvr_device); pic2_init(); if (joystick_type != 7) device_add(&gameport_device); diff --git a/src/machine/machine.c b/src/machine/machine.c index b344ddd10..a54736307 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.c 1.0.32 2018/03/19 + * Version: @(#)machine.c 1.0.33 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, @@ -31,8 +31,7 @@ #include "../rom.h" #include "../lpt.h" #include "../serial.h" -#include "../disk/hdc.h" -#include "../disk/hdc_ide.h" +#include "../cpu/cpu.h" #include "machine.h" @@ -46,8 +45,6 @@ machine_init(void) { pclog("Initializing as \"%s\"\n", machine_getname()); - ide_set_bus_master(NULL, NULL, NULL); - /* Set up the architecture flags. */ AT = IS_ARCH(machine, MACHINE_AT); PCI = IS_ARCH(machine, MACHINE_PCI); @@ -68,10 +65,16 @@ void machine_common_init(const machine_t *model) { /* System devices first. */ - dma_init(); pic_init(); + dma_init(); pit_init(); + cpu_set(); + if (AT) + setrtcconst(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + else + setrtcconst(14318184.0); + if (lpt_enabled) lpt_init(); diff --git a/src/machine/machine.h b/src/machine/machine.h index 7822ffd2f..c1c66d80d 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.h 1.0.22 2018/03/18 + * Version: @(#)machine.h 1.0.23 2018/03/28 * * Authors: Sarah Walker, * Miran Grca, @@ -55,7 +55,7 @@ typedef struct _machine_ { } cpu[5]; int fixed_gfxcard; int flags; - int min_ram, max_ram; + uint32_t min_ram, max_ram; int ram_granularity; int nvrmask; void (*init)(const struct _machine_ *); @@ -64,7 +64,6 @@ typedef struct _machine_ { #else void *get_device; #endif - void (*nvr_close)(void); } machine_t; @@ -156,6 +155,12 @@ extern void machine_at_4gpv31_init(const machine_t *); extern void machine_pcjr_init(const machine_t *); extern void machine_ps1_m2011_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern void ps1_hdc_inform(void *, void *); +extern void ps1_set_feedback(void *); +extern const device_t ps1_hdc_device; +#endif + extern void machine_ps1_m2121_init(const machine_t *); extern void machine_ps1_m2133_init(const machine_t *); @@ -173,8 +178,7 @@ extern void machine_amstrad_init(const machine_t *); extern void machine_europc_init(const machine_t *); #ifdef EMU_DEVICE_H -extern const device_t europc_device, - europc_hdc_device; +extern const device_t europc_device; #endif extern void machine_olim24_init(const machine_t *); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index eaee5820a..b307ab53c 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -11,7 +11,7 @@ * NOTES: OpenAT wip for 286-class machine with open BIOS. * PS2_M80-486 wip, pending receipt of TRM's for machine. * - * Version: @(#)machine_table.c 1.0.27 2018/03/22 + * Version: @(#)machine_table.c 1.0.28 2018/04/10 * * Authors: Sarah Walker, * Miran Grca, @@ -28,155 +28,146 @@ #include "../86box.h" #include "../cpu/cpu.h" #include "../mem.h" -#include "../nvr.h" #include "../rom.h" #include "../device.h" #include "machine.h" const machine_t machines[] = { - { "[8088] AMI XT clone", ROM_AMIXT, "amixt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, - { "[8088] Compaq Portable", ROM_PORTABLE, "portable", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL, NULL }, - { "[8088] DTK XT clone", ROM_DTKXT, "dtk", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, - { "[8088] IBM PC", ROM_IBMPC, "ibmpc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 32, 0, machine_xt_init, NULL, NULL }, - { "[8088] IBM PCjr", ROM_IBMPCJR, "ibmpcjr", {{"", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device, NULL }, - { "[8088] IBM XT", ROM_IBMXT, "ibmxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, - { "[8088] Generic XT clone", ROM_GENXT, "genxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, - { "[8088] Juko XT clone", ROM_JUKOPC, "jukopc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, - { "[8088] Phoenix XT clone", ROM_PXXT, "pxxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL }, - { "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL, NULL }, - { "[8088] Tandy 1000", ROM_TANDY, "tandy", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 128, 640, 128, 0, machine_tandy1k_init, tandy1k_get_device, NULL }, - { "[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 256, 640, 128, 0, machine_tandy1k_init, tandy1k_hx_get_device, NULL }, - { "[8088] Toshiba 1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, NULL, NULL }, + { "[8088] AMI XT clone", ROM_AMIXT, "amixt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Compaq Portable", ROM_PORTABLE, "portable", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL }, + { "[8088] DTK XT clone", ROM_DTKXT, "dtk", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] IBM PC", ROM_IBMPC, "ibmpc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 32, 0, machine_xt_init, NULL }, + { "[8088] IBM PCjr", ROM_IBMPCJR, "ibmpcjr", {{"", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device }, + { "[8088] IBM XT", ROM_IBMXT, "ibmxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Generic XT clone", ROM_GENXT, "genxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Juko XT clone", ROM_JUKOPC, "jukopc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Phoenix XT clone", ROM_PXXT, "pxxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL }, + { "[8088] Tandy 1000", ROM_TANDY, "tandy", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 128, 640, 128, 0, machine_tandy1k_init, tandy1k_get_device }, + { "[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 256, 640, 128, 0, machine_tandy1k_init, tandy1k_hx_get_device }, + { "[8088] Toshiba T1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) - { "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL }, + { "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL }, #endif - { "[8088] Xi8088", ROM_XI8088, "xi8088", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, NULL, nvr_at_close }, + { "[8088] Xi8088", ROM_XI8088, "xi8088", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, NULL }, - { "[8086] Amstrad PC1512", ROM_PC1512, "pc1512", {{"", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL, nvr_at_close }, - { "[8086] Amstrad PC1640", ROM_PC1640, "pc1640", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL, nvr_at_close }, - { "[8086] Amstrad PC2086", ROM_PC2086, "pc2086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL, nvr_at_close }, - { "[8086] Amstrad PC3086", ROM_PC3086, "pc3086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL, nvr_at_close }, - { "[8086] Amstrad PC20(0)", ROM_PC200, "pc200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL, nvr_at_close }, - { "[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL, NULL }, - { "[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 768, 128, 0, machine_tandy1k_init, NULL, NULL }, - { "[8086] Toshiba 1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, NULL, NULL }, + { "[8086] Amstrad PC1512", ROM_PC1512, "pc1512", {{"", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL }, + { "[8086] Amstrad PC1640", ROM_PC1640, "pc1640", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, + { "[8086] Amstrad PC2086", ROM_PC2086, "pc2086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, + { "[8086] Amstrad PC3086", ROM_PC3086, "pc3086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, + { "[8086] Amstrad PC20(0)", ROM_PC200, "pc200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL }, + { "[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL }, + { "[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 768, 128, 0, machine_tandy1k_init, NULL }, + { "[8086] Toshiba T1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_LASERXT) - { "[8086] VTech Laser XT3", ROM_LXT3, "lxt3", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL }, + { "[8086] VTech Laser XT3", ROM_LXT3, "lxt3", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 512, 256, 0, machine_xt_laserxt_init, NULL }, #endif - { "[286 ISA] AMI 286 clone", ROM_AMI286, "ami286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_neat_ami_init, NULL, nvr_at_close }, - { "[286 ISA] Award 286 clone", ROM_AWARD286, "award286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL, nvr_at_close }, - { "[286 ISA] Commodore PC 30 III", ROM_CMDPC30, "cmdpc30", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_cmdpc_init, NULL, nvr_at_close }, - { "[286 ISA] Compaq Portable II", ROM_PORTABLEII, "portableii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_compaq_init, NULL, nvr_at_close }, + { "[286 ISA] AMI 286 clone", ROM_AMI286, "ami286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_neat_ami_init, NULL }, + { "[286 ISA] Award 286 clone", ROM_AWARD286, "award286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, + { "[286 ISA] Commodore PC 30 III", ROM_CMDPC30, "cmdpc30", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_cmdpc_init, NULL }, + { "[286 ISA] Compaq Portable II", ROM_PORTABLEII, "portableii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_compaq_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - { "[286 ISA] Compaq Portable III", ROM_PORTABLEIII, "portableiii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO, 640,16384, 128, 127, machine_at_compaq_init, NULL, nvr_at_close }, + { "[286 ISA] Compaq Portable III", ROM_PORTABLEIII, "portableiii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO, 640,16384, 128, 127, machine_at_compaq_init, NULL }, #endif - { "[286 ISA] GW-286CT GEAR", ROM_GW286CT, "gw286ct", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL, nvr_at_close }, - { "[286 ISA] Hyundai Super-286TR", ROM_SUPER286TR, "super286tr", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL, nvr_at_close }, - { "[286 ISA] IBM AT", ROM_IBMAT, "ibmat", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibm_init, NULL, nvr_at_close }, - { "[286 ISA] IBM PS/1 model 2011", ROM_IBMPS1_2011, "ibmps1es", {{"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 512,16384, 512, 127, machine_ps1_m2011_init, NULL, nvr_at_close }, - { "[286 ISA] IBM PS/2 model 30-286", ROM_IBMPS2_M30_286, "ibmps2_m30_286", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 16, 1, 127, machine_ps2_m30_286_init, NULL, nvr_at_close }, - { "[286 ISA] IBM XT Model 286", ROM_IBMXT286, "ibmxt286", {{"", cpus_ibmxt286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibm_init, NULL, nvr_at_close }, - { "[286 ISA] Samsung SPC-4200P", ROM_SPC4200P, "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512, 2048, 128, 127, machine_at_scat_init, NULL, nvr_at_close }, - { "[286 ISA] Samsung SPC-4216P", ROM_SPC4216P, "spc4216p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 1, 5, 1, 127, machine_at_scat_init, NULL, nvr_at_close }, + { "[286 ISA] GW-286CT GEAR", ROM_GW286CT, "gw286ct", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, + { "[286 ISA] Hyundai Super-286TR", ROM_SUPER286TR, "super286tr", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, + { "[286 ISA] IBM AT", ROM_IBMAT, "ibmat", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibm_init, NULL }, + { "[286 ISA] IBM PS/1 model 2011", ROM_IBMPS1_2011, "ibmps1es", {{"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_PS2 | MACHINE_HDC_PS2, 512,16384, 512, 63, machine_ps1_m2011_init, NULL }, + { "[286 ISA] IBM PS/2 model 30-286", ROM_IBMPS2_M30_286, "ibmps2_m30_286", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 16, 1, 127, machine_ps2_m30_286_init, NULL }, + { "[286 ISA] IBM XT Model 286", ROM_IBMXT286, "ibmxt286", {{"", cpus_ibmxt286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 127, machine_at_ibm_init, NULL }, + { "[286 ISA] Samsung SPC-4200P", ROM_SPC4200P, "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512, 2048, 128, 127, machine_at_scat_init, NULL }, + { "[286 ISA] Samsung SPC-4216P", ROM_SPC4216P, "spc4216p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 1, 5, 1, 127, machine_at_scat_init, NULL }, #ifdef WALTJE - { "[286 ISA] OpenAT 286", ROM_OPENAT, "open_at", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512, 4096, 128, 127, machine_at_init, NULL, nvr_at_close }, + { "[286 ISA] OpenAT 286", ROM_OPENAT, "open_at", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512, 4096, 128, 127, machine_at_init, NULL }, #endif - { "[286 ISA] Toshiba 3100e", ROM_T3100E, "t3100e", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL, nvr_at_close }, + { "[286 ISA] Toshiba T3100e", ROM_T3100E, "t3100e", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, - { "[286 MCA] IBM PS/2 model 50", ROM_IBMPS2_M50, "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 10, 1, 63, machine_ps2_model_50_init, NULL, nvr_at_close }, + { "[286 MCA] IBM PS/2 model 50", ROM_IBMPS2_M50, "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, - { "[386SX ISA] AMI 386SX clone", ROM_AMI386SX, "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL, nvr_at_close }, - { "[386SX ISA] Amstrad MegaPC", ROM_MEGAPC, "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 16, 1, 127, machine_at_wd76c10_init, NULL, nvr_at_close }, - { "[386SX ISA] Award 386SX clone", ROM_AWARD386SX_OPTI495, "award386sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL, nvr_at_close }, - { "[386SX ISA] DTK 386SX clone", ROM_DTK386, "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_neat_init, NULL, nvr_at_close }, - { "[386SX ISA] IBM PS/1 model 2121", ROM_IBMPS1_2121, "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 127, machine_ps1_m2121_init, NULL, nvr_at_close }, - { "[386SX ISA] IBM PS/1 m.2121+ISA", ROM_IBMPS1_2121_ISA, "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 127, machine_ps1_m2121_init, NULL, nvr_at_close }, - { "[386SX ISA] KMX-C-02", ROM_KMXC02, "kmxc02", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 512, 127, machine_at_scatsx_init, NULL, nvr_at_close }, + { "[386SX ISA] AMI 386SX clone", ROM_AMI386SX, "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, + { "[386SX ISA] Amstrad MegaPC", ROM_MEGAPC, "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 16, 1, 127, machine_at_wd76c10_init, NULL }, + { "[386SX ISA] Award 386SX clone", ROM_AWARD386SX_OPTI495, "award386sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL }, + { "[386SX ISA] DTK 386SX clone", ROM_DTK386, "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_neat_init, NULL }, + { "[386SX ISA] IBM PS/1 model 2121", ROM_IBMPS1_2121, "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] IBM PS/1 m.2121+ISA", ROM_IBMPS1_2121_ISA, "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] KMX-C-02", ROM_KMXC02, "kmxc02", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 512, 127, machine_at_scatsx_init, NULL }, - { "[386SX MCA] IBM PS/2 model 55SX", ROM_IBMPS2_M55SX, "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 8, 1, 63, machine_ps2_model_55sx_init, NULL, nvr_at_close }, + { "[386SX MCA] IBM PS/2 model 55SX", ROM_IBMPS2_M55SX, "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 8, 1, 63, machine_ps2_model_55sx_init, NULL }, - { "[386DX ISA] AMI 386DX clone", ROM_AMI386DX_OPTI495, "ami386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL, nvr_at_close }, - { "[386DX ISA] Amstrad MegaPC 386DX", ROM_MEGAPCDX, "megapcdx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 32, 1, 127, machine_at_wd76c10_init, NULL, nvr_at_close }, - { "[386DX ISA] Award 386DX clone", ROM_AWARD386DX_OPTI495, "award386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL, nvr_at_close }, - { "[386DX ISA] MR 386DX clone", ROM_MR386DX_OPTI495, "mr386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL, nvr_at_close }, + { "[386DX ISA] AMI 386DX clone", ROM_AMI386DX_OPTI495, "ami386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL }, + { "[386DX ISA] Amstrad MegaPC 386DX", ROM_MEGAPCDX, "megapcdx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, + { "[386DX ISA] Award 386DX clone", ROM_AWARD386DX_OPTI495, "award386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL }, + { "[386DX ISA] MR 386DX clone", ROM_MR386DX_OPTI495, "mr386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_PORTABLE3) - { "[386DX ISA] Compaq Portable III (386)", ROM_PORTABLEIII386, "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 1, 14, 1, 127, machine_at_compaq_init, NULL, nvr_at_close }, -#endif - { "[386DX MCA] IBM PS/2 model 70 (type 3)", ROM_IBMPS2_M70_TYPE3, "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 2, 16, 2, 63, machine_ps2_model_70_type3_init, NULL, nvr_at_close }, - - { "[386DX MCA] IBM PS/2 model 80", ROM_IBMPS2_M80, "ibmps2_m80", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 12, 1, 63, machine_ps2_model_80_init, NULL, nvr_at_close }, - - { "[486 ISA] AMI 486 clone", ROM_AMI486, "ami486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL, nvr_at_close }, - { "[486 ISA] AMI WinBIOS 486", ROM_WIN486, "win486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL, nvr_at_close }, - { "[486 ISA] Award 486 clone", ROM_AWARD486_OPTI495, "award486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL, nvr_at_close }, - { "[486 ISA] DTK PKM-0038S E-2", ROM_DTK486, "dtk486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_dtk486_init, NULL, nvr_at_close }, - { "[486 ISA] IBM PS/1 model 2133", ROM_IBMPS1_2133, "ibmps1_2133", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 1, 64, 1, 127, machine_ps1_m2133_init, NULL, nvr_at_close }, - - { "[486 MCA] IBM PS/2 model 70 (type 4)", ROM_IBMPS2_M70_TYPE4, "ibmps2_m70_type4", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 2, 16, 2, 63, machine_ps2_model_70_type4_init, NULL, nvr_at_close }, - -#ifdef WALTJE - { "[486 MCA] IBM PS/2 model 80-486", ROM_IBMPS2_M80_486, "ibmps2_m80-486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 32, 1, 63, machine_ps2_model_80_486_init, NULL, nvr_at_close }, + { "[386DX ISA] Compaq Portable III (386)", ROM_PORTABLEIII386, "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 1, 14, 1, 127, machine_at_compaq_init, NULL }, #endif - { "[486 PCI] Rise Computer R418", ROM_R418, "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL, nvr_at_close }, + { "[386DX MCA] IBM PS/2 model 70 (type 3)", ROM_IBMPS2_M70_TYPE3, "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 2, 16, 2, 63, machine_ps2_model_70_type3_init, NULL }, + { "[386DX MCA] IBM PS/2 model 80", ROM_IBMPS2_M80, "ibmps2_m80", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 12, 1, 63, machine_ps2_model_80_init, NULL }, -#if defined(DEV_BRANCH) && defined(USE_GREENB) - { "[486 VLB] Green-B 4GP V3.1", ROM_4GPV31, "4gpv31", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT, 1, 128, 1, 127, machine_at_4gpv31_init, NULL, nvr_at_close }, -#endif + { "[486 ISA] AMI 486 clone", ROM_AMI486, "ami486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL }, + { "[486 ISA] AMI WinBIOS 486", ROM_WIN486, "win486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL }, + { "[486 ISA] Award 486 clone", ROM_AWARD486_OPTI495, "award486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL }, + { "[486 ISA] DTK PKM-0038S E-2", ROM_DTK486, "dtk486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_dtk486_init, NULL }, + { "[486 ISA] IBM PS/1 model 2133", ROM_IBMPS1_2133, "ibmps1_2133", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 1, 64, 1, 127, machine_ps1_m2133_init, NULL }, - { "[Socket 4 LX] Intel Premiere/PCI", ROM_REVENGE, "revenge", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_batman_init, NULL, nvr_at_close }, + { "[486 MCA] IBM PS/2 model 70 (type 4)", ROM_IBMPS2_M70_TYPE4, "ibmps2_m70_type4", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 2, 16, 2, 63, machine_ps2_model_70_type4_init, NULL }, + + { "[486 PCI] Rise Computer R418", ROM_R418, "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL }, + + { "[Socket 4 LX] Intel Premiere/PCI", ROM_REVENGE, "revenge", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_batman_init, NULL }, #if defined(DEV_BRANCH) && defined(USE_AMD_K) - { "[Socket 5 NX] Intel Premiere/PCI II", ROM_PLATO, "plato", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL, nvr_at_close }, + { "[Socket 5 NX] Intel Premiere/PCI II", ROM_PLATO, "plato", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, - { "[Socket 5 FX] ASUS P/I-P54TP4XE", ROM_P54TP4XE, "p54tp4xe", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL, nvr_at_close }, - { "[Socket 5 FX] Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device, nvr_at_close }, - { "[Socket 5 FX] Intel Advanced/ZP", ROM_ZAPPA, "zappa", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL, nvr_at_close }, - { "[Socket 5 FX] PC Partner MB500N", ROM_MB500N, "mb500n", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL, nvr_at_close }, - { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL, nvr_at_close }, + { "[Socket 5 FX] ASUS P/I-P54TP4XE", ROM_P54TP4XE, "p54tp4xe", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL }, + { "[Socket 5 FX] Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, + { "[Socket 5 FX] Intel Advanced/ZP", ROM_ZAPPA, "zappa", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, + { "[Socket 5 FX] PC Partner MB500N", ROM_MB500N, "mb500n", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL }, + { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL }, - { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, - { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, + { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, + { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, - { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL, nvr_at_close }, - { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL, nvr_at_close }, - { "[Socket 7 HX] AOpen AP53", ROM_AP53, "ap53", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL, nvr_at_close }, - { "[Socket 7 HX] ASUS P/I-P55T2P4", ROM_P55T2P4, "p55t2p4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_p55t2p4_init, NULL, nvr_at_close }, - { "[Socket 7 HX] SuperMicro Super P55T2S", ROM_P55T2S, "p55t2s", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL, nvr_at_close }, + { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL }, + { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL }, + { "[Socket 7 HX] AOpen AP53", ROM_AP53, "ap53", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL }, + { "[Socket 7 HX] ASUS P/I-P55T2P4", ROM_P55T2P4, "p55t2p4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_p55t2p4_init, NULL }, + { "[Socket 7 HX] SuperMicro Super P55T2S", ROM_P55T2S, "p55t2s", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL }, - { "[Socket 7 VX] ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL, nvr_at_close }, - { "[Socket 7 VX] Award 430VX PCI", ROM_430VX, "430vx", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL, nvr_at_close }, - { "[Socket 7 VX] Epox P55-VA", ROM_P55VA, "p55va", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL, nvr_at_close }, + { "[Socket 7 VX] ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL }, + { "[Socket 7 VX] Award 430VX PCI", ROM_430VX, "430vx", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, + { "[Socket 7 VX] Epox P55-VA", ROM_P55VA, "p55va", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, #else - { "[Socket 5 NX] Intel Premiere/PCI II", ROM_PLATO, "plato", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL, nvr_at_close }, + { "[Socket 5 NX] Intel Premiere/PCI II", ROM_PLATO, "plato", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, - { "[Socket 5 FX] ASUS P/I-P54TP4XE", ROM_P54TP4XE, "p54tp4xe", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL, nvr_at_close }, - { "[Socket 5 FX] Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device, nvr_at_close }, - { "[Socket 5 FX] Intel Advanced/ZP", ROM_ZAPPA, "zappa", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL, nvr_at_close }, - { "[Socket 5 FX] PC Partner MB500N", ROM_MB500N, "mb500n", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL, nvr_at_close }, - { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL, nvr_at_close }, + { "[Socket 5 FX] ASUS P/I-P54TP4XE", ROM_P54TP4XE, "p54tp4xe", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_p54tp4xe_init, NULL }, + { "[Socket 5 FX] Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, + { "[Socket 5 FX] Intel Advanced/ZP", ROM_ZAPPA, "zappa", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, + { "[Socket 5 FX] PC Partner MB500N", ROM_MB500N, "mb500n", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_mb500n_init, NULL }, + { "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL }, - { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, - { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close }, + { "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, + { "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL }, - { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL, nvr_at_close }, - { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL, nvr_at_close }, - { "[Socket 7 HX] AOpen AP53", ROM_AP53, "ap53", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL, nvr_at_close }, - { "[Socket 7 HX] ASUS P/I-P55T2P4", ROM_P55T2P4, "p55t2p4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_p55t2p4_init, NULL, nvr_at_close }, - { "[Socket 7 HX] SuperMicro Super P55T2S", ROM_P55T2S, "p55t2s", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL, nvr_at_close }, + { "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL }, + { "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL }, + { "[Socket 7 HX] AOpen AP53", ROM_AP53, "ap53", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_ap53_init, NULL }, + { "[Socket 7 HX] ASUS P/I-P55T2P4", ROM_P55T2P4, "p55t2p4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 512, 8, 127, machine_at_p55t2p4_init, NULL }, + { "[Socket 7 HX] SuperMicro Super P55T2S", ROM_P55T2S, "p55t2s", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 768, 8, 127, machine_at_p55t2s_init, NULL }, - { "[Socket 7 VX] ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL, nvr_at_close }, - { "[Socket 7 VX] Award 430VX PCI", ROM_430VX, "430vx", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL, nvr_at_close }, - { "[Socket 7 VX] Epox P55-VA", ROM_P55VA, "p55va", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL, nvr_at_close }, + { "[Socket 7 VX] ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55tvp4_init, NULL }, + { "[Socket 7 VX] Award 430VX PCI", ROM_430VX, "430vx", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_i430vx_init, NULL }, + { "[Socket 7 VX] Epox P55-VA", ROM_P55VA, "p55va", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_p55va_init, NULL }, #endif #if defined(DEV_BRANCH) && defined(USE_I686) - { "[Socket 8 FX] Tyan Titan-Pro AT", ROM_440FX, "440fx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_i440fx_init, NULL, nvr_at_close }, - { "[Socket 8 FX] Tyan Titan-Pro ATX", ROM_S1668, "tpatx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_s1668_init, NULL, nvr_at_close }, + { "[Socket 8 FX] Tyan Titan-Pro AT", ROM_440FX, "440fx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_i440fx_init, NULL }, + { "[Socket 8 FX] Tyan Titan-Pro ATX", ROM_S1668, "tpatx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_s1668_init, NULL }, #endif - { "", -1, "", {{"", 0}, {"", 0}, {"", 0}}, 0,0,0,0, 0 } + { "", -1, "", {{"", 0}, {"", 0}, {"", 0}}, 0,0,0,0, 0 } }; @@ -267,11 +258,3 @@ machine_get_machine_from_internal_name(char *s) return(0); } - - -void -machine_close(void) -{ - if (machines[machine].nvr_close) - machines[machine].nvr_close(); -} diff --git a/src/mem.c b/src/mem.c index bd19461f7..0dbcf2645 100644 --- a/src/mem.c +++ b/src/mem.c @@ -193,11 +193,11 @@ flushmmucache(void) int c; for (c = 0; c < 256; c++) { - if (readlookup[c] != 0xffffffff) { + if (readlookup[c] != (int) 0xffffffff) { readlookup2[readlookup[c]] = -1; readlookup[c] = 0xffffffff; } - if (writelookup[c] != 0xffffffff) { + if (writelookup[c] != (int) 0xffffffff) { page_lookup[writelookup[c]] = NULL; writelookup2[writelookup[c]] = -1; writelookup[c] = 0xffffffff; @@ -220,11 +220,11 @@ flushmmucache_nopc(void) int c; for (c = 0; c < 256; c++) { - if (readlookup[c] != 0xffffffff) { + if (readlookup[c] != (int) 0xffffffff) { readlookup2[readlookup[c]] = -1; readlookup[c] = 0xffffffff; } - if (writelookup[c] != 0xffffffff) { + if (writelookup[c] != (int) 0xffffffff) { page_lookup[writelookup[c]] = NULL; writelookup2[writelookup[c]] = -1; writelookup[c] = 0xffffffff; @@ -239,11 +239,11 @@ flushmmucache_cr3(void) int c; for (c = 0; c < 256; c++) { - if (readlookup[c] != 0xffffffff) { + if (readlookup[c] != (int) 0xffffffff) { readlookup2[readlookup[c]] = -1; readlookup[c] = 0xffffffff; } - if (writelookup[c] != 0xffffffff) { + if (writelookup[c] != (int) 0xffffffff) { page_lookup[writelookup[c]] = NULL; writelookup2[writelookup[c]] = -1; writelookup[c] = 0xffffffff; @@ -259,7 +259,7 @@ mem_flush_write_page(uint32_t addr, uint32_t virt) int c; for (c = 0; c < 256; c++) { - if (writelookup[c] != 0xffffffff) { + if (writelookup[c] != (int) 0xffffffff) { uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)]; if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) { @@ -403,9 +403,9 @@ addreadlookup(uint32_t virt, uint32_t phys) { if (virt == 0xffffffff) return; - if (readlookup2[virt>>12] != -1) return; + if (readlookup2[virt>>12] != (uintptr_t) -1) return; - if (readlookup[readlnext] != 0xffffffff) + if (readlookup[readlnext] != (int) 0xffffffff) readlookup2[readlookup[readlnext]] = -1; readlookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; @@ -496,7 +496,7 @@ readmembl(uint32_t addr) if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if(addr < mem_size * 1024) return ram[addr]; + if(addr < (uint32_t) (mem_size * 1024)) return ram[addr]; return 0xff; } @@ -520,7 +520,7 @@ writemembl(uint32_t addr, uint8_t val) if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < mem_size * 1024) + if (addr < (uint32_t) (mem_size * 1024)) ram[addr] = val; return; } @@ -545,7 +545,7 @@ writemembl(uint32_t addr, uint8_t val) uint8_t readmemb386l(uint32_t seg, uint32_t addr) { - if (seg == -1) { + if (seg == (uint32_t) -1) { x86gpf("NULL segment", 0); return -1; @@ -554,7 +554,7 @@ readmemb386l(uint32_t seg, uint32_t addr) mem_logical_addr = addr = addr + seg; if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < mem_size * 1024) + if (addr < (uint32_t) (mem_size * 1024)) return ram[addr]; return 0xff; } @@ -577,7 +577,7 @@ readmemb386l(uint32_t seg, uint32_t addr) void writememb386l(uint32_t seg, uint32_t addr, uint8_t val) { - if (seg == -1) { + if (seg == (uint32_t) -1) { x86gpf("NULL segment", 0); return; } @@ -585,7 +585,7 @@ writememb386l(uint32_t seg, uint32_t addr, uint8_t val) mem_logical_addr = addr = addr + seg; if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < mem_size * 1024) + if (addr < (uint32_t) (mem_size * 1024)) ram[addr] = val; return; } @@ -613,7 +613,7 @@ readmemwl(uint32_t seg, uint32_t addr) { uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == -1) { + if (seg == (uint32_t) -1) { x86gpf("NULL segment", 0); return -1; } @@ -626,16 +626,16 @@ readmemwl(uint32_t seg, uint32_t addr) if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff; if (mmutranslate_read(addr2+1) == 0xffffffff) return 0xffff; } - if (is386) return readmemb386l(seg,addr)|(readmemb386l(seg,addr+1)<<8); - else return readmembl(seg+addr)|(readmembl(seg+addr+1)<<8); + if (is386) return readmemb386l(seg,addr)|(((uint16_t) readmemb386l(seg,addr+1))<<8); + else return readmembl(seg+addr)|(((uint16_t) readmembl(seg+addr+1))<<8); } - else if (readlookup2[addr2 >> 12] != -1) + else if (readlookup2[addr2 >> 12] != (uintptr_t) -1) return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2); } if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) + if (addr < (uint32_t) (mem_size * 1024)) return *((uint16_t *)&ram[addr]); return 0xffff; } @@ -653,9 +653,11 @@ readmemwl(uint32_t seg, uint32_t addr) if (_mem_read_b[addr2 >> 14]) { if (AT) - return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(addr2 + 1) >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8); + return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint16_t) (_mem_read_b[(addr2 + 1) >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14])) << 8); else - return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14]) << 8); + return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint16_t) (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14])) << 8); } return 0xffff; @@ -667,7 +669,7 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val) { uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == -1) { + if (seg == (uint32_t) -1) { x86gpf("NULL segment", 0); return; } @@ -695,7 +697,7 @@ writememwl(uint32_t seg, uint32_t addr, uint16_t val) writemembl(seg+addr+1,val>>8); } return; - } else if (writelookup2[addr2 >> 12] != -1) { + } else if (writelookup2[addr2 >> 12] != (uintptr_t) -1) { *(uint16_t *)(writelookup2[addr2 >> 12] + addr2) = val; return; } @@ -736,7 +738,7 @@ readmemll(uint32_t seg, uint32_t addr) { uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == -1) { + if (seg == (uint32_t) -1) { x86gpf("NULL segment", 0); return -1; } @@ -757,7 +759,7 @@ readmemll(uint32_t seg, uint32_t addr) if (mmutranslate_read(addr2+3) == 0xffffffff) return 0xffffffff; } return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); - } else if (readlookup2[addr2 >> 12] != -1) + } else if (readlookup2[addr2 >> 12] != (uintptr_t) -1) return *(uint32_t *)(readlookup2[addr2 >> 12] + addr2); } @@ -773,10 +775,14 @@ readmemll(uint32_t seg, uint32_t addr) return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); if (_mem_read_w[addr2 >> 14]) - return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_w[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16); + return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint32_t) (_mem_read_w[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14])) << 16); if (_mem_read_b[addr2 >> 14]) - return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8) | (_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16) | (_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14]) << 24); + return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14])) << 8) | + ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14])) << 16) | + ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14])) << 24); return 0xffffffff; } @@ -787,7 +793,7 @@ writememll(uint32_t seg, uint32_t addr, uint32_t val) { uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == -1) { + if (seg == (uint32_t) -1) { x86gpf("NULL segment", 0); return; } @@ -810,7 +816,7 @@ writememll(uint32_t seg, uint32_t addr, uint32_t val) writememwl(seg,addr,val); writememwl(seg,addr+2,val>>16); return; - } else if (writelookup2[addr2 >> 12] != -1) { + } else if (writelookup2[addr2 >> 12] != (uintptr_t) -1) { *(uint32_t *)(writelookup2[addr2 >> 12] + addr2) = val; return; } @@ -852,7 +858,7 @@ readmemql(uint32_t seg, uint32_t addr) { uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == -1) { + if (seg == (uint32_t) -1) { x86gpf("NULL segment", 0); return -1; } @@ -872,7 +878,7 @@ readmemql(uint32_t seg, uint32_t addr) if (mmutranslate_read(addr2+7) == 0xffffffff) return 0xffffffff; } return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32); - } else if (readlookup2[addr2 >> 12] != -1) + } else if (readlookup2[addr2 >> 12] != (uintptr_t) -1) return *(uint64_t *)(readlookup2[addr2 >> 12] + addr2); } @@ -897,7 +903,7 @@ writememql(uint32_t seg, uint32_t addr, uint64_t val) { uint32_t addr2 = mem_logical_addr = seg + addr; - if (seg == -1) { + if (seg == (uint32_t) -1) { x86gpf("NULL segment", 0); return; } @@ -919,7 +925,7 @@ writememql(uint32_t seg, uint32_t addr, uint64_t val) writememll(seg, addr, val); writememll(seg, addr+4, val >> 32); return; - } else if (writelookup2[addr2 >> 12] != -1) { + } else if (writelookup2[addr2 >> 12] != (uintptr_t) -1) { *(uint64_t *)(writelookup2[addr2 >> 12] + addr2) = val; return; } @@ -1278,6 +1284,7 @@ mem_mapping_recalc(uint64_t base, uint64_t size) _mem_read_b[c >> 14] = NULL; _mem_read_w[c >> 14] = NULL; _mem_read_l[c >> 14] = NULL; + _mem_exec[c >> 14] = NULL; _mem_priv_r[c >> 14] = NULL; _mem_mapping_r[c >> 14] = NULL; _mem_write_b[c >> 14] = NULL; @@ -1760,7 +1767,7 @@ mem_init(void) static void mem_remap_top(int max_size) { - int c; + uint32_t c; if (mem_size > 640) { uint32_t start = (mem_size >= 1024) ? mem_size : 1024; @@ -1799,7 +1806,7 @@ mem_remap_top_384k(void) void mem_reset_page_blocks(void) { - int c; + uint32_t c; if (pages == NULL) return; diff --git a/src/network/net_pcap.c b/src/network/net_pcap.c index a619868b6..3b4b328a6 100644 --- a/src/network/net_pcap.c +++ b/src/network/net_pcap.c @@ -49,7 +49,7 @@ #include #include #include -#include +// #include #include "../86box.h" #include "../config.h" #include "../device.h" @@ -58,8 +58,53 @@ #include "network.h" +typedef int bpf_int32; +typedef unsigned int bpf_u_int32; + +/* + * The instruction data structure. + */ +struct bpf_insn { + unsigned short code; + unsigned char jt; + unsigned char jf; + bpf_u_int32 k; +}; + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + unsigned int bf_len; + struct bpf_insn *bf_insns; +}; + +typedef struct pcap_if pcap_if_t; + +typedef struct timeval { + long tv_sec; + long tv_usec; +} timeval; + +#define PCAP_ERRBUF_SIZE 256 + +struct pcap_pkthdr { + struct timeval ts; + bpf_u_int32 caplen; + bpf_u_int32 len; +}; + +struct pcap_if { + struct pcap_if *next; + char *name; + char *description; + void *addresses; + unsigned int flags; +}; + + static volatile void *pcap_handle; /* handle to WinPcap DLL */ -static volatile pcap_t *pcap; /* handle to WinPcap library */ +static volatile void *pcap; /* handle to WinPcap library */ static volatile thread_t *poll_tid; static const netcard_t *poll_card; /* netcard linked to us */ static event_t *poll_state; @@ -68,14 +113,15 @@ static event_t *poll_state; /* Pointers to the real functions. */ static const char *(*f_pcap_lib_version)(void); static int (*f_pcap_findalldevs)(pcap_if_t **,char *); -static void (*f_pcap_freealldevs)(pcap_if_t *); -static pcap_t *(*f_pcap_open_live)(const char *,int,int,int,char *); -static int (*f_pcap_compile)(pcap_t *,struct bpf_program *, +static void (*f_pcap_freealldevs)(void *); +static void *(*f_pcap_open_live)(const char *,int,int,int,char *); +static int (*f_pcap_compile)(void *,void *, const char *,int,bpf_u_int32); -static int (*f_pcap_setfilter)(pcap_t *,struct bpf_program *); -static const u_char *(*f_pcap_next)(pcap_t *,struct pcap_pkthdr *); -static int (*f_pcap_sendpacket)(pcap_t *,const u_char *,int); -static void (*f_pcap_close)(pcap_t *); +static int (*f_pcap_setfilter)(void *,void *); +static const unsigned char + *(*f_pcap_next)(void *,void *); +static int (*f_pcap_sendpacket)(void *,const unsigned char *,int); +static void (*f_pcap_close)(void *); static dllimp_t pcap_imports[] = { { "pcap_lib_version", &f_pcap_lib_version }, { "pcap_findalldevs", &f_pcap_findalldevs }, @@ -118,7 +164,7 @@ poll_thread(void *arg) if (pcap == NULL) break; /* Wait for the next packet to arrive. */ - data = (uint8_t *)f_pcap_next((pcap_t *)pcap, &h); + data = (uint8_t *)f_pcap_next((void *)pcap, &h); if (data != NULL) { /* Received MAC. */ mac_cmp32[0] = *(uint32_t *)(data+6); @@ -251,14 +297,14 @@ net_pcap_init(void) void net_pcap_close(void) { - pcap_t *pc; + void *pc; if (pcap == NULL) return; pclog("PCAP: closing.\n"); /* Tell the polling thread to shut down. */ - pc = (pcap_t *)pcap; pcap = NULL; + pc = (void *)pcap; pcap = NULL; /* Tell the thread to terminate. */ if (poll_tid != NULL) { @@ -326,15 +372,15 @@ net_pcap_reset(const netcard_t *card, uint8_t *mac) "( ((ether dst ff:ff:ff:ff:ff:ff) or (ether dst %02x:%02x:%02x:%02x:%02x:%02x)) and not (ether src %02x:%02x:%02x:%02x:%02x:%02x) )", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - if (f_pcap_compile((pcap_t *)pcap, &fp, filter_exp, 0, 0xffffffff) != -1) { - if (f_pcap_setfilter((pcap_t *)pcap, &fp) != 0) { + if (f_pcap_compile((void *)pcap, &fp, filter_exp, 0, 0xffffffff) != -1) { + if (f_pcap_setfilter((void *)pcap, &fp) != 0) { pclog("PCAP: error installing filter (%s) !\n", filter_exp); - f_pcap_close((pcap_t *)pcap); + f_pcap_close((void *)pcap); return(-1); } } else { pclog("PCAP: could not compile filter (%s) !\n", filter_exp); - f_pcap_close((pcap_t *)pcap); + f_pcap_close((void *)pcap); return(-1); } @@ -358,7 +404,7 @@ net_pcap_in(uint8_t *bufp, int len) network_busy(1); - f_pcap_sendpacket((pcap_t *)pcap, bufp, len); + f_pcap_sendpacket((void *)pcap, bufp, len); network_busy(0); } diff --git a/src/nvr.c b/src/nvr.c index fccde1882..5ad0a6cf8 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -8,9 +8,7 @@ * * Implement a generic NVRAM/CMOS/RTC device. * - * NOTE: I should re-do 'intclk' using a TM struct. - * - * Version: @(#)nvr.c 1.0.3 2018/03/19 + * Version: @(#)nvr.c 1.0.6 2018/04/11 * * Author: Fred N. van Kempen, * @@ -65,23 +63,11 @@ #include "nvr.h" -/* Define the internal clock. */ -typedef struct { - int16_t year; - int8_t sec; - int8_t min; - int8_t hour; - int8_t mday; - int8_t mon; -} intclk_t; - - -int enable_sync; /* configuration variable: enable time sync */ int nvr_dosave; /* NVR is dirty, needs saved */ static int8_t days_in_month[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; -static intclk_t intclk; +static struct tm intclk; static nvr_t *saved_nvr = NULL; @@ -113,25 +99,23 @@ static void rtc_tick(void) { /* Ping the internal clock. */ - if (++intclk.sec == 60) { - intclk.sec = 0; - intclk.min++; - } - if (intclk.min == 60) { - intclk.min = 0; - intclk.hour++; - } - if (intclk.hour == 24) { - intclk.hour = 0; - intclk.mday++; - } - if (intclk.mday == (nvr_get_days(intclk.mon, intclk.year) + 1)) { - intclk.mday = 1; - intclk.mon++; - } - if (intclk.mon == 13) { - intclk.mon = 1; - intclk.year++; + if (++intclk.tm_sec == 60) { + intclk.tm_sec = 0; + if (++intclk.tm_min == 60) { + intclk.tm_min = 0; + if (++intclk.tm_hour == 24) { + intclk.tm_hour = 0; + if (++intclk.tm_mday == (nvr_get_days(intclk.tm_mon, + intclk.tm_year) + 1)) { + intclk.tm_mday = 1; + intclk.tm_mon++; + if (++intclk.tm_mon == 13) { + intclk.tm_mon = 1; + intclk.tm_year++; + } + } + } + } } } @@ -168,9 +152,9 @@ nvr_init(nvr_t *nvr) /* Set up the NVR file's name. */ sprintf(temp, "%s.nvr", machine_get_internal_name()); - c = strlen(temp)+1; - nvr->fn = (wchar_t *)malloc(c*sizeof(wchar_t)); - mbstowcs(nvr->fn, temp, c); + c = strlen(temp); + nvr->fn = (wchar_t *)malloc((c + 1) * sizeof(wchar_t)); + mbstowcs(nvr->fn, temp, c + 1); /* Initialize the internal clock as needed. */ memset(&intclk, 0x00, sizeof(intclk)); @@ -183,8 +167,8 @@ nvr_init(nvr_t *nvr) nvr_time_set(tm); } else { /* Reset the internal clock to 1980/01/01 00:00. */ - intclk.mon = 1; - intclk.year = 1980; + intclk.tm_mon = 1; + intclk.tm_year = 1980; } /* Set up our timer. */ @@ -201,124 +185,7 @@ nvr_init(nvr_t *nvr) } -/* - * Load an NVR from file. - * - * This function does two things, really. It clears and initializes - * the RTC and NVRAM areas, sets up defaults for the RTC part, and - * then attempts to load data from a saved file. - * - * Either way, after that, it will continue to configure the local - * RTC to operate, so it can update either the local RTC, and/or - * the one supplied by a client. - */ -int -nvr_load(void) -{ - FILE *f; - - /* Make sure we have been initialized. */ - if (saved_nvr == NULL) return(0); - - /* Clear out any old data. */ - memset(saved_nvr->regs, 0xff, sizeof(saved_nvr->regs)); - - /* Set the defaults. */ - if (saved_nvr->reset != NULL) - saved_nvr->reset(saved_nvr); - - /* Load the (relevant) part of the NVR contents. */ - if (saved_nvr->size != 0) { - pclog("NVR: loading from '%ls'\n", nvr_path(saved_nvr->fn)); - f = plat_fopen(nvr_path(saved_nvr->fn), L"rb"); - if (f != NULL) { - /* Read NVR contents from file. */ - (void)fread(saved_nvr->regs, saved_nvr->size, 1, f); - (void)fclose(f); - } - } - - if (romset == ROM_T1000) - t1000_nvr_load(); - else if (romset == ROM_T1200) - t1200_nvr_load(); - - /* Get the local RTC running! */ - if (saved_nvr->start != NULL) - saved_nvr->start(saved_nvr); - - return(1); -} - - -/* Save the current NVR to a file. */ -int -nvr_save(void) -{ - FILE *f; - - /* Make sure we have been initialized. */ - if (saved_nvr == NULL) return(0); - - if (saved_nvr->size != 0) { - pclog("NVR: saving to '%ls'\n", nvr_path(saved_nvr->fn)); - f = plat_fopen(nvr_path(saved_nvr->fn), L"wb"); - if (f != NULL) { - /* Save NVR contents to file. */ - (void)fwrite(saved_nvr->regs, saved_nvr->size, 1, f); - fclose(f); - } - } - - if (romset == ROM_T1000) - t1000_nvr_save(); - else if (romset == ROM_T1200) - t1200_nvr_save(); - - /* Device is clean again. */ - nvr_dosave = 0; - - return(1); -} - - -/* Get current time from internal clock. */ -void -nvr_time_get(struct tm *tm) -{ - int8_t dom, mon, sum, wd; - int16_t cent, yr; - - tm->tm_sec = intclk.sec; - tm->tm_min = intclk.min; - tm->tm_hour = intclk.hour; - dom = intclk.mday; - mon = intclk.mon; - yr = (intclk.year % 100); - cent = ((intclk.year - yr) / 100) % 4; - sum = dom+mon+yr+cent; - wd = ((sum + 6) % 7); - tm->tm_wday = wd; - tm->tm_mday = intclk.mday; - tm->tm_mon = (intclk.mon - 1); - tm->tm_year = (intclk.year - 1900); -} - - -/* Set internal clock time. */ -void -nvr_time_set(struct tm *tm) -{ - intclk.sec = tm->tm_sec; - intclk.min = tm->tm_min; - intclk.hour = tm->tm_hour; - intclk.mday = tm->tm_mday; - intclk.mon = (tm->tm_mon + 1); - intclk.year = (tm->tm_year + 1900); -} - - -/* Get an absolute path to the NVR folder. */ +/* Get path to the NVR folder. */ wchar_t * nvr_path(wchar_t *str) { @@ -341,6 +208,138 @@ nvr_path(wchar_t *str) } +/* + * Load an NVR from file. + * + * This function does two things, really. It clears and initializes + * the RTC and NVRAM areas, sets up defaults for the RTC part, and + * then attempts to load data from a saved file. + * + * Either way, after that, it will continue to configure the local + * RTC to operate, so it can update either the local RTC, and/or + * the one supplied by a client. + */ +int +nvr_load(void) +{ + wchar_t *path; + FILE *fp; + + /* Make sure we have been initialized. */ + if (saved_nvr == NULL) return(0); + + /* Clear out any old data. */ + memset(saved_nvr->regs, 0x00, sizeof(saved_nvr->regs)); + + /* Set the defaults. */ + if (saved_nvr->reset != NULL) + saved_nvr->reset(saved_nvr); + + /* Load the (relevant) part of the NVR contents. */ + if (saved_nvr->size != 0) { + path = nvr_path(saved_nvr->fn); + pclog("NVR: loading from '%ls'\n", path); + fp = plat_fopen(path, L"rb"); + if (fp != NULL) { + /* Read NVR contents from file. */ + (void)fread(saved_nvr->regs, saved_nvr->size, 1, fp); + (void)fclose(fp); + } + } + + if (romset == ROM_T1000) + t1000_nvr_load(); + else if (romset == ROM_T1200) + t1200_nvr_load(); + + /* Get the local RTC running! */ + if (saved_nvr->start != NULL) + saved_nvr->start(saved_nvr); + + return(1); +} + + +/* Save the current NVR to a file. */ +int +nvr_save(void) +{ + wchar_t *path; + FILE *fp; + + /* Make sure we have been initialized. */ + if (saved_nvr == NULL) return(0); + + if (saved_nvr->size != 0) { + path = nvr_path(saved_nvr->fn); + pclog("NVR: saving to '%ls'\n", path); + fp = plat_fopen(path, L"wb"); + if (fp != NULL) { + /* Save NVR contents to file. */ + (void)fwrite(saved_nvr->regs, saved_nvr->size, 1, fp); + fclose(fp); + } + } + + if (romset == ROM_T1000) + t1000_nvr_save(); + else if (romset == ROM_T1200) + t1200_nvr_save(); + + /* Device is clean again. */ + nvr_dosave = 0; + + return(1); +} + + +void +nvr_period_recalc(void) +{ + /* Make sure we have been initialized. */ + if (saved_nvr == NULL) return; + + if (saved_nvr->size != 0) + saved_nvr->recalc(saved_nvr); +} + + +/* Get current time from internal clock. */ +void +nvr_time_get(struct tm *tm) +{ + int8_t dom, mon, sum, wd; + int16_t cent, yr; + + tm->tm_sec = intclk.tm_sec; + tm->tm_min = intclk.tm_min; + tm->tm_hour = intclk.tm_hour; + dom = intclk.tm_mday; + mon = intclk.tm_mon; + yr = (intclk.tm_year % 100); + cent = ((intclk.tm_year - yr) / 100) % 4; + sum = dom+mon+yr+cent; + wd = ((sum + 6) % 7); + tm->tm_wday = wd; + tm->tm_mday = intclk.tm_mday; + tm->tm_mon = (intclk.tm_mon - 1); + tm->tm_year = (intclk.tm_year - 1900); +} + + +/* Set internal clock time. */ +void +nvr_time_set(struct tm *tm) +{ + intclk.tm_sec = tm->tm_sec; + intclk.tm_min = tm->tm_min; + intclk.tm_hour = tm->tm_hour; + intclk.tm_mday = tm->tm_mday; + intclk.tm_mon = (tm->tm_mon + 1); + intclk.tm_year = (tm->tm_year + 1900); +} + + /* Open or create a file in the NVR area. */ FILE * nvr_fopen(wchar_t *str, wchar_t *mode) diff --git a/src/nvr.h b/src/nvr.h index 8119948a2..7bfe72ba1 100644 --- a/src/nvr.h +++ b/src/nvr.h @@ -8,7 +8,7 @@ * * Definitions for the generic NVRAM/CMOS driver. * - * Version: @(#)nvr.h 1.0.2 2018/03/11 + * Version: @(#)nvr.h 1.0.6 2018/04/11 * * Author: Fred N. van Kempen, * @@ -58,29 +58,36 @@ /* Define a generic RTC/NVRAM device. */ typedef struct _nvr_ { - uint8_t regs[NVR_MAXSIZE]; /* these are the registers */ - wchar_t *fn; /* pathname of image file */ - uint16_t size; /* device configuration */ + wchar_t *fn; /* pathname of image file */ + uint16_t size; /* device configuration */ int8_t irq; - int8_t upd_stat, /* FIXME: move to private struct */ - addr; - int64_t upd_ecount, /* FIXME: move to private struct */ - onesec_time, - onesec_cnt, - rtctime; + uint8_t onesec_cnt; + int64_t onesec_time; + + void *data; /* local data */ /* Hooks to device functions. */ void (*reset)(struct _nvr_ *); void (*start)(struct _nvr_ *); void (*tick)(struct _nvr_ *); + void (*recalc)(struct _nvr_ *); + + uint8_t regs[NVR_MAXSIZE]; /* these are the registers */ } nvr_t; extern int nvr_dosave; +#ifdef EMU_DEVICE_H +extern const device_t at_nvr_device; +extern const device_t ps_nvr_device; +extern const device_t amstrad_nvr_device; +#endif extern void nvr_init(nvr_t *); +extern wchar_t *nvr_path(wchar_t *str); +extern FILE *nvr_fopen(wchar_t *str, wchar_t *mode); extern int nvr_load(void); extern int nvr_save(void); @@ -88,12 +95,7 @@ extern int nvr_is_leap(int year); extern int nvr_get_days(int month, int year); extern void nvr_time_get(struct tm *); extern void nvr_time_set(struct tm *); - -extern wchar_t *nvr_path(wchar_t *str); -extern FILE *nvr_fopen(wchar_t *str, wchar_t *mode); - -extern void nvr_at_init(int irq); -extern void nvr_at_close(void); +extern void nvr_period_recalc(void); #endif /*EMU_NVR_H*/ diff --git a/src/nvr_at.c b/src/nvr_at.c index a982a962f..e9a13343b 100644 --- a/src/nvr_at.c +++ b/src/nvr_at.c @@ -189,7 +189,7 @@ * including the later update (DS12887A) which implemented a * "century" register to be compatible with Y2K. * - * Version: @(#)nvr_at.c 1.0.3 2018/03/11 + * Version: @(#)nvr_at.c 1.0.5 2018/04/09 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -218,6 +218,7 @@ * Boston, MA 02111-1307 * USA. */ +#include #include #include #include @@ -228,19 +229,20 @@ #include "cpu/cpu.h" #include "machine/machine.h" #include "io.h" -#include "pic.h" -#include "pit.h" #include "mem.h" #include "nmi.h" +#include "pic.h" +#include "pit.h" +#include "rom.h" #include "timer.h" #include "device.h" #include "nvr.h" -#include "rom.h" /* RTC registers and bit definitions. */ #define RTC_SECONDS 0 #define RTC_ALSECONDS 1 +# define AL_DONTCARE 0xc0 /* Alarm time is not set */ #define RTC_MINUTES 2 #define RTC_ALMINUTES 3 #define RTC_HOURS 4 @@ -277,43 +279,53 @@ # define REGC_UF 0x10 #define RTC_REGD 13 # define REGD_VRT 0x80 -#define RTC_CENTURY 0x32 /* century register */ +#define RTC_CENTURY_AT 0x32 /* century register for AT etc */ +#define RTC_CENTURY_PS 0x37 /* century register for PS/1 PS/2 */ #define RTC_REGS 14 /* number of registers */ -static nvr_t *nvrp; +typedef struct { + int8_t stat; + uint8_t cent; + + uint16_t addr; + + int64_t ecount, + rtctime; +} local_t; /* Get the current NVR time. */ static void -time_get(uint8_t *regs, struct tm *tm) +time_get(nvr_t *nvr, struct tm *tm) { + local_t *local = (local_t *)nvr->data; int8_t temp; - if (regs[RTC_REGB] & REGB_DM) { + if (nvr->regs[RTC_REGB] & REGB_DM) { /* NVR is in Binary data mode. */ - tm->tm_sec = regs[RTC_SECONDS]; - tm->tm_min = regs[RTC_MINUTES]; - temp = regs[RTC_HOURS]; - tm->tm_wday = (regs[RTC_DOW] - 1); - tm->tm_mday = regs[RTC_DOM]; - tm->tm_mon = (regs[RTC_MONTH] - 1); - tm->tm_year = regs[RTC_YEAR]; - tm->tm_year += (regs[RTC_CENTURY] * 100) - 1900; + tm->tm_sec = nvr->regs[RTC_SECONDS]; + tm->tm_min = nvr->regs[RTC_MINUTES]; + temp = nvr->regs[RTC_HOURS]; + tm->tm_wday = (nvr->regs[RTC_DOW] - 1); + tm->tm_mday = nvr->regs[RTC_DOM]; + tm->tm_mon = (nvr->regs[RTC_MONTH] - 1); + tm->tm_year = nvr->regs[RTC_YEAR]; + tm->tm_year += (nvr->regs[local->cent] * 100) - 1900; } else { /* NVR is in BCD data mode. */ - tm->tm_sec = RTC_DCB(regs[RTC_SECONDS]); - tm->tm_min = RTC_DCB(regs[RTC_MINUTES]); - temp = RTC_DCB(regs[RTC_HOURS]); - tm->tm_wday = (RTC_DCB(regs[RTC_DOW]) - 1); - tm->tm_mday = RTC_DCB(regs[RTC_DOM]); - tm->tm_mon = (RTC_DCB(regs[RTC_MONTH]) - 1); - tm->tm_year = RTC_DCB(regs[RTC_YEAR]); - tm->tm_year += (RTC_DCB(regs[RTC_CENTURY]) * 100) - 1900; + tm->tm_sec = RTC_DCB(nvr->regs[RTC_SECONDS]); + tm->tm_min = RTC_DCB(nvr->regs[RTC_MINUTES]); + temp = RTC_DCB(nvr->regs[RTC_HOURS]); + tm->tm_wday = (RTC_DCB(nvr->regs[RTC_DOW]) - 1); + tm->tm_mday = RTC_DCB(nvr->regs[RTC_DOM]); + tm->tm_mon = (RTC_DCB(nvr->regs[RTC_MONTH]) - 1); + tm->tm_year = RTC_DCB(nvr->regs[RTC_YEAR]); + tm->tm_year += (RTC_DCB(nvr->regs[local->cent]) * 100) - 1900; } /* Adjust for 12/24 hour mode. */ - if (regs[RTC_REGB] & REGB_2412) + if (nvr->regs[RTC_REGB] & REGB_2412) tm->tm_hour = temp; else tm->tm_hour = ((temp & ~RTC_AMPM)%12) + ((temp&RTC_AMPM) ? 12 : 0); @@ -322,49 +334,50 @@ time_get(uint8_t *regs, struct tm *tm) /* Set the current NVR time. */ static void -time_set(uint8_t *regs, struct tm *tm) +time_set(nvr_t *nvr, struct tm *tm) { + local_t *local = (local_t *)nvr->data; int year = (tm->tm_year + 1900); - if (regs[RTC_REGB] & REGB_DM) { + if (nvr->regs[RTC_REGB] & REGB_DM) { /* NVR is in Binary data mode. */ - regs[RTC_SECONDS] = tm->tm_sec; - regs[RTC_MINUTES] = tm->tm_min; - regs[RTC_DOW] = (tm->tm_wday + 1); - regs[RTC_DOM] = tm->tm_mday; - regs[RTC_MONTH] = (tm->tm_mon + 1); - regs[RTC_YEAR] = (year % 100); - regs[RTC_CENTURY] = (year / 100); + nvr->regs[RTC_SECONDS] = tm->tm_sec; + nvr->regs[RTC_MINUTES] = tm->tm_min; + nvr->regs[RTC_DOW] = (tm->tm_wday + 1); + nvr->regs[RTC_DOM] = tm->tm_mday; + nvr->regs[RTC_MONTH] = (tm->tm_mon + 1); + nvr->regs[RTC_YEAR] = (year % 100); + nvr->regs[local->cent] = (year / 100); - if (regs[RTC_REGB] & REGB_2412) { + if (nvr->regs[RTC_REGB] & REGB_2412) { /* NVR is in 24h mode. */ - regs[RTC_HOURS] = tm->tm_hour; + nvr->regs[RTC_HOURS] = tm->tm_hour; } else { /* NVR is in 12h mode. */ - regs[RTC_HOURS] = (tm->tm_hour % 12) ? (tm->tm_hour % 12) : 12; + nvr->regs[RTC_HOURS] = (tm->tm_hour % 12) ? (tm->tm_hour % 12) : 12; if (tm->tm_hour > 11) - regs[RTC_HOURS] |= RTC_AMPM; + nvr->regs[RTC_HOURS] |= RTC_AMPM; } } else { /* NVR is in BCD data mode. */ - regs[RTC_SECONDS] = RTC_BCD(tm->tm_sec); - regs[RTC_MINUTES] = RTC_BCD(tm->tm_min); - regs[RTC_DOW] = (RTC_BCD(tm->tm_wday) + 1); - regs[RTC_DOM] = RTC_BCD(tm->tm_mday); - regs[RTC_MONTH] = (RTC_BCD(tm->tm_mon) + 1); - regs[RTC_YEAR] = RTC_BCD(year % 100); - regs[RTC_CENTURY] = RTC_BCD(year / 100); + nvr->regs[RTC_SECONDS] = RTC_BCD(tm->tm_sec); + nvr->regs[RTC_MINUTES] = RTC_BCD(tm->tm_min); + nvr->regs[RTC_DOW] = (RTC_BCD(tm->tm_wday) + 1); + nvr->regs[RTC_DOM] = RTC_BCD(tm->tm_mday); + nvr->regs[RTC_MONTH] = (RTC_BCD(tm->tm_mon) + 1); + nvr->regs[RTC_YEAR] = RTC_BCD(year % 100); + nvr->regs[local->cent] = RTC_BCD(year / 100); - if (regs[RTC_REGB] & REGB_2412) { + if (nvr->regs[RTC_REGB] & REGB_2412) { /* NVR is in 24h mode. */ - regs[RTC_HOURS] = RTC_BCD(tm->tm_hour); + nvr->regs[RTC_HOURS] = RTC_BCD(tm->tm_hour); } else { /* NVR is in 12h mode. */ - regs[RTC_HOURS] = (tm->tm_hour % 12) + nvr->regs[RTC_HOURS] = (tm->tm_hour % 12) ? RTC_BCD(tm->tm_hour % 12) : RTC_BCD(12); if (tm->tm_hour > 11) - regs[RTC_HOURS] |= RTC_AMPM; + nvr->regs[RTC_HOURS] |= RTC_AMPM; } } } @@ -372,19 +385,19 @@ time_set(uint8_t *regs, struct tm *tm) /* Check if the current time matches a set alarm time. */ static int8_t -check_alarm(uint8_t *regs, int8_t addr) +check_alarm(nvr_t *nvr, int8_t addr) { -#define ALARM_DONTCARE 0xc0 - return((regs[addr+1] == regs[addr]) || - ((regs[addr+1] & ALARM_DONTCARE) == ALARM_DONTCARE)); + return((nvr->regs[addr+1] == nvr->regs[addr]) || + ((nvr->regs[addr+1] & AL_DONTCARE) == AL_DONTCARE)); } /* Update the NVR registers from the internal clock. */ static void -update_timer(void *priv) +timer_update(void *priv) { nvr_t *nvr = (nvr_t *)priv; + local_t *local = (local_t *)nvr->data; struct tm tm; if (! (nvr->regs[RTC_REGB] & REGB_SET)) { @@ -392,22 +405,22 @@ update_timer(void *priv) nvr_time_get(&tm); /* Update registers with current time. */ - time_set(nvr->regs, &tm); - + time_set(nvr, &tm); + /* Clear update status. */ - nvr->upd_stat = 0x00; + local->stat = 0x00; /* Check for any alarms we need to handle. */ - if (check_alarm(nvr->regs, RTC_SECONDS) && - check_alarm(nvr->regs, RTC_MINUTES) && - check_alarm(nvr->regs, RTC_HOURS)) { + if (check_alarm(nvr, RTC_SECONDS) && + check_alarm(nvr, RTC_MINUTES) && + check_alarm(nvr, RTC_HOURS)) { nvr->regs[RTC_REGC] |= REGC_AF; if (nvr->regs[RTC_REGB] & REGB_AIE) { nvr->regs[RTC_REGC] |= REGC_IRQF; /* Generate an interrupt. */ if (nvr->irq != -1) - picint(1<irq); + picint(1 << nvr->irq); } } @@ -421,41 +434,43 @@ update_timer(void *priv) /* Generate an interrupt. */ if (nvr->irq != -1) - picint(1<irq); + picint(1 << nvr->irq); } } - nvr->upd_ecount = 0; + local->ecount = 0; } /* Re-calculate the timer values. */ static void -rtc_timer_recalc(nvr_t *nvr, int add) +timer_recalc(nvr_t *nvr, int add) { + local_t *local = (local_t *)nvr->data; int64_t c, nt; - c = 1 << ((nvr->regs[RTC_REGA] & REGA_RS) - 1); + c = 1ULL << ((nvr->regs[RTC_REGA] & REGA_RS) - 1); nt = (int64_t)(RTCCONST * c * (1<rtctime += nt; - else if (nvr->rtctime > nt) - nvr->rtctime = nt; + local->rtctime += nt; + else if (local->rtctime > nt) + local->rtctime = nt; } static void -rtc_timer(void *priv) +timer_intr(void *priv) { nvr_t *nvr = (nvr_t *)priv; + local_t *local = (local_t *)nvr->data; if (! (nvr->regs[RTC_REGA] & REGA_RS)) { - nvr->rtctime = 0x7fffffff; + local->rtctime = 0x7fffffff; return; } /* Update our timer interval. */ - rtc_timer_recalc(nvr, 1); + timer_recalc(nvr, 1); nvr->regs[RTC_REGC] |= REGC_PF; if (nvr->regs[RTC_REGB] & REGB_PIE) { @@ -463,20 +478,27 @@ rtc_timer(void *priv) /* Generate an interrupt. */ if (nvr->irq != -1) - picint(1<irq); + picint(1 << nvr->irq); } } /* Callback from internal clock, another second passed. */ static void -tick_timer(nvr_t *nvr) +timer_tick(nvr_t *nvr) { - if (nvr->regs[RTC_REGB] & REGB_SET) return; + local_t *local = (local_t *)nvr->data; - nvr->upd_stat = REGA_UIP; + /* Only update it there is no SET in progress. */ + if (! (nvr->regs[RTC_REGB] & REGB_SET)) { + /* Set the UIP bit, announcing the update. */ + local->stat = REGA_UIP; - nvr->upd_ecount = (int64_t)((244.0 + 1984.0) * TIMER_USEC); + timer_recalc(nvr, 0); + + /* Schedule the actual update. */ + local->ecount = (int64_t)((244.0 + 1984.0) * TIMER_USEC); + } } @@ -485,20 +507,21 @@ static void nvr_write(uint16_t addr, uint8_t val, void *priv) { nvr_t *nvr = (nvr_t *)priv; + local_t *local = (local_t *)nvr->data; struct tm tm; uint8_t old; cycles -= ISA_CYCLES(8); if (addr & 1) { - old = nvr->regs[nvr->addr]; - switch(nvr->addr) { + old = nvr->regs[local->addr]; + switch(local->addr) { case RTC_REGA: nvr->regs[RTC_REGA] = val; if (val & REGA_RS) - rtc_timer_recalc(nvr, 1); + timer_recalc(nvr, 1); else - nvr->rtctime = 0x7fffffff; + local->rtctime = 0x7fffffff; break; case RTC_REGB: @@ -515,25 +538,25 @@ nvr_write(uint16_t addr, uint8_t val, void *priv) break; default: /* non-RTC registers are just NVRAM */ - if (nvr->regs[nvr->addr] != val) { - nvr->regs[nvr->addr] = val; + if (nvr->regs[local->addr] != val) { + nvr->regs[local->addr] = val; nvr_dosave = 1; } break; } - if ((nvr->addr < RTC_REGA) || (nvr->addr == RTC_CENTURY)) { - if ((nvr->addr != 1) && (nvr->addr != 3) && (nvr->addr != 5)) { + if ((local->addr < RTC_REGA) || (local->addr == local->cent)) { + if ((local->addr != 1) && (local->addr != 3) && (local->addr != 5)) { if ((old != val) && !enable_sync) { /* Update internal clock. */ - time_get(nvr->regs, &tm); + time_get(nvr, &tm); nvr_time_set(&tm); nvr_dosave = 1; } } } } else { - nvr->addr = (val & (nvr->size - 1)); + local->addr = (val & (nvr->size - 1)); if (!(machines[machine].flags & MACHINE_MCA) && (romset != ROM_IBMPS1_2133)) nmi_mask = (~val & 0x80); @@ -546,17 +569,18 @@ static uint8_t nvr_read(uint16_t addr, void *priv) { nvr_t *nvr = (nvr_t *)priv; + local_t *local = (local_t *)nvr->data; uint8_t ret; cycles -= ISA_CYCLES(8); - if (addr & 1) switch(nvr->addr) { + if (addr & 1) switch(local->addr) { case RTC_REGA: - ret = (nvr->regs[RTC_REGA] & 0x7f) | nvr->upd_stat; + ret = (nvr->regs[RTC_REGA] & 0x7f) | local->stat; break; case RTC_REGC: - picintc(1<irq); + picintc(1 << nvr->irq); ret = nvr->regs[RTC_REGC]; nvr->regs[RTC_REGC] = 0x00; break; @@ -567,10 +591,10 @@ nvr_read(uint16_t addr, void *priv) break; default: - ret = nvr->regs[nvr->addr]; + ret = nvr->regs[local->addr]; break; } else { - ret = nvr->addr; + ret = local->addr; } return(ret); @@ -579,19 +603,21 @@ nvr_read(uint16_t addr, void *priv) /* Reset the RTC state to 1980/01/01 00:00. */ static void -nvr_at_reset(nvr_t *nvr) +nvr_reset(nvr_t *nvr) { + local_t *local = (local_t *)nvr->data; + memset(nvr->regs, 0x00, RTC_REGS); nvr->regs[RTC_DOM] = 1; nvr->regs[RTC_MONTH] = 1; nvr->regs[RTC_YEAR] = RTC_BCD(80); - nvr->regs[RTC_CENTURY] = RTC_BCD(19); + nvr->regs[local->cent] = RTC_BCD(19); } /* Process after loading from file. */ static void -nvr_at_start(nvr_t *nvr) +nvr_start(nvr_t *nvr) { struct tm tm; @@ -599,63 +625,120 @@ nvr_at_start(nvr_t *nvr) if (enable_sync) { /* Use the internal clock's time. */ nvr_time_get(&tm); - time_set(nvr->regs, &tm); + time_set(nvr, &tm); } else { /* Set the internal clock from the chip time. */ - time_get(nvr->regs, &tm); + time_get(nvr, &tm); nvr_time_set(&tm); } /* Start the RTC. */ nvr->regs[RTC_REGA] = (REGA_RS2|REGA_RS1); nvr->regs[RTC_REGB] = REGB_2412; - rtc_timer_recalc(nvr, 0); + timer_recalc(nvr, 1); } -void -nvr_at_init(int irq) +static void +nvr_recalc(nvr_t *nvr) { + timer_recalc(nvr, 0); +} + + +static void * +nvr_at_init(const device_t *info) +{ + local_t *local; nvr_t *nvr; /* Allocate an NVR for this machine. */ nvr = (nvr_t *)malloc(sizeof(nvr_t)); - if (nvr == NULL) return; + if (nvr == NULL) return(NULL); memset(nvr, 0x00, sizeof(nvr_t)); + local = (local_t *)malloc(sizeof(local_t)); + memset(local, 0xff, sizeof(local_t)); + nvr->data = local; + /* This is machine specific. */ nvr->size = machines[machine].nvrmask + 1; - nvr->irq = irq; + switch(info->local) { + case 0: /* standard AT */ + nvr->irq = 8; + local->cent = RTC_CENTURY_AT; + break; + + case 1: /* PS/1 or PS/2 */ + nvr->irq = 8; + local->cent = RTC_CENTURY_PS; + break; + + case 2: /* Amstrad PC's */ + nvr->irq = 1; + local->cent = RTC_CENTURY_AT; + break; + } /* Set up any local handlers here. */ - nvr->reset = nvr_at_reset; - nvr->start = nvr_at_start; - nvr->tick = tick_timer; + nvr->reset = nvr_reset; + nvr->start = nvr_start; + nvr->tick = timer_tick; + nvr->recalc = nvr_recalc; /* Initialize the generic NVR. */ nvr_init(nvr); /* Start the timers. */ - timer_add(update_timer, &nvr->upd_ecount, &nvr->upd_ecount, nvr); - timer_add(rtc_timer, &nvr->rtctime, TIMER_ALWAYS_ENABLED, nvr); + timer_add(timer_update, &local->ecount, &local->ecount, nvr); + timer_add(timer_intr, &local->rtctime, TIMER_ALWAYS_ENABLED, nvr); /* Set up the I/O handler for this device. */ io_sethandler(0x0070, 2, nvr_read,NULL,NULL, nvr_write,NULL,NULL, nvr); - nvrp = nvr; + return(nvr); } -void -nvr_at_close(void) +static void +nvr_at_close(void *priv) { - if (nvrp == NULL) return; + nvr_t *nvr = (nvr_t *)priv; - if (nvrp->fn != NULL) - free(nvrp->fn); + if (nvr->fn != NULL) + free(nvr->fn); - free(nvrp); + if (nvr->data != NULL) + free(nvr->data); - nvrp = NULL; + free(nvr); } + + +const device_t at_nvr_device = { + "PC/AT NVRAM", + DEVICE_ISA | DEVICE_AT, + 0, + nvr_at_init, nvr_at_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t ps_nvr_device = { + "PS/1 or PS/2 NVRAM", + DEVICE_PS2, + 1, + nvr_at_init, nvr_at_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t amstrad_nvr_device = { + "Amstrad NVRAM", + MACHINE_ISA | MACHINE_AT, + 2, + nvr_at_init, nvr_at_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/pc.c b/src/pc.c index 09268e0c5..7115d3f25 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,7 +8,7 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.68 2018/03/19 + * Version: @(#)pc.c 1.0.69 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, @@ -38,6 +38,7 @@ #include "mem.h" #include "rom.h" #include "dma.h" +#include "pci.h" #include "pic.h" #include "pit.h" #include "random.h" @@ -57,21 +58,14 @@ #include "disk/hdc.h" #include "disk/hdc_ide.h" #include "disk/zip.h" +#include "scsi/scsi.h" #include "cdrom/cdrom.h" #include "cdrom/cdrom_image.h" #include "cdrom/cdrom_null.h" -#include "scsi/scsi.h" #include "network/network.h" #include "sound/sound.h" #include "sound/midi.h" -#include "sound/snd_cms.h" -#include "sound/snd_dbopl.h" -#include "sound/snd_mpu401.h" -#include "sound/snd_opl.h" -#include "sound/snd_gus.h" -#include "sound/snd_sb.h" #include "sound/snd_speaker.h" -#include "sound/snd_ssi2001.h" #include "video/video.h" #include "ui.h" #include "plat.h" @@ -120,7 +114,7 @@ int sound_is_float = 1, /* (C) sound uses FP values */ GUS = 0, /* (C) sound option */ SSI2001 = 0, /* (C) sound option */ voodoo_enabled = 0; /* (C) video option */ -int mem_size = 0; /* (C) memory size */ +uint32_t mem_size = 0; /* (C) memory size */ int cpu_manufacturer = 0, /* (C) cpu manufacturer */ cpu_use_dynarec = 0, /* (C) cpu uses/needs Dyna */ cpu = 3, /* (C) cpu type */ @@ -299,6 +293,7 @@ pc_init(int argc, wchar_t *argv[]) struct tm *info; time_t now; int c; + uint32_t *uid, *shwnd; /* Grab the executable's full path. */ plat_get_exe_name(exe_path, sizeof(exe_path)-1); @@ -329,12 +324,8 @@ usage: printf("-D or --debug - force debug output logging\n"); #endif printf("-F or --fullscreen - start in fullscreen mode\n"); - printf("-M or --memdump - dump memory on exit\n"); printf("-L or --logfile path - set 'path' to be the logfile\n"); printf("-P or --vmpath path - set 'path' to be root for vm\n"); -#ifdef USE_WX - printf("-R or --fps num - set render speed to 'num' fps\n"); -#endif printf("-S or --settings - show only the settings dialog\n"); #ifdef _WIN32 printf("-H or --hwnd id,hwnd - sends back the main dialog's hwnd\n"); @@ -357,20 +348,11 @@ usage: if ((c+1) == argc) goto usage; wcscpy(log_path, argv[++c]); - } else if (!wcscasecmp(argv[c], L"--memdump") || - !wcscasecmp(argv[c], L"-M")) { } else if (!wcscasecmp(argv[c], L"--vmpath") || !wcscasecmp(argv[c], L"-P")) { if ((c+1) == argc) goto usage; wcscpy(path, argv[++c]); -#ifdef USE_WX - } else if (!wcscasecmp(argv[c], L"--fps") || - !wcscasecmp(argv[c], L"-R")) { - if ((c+1) == argc) goto usage; - - video_fps = wcstol(argv[++c], NULL, 10); -#endif } else if (!wcscasecmp(argv[c], L"--settings") || !wcscasecmp(argv[c], L"-S")) { settings_only = 1; @@ -381,7 +363,9 @@ usage: if ((c+1) == argc) goto usage; wcstombs(temp, argv[++c], 128); - sscanf(temp, "%016" PRIX64 ",%016" PRIX64, &unique_id, &source_hwnd); + uid = (uint32_t *) &unique_id; + shwnd = (uint32_t *) &source_hwnd; + sscanf(temp, "%08X%08X,%08X%08X", uid + 1, uid, shwnd + 1, shwnd); #endif } else if (!wcscasecmp(argv[c], L"--test")) { /* some (undocumented) test function here.. */ @@ -512,6 +496,8 @@ pc_full_speed(void) setpitclock(14318184.0); } atfullspeed = 1; + + nvr_period_recalc(); } @@ -522,9 +508,12 @@ pc_speed_changed(void) setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); else setpitclock(14318184.0); + + nvr_period_recalc(); } +#if 0 /* Re-load system configuration and restart. */ /* FIXME: this has to be reviewed! */ void @@ -536,10 +525,8 @@ pc_reload(wchar_t *fn) for (i=0; iexit(i); - cdrom_close(i); - } + + cdrom_close(); pc_reset_hard_close(); @@ -547,24 +534,9 @@ pc_reload(wchar_t *fn) config_load(); - for (i=0; i= 'A') && (cdrom_drives[i].host_drive <= 'Z')) - ioctl_open(i, cdrom_drives[i].host_drive); - else - cdrom_null_open(i, cdrom_drives[i].host_drive); - } - - for (i=0; iexit(i); - for (i=0; i #include #include +#include "86box.h" #include "io.h" #include "pci.h" #include "pci_dummy.h" diff --git a/src/piix.h b/src/piix.h index c781994df..936f79899 100644 --- a/src/piix.h +++ b/src/piix.h @@ -8,26 +8,18 @@ * * Emulation core dispatcher. * - * Version: @(#)piix.h 1.0.2 2017/10/25 + * Version: @(#)piix.h 1.0.3 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ -extern void piix_init(int card); +extern const device_t piix_device; +extern const device_t piix3_device; -extern void piix3_init(int card); +extern int piix_bus_master_dma_read(int channel, uint8_t *data, int transfer_length, void *priv); +extern int piix_bus_master_dma_write(int channel, uint8_t *data, int transfer_length, void *priv); -extern void piix4_init(int card); - -extern uint8_t piix_bus_master_read(uint16_t port, void *priv); -extern void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); - -extern int piix_bus_master_get_count(int channel); - -extern int piix_bus_master_dma_read(int channel, uint8_t *data, int transfer_length); -extern int piix_bus_master_dma_write(int channel, uint8_t *data, int transfer_length); - -extern void piix_bus_master_set_irq(int channel); +extern void piix_bus_master_set_irq(int channel, void *priv); diff --git a/src/pit.c b/src/pit.c index edac967a4..3a7565c25 100644 --- a/src/pit.c +++ b/src/pit.c @@ -39,6 +39,12 @@ float VGACONST1, float RTCCONST; int64_t firsttime=1; +void setrtcconst(float clock) +{ + RTCCONST=clock/32768.0; + TIMER_USEC = (int64_t)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); +} + void setpitclock(float clock) { cpuclock=clock; @@ -52,8 +58,8 @@ void setpitclock(float clock) video_update_timing(); xt_cpu_multi = (int64_t)((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); - RTCCONST=clock/32768.0; - TIMER_USEC = (int64_t)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); + /* RTCCONST=clock/32768.0; + TIMER_USEC = (int64_t)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); */ device_speed_changed(); } @@ -336,7 +342,6 @@ void pit_write(uint16_t addr, uint8_t val, void *p) { PIT *pit = (PIT *)p; int t; - cycles -= (int)PITCONST; switch (addr&3) { @@ -444,7 +449,6 @@ uint8_t pit_read(uint16_t addr, void *p) PIT *pit = (PIT *)p; int64_t t; uint8_t temp = 0xff; - cycles -= (int)PITCONST; switch (addr&3) { case 0: case 1: case 2: /*Timers*/ diff --git a/src/pit.h b/src/pit.h index d5ccc4f91..00297eb26 100644 --- a/src/pit.h +++ b/src/pit.h @@ -58,6 +58,8 @@ extern void pit_set_using_timer(PIT *pit, int t, int using_timer); extern void pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out)); extern void pit_clock(PIT *pit, int t); +extern void setrtcconst(float clock); + extern void setpitclock(float clock); extern float pit_timer0_freq(void); diff --git a/src/plat.h b/src/plat.h index c8291528a..fc7e5e252 100644 --- a/src/plat.h +++ b/src/plat.h @@ -107,14 +107,13 @@ extern void do_stop(void); extern uint8_t host_cdrom_drive_available[26]; extern uint8_t host_cdrom_drive_available_num; +#ifdef USE_IOCTL extern void cdrom_init_host_drives(void); +#endif extern void cdrom_eject(uint8_t id); extern void cdrom_reload(uint8_t id); extern void zip_eject(uint8_t id); extern void zip_reload(uint8_t id); -extern void removable_disk_unload(uint8_t id); -extern void removable_disk_eject(uint8_t id); -extern void removable_disk_reload(uint8_t id); extern int ioctl_open(uint8_t id, char d); extern void ioctl_reset(uint8_t id); extern void ioctl_close(uint8_t id); diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index e75993d82..61b452f35 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -8,7 +8,7 @@ * * Handling of the SCSI controllers. * - * Version: @(#)scsi.c 1.0.17 2018/03/18 + * Version: @(#)scsi.c 1.0.18 2018/03/26 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -27,11 +27,12 @@ #include "../rom.h" #include "../timer.h" #include "../device.h" -#include "../cdrom/cdrom.h" #include "../disk/hdc.h" #include "../disk/zip.h" #include "../plat.h" #include "scsi.h" +#include "../cdrom/cdrom.h" +#include "scsi_device.h" #include "scsi_aha154x.h" #include "scsi_buslogic.h" #include "scsi_ncr5380.h" @@ -60,30 +61,29 @@ typedef const struct { const char *name; const char *internal_name; const device_t *device; - void (*reset)(void *p); } SCSI_CARD; static SCSI_CARD scsi_cards[] = { - { "None", "none", NULL, NULL }, - { "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, x54x_device_reset }, - { "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, x54x_device_reset }, - { "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, x54x_device_reset }, - { "[ISA] BusLogic BT-542BH","bt542bh", &buslogic_device, BuslogicDeviceReset }, - { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device,BuslogicDeviceReset }, - { "[ISA] Longshine LCS-6821N","lcs6821n", &scsi_lcs6821n_device,NULL }, - { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, NULL }, - { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, NULL }, - { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, NULL }, + { "None", "none", NULL, }, + { "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, }, + { "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, }, + { "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, }, + { "[ISA] BusLogic BT-542BH","bt542bh", &buslogic_device, }, + { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device,}, + { "[ISA] Longshine LCS-6821N","lcs6821n", &scsi_lcs6821n_device,}, + { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, }, + { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, + { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, #ifdef WALTJE - { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, NULL }, + { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, #endif - { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, x54x_device_reset }, - { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device,BuslogicDeviceReset }, - { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, BuslogicDeviceReset }, - { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device,NULL }, - { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device,BuslogicDeviceReset }, - { "", "", NULL, NULL }, + { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, + { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device,}, + { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, + { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device,}, + { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device,}, + { "", "", NULL, }, }; @@ -149,6 +149,9 @@ void scsi_card_init(void) { int i, j; + if (!scsi_cards[scsi_card_current].device) + return; + pclog("Building SCSI hard disk map...\n"); build_scsi_hd_map(); pclog("Building SCSI CD-ROM map...\n"); @@ -158,41 +161,24 @@ void scsi_card_init(void) for (i=0; i * Miran Grca, @@ -103,6 +103,13 @@ #define GPMODE_CAPABILITIES_PAGE 0x2a #define GPMODE_ALL_PAGES 0x3f +/* Mode page codes for presence */ +#define GPMODEP_R_W_ERROR_PAGE 0x0000000000000002LL +#define GPMODEP_CDROM_PAGE 0x0000000000002000LL +#define GPMODEP_CDROM_AUDIO_PAGE 0x0000000000004000LL +#define GPMODEP_CAPABILITIES_PAGE 0x0000040000000000LL +#define GPMODEP_ALL_PAGES 0x8000000000000000LL + /* SCSI Status Codes */ #define SCSI_STATUS_OK 0 #define SCSI_STATUS_CHECK_CONDITION 2 @@ -306,7 +313,6 @@ extern char *scsi_card_get_internal_name(int card); extern int scsi_card_get_from_internal_name(char *s); extern void scsi_mutex(uint8_t start); extern void scsi_card_init(void); -extern void scsi_card_reset(void); extern uint8_t scsi_hard_disks[16][8]; diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index efb34ebf8..3e2442381 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -10,7 +10,7 @@ * made by Adaptec, Inc. These controllers were designed for * the ISA bus. * - * Version: @(#)scsi_aha154x.c 1.0.40 2018/03/18 + * Version: @(#)scsi_aha154x.c 1.0.40 2018/04/11 * * Authors: Fred N. van Kempen, * Original Buslogic version by SA1988 and Miran Grca. @@ -30,11 +30,11 @@ #include "../mem.h" #include "../mca.h" #include "../rom.h" +#include "../device.h" #include "../nvr.h" #include "../dma.h" #include "../pic.h" #include "../timer.h" -#include "../device.h" #include "../plat.h" #include "../cpu/cpu.h" #include "scsi.h" diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index e796ec23e..6d0a01753 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -11,7 +11,7 @@ * 1 - BT-545S ISA; * 2 - BT-958D PCI * - * Version: @(#)scsi_buslogic.c 1.0.36 2018/03/18 + * Version: @(#)scsi_buslogic.c 1.0.37 2018/03/28 * * Authors: TheCollector1995, * Miran Grca, @@ -33,12 +33,12 @@ #include "../mem.h" #include "../mca.h" #include "../rom.h" +#include "../device.h" #include "../nvr.h" #include "../dma.h" #include "../pic.h" #include "../pci.h" #include "../timer.h" -#include "../device.h" #include "../plat.h" #include "scsi.h" #include "scsi_buslogic.h" @@ -529,6 +529,7 @@ buslogic_param_len(void *p) case 0x91: return 2; case 0x94: + case 0xFB: return 3; case 0x93: /* Valid only for VLB */ return (bl->chip == CHIP_BUSLOGIC_VLB) ? 1 : 0; @@ -550,7 +551,7 @@ static void BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN, int dir) { uint32_t DataPointer = ESCSICmd->DataPointer; - uint32_t DataLength = ESCSICmd->DataLength; + int DataLength = ESCSICmd->DataLength; uint32_t Address; uint32_t TransferLength; @@ -997,6 +998,9 @@ buslogic_cmds(void *p) dev->DataReply = 0; break; + case 0xFB: + dev->DataReplyLeft = dev->CmdBuf[2]; + break; default: dev->DataReplyLeft = 0; dev->Status |= STAT_INVCMD; @@ -1583,6 +1587,7 @@ buslogic_init(const device_t *info) dev->cdrom_boot = 1; dev->bit32 = 1; dev->ha_bps = 20000000.0; /* ultra SCSI */ + dev->max_id = 15; /* wide SCSI */ break; } @@ -1683,7 +1688,7 @@ static const device_config_t BT_ISA_Config[] = { "0x134", 0x134 }, { - "" + "", 0 } }, }, @@ -1709,7 +1714,7 @@ static const device_config_t BT_ISA_Config[] = { "IRQ 15", 15 }, { - "" + "", 0 } }, }, @@ -1726,7 +1731,7 @@ static const device_config_t BT_ISA_Config[] = { "DMA 7", 7 }, { - "" + "", 0 } }, }, @@ -1746,7 +1751,7 @@ static const device_config_t BT_ISA_Config[] = { "D800H", 0xd8000 }, { - "" + "", 0 } }, }, diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index aed66bf6c..e4eeb5a0f 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -8,7 +8,7 @@ * * The generic SCSI device command handler. * - * Version: @(#)scsi_device.c 1.0.15 2018/03/16 + * Version: @(#)scsi_device.c 1.0.16 2018/03/26 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -22,10 +22,10 @@ #include #include "../86box.h" #include "../device.h" -#include "../cdrom/cdrom.h" #include "../disk/hdd.h" #include "../disk/zip.h" #include "scsi.h" +#include "../cdrom/cdrom.h" #include "scsi_disk.h" @@ -41,8 +41,8 @@ static uint8_t scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb } else if (lun_type == SCSI_CDROM) { - cdrom_command(id, cdb); - return cdrom_CDROM_PHASE_to_scsi(id); + cdrom_command(cdrom[id], cdb); + return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); } else if (lun_type == SCSI_ZIP) { @@ -64,7 +64,7 @@ static void scsi_device_target_phase_callback(int lun_type, uint8_t id) } else if (lun_type == SCSI_CDROM) { - cdrom_phase_callback(id); + cdrom_phase_callback(cdrom[id]); } else if (lun_type == SCSI_ZIP) { @@ -85,7 +85,7 @@ static int scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id) } else if (lun_type == SCSI_CDROM) { - return cdrom_CDROM_PHASE_to_scsi(id); + return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); } else if (lun_type == SCSI_ZIP) { @@ -110,7 +110,7 @@ static void scsi_device_target_save_cdb_byte(int lun_type, uint8_t id, uint8_t c } else if (lun_type == SCSI_ZIP) { - zip[id].request_length = cdb_byte; + zip[id]->request_length = cdb_byte; } else { @@ -137,7 +137,7 @@ int64_t scsi_device_get_callback(uint8_t scsi_id, uint8_t scsi_lun) break; case SCSI_ZIP: id = scsi_zip_drives[scsi_id][scsi_lun]; - return zip[id].callback; + return zip[id]->callback; break; default: return -1LL; @@ -164,7 +164,7 @@ uint8_t *scsi_device_sense(uint8_t scsi_id, uint8_t scsi_lun) break; case SCSI_ZIP: id = scsi_zip_drives[scsi_id][scsi_lun]; - return zip[id].sense; + return zip[id]->sense; break; default: return scsi_null_device_sense; @@ -187,7 +187,7 @@ void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffe break; case SCSI_CDROM: id = scsi_cdrom_drives[scsi_id][scsi_lun]; - cdrom_request_sense_for_scsi(id, buffer, alloc_length); + cdrom_request_sense_for_scsi(cdrom[id], buffer, alloc_length); break; case SCSI_ZIP: id = scsi_zip_drives[scsi_id][scsi_lun]; @@ -200,7 +200,7 @@ void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffe } -void scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uint8_t *rmb) +void scsi_device_reset(uint8_t scsi_id, uint8_t scsi_lun) { uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; @@ -210,8 +210,28 @@ void scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uin { case SCSI_DISK: id = scsi_hard_disks[scsi_id][scsi_lun]; - *type = 0x00; - *rmb = (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? 0x80 : 0x00; + scsi_hd_reset(id); + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + cdrom_reset(cdrom[id]); + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + zip_reset(id); + break; + } +} + + +void scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uint8_t *rmb) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + switch (lun_type) + { + case SCSI_DISK: + *type = *rmb = 0x00; break; case SCSI_CDROM: *type = 0x05; @@ -222,7 +242,7 @@ void scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uin *rmb = 0x80; break; default: - *type = *rmb = 0xFF; + *type = *rmb = 0xff; break; } } @@ -241,7 +261,7 @@ int scsi_device_read_capacity(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *cdb, u return scsi_hd_read_capacity(id, cdb, buffer, len); case SCSI_CDROM: id = scsi_cdrom_drives[scsi_id][scsi_lun]; - return cdrom_read_capacity(id, cdb, buffer, len); + return cdrom_read_capacity(cdrom[id], cdb, buffer, len); case SCSI_ZIP: id = scsi_zip_drives[scsi_id][scsi_lun]; return zip_read_capacity(id, cdb, buffer, len); @@ -304,7 +324,7 @@ int scsi_device_cdb_length(uint8_t scsi_id, uint8_t scsi_lun) return cdrom[id]->cdb_len; case SCSI_ZIP: id = scsi_zip_drives[scsi_id][scsi_lun]; - return zip[id].cdb_len; + return zip[id]->cdb_len; default: return 12; } diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index 9d7267528..23d6cbc02 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -8,7 +8,7 @@ * * Definitions for the generic SCSI device command handler. * - * Version: @(#)scsi_device.h 1.0.6 2018/03/07 + * Version: @(#)scsi_device.h 1.0.7 2018/03/29 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -39,6 +39,7 @@ extern int64_t scsi_device_get_callback(uint8_t scsi_id, uint8_t scsi_lun); extern void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffer, uint8_t alloc_length); +extern void scsi_device_reset(uint8_t scsi_id, uint8_t scsi_lun); extern int scsi_device_read_capacity(uint8_t id, uint8_t lun, uint8_t *cdb, uint8_t *buffer, uint32_t *len); diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index b4121ed36..4a7c0cfe4 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -4,9 +4,9 @@ * PC systems and compatibles from 1981 through fairly recent * system designs based on the PCI bus. * - * Emulation of SCSI fixed and removable disks. + * Emulation of SCSI fixed disks. * - * Version: @(#)scsi_disk.c 1.0.18 2018/03/18 + * Version: @(#)scsi_disk.c 1.0.19 2018/03/26 * * Author: Miran Grca, * @@ -24,13 +24,13 @@ #include "../device.h" #include "../nvr.h" #include "../piix.h" -#include "../cdrom/cdrom.h" #include "../disk/hdd.h" #include "../disk/hdc.h" #include "../disk/hdc_ide.h" #include "../plat.h" #include "../ui.h" #include "scsi.h" +#include "../cdrom/cdrom.h" #include "scsi_disk.h" @@ -96,9 +96,8 @@ const uint8_t scsi_hd_command_flags[0x100] = { IMPLEMENTED | SCSI_ONLY, /* 0x16 */ IMPLEMENTED | SCSI_ONLY, /* 0x17 */ 0, 0, - IMPLEMENTED, - IMPLEMENTED | CHECK_READY, /* 0x1B */ - 0, + IMPLEMENTED, /* 0x1A */ + 0, 0, IMPLEMENTED, /* 0x1D */ IMPLEMENTED | CHECK_READY, /* 0x1E */ 0, 0, 0, 0, 0, 0, @@ -179,1523 +178,1112 @@ scsi_hd_log(const char *fmt, ...) /* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int scsi_hd_err_stat_to_scsi(uint8_t id) +int +scsi_hd_err_stat_to_scsi(uint8_t id) { - if (shdc[id].status & ERR_STAT) - { - return SCSI_STATUS_CHECK_CONDITION; - } - else - { - return SCSI_STATUS_OK; - } - + if (shdc[id].status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else return SCSI_STATUS_OK; } -int find_hdd_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +int +find_hdd_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) { - uint8_t i = 0; + uint8_t i = 0; - for (i = 0; i < HDD_NUM; i++) - { - if ((wcslen(hdd[i].fn) == 0) && (hdd[i].bus != HDD_BUS_SCSI_REMOVABLE)) - { - continue; - } - if (((hdd[i].spt == 0) || (hdd[i].hpc == 0) || (hdd[i].tracks == 0)) && (hdd[i].bus != HDD_BUS_SCSI_REMOVABLE)) - { - continue; - } - if (((hdd[i].bus == HDD_BUS_SCSI) || (hdd[i].bus == HDD_BUS_SCSI_REMOVABLE)) && (hdd[i].scsi_id == scsi_id) && (hdd[i].scsi_lun == scsi_lun)) - { - return i; + for (i = 0; i < HDD_NUM; i++) { + if (wcslen(hdd[i].fn) == 0) + continue; + if ((hdd[i].spt == 0) || (hdd[i].hpc == 0) || (hdd[i].tracks == 0)) + continue; + if ((hdd[i].bus == HDD_BUS_SCSI) && (hdd[i].scsi_id == scsi_id) && (hdd[i].scsi_lun == scsi_lun)) + return i; + } + return 0xff; +} + + +void +scsi_loadhd(int scsi_id, int scsi_lun, int id) +{ + if (! hdd_image_load(id)) + scsi_hard_disks[scsi_id][scsi_lun] = 0xff; +} + + +void +build_scsi_hd_map(void) +{ + uint8_t i = 0, j = 0; + + for (i = 0; i < 16; i++) + memset(scsi_hard_disks[i], 0xff, 8); + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) { + scsi_hard_disks[i][j] = find_hdd_for_scsi_id(i, j); + if (scsi_hard_disks[i][j] != 0xff) { + memset(&(shdc[scsi_hard_disks[i][j]]), 0, + sizeof(shdc[scsi_hard_disks[i][j]])); + if (wcslen(hdd[scsi_hard_disks[i][j]].fn) > 0) + scsi_loadhd(i, j, scsi_hard_disks[i][j]); } } - return 0xff; + } } -void scsi_disk_insert(uint8_t id) +void +scsi_hd_mode_sense_load(uint8_t id) { - shdc[id].unit_attention = (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? 1 : 0; + FILE *f; + wchar_t file_name[512]; + int i; + memset(&scsi_hd_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (scsi_hd_mode_sense_pages_default.pages[i][1] != 0) + memcpy(scsi_hd_mode_sense_pages_saved[id].pages[i], scsi_hd_mode_sense_pages_default.pages[i], scsi_hd_mode_sense_pages_default.pages[i][1] + 2); + } + swprintf(file_name, 512, L"scsi_hd_%02i_mode_sense.bin", id); + memset(file_name, 0, 512 * sizeof(wchar_t)); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) { + fread(scsi_hd_mode_sense_pages_saved[id].pages[0x30], 1, 0x18, f); + fclose(f); + } } -void scsi_loadhd(int scsi_id, int scsi_lun, int id) +void +scsi_hd_mode_sense_save(uint8_t id) { - if (! hdd_image_load(id)) { - if (hdd[id].bus != HDD_BUS_SCSI_REMOVABLE) - { - scsi_hard_disks[scsi_id][scsi_lun] = 0xff; - } - } - else - { - scsi_disk_insert(id); - } + FILE *f; + wchar_t file_name[512]; + memset(file_name, 0, 512 * sizeof(wchar_t)); + swprintf(file_name, 512, L"scsi_hd_%02i_mode_sense.bin", id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) { + fwrite(scsi_hd_mode_sense_pages_saved[id].pages[0x30], 1, 0x18, f); + fclose(f); + } } -void scsi_reloadhd(int id) +int +scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) { - int ret = 0; + int size = 0; - if (wcslen(hdd[id].prev_fn) == 0) - { - return; - } - else - { - wcscpy(hdd[id].fn, hdd[id].prev_fn); - memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn)); - } + size = hdd_image_get_last_sector(id); + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 2; /* 512 = 0x0200 */ + *len = 8; - ret = hdd_image_load(id); - - if (ret) - { - scsi_disk_insert(id); - } -} - - -void scsi_unloadhd(int scsi_id, int scsi_lun, int id) -{ - hdd_image_unload(id, 1); -} - - -void build_scsi_hd_map(void) -{ - uint8_t i = 0; - uint8_t j = 0; - - for (i = 0; i < 16; i++) - { - memset(scsi_hard_disks[i], 0xff, 8); - } - - for (i = 0; i < 16; i++) - { - for (j = 0; j < 8; j++) - { - scsi_hard_disks[i][j] = find_hdd_for_scsi_id(i, j); - if (scsi_hard_disks[i][j] != 0xff) - { - memset(&(shdc[scsi_hard_disks[i][j]]), 0, sizeof(shdc[scsi_hard_disks[i][j]])); - if (wcslen(hdd[scsi_hard_disks[i][j]].fn) > 0) - { - scsi_loadhd(i, j, scsi_hard_disks[i][j]); - } - } - } - } -} - -void scsi_hd_mode_sense_load(uint8_t id) -{ - FILE *f; - wchar_t file_name[512]; - int i; - memset(&scsi_hd_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); - for (i = 0; i < 0x3f; i++) { - if (scsi_hd_mode_sense_pages_default.pages[i][1] != 0) - memcpy(scsi_hd_mode_sense_pages_saved[id].pages[i], scsi_hd_mode_sense_pages_default.pages[i], scsi_hd_mode_sense_pages_default.pages[i][1] + 2); - } - swprintf(file_name, 512, L"scsi_hd_%02i_mode_sense.bin", id); - memset(file_name, 0, 512 * sizeof(wchar_t)); - f = plat_fopen(nvr_path(file_name), L"rb"); - if (f) { - fread(scsi_hd_mode_sense_pages_saved[id].pages[0x30], 1, 0x18, f); - fclose(f); - } -} - -void scsi_hd_mode_sense_save(uint8_t id) -{ - FILE *f; - wchar_t file_name[512]; - memset(file_name, 0, 512 * sizeof(wchar_t)); - swprintf(file_name, 512, L"scsi_hd_%02i_mode_sense.bin", id); - f = plat_fopen(nvr_path(file_name), L"wb"); - if (f) { - fwrite(scsi_hd_mode_sense_pages_saved[id].pages[0x30], 1, 0x18, f); - fclose(f); - } -} - -int scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - int size = 0; - - size = hdd_image_get_last_sector(id); - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 2; /* 512 = 0x0200 */ - *len = 8; - - return 1; + return 1; } /*SCSI Mode Sense 6/10*/ -uint8_t scsi_hd_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) +uint8_t +scsi_hd_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) { - switch (page_control) - { - case 0: - case 3: - return scsi_hd_mode_sense_pages_saved[id].pages[page][pos]; - break; - case 1: - return scsi_hd_mode_sense_pages_changeable.pages[page][pos]; - break; - case 2: - return scsi_hd_mode_sense_pages_default.pages[page][pos]; - break; - } + switch (page_control) { + case 0: + case 3: + return scsi_hd_mode_sense_pages_saved[id].pages[page][pos]; + break; + case 1: + return scsi_hd_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + return scsi_hd_mode_sense_pages_default.pages[page][pos]; + break; + } - return 0; + return 0; } -uint32_t scsi_hd_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) + +uint32_t +scsi_hd_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) { - uint8_t page_control = (type >> 6) & 3; + uint8_t msplen, page_control = (type >> 6) & 3; - int i = 0; - int j = 0; + int i = 0, j = 0; + int size = 0; - uint8_t msplen; - int size = 0; + type &= 0x3f; - type &= 0x3f; + size = hdd_image_get_last_sector(id); - size = hdd_image_get_last_sector(id); + if (block_descriptor_len) { + buf[pos++] = 1; /* Density code. */ + buf[pos++] = (size >> 16) & 0xff; /* Number of blocks (0 = all). */ + buf[pos++] = (size >> 8) & 0xff; + buf[pos++] = size & 0xff; + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ + buf[pos++] = 2; + buf[pos++] = 0; + } - if (block_descriptor_len) - { - buf[pos++] = 1; /* Density code. */ - buf[pos++] = (size >> 16) & 0xff; /* Number of blocks (0 = all). */ - buf[pos++] = (size >> 8) & 0xff; - buf[pos++] = size & 0xff; - buf[pos++] = 0; /* Reserved. */ - buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ - buf[pos++] = 2; - buf[pos++] = 0; - } - - for (i = 0; i < 0x40; i++) - { - if ((type == GPMODE_ALL_PAGES) || (type == i)) - { - if (scsi_hd_mode_sense_page_flags & (1LL << shdc[id].current_page_code)) - { - buf[pos++] = scsi_hd_mode_sense_read(id, page_control, i, 0); - msplen = scsi_hd_mode_sense_read(id, page_control, i, 1); - buf[pos++] = msplen; - scsi_hd_log("SCSI HDD %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); - for (j = 0; j < msplen; j++) - { - buf[pos++] = scsi_hd_mode_sense_read(id, page_control, i, 2 + j); - } - } + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (scsi_hd_mode_sense_page_flags & (1LL << shdc[id].current_page_code)) { + buf[pos++] = scsi_hd_mode_sense_read(id, page_control, i, 0); + msplen = scsi_hd_mode_sense_read(id, page_control, i, 1); + buf[pos++] = msplen; + scsi_hd_log("SCSI HDD %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); + for (j = 0; j < msplen; j++) + buf[pos++] = scsi_hd_mode_sense_read(id, page_control, i, 2 + j); } } + } - return pos; + return pos; } -void scsi_hd_update_request_length(uint8_t id, int len, int block_len) + +static void +scsi_hd_command_common(uint8_t id) { - /* For media access commands, make sure the requested DRQ length matches the block length. */ - switch (shdc[id].current_cdb[0]) - { - case 0x08: - case 0x0a: - case 0x28: - case 0x2a: - case 0xa8: - case 0xaa: - if (shdc[id].request_length < block_len) - { - shdc[id].request_length = block_len; - } - /* Make sure we respect the limit of how many blocks we can transfer at once. */ - if (shdc[id].requested_blocks > shdc[id].max_blocks_at_once) - { - shdc[id].requested_blocks = shdc[id].max_blocks_at_once; - } - shdc[id].block_total = (shdc[id].requested_blocks * block_len); - if (len > shdc[id].block_total) - { - len = shdc[id].block_total; - } - break; - default: - shdc[id].packet_len = len; - break; - } - /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ - if ((shdc[id].request_length & 1) && (shdc[id].request_length < len)) - { - shdc[id].request_length &= 0xfffe; - } - /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ - if (len <= shdc[id].request_length) - { - shdc[id].request_length = len; - } + shdc[id].status = BUSY_STAT; + shdc[id].phase = 1; + if (shdc[id].packet_status == CDROM_PHASE_COMPLETE) { + scsi_hd_callback(id); + shdc[id].callback = 0LL; + } else + shdc[id].callback = -1LL; /* Speed depends on SCSI controller */ +} + + +static void +scsi_hd_command_complete(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + scsi_hd_command_common(id); +} + + +static void +scsi_hd_command_read_dma(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_DATA_IN_DMA; + scsi_hd_command_common(id); +} + + +static void +scsi_hd_command_write_dma(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_DATA_OUT_DMA; + scsi_hd_command_common(id); +} + + +static void +scsi_hd_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +{ + scsi_hd_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, + shdc[id].current_cdb[0], len, block_len, alloc_len, direction, shdc[id].request_length); + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if (len == 0) + scsi_hd_command_complete(id); + else { + if (direction == 0) + scsi_hd_command_read_dma(id); + else + scsi_hd_command_write_dma(id); + } +} + + +static void +scsi_hd_sense_clear(int id, int command) +{ + scsi_hd_sense_key = scsi_hd_asc = scsi_hd_ascq = 0; +} + + +static void +scsi_hd_set_phase(uint8_t id, uint8_t phase) +{ + uint8_t scsi_id = hdd[id].scsi_id; + uint8_t scsi_lun = hdd[id].scsi_lun; + + if (hdd[id].bus != HDD_BUS_SCSI) return; + + SCSIDevices[scsi_id][scsi_lun].Phase = phase; } -static void scsi_hd_command_common(uint8_t id) +static void +scsi_hd_cmd_error(uint8_t id) { - shdc[id].status = BUSY_STAT; - shdc[id].phase = 1; - shdc[id].pos = 0; - if (shdc[id].packet_status == CDROM_PHASE_COMPLETE) { - scsi_hd_callback(id); - shdc[id].callback = 0LL; - } else - shdc[id].callback = -1LL; /* Speed depends on SCSI controller */ + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + shdc[id].error = ((scsi_hd_sense_key & 0xf) << 4) | ABRT_ERR; + shdc[id].status = READY_STAT | ERR_STAT; + shdc[id].phase = 3; + shdc[id].packet_status = 0x80; + shdc[id].callback = 50 * SCSI_TIME; + scsi_hd_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", id, scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq); } -void scsi_hd_command_complete(uint8_t id) +static void +scsi_hd_invalid_lun(uint8_t id) { - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - scsi_hd_command_common(id); + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_LUN; + scsi_hd_ascq = 0; + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_cmd_error(id); } -static void scsi_hd_command_read_dma(uint8_t id) +static void +scsi_hd_illegal_opcode(uint8_t id) { - shdc[id].packet_status = CDROM_PHASE_DATA_IN_DMA; - scsi_hd_command_common(id); - shdc[id].total_read = 0; + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_ILLEGAL_OPCODE; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); } -static void scsi_hd_command_write_dma(uint8_t id) +static void +scsi_hd_lba_out_of_range(uint8_t id) { - shdc[id].packet_status = CDROM_PHASE_DATA_OUT_DMA; - scsi_hd_command_common(id); + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_LBA_OUT_OF_RANGE; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); } -void scsi_hd_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +static void +scsi_hd_invalid_field(uint8_t id) { - scsi_hd_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, shdc[id].current_cdb[0], len, block_len, alloc_len, direction, shdc[id].request_length); - shdc[id].pos=0; - if (alloc_len >= 0) - { - if (alloc_len < len) - { - len = alloc_len; - } - } - if (len == 0) - { - scsi_hd_command_complete(id); - } - else - { - if (direction == 0) - { - scsi_hd_command_read_dma(id); - } - else - { - scsi_hd_command_write_dma(id); - } - } - - scsi_hd_log("SCSI HD %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", id, shdc[id].packet_status, shdc[id].request_length, shdc[id].packet_len, shdc[id].pos, shdc[id].phase); + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_FIELD_IN_CMD_PACKET; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); + shdc[id].status = 0x53; } -static void scsi_hd_sense_clear(int id, int command) +static void +scsi_hd_invalid_field_pl(uint8_t id) { - shdc[id].previous_command = command; - scsi_hd_sense_key = scsi_hd_asc = scsi_hd_ascq = 0; + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); + shdc[id].status = 0x53; } -static void scsi_hd_set_phase(uint8_t id, uint8_t phase) +static void +scsi_hd_data_phase_error(uint8_t id) { - uint8_t scsi_id = hdd[id].scsi_id; - uint8_t scsi_lun = hdd[id].scsi_lun; - - if ((hdd[id].bus != HDD_BUS_SCSI) && (hdd[id].bus != HDD_BUS_SCSI_REMOVABLE)) - return; - - SCSIDevices[scsi_id][scsi_lun].Phase = phase; + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_DATA_PHASE_ERROR; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); } -static void scsi_hd_cmd_error(uint8_t id) +static int +scsi_hd_pre_execution_check(uint8_t id, uint8_t *cdb) { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - shdc[id].error = ((scsi_hd_sense_key & 0xf) << 4) | ABRT_ERR; - if (shdc[id].unit_attention & 3) - { - shdc[id].error |= MCR_ERR; - } - shdc[id].status = READY_STAT | ERR_STAT; - shdc[id].phase = 3; - shdc[id].packet_status = 0x80; - shdc[id].callback = 50 * SCSI_TIME; - scsi_hd_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", id, scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq); + if (((shdc[id].request_length >> 5) & 7) != hdd[id].scsi_lun) { + scsi_hd_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", + id, ((shdc[id].request_length >> 5) & 7)); + scsi_hd_invalid_lun(id); + return 0; + } + + if (!(scsi_hd_command_flags[cdb[0]] & IMPLEMENTED)) { + scsi_hd_log("SCSI HD %i: Attempting to execute unknown command %02X\n", id, cdb[0]); + scsi_hd_illegal_opcode(id); + return 0; + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + scsi_hd_sense_clear(id, cdb[0]); + + scsi_hd_log("SCSI HD %i: Continuing with command\n", id); + + return 1; } -static void scsi_hd_unit_attention(uint8_t id) +static void +scsi_hd_seek(uint8_t id, uint32_t pos) { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - shdc[id].error = (SENSE_NOT_READY << 4) | ABRT_ERR; - if (shdc[id].unit_attention & 3) - { - shdc[id].error |= MCR_ERR; - } - shdc[id].status = READY_STAT | ERR_STAT; - shdc[id].phase = 3; - shdc[id].packet_status = 0x80; - shdc[id].callback = 50 * CDROM_TIME; - scsi_hd_log("SCSI HD %i: UNIT ATTENTION\n", id); + /* scsi_hd_log("SCSI HD %i: Seek %08X\n", id, pos); */ + hdd_image_seek(id, pos); } -static void scsi_hd_not_ready(uint8_t id) +static void +scsi_hd_rezero(uint8_t id) { - scsi_hd_sense_key = SENSE_NOT_READY; - scsi_hd_asc = ASC_MEDIUM_NOT_PRESENT; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); + if (id == 0xff) + return; + + shdc[id].sector_pos = shdc[id].sector_len = 0; + scsi_hd_seek(id, 0); } -static void scsi_hd_write_protected(uint8_t id) +void +scsi_hd_reset(uint8_t id) { - scsi_hd_sense_key = SENSE_UNIT_ATTENTION; - scsi_hd_asc = ASC_WRITE_PROTECTED; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); + scsi_hd_rezero(id); + shdc[id].status = 0; + shdc[id].callback = 0; + shdc[id].packet_status = 0xff; } -static void scsi_hd_invalid_lun(uint8_t id) -{ - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_INV_LUN; - scsi_hd_ascq = 0; - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - scsi_hd_cmd_error(id); -} - - -static void scsi_hd_illegal_opcode(uint8_t id) -{ - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_ILLEGAL_OPCODE; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); -} - - -void scsi_hd_lba_out_of_range(uint8_t id) -{ - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_LBA_OUT_OF_RANGE; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); -} - - -static void scsi_hd_invalid_field(uint8_t id) -{ - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_INV_FIELD_IN_CMD_PACKET; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); - shdc[id].status = 0x53; -} - - -static void scsi_hd_invalid_field_pl(uint8_t id) -{ - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); - shdc[id].status = 0x53; -} - - -static void scsi_hd_data_phase_error(uint8_t id) -{ - scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; - scsi_hd_asc = ASC_DATA_PHASE_ERROR; - scsi_hd_ascq = 0; - scsi_hd_cmd_error(id); -} - - -/*SCSI Sense Initialization*/ -void scsi_hd_sense_code_ok(uint8_t id) -{ - scsi_hd_sense_key = SENSE_NONE; - scsi_hd_asc = 0; - scsi_hd_ascq = 0; -} - - -int scsi_hd_pre_execution_check(uint8_t id, uint8_t *cdb) -{ - int ready = 1; - - if (((shdc[id].request_length >> 5) & 7) != hdd[id].scsi_lun) - { - scsi_hd_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((shdc[id].request_length >> 5) & 7)); - scsi_hd_invalid_lun(id); - return 0; - } - - if (!(scsi_hd_command_flags[cdb[0]] & IMPLEMENTED)) - { - scsi_hd_log("SCSI HD %i: Attempting to execute unknown command %02X\n", id, cdb[0]); - scsi_hd_illegal_opcode(id); - return 0; - } - - if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) - { - /* Removable disk, set ready state. */ - if (wcslen(hdd[id].fn) > 0) - { - ready = 1; - } - else - { - ready = 0; - } - } - else - { - /* Fixed disk, clear UNIT ATTENTION, just in case it might have been set when the disk was removable). */ - shdc[id].unit_attention = 0; - } - - if (!ready && shdc[id].unit_attention) - { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - shdc[id].unit_attention = 0; - } - - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ - if (shdc[id].unit_attention == 1) - { - /* Only increment the unit attention phase if the command can not pass through it. */ - if (!(scsi_hd_command_flags[cdb[0]] & ALLOW_UA)) - { - /* scsi_hd_log("SCSI HD %i: Unit attention now 2\n", id); */ - shdc[id].unit_attention = 2; - scsi_hd_log("SCSI HD %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); - scsi_hd_unit_attention(id); - return 0; - } - } - else if (shdc[id].unit_attention == 2) - { - if (cdb[0] != GPCMD_REQUEST_SENSE) - { - /* scsi_hd_log("SCSI HD %i: Unit attention now 0\n", id); */ - shdc[id].unit_attention = 0; - } - } - - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ - if (cdb[0] != GPCMD_REQUEST_SENSE) - { - scsi_hd_sense_clear(id, cdb[0]); - } - - /* Next it's time for NOT READY. */ - if ((scsi_hd_command_flags[cdb[0]] & CHECK_READY) && !ready) - { - scsi_hd_log("SCSI HD %i: Not ready (%02X)\n", id, cdb[0]); - scsi_hd_not_ready(id); - return 0; - } - - scsi_hd_log("SCSI HD %i: Continuing with command\n", id); - - return 1; -} - - -static void scsi_hd_seek(uint8_t id, uint32_t pos) -{ - /* scsi_hd_log("SCSI HD %i: Seek %08X\n", id, pos); */ - hdd_image_seek(id, pos); -} - - -static void scsi_hd_rezero(uint8_t id) -{ - if (id == 255) - { - return; - } - - shdc[id].sector_pos = shdc[id].sector_len = 0; - scsi_hd_seek(id, 0); -} - - -void scsi_hd_reset(uint8_t id) -{ - scsi_hd_rezero(id); - shdc[id].status = 0; - shdc[id].callback = 0; - shdc[id].packet_status = 0xff; -} - - -void scsi_hd_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) +void +scsi_hd_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) { - /*Will return 18 bytes of 0*/ - if (alloc_length != 0) - { - memset(buffer, 0, alloc_length); - if (!desc) - memcpy(buffer, shdc[id].sense, alloc_length); - else { - buffer[1] = scsi_hd_sense_key; - buffer[2] = scsi_hd_asc; - buffer[3] = scsi_hd_ascq; - } - } - else - { - return; + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + if (!desc) + memcpy(buffer, shdc[id].sense, alloc_length); + else { + buffer[1] = scsi_hd_sense_key; + buffer[2] = scsi_hd_asc; + buffer[3] = scsi_hd_ascq; } + } else + return; - buffer[0] = 0x70; + buffer[0] = 0x70; - if (shdc[id].unit_attention && (scsi_hd_sense_key == 0)) - { - buffer[desc ? 1 : 2]=SENSE_UNIT_ATTENTION; - buffer[desc ? 2 : 12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - buffer[desc ? 3 : 13]=0x00; - } + scsi_hd_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); - scsi_hd_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); - - if (buffer[desc ? 1: 2] == SENSE_UNIT_ATTENTION) - { - /* If the last remaining sense is unit attention, clear - that condition. */ - shdc[id].unit_attention = 0; - } - - /* Clear the sense stuff as per the spec. */ - scsi_hd_sense_clear(id, GPCMD_REQUEST_SENSE); + /* Clear the sense stuff as per the spec. */ + scsi_hd_sense_clear(id, GPCMD_REQUEST_SENSE); } -void scsi_hd_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) +void +scsi_hd_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) { - int ready = 1; + scsi_hd_request_sense(id, buffer, alloc_length, 0); +} - if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) - { - /* Removable disk, set ready state. */ - if (wcslen(hdd[id].fn) > 0) - { - ready = 1; + +void +scsi_hd_command(uint8_t id, uint8_t *cdb) +{ + uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + uint32_t len; + int max_len, pos = 0; + unsigned idx = 0; + unsigned size_idx, preamble_len; + uint32_t alloc_length, last_sector = 0; + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; + int block_desc = 0; + int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + + last_sector = hdd_image_get_last_sector(id); + + shdc[id].status &= ~ERR_STAT; + shdc[id].packet_len = 0; + + device_identify[6] = (id / 10) + 0x30; + device_identify[7] = (id % 10) + 0x30; + + device_identify_ex[6] = (id / 10) + 0x30; + device_identify_ex[7] = (id % 10) + 0x30; + device_identify_ex[10] = EMU_VERSION[0]; + device_identify_ex[12] = EMU_VERSION[2]; + device_identify_ex[13] = EMU_VERSION[3]; + + memcpy(shdc[id].current_cdb, cdb, 12); + + if (cdb[0] != 0) { + scsi_hd_log("SCSI HD %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X\n", + id, cdb[0], scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq); + scsi_hd_log("SCSI HD %i: Request length: %04X\n", id, shdc[id].request_length); + + scsi_hd_log("SCSI HD %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + shdc[id].sector_len = 0; + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (scsi_hd_pre_execution_check(id, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_SEND_DIAGNOSTIC: + if (!(cdb[1] & (1 << 2))) { + scsi_hd_invalid_field(id); + return; } + case GPCMD_SCSI_RESERVE: + case GPCMD_SCSI_RELEASE: + case GPCMD_TEST_UNIT_READY: + case GPCMD_FORMAT_UNIT: + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_command_complete(id); + break; + + case GPCMD_REZERO_UNIT: + shdc[id].sector_pos = shdc[id].sector_len = 0; + scsi_hd_seek(id, 0); + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + if ((*BufLen == -1) || (cdb[4] < *BufLen)) + *BufLen = cdb[4]; + + if (*BufLen < cdb[4]) + cdb[4] = *BufLen; + + len = (cdb[1] & 1) ? 8 : 18; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, len, len, cdb[4], 0); + break; + + case GPCMD_MECHANISM_STATUS: + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, 8, 8, len, 0); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + switch(cdb[0]) { + case GPCMD_READ_6: + shdc[id].sector_len = cdb[4]; + shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + break; + case GPCMD_READ_10: + shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; + shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + break; + case GPCMD_READ_12: + shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if ((shdc[id].sector_pos > last_sector) || + ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (*BufLen == 0)) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_log("SCSI HD %i: All done - callback set\n", id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; + break; + } + + max_len = shdc[id].sector_len; + shdc[id].requested_blocks = max_len; + + alloc_length = shdc[id].packet_len = max_len << 9; + + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + + if (shdc[id].requested_blocks > 1) + scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 0); else - { - ready = 0; - } - } - else - { - /* Fixed disk, clear UNIT ATTENTION, just in case it might have been set when the disk was removable). */ - shdc[id].unit_attention = 0; - } - - if (!ready && shdc[id].unit_attention) - { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - shdc[id].unit_attention = 0; - } - - /* Do *NOT* advance the unit attention phase. */ - - scsi_hd_request_sense(id, buffer, alloc_length, 0); -} - - -void scsi_hd_command(uint8_t id, uint8_t *cdb) -{ - /* uint8_t *hdbufferb = (uint8_t *) shdc[id].buffer; */ - uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; - uint32_t len; - int pos=0; - int max_len; - unsigned idx = 0; - unsigned size_idx; - unsigned preamble_len; - uint32_t alloc_length; - char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; - char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; - uint32_t last_sector = 0; - int block_desc = 0; - int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; - -#if 0 - int CdbLength; -#endif - last_sector = hdd_image_get_last_sector(id); - - shdc[id].status &= ~ERR_STAT; - - shdc[id].packet_len = 0; - shdc[id].request_pos = 0; - - device_identify[6] = (id / 10) + 0x30; - device_identify[7] = (id % 10) + 0x30; - - device_identify_ex[6] = (id / 10) + 0x30; - device_identify_ex[7] = (id % 10) + 0x30; - device_identify_ex[10] = EMU_VERSION[0]; - device_identify_ex[12] = EMU_VERSION[2]; - device_identify_ex[13] = EMU_VERSION[3]; - - if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) - { - device_identify[4] = 'R'; - - device_identify_ex[4] = 'R'; - } - - shdc[id].data_pos = 0; - - memcpy(shdc[id].current_cdb, cdb, 12); - - if (cdb[0] != 0) - { - scsi_hd_log("SCSI HD %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X\n", id, cdb[0], scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq); - scsi_hd_log("SCSI HD %i: Request length: %04X\n", id, shdc[id].request_length); - -#if 0 - for (CdbLength = 1; CdbLength < 12; CdbLength++) - { - scsi_hd_log("SCSI HD %i: CDB[%d] = %d\n", id, CdbLength, cdb[CdbLength]); - } -#endif - } - - shdc[id].sector_len = 0; - - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ - if (scsi_hd_pre_execution_check(id, cdb) == 0) - { + scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 0); return; - } - switch (cdb[0]) - { - case GPCMD_SEND_DIAGNOSTIC: - if (!(cdb[1] & (1 << 2))) { - scsi_hd_invalid_field(id); - return; - } - case GPCMD_SCSI_RESERVE: - case GPCMD_SCSI_RELEASE: - case GPCMD_TEST_UNIT_READY: - case GPCMD_FORMAT_UNIT: + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + if (!(cdb[1] & 2)) { scsi_hd_set_phase(id, SCSI_PHASE_STATUS); scsi_hd_command_complete(id); break; + } + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + switch(cdb[0]) + { + case GPCMD_VERIFY_6: + case GPCMD_WRITE_6: + shdc[id].sector_len = cdb[4]; + shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); + break; + case GPCMD_VERIFY_10: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; + shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); + break; + case GPCMD_VERIFY_12: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } - case GPCMD_REZERO_UNIT: - shdc[id].sector_pos = shdc[id].sector_len = 0; - scsi_hd_seek(id, 0); + if ((shdc[id].sector_pos > last_sector) || + ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (*BufLen == 0)) { scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_log("SCSI HD %i: All done - callback set\n", id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; break; + } - case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE - should forget about the not ready, and report unit attention straight away. */ - if ((*BufLen == -1) || (cdb[4] < *BufLen)) - { - *BufLen = cdb[4]; - } + max_len = shdc[id].sector_len; + shdc[id].requested_blocks = max_len; - if (*BufLen < cdb[4]) - { - cdb[4] = *BufLen; - } + alloc_length = shdc[id].packet_len = max_len << 9; - len = (cdb[1] & 1) ? 8 : 18; + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - scsi_hd_data_command_finish(id, len, len, cdb[4], 0); + scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); + + if (shdc[id].requested_blocks > 1) + scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); + else + scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); + return; + + case GPCMD_WRITE_SAME_10: + if ((cdb[1] & 6) == 6) { + scsi_hd_invalid_field(id); + return; + } + + shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; + shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); + + if ((shdc[id].sector_pos > last_sector) || + ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (*BufLen == 0)) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_log("SCSI HD %i: All done - callback set\n", id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; break; + } - case GPCMD_MECHANISM_STATUS: - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + max_len = 1; + shdc[id].requested_blocks = max_len; - if ((*BufLen == -1) || (len < *BufLen)) - { - *BufLen = len; - } + alloc_length = shdc[id].packet_len = max_len << 9; - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - scsi_hd_data_command_finish(id, 8, 8, len, 0); - break; + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - switch(cdb[0]) - { - case GPCMD_READ_6: - shdc[id].sector_len = cdb[4]; - shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - break; - case GPCMD_READ_10: - shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; - shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - break; - case GPCMD_READ_12: - shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - break; - } + scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); - if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) - { - scsi_hd_lba_out_of_range(id); - return; - } + if (shdc[id].requested_blocks > 1) + scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); + else + scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); + return; - if ((!shdc[id].sector_len) || (*BufLen == 0)) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - scsi_hd_log("SCSI HD %i: All done - callback set\n", id); - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].callback = 20 * SCSI_TIME; - break; - } + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - max_len = shdc[id].sector_len; - shdc[id].requested_blocks = max_len; + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - alloc_length = shdc[id].packet_len = max_len << 9; + if (cdb[0] == GPCMD_MODE_SENSE_6) + len = cdb[4]; + else + len = (cdb[8] | (cdb[7] << 8)); - if ((*BufLen == -1) || (alloc_length < *BufLen)) - { - *BufLen = alloc_length; - } + shdc[id].current_page_code = cdb[2] & 0x3F; - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + alloc_length = len; - if (shdc[id].requested_blocks > 1) - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 0); - } - else - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 0); - } - shdc[id].all_blocks_total = shdc[id].block_total; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); - return; - - case GPCMD_VERIFY_6: - case GPCMD_VERIFY_10: - case GPCMD_VERIFY_12: - if (!(cdb[1] & 2)) { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - scsi_hd_command_complete(id); - break; - } - case GPCMD_WRITE_6: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - if ((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) && hdd[id].wp) - { - scsi_hd_write_protected(id); - return; - } - - switch(cdb[0]) - { - case GPCMD_VERIFY_6: - case GPCMD_WRITE_6: - shdc[id].sector_len = cdb[4]; - shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); - break; - case GPCMD_VERIFY_10: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; - shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); - break; - case GPCMD_VERIFY_12: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - break; - } - - if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) - { - scsi_hd_lba_out_of_range(id); - return; - } - - if ((!shdc[id].sector_len) || (*BufLen == 0)) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - scsi_hd_log("SCSI HD %i: All done - callback set\n", id); - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].callback = 20 * SCSI_TIME; - break; - } - - max_len = shdc[id].sector_len; - shdc[id].requested_blocks = max_len; - - alloc_length = shdc[id].packet_len = max_len << 9; - - if ((*BufLen == -1) || (alloc_length < *BufLen)) - { - *BufLen = alloc_length; - } - - scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); - - if (shdc[id].requested_blocks > 1) - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); - } - else - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); - } - shdc[id].all_blocks_total = shdc[id].block_total; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); - return; - - case GPCMD_WRITE_SAME_10: - if ((cdb[1] & 6) == 6) - { - scsi_hd_invalid_field(id); - return; - } - - if ((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) && hdd[id].wp) - { - scsi_hd_write_protected(id); - return; - } - - shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; - shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); - - if ((shdc[id].sector_pos > last_sector) || ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) - { - scsi_hd_lba_out_of_range(id); - return; - } - - if ((!shdc[id].sector_len) || (*BufLen == 0)) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - scsi_hd_log("SCSI HD %i: All done - callback set\n", id); - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].callback = 20 * SCSI_TIME; - break; - } - - max_len = 1; - shdc[id].requested_blocks = max_len; - - alloc_length = shdc[id].packet_len = max_len << 9; - - if ((*BufLen == -1) || (alloc_length < *BufLen)) - { - *BufLen = alloc_length; - } - - scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); - - if (shdc[id].requested_blocks > 1) - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); - } - else - { - scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); - } - shdc[id].all_blocks_total = shdc[id].block_total; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - - block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - - if (cdb[0] == GPCMD_MODE_SENSE_6) - len = cdb[4]; - else - len = (cdb[8] | (cdb[7] << 8)); - - shdc[id].current_page_code = cdb[2] & 0x3F; - - alloc_length = len; - - shdc[id].temp_buffer = (uint8_t *) malloc(65536); - memset(shdc[id].temp_buffer, 0, 65536); - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = scsi_hd_mode_sense(id, shdc[id].temp_buffer, 4, cdb[2], block_desc); - if (len > alloc_length) - len = alloc_length; - shdc[id].temp_buffer[0] = len - 1; - shdc[id].temp_buffer[1] = 0; - if (block_desc) - shdc[id].temp_buffer[3] = 8; - } - else - { - len = scsi_hd_mode_sense(id, shdc[id].temp_buffer, 8, cdb[2], block_desc); - if (len > alloc_length) - len = alloc_length; - shdc[id].temp_buffer[0]=(len - 2) >> 8; - shdc[id].temp_buffer[1]=(len - 2) & 255; - shdc[id].temp_buffer[2] = 0; - if (block_desc) { - shdc[id].temp_buffer[6] = 0; - shdc[id].temp_buffer[7] = 8; - } - } + shdc[id].temp_buffer = (uint8_t *) malloc(65536); + memset(shdc[id].temp_buffer, 0, 65536); + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = scsi_hd_mode_sense(id, shdc[id].temp_buffer, 4, cdb[2], block_desc); if (len > alloc_length) len = alloc_length; - else if (len < alloc_length) - alloc_length = len; - - if ((*BufLen == -1) || (alloc_length < *BufLen)) - *BufLen = alloc_length; - - scsi_hd_log("SCSI HDD %i: Reading mode page: %02X...\n", id, cdb[2]); - - scsi_hd_data_command_finish(id, len, len, alloc_length, 0); - return; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); - - if (cdb[0] == GPCMD_MODE_SELECT_6) - len = cdb[4]; - else - len = (cdb[7] << 8) | cdb[8]; - - if ((*BufLen == -1) || (len < *BufLen)) - *BufLen = len; - - shdc[id].total_length = len; - shdc[id].do_page_save = cdb[1] & 1; - - shdc[id].current_page_pos = 0; - - scsi_hd_data_command_finish(id, len, len, len, 1); - return; - - case GPCMD_START_STOP_UNIT: - if (hdd[id].bus != HDD_BUS_SCSI_REMOVABLE) - { - scsi_hd_illegal_opcode(id); - break; + shdc[id].temp_buffer[0] = len - 1; + shdc[id].temp_buffer[1] = 0; + if (block_desc) + shdc[id].temp_buffer[3] = 8; + } else { + len = scsi_hd_mode_sense(id, shdc[id].temp_buffer, 8, cdb[2], block_desc); + if (len > alloc_length) + len = alloc_length; + shdc[id].temp_buffer[0]=(len - 2) >> 8; + shdc[id].temp_buffer[1]=(len - 2) & 255; + shdc[id].temp_buffer[2] = 0; + if (block_desc) { + shdc[id].temp_buffer[6] = 0; + shdc[id].temp_buffer[7] = 8; } + } - switch(cdb[4] & 3) - { - case 0: /* Stop the disc. */ - case 1: /* Start the disc and read the TOC. */ - break; - case 2: /* Eject the disc if possible. */ - removable_disk_eject(id); - break; - case 3: /* Load the disc (close tray). */ - removable_disk_reload(id); - break; - } + if (len > alloc_length) + len = alloc_length; + else if (len < alloc_length) + alloc_length = len; + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; + + scsi_hd_log("SCSI HDD %i: Reading mode page: %02X...\n", id, cdb[2]); + + scsi_hd_data_command_finish(id, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) + len = cdb[4]; + else + len = (cdb[7] << 8) | cdb[8]; + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + shdc[id].total_length = len; + shdc[id].do_page_save = cdb[1] & 1; + + scsi_hd_data_command_finish(id, len, len, len, 1); + return; + + case GPCMD_INQUIRY: + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + if ((!max_len) || (*BufLen == 0)) { scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - scsi_hd_command_complete(id); + /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; break; + } - case GPCMD_INQUIRY: - max_len = cdb[3]; - max_len <<= 8; - max_len |= cdb[4]; + shdc[id].temp_buffer = malloc(1024); - if ((!max_len) || (*BufLen == 0)) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].callback = 20 * SCSI_TIME; - break; - } - - shdc[id].temp_buffer = malloc(1024); + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; - if (cdb[1] & 1) - { - preamble_len = 4; - size_idx = 3; - - shdc[id].temp_buffer[idx++] = 05; - shdc[id].temp_buffer[idx++] = cdb[2]; - shdc[id].temp_buffer[idx++] = 0; + shdc[id].temp_buffer[idx++] = 05; + shdc[id].temp_buffer[idx++] = cdb[2]; + shdc[id].temp_buffer[idx++] = 0; - idx++; + idx++; - switch (cdb[2]) - { - case 0x00: - shdc[id].temp_buffer[idx++] = 0x00; - shdc[id].temp_buffer[idx++] = 0x83; - break; - case 0x83: - if (idx + 24 > max_len) - { - free(shdc[id].temp_buffer); - shdc[id].temp_buffer = NULL; - scsi_hd_data_phase_error(id); - return; - } - - shdc[id].temp_buffer[idx++] = 0x02; - shdc[id].temp_buffer[idx++] = 0x00; - shdc[id].temp_buffer[idx++] = 0x00; - shdc[id].temp_buffer[idx++] = 20; - ide_padstr8(shdc[id].temp_buffer + idx, 20, "53R141"); /* Serial */ - idx += 20; - - if (idx + 72 > cdb[4]) - { - goto atapi_out; - } - shdc[id].temp_buffer[idx++] = 0x02; - shdc[id].temp_buffer[idx++] = 0x01; - shdc[id].temp_buffer[idx++] = 0x00; - shdc[id].temp_buffer[idx++] = 68; - ide_padstr8(shdc[id].temp_buffer + idx, 8, EMU_NAME); /* Vendor */ - idx += 8; - ide_padstr8(shdc[id].temp_buffer + idx, 40, device_identify_ex); /* Product */ - idx += 40; - ide_padstr8(shdc[id].temp_buffer + idx, 20, "53R141"); /* Product */ - idx += 20; - break; - default: - scsi_hd_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + switch (cdb[2]) { + case 0x00: + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { free(shdc[id].temp_buffer); shdc[id].temp_buffer = NULL; - scsi_hd_invalid_field(id); + scsi_hd_data_phase_error(id); return; - } + } + + shdc[id].temp_buffer[idx++] = 0x02; + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 20; + ide_padstr8(shdc[id].temp_buffer + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + shdc[id].temp_buffer[idx++] = 0x02; + shdc[id].temp_buffer[idx++] = 0x01; + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 68; + ide_padstr8(shdc[id].temp_buffer + idx, 8, EMU_NAME); /* Vendor */ + idx += 8; + ide_padstr8(shdc[id].temp_buffer + idx, 40, device_identify_ex); /* Product */ + idx += 40; + ide_padstr8(shdc[id].temp_buffer + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + scsi_hd_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + free(shdc[id].temp_buffer); + shdc[id].temp_buffer = NULL; + scsi_hd_invalid_field(id); + return; } - else - { - preamble_len = 5; - size_idx = 4; + } else { + preamble_len = 5; + size_idx = 4; - memset(shdc[id].temp_buffer, 0, 8); - shdc[id].temp_buffer[0] = 0; /*SCSI HD*/ - if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) - { - shdc[id].temp_buffer[1] = 0x80; /*Removable*/ - } - else - { - shdc[id].temp_buffer[1] = 0; /*Fixed*/ - } - shdc[id].temp_buffer[2] = 0x02; /*SCSI-2 compliant*/ - shdc[id].temp_buffer[3] = 0x02; - shdc[id].temp_buffer[4] = 31; - shdc[id].temp_buffer[6] = 1; /* 16-bit transfers supported */ - shdc[id].temp_buffer[7] = 0x20; /* Wide bus supported */ + memset(shdc[id].temp_buffer, 0, 8); + shdc[id].temp_buffer[0] = 0; /*SCSI HD*/ + shdc[id].temp_buffer[1] = 0; /*Fixed*/ + shdc[id].temp_buffer[2] = 0x02; /*SCSI-2 compliant*/ + shdc[id].temp_buffer[3] = 0x02; + shdc[id].temp_buffer[4] = 31; + shdc[id].temp_buffer[6] = 1; /* 16-bit transfers supported */ + shdc[id].temp_buffer[7] = 0x20; /* Wide bus supported */ - ide_padstr8(shdc[id].temp_buffer + 8, 8, EMU_NAME); /* Vendor */ - ide_padstr8(shdc[id].temp_buffer + 16, 16, device_identify); /* Product */ - ide_padstr8(shdc[id].temp_buffer + 32, 4, EMU_VERSION); /* Revision */ - idx = 36; + ide_padstr8(shdc[id].temp_buffer + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(shdc[id].temp_buffer + 16, 16, device_identify); /* Product */ + ide_padstr8(shdc[id].temp_buffer + 32, 4, EMU_VERSION); /* Revision */ + idx = 36; - if (max_len == 96) { - shdc[id].temp_buffer[4] = 91; - idx = 96; - } + if (max_len == 96) { + shdc[id].temp_buffer[4] = 91; + idx = 96; } + } atapi_out: - shdc[id].temp_buffer[size_idx] = idx - preamble_len; - len=idx; + shdc[id].temp_buffer[size_idx] = idx - preamble_len; + len=idx; - scsi_hd_log("scsi_hd_command(): Inquiry (%08X, %08X)\n", hdbufferb, shdc[id].temp_buffer); - - if (len > max_len) - { - len = max_len; - } - - if ((*BufLen == -1) || (len < *BufLen)) - { - *BufLen = len; - } + scsi_hd_log("scsi_hd_command(): Inquiry (%08X, %08X)\n", hdbufferb, shdc[id].temp_buffer); + + if (len > max_len) + len = max_len; - if (len > *BufLen) - { - len = *BufLen; - } + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - scsi_hd_data_command_finish(id, len, len, max_len, 0); - break; + if (len > *BufLen) + len = *BufLen; - case GPCMD_PREVENT_REMOVAL: + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_command_complete(id); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + scsi_hd_seek(id, pos); + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_command_complete(id); + break; + + case GPCMD_READ_CDROM_CAPACITY: + shdc[id].temp_buffer = (uint8_t *) malloc(8); + + if (scsi_hd_read_capacity(id, shdc[id].current_cdb, shdc[id].temp_buffer, &len) == 0) { scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - scsi_hd_command_complete(id); - break; + return; + } - case GPCMD_SEEK_6: - case GPCMD_SEEK_10: - switch(cdb[0]) - { - case GPCMD_SEEK_6: - pos = (cdb[2] << 8) | cdb[3]; - break; - case GPCMD_SEEK_10: - pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; - break; - } - scsi_hd_seek(id, pos); - - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - scsi_hd_command_complete(id); - break; + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; - case GPCMD_READ_CDROM_CAPACITY: - shdc[id].temp_buffer = (uint8_t *) malloc(8); + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, len, len, len, 0); + break; - if (scsi_hd_read_capacity(id, shdc[id].current_cdb, shdc[id].temp_buffer, &len) == 0) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - return; - } - - if ((*BufLen == -1) || (len < *BufLen)) - { - *BufLen = len; - } + default: + scsi_hd_illegal_opcode(id); + break; + } - scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); - scsi_hd_data_command_finish(id, len, len, len, 0); - break; - - default: - scsi_hd_illegal_opcode(id); - break; - } - - /* scsi_hd_log("SCSI HD %i: Phase: %02X, request length: %i\n", shdc[id].phase, shdc[id].request_length); */ + /* scsi_hd_log("SCSI HD %i: Phase: %02X, request length: %i\n", shdc[id].phase, shdc[id].request_length); */ } -void scsi_hd_phase_data_in(uint8_t id) +static void +scsi_hd_phase_data_in(uint8_t id) { - uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; - int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; - - if (!*BufLen) - { - scsi_hd_log("scsi_hd_phase_data_in(): Buffer length is 0\n"); - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - - return; - } - - switch (shdc[id].current_cdb[0]) - { - case GPCMD_REQUEST_SENSE: - scsi_hd_log("SCSI HDD %i: %08X, %08X\n", id, hdbufferb, *BufLen); - scsi_hd_request_sense(id, hdbufferb, *BufLen, shdc[id].current_cdb[1] & 1); - break; - case GPCMD_MECHANISM_STATUS: - memset(hdbufferb, 0, *BufLen); - hdbufferb[5] = 1; - break; - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - if ((shdc[id].requested_blocks > 0) && (*BufLen > 0)) - { - if (shdc[id].packet_len > *BufLen) - { - hdd_image_read(id, shdc[id].sector_pos, *BufLen >> 9, hdbufferb); - } - else - { - hdd_image_read(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); - } - } - break; - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - case GPCMD_INQUIRY: - case GPCMD_READ_CDROM_CAPACITY: - scsi_hd_log("scsi_hd_phase_data_in(): Filling buffer (%08X, %08X)\n", hdbufferb, shdc[id].temp_buffer); - memcpy(hdbufferb, shdc[id].temp_buffer, *BufLen); - free(shdc[id].temp_buffer); - shdc[id].temp_buffer = NULL; - scsi_hd_log("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - hdbufferb[0], hdbufferb[1], hdbufferb[2], hdbufferb[3], hdbufferb[4], hdbufferb[5], hdbufferb[6], hdbufferb[7], - hdbufferb[8], hdbufferb[9], hdbufferb[10], hdbufferb[11], hdbufferb[12], hdbufferb[13], hdbufferb[14], hdbufferb[15]); - break; - default: - fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); - break; - } + uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + if (!*BufLen) { + scsi_hd_log("scsi_hd_phase_data_in(): Buffer length is 0\n"); scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + + return; + } + + switch (shdc[id].current_cdb[0]) { + case GPCMD_REQUEST_SENSE: + scsi_hd_log("SCSI HDD %i: %08X, %08X\n", id, hdbufferb, *BufLen); + scsi_hd_request_sense(id, hdbufferb, *BufLen, shdc[id].current_cdb[1] & 1); + break; + case GPCMD_MECHANISM_STATUS: + memset(hdbufferb, 0, *BufLen); + hdbufferb[5] = 1; + break; + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + if ((shdc[id].requested_blocks > 0) && (*BufLen > 0)) { + if (shdc[id].packet_len > *BufLen) + hdd_image_read(id, shdc[id].sector_pos, *BufLen >> 9, hdbufferb); + else + hdd_image_read(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); + } + break; + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + case GPCMD_INQUIRY: + case GPCMD_READ_CDROM_CAPACITY: + scsi_hd_log("scsi_hd_phase_data_in(): Filling buffer (%08X, %08X)\n", hdbufferb, shdc[id].temp_buffer); + memcpy(hdbufferb, shdc[id].temp_buffer, *BufLen); + free(shdc[id].temp_buffer); + shdc[id].temp_buffer = NULL; + scsi_hd_log("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + hdbufferb[0], hdbufferb[1], hdbufferb[2], hdbufferb[3], hdbufferb[4], hdbufferb[5], hdbufferb[6], hdbufferb[7], + hdbufferb[8], hdbufferb[9], hdbufferb[10], hdbufferb[11], hdbufferb[12], hdbufferb[13], hdbufferb[14], hdbufferb[15]); + break; + default: + fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); + break; + } + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); } -void scsi_hd_phase_data_out(uint8_t id) + +static void +scsi_hd_phase_data_out(uint8_t id) { - uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + int i; + int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + uint32_t last_sector = hdd_image_get_last_sector(id); + uint32_t c, h, s, last_to_write = 0; + uint16_t block_desc_len, pos; + uint8_t hdr_len, val, old_val, ch, error = 0; + uint8_t page, page_len; - int i; + if (!*BufLen) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + return; + } - uint32_t last_sector = hdd_image_get_last_sector(id); - uint32_t last_to_write = 0; - - uint32_t c, h, s; - - uint16_t block_desc_len; - uint16_t pos; - - uint8_t error = 0; - uint8_t page, page_len; - - uint8_t hdr_len, val, old_val, ch; - - if (!*BufLen) - { - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - - return; - } - - switch (shdc[id].current_cdb[0]) - { - case GPCMD_VERIFY_6: - case GPCMD_VERIFY_10: - case GPCMD_VERIFY_12: - break; - case GPCMD_WRITE_6: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - if ((shdc[id].requested_blocks > 0) && (*BufLen > 0)) - { - if (shdc[id].packet_len > *BufLen) - { - hdd_image_write(id, shdc[id].sector_pos, *BufLen >> 9, hdbufferb); - } - else - { - hdd_image_write(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); - } - } - break; - case GPCMD_WRITE_SAME_10: - if (!shdc[id].current_cdb[7] && !shdc[id].current_cdb[8]) - last_to_write = last_sector; + switch (shdc[id].current_cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + break; + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + if ((shdc[id].requested_blocks > 0) && (*BufLen > 0)) { + if (shdc[id].packet_len > *BufLen) + hdd_image_write(id, shdc[id].sector_pos, *BufLen >> 9, hdbufferb); else - last_to_write = shdc[id].sector_pos + shdc[id].sector_len - 1; + hdd_image_write(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); + } + break; + case GPCMD_WRITE_SAME_10: + if (!shdc[id].current_cdb[7] && !shdc[id].current_cdb[8]) + last_to_write = last_sector; + else + last_to_write = shdc[id].sector_pos + shdc[id].sector_len - 1; - for (i = shdc[id].sector_pos; i <= last_to_write; i++) { - if (shdc[id].current_cdb[1] & 2) { - hdbufferb[0] = (i >> 24) & 0xff; - hdbufferb[1] = (i >> 16) & 0xff; - hdbufferb[2] = (i >> 8) & 0xff; - hdbufferb[3] = i & 0xff; - } else if (shdc[id].current_cdb[1] & 4) { - s = (i % hdd[id].spt); - h = ((i - s) / hdd[id].spt) % hdd[id].hpc; - c = ((i - s) / hdd[id].spt) / hdd[id].hpc; - hdbufferb[0] = (c >> 16) & 0xff; - hdbufferb[1] = (c >> 8) & 0xff; - hdbufferb[2] = c & 0xff; - hdbufferb[3] = h & 0xff; - hdbufferb[4] = (s >> 24) & 0xff; - hdbufferb[5] = (s >> 16) & 0xff; - hdbufferb[6] = (s >> 8) & 0xff; - hdbufferb[7] = s & 0xff; - } - hdd_image_write(id, i, 1, hdbufferb); + for (i = shdc[id].sector_pos; i <= last_to_write; i++) { + if (shdc[id].current_cdb[1] & 2) { + hdbufferb[0] = (i >> 24) & 0xff; + hdbufferb[1] = (i >> 16) & 0xff; + hdbufferb[2] = (i >> 8) & 0xff; + hdbufferb[3] = i & 0xff; + } else if (shdc[id].current_cdb[1] & 4) { + s = (i % hdd[id].spt); + h = ((i - s) / hdd[id].spt) % hdd[id].hpc; + c = ((i - s) / hdd[id].spt) / hdd[id].hpc; + hdbufferb[0] = (c >> 16) & 0xff; + hdbufferb[1] = (c >> 8) & 0xff; + hdbufferb[2] = c & 0xff; + hdbufferb[3] = h & 0xff; + hdbufferb[4] = (s >> 24) & 0xff; + hdbufferb[5] = (s >> 16) & 0xff; + hdbufferb[6] = (s >> 8) & 0xff; + hdbufferb[7] = s & 0xff; } - break; - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - if (shdc[id].current_cdb[0] == GPCMD_MODE_SELECT_10) - hdr_len = 8; - else - hdr_len = 4; + hdd_image_write(id, i, 1, hdbufferb); + } + break; + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (shdc[id].current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; - if (shdc[id].current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = hdbufferb[2]; - block_desc_len <<= 8; - block_desc_len |= hdbufferb[3]; - } else { - block_desc_len = hdbufferb[6]; - block_desc_len <<= 8; - block_desc_len |= hdbufferb[7]; - } + if (shdc[id].current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = hdbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= hdbufferb[3]; + } else { + block_desc_len = hdbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= hdbufferb[7]; + } - pos = hdr_len + block_desc_len; + pos = hdr_len + block_desc_len; - while(1) { - page = hdbufferb[pos] & 0x3F; - page_len = hdbufferb[pos + 1]; + while(1) { + page = hdbufferb[pos] & 0x3F; + page_len = hdbufferb[pos + 1]; - pos += 2; + pos += 2; - if (!(scsi_hd_mode_sense_page_flags & (1LL << ((uint64_t) page)))) - error |= 1; - else { - for (i = 0; i < page_len; i++) { - ch = scsi_hd_mode_sense_pages_changeable.pages[page][i + 2]; - val = hdbufferb[pos + i]; - old_val = scsi_hd_mode_sense_pages_saved[id].pages[page][i + 2]; - if (val != old_val) { - if (ch) - scsi_hd_mode_sense_pages_saved[id].pages[page][i + 2] = val; - else - error |= 1; - } + if (!(scsi_hd_mode_sense_page_flags & (1LL << ((uint64_t) page)))) + error |= 1; + else { + for (i = 0; i < page_len; i++) { + ch = scsi_hd_mode_sense_pages_changeable.pages[page][i + 2]; + val = hdbufferb[pos + i]; + old_val = scsi_hd_mode_sense_pages_saved[id].pages[page][i + 2]; + if (val != old_val) { + if (ch) + scsi_hd_mode_sense_pages_saved[id].pages[page][i + 2] = val; + else + error |= 1; } } - - pos += page_len; - - val = scsi_hd_mode_sense_pages_default.pages[page][0] & 0x80; - if (shdc[id].do_page_save && val) - scsi_hd_mode_sense_save(id); - - if (pos >= shdc[id].total_length) - break; } - if (error) - scsi_hd_invalid_field_pl(id); - break; - default: - fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); - break; - } + pos += page_len; - scsi_hd_set_phase(id, SCSI_PHASE_STATUS); - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); + val = scsi_hd_mode_sense_pages_default.pages[page][0] & 0x80; + if (shdc[id].do_page_save && val) + scsi_hd_mode_sense_save(id); + + if (pos >= shdc[id].total_length) + break; + } + + if (error) + scsi_hd_invalid_field_pl(id); + break; + default: + fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); + break; + } + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); } + /* If the result is 1, issue an IRQ, otherwise not. */ -void scsi_hd_callback(uint8_t id) +void +scsi_hd_callback(uint8_t id) { - switch(shdc[id].packet_status) - { - case CDROM_PHASE_IDLE: - scsi_hd_log("SCSI HD %i: PHASE_IDLE\n", id); - shdc[id].pos=0; - shdc[id].phase = 1; - shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); - return; - case CDROM_PHASE_COMPLETE: - scsi_hd_log("SCSI HD %i: PHASE_COMPLETE\n", id); - shdc[id].status = READY_STAT; - shdc[id].phase = 3; - shdc[id].packet_status = 0xFF; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - return; - case CDROM_PHASE_DATA_OUT: - scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT\n", id); - shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); - shdc[id].phase = 0; - return; - case CDROM_PHASE_DATA_OUT_DMA: - scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", id); - scsi_hd_phase_data_out(id); - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].status = READY_STAT; - shdc[id].phase = 3; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - return; - case CDROM_PHASE_DATA_IN: - scsi_hd_log("SCSI HD %i: PHASE_DATA_IN\n", id); - shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); - shdc[id].phase = 2; - return; - case CDROM_PHASE_DATA_IN_DMA: - scsi_hd_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", id); - scsi_hd_phase_data_in(id); - shdc[id].packet_status = CDROM_PHASE_COMPLETE; - shdc[id].status = READY_STAT; - shdc[id].phase = 3; - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - return; - case CDROM_PHASE_ERROR: - scsi_hd_log("SCSI HD %i: PHASE_ERROR\n", id); - shdc[id].status = READY_STAT | ERR_STAT; - shdc[id].phase = 3; - return; - } + switch(shdc[id].packet_status) { + case CDROM_PHASE_IDLE: + scsi_hd_log("SCSI HD %i: PHASE_IDLE\n", id); + shdc[id].phase = 1; + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + return; + case CDROM_PHASE_COMPLETE: + scsi_hd_log("SCSI HD %i: PHASE_COMPLETE\n", id); + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + shdc[id].packet_status = 0xFF; + return; + case CDROM_PHASE_DATA_OUT: + scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT\n", id); + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + shdc[id].phase = 0; + return; + case CDROM_PHASE_DATA_OUT_DMA: + scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", id); + scsi_hd_phase_data_out(id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + return; + case CDROM_PHASE_DATA_IN: + scsi_hd_log("SCSI HD %i: PHASE_DATA_IN\n", id); + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + shdc[id].phase = 2; + return; + case CDROM_PHASE_DATA_IN_DMA: + scsi_hd_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", id); + scsi_hd_phase_data_in(id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + return; + case CDROM_PHASE_ERROR: + scsi_hd_log("SCSI HD %i: PHASE_ERROR\n", id); + shdc[id].status = READY_STAT | ERR_STAT; + shdc[id].phase = 3; + return; + } } diff --git a/src/scsi/scsi_disk.h b/src/scsi/scsi_disk.h index 5a1a48c4f..f41906d46 100644 --- a/src/scsi/scsi_disk.h +++ b/src/scsi/scsi_disk.h @@ -6,54 +6,31 @@ * * Emulation of SCSI fixed and removable disks. * - * Version: @(#)scsi_disk.h 1.0.3 2017/10/14 + * Version: @(#)scsi_disk.h 1.0.4 2018/04/24 * * Author: Miran Grca, - * Copyright 2017 Miran Grca. + * Copyright 2017,2018 Miran Grca. */ typedef struct { /* Stuff for SCSI hard disks. */ - uint8_t cdb[16]; - uint8_t current_cdb[16]; - uint8_t max_cdb_len; - int requested_blocks; - int max_blocks_at_once; + uint8_t status, phase, + error, + current_cdb[16], + sense[256]; + uint16_t request_length; - int block_total; - int all_blocks_total; - uint32_t packet_len; - int packet_status; - uint8_t status; - uint8_t phase; - uint32_t pos; - int callback; - int total_read; - int unit_attention; - uint8_t sense[256]; - uint8_t previous_command; - uint8_t error; - uint32_t sector_pos; - uint32_t sector_len; - uint32_t seek_pos; - int data_pos; - int old_len; - int request_pos; - uint8_t hd_cdb[16]; + + int requested_blocks, block_total, + packet_status, callback, + block_descriptor_len, + total_length, do_page_save; + + uint32_t sector_pos, sector_len, + packet_len; uint64_t current_page_code; - int current_page_len; - - int current_page_pos; - - int mode_select_phase; - - int total_length; - int written_length; - - int do_page_save; - int block_descriptor_len; uint8_t *temp_buffer; } scsi_hard_disk_t; @@ -63,9 +40,6 @@ extern scsi_hard_disk_t shdc[HDD_NUM]; extern FILE *shdf[HDD_NUM]; -extern void scsi_disk_insert(uint8_t id); extern void scsi_loadhd(int scsi_id, int scsi_lun, int id); -extern void scsi_reloadhd(int id); -extern void scsi_unloadhd(int scsi_id, int scsi_lun, int id); int scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len); diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index fd88997c4..507224c2b 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -9,7 +9,7 @@ * Implementation of the NCR 5380 series of SCSI Host Adapters * made by NCR. These controllers were designed for the ISA bus. * - * Version: @(#)scsi_ncr5380.c 1.0.12 2018/03/18 + * Version: @(#)scsi_ncr5380.c 1.0.13 2018/04/11 * * Authors: Sarah Walker, * TheCollector1995, @@ -34,8 +34,8 @@ #include "../mca.h" #include "../mem.h" #include "../rom.h" -#include "../nvr.h" #include "../device.h" +#include "../nvr.h" #include "../timer.h" #include "../plat.h" #include "scsi.h" diff --git a/src/scsi/scsi_ncr53c810.c b/src/scsi/scsi_ncr53c810.c index 0dcb1fced..2135f0820 100644 --- a/src/scsi/scsi_ncr53c810.c +++ b/src/scsi/scsi_ncr53c810.c @@ -10,7 +10,7 @@ * NCR and later Symbios and LSI. This controller was designed * for the PCI bus. * - * Version: @(#)scsi_ncr53c810.c 1.0.10 2018/03/18 + * Version: @(#)scsi_ncr53c810.c 1.0.11 2018/03/28 * * Authors: Paul Brook (QEMU) * Artyom Tarasenko (QEMU) @@ -35,8 +35,8 @@ #include "../mem.h" #include "../rom.h" #include "../pci.h" -#include "../nvr.h" #include "../device.h" +#include "../nvr.h" #include "../timer.h" #include "../plat.h" #include "scsi.h" @@ -329,6 +329,8 @@ ncr53c810_irq_on_rsl(ncr53c810_t *dev) static void ncr53c810_soft_reset(ncr53c810_t *dev) { + int i, j; + ncr53c810_log("LSI Reset\n"); dev->timer_period = dev->timer_enabled = 0; @@ -383,13 +385,18 @@ ncr53c810_soft_reset(ncr53c810_t *dev) dev->last_level = 0; dev->gpreg0 = 0; dev->sstop = 1; + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) + scsi_device_reset(i, j); + } } static void ncr53c810_read(ncr53c810_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) { - int i = 0; + uint32_t i = 0; ncr53c810_log("ncr53c810_read(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); @@ -407,7 +414,7 @@ ncr53c810_read(ncr53c810_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) static void ncr53c810_write(ncr53c810_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) { - int i = 0; + uint32_t i = 0; ncr53c810_log("ncr53c810_write(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); @@ -582,13 +589,14 @@ ncr53c810_command_complete(void *priv, uint32_t status) static void ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) { - uint32_t addr, count, tdbc; + uint32_t addr, tdbc; + int count; scsi_device_t *sd; sd = &SCSIDevices[id][dev->current_lun]; - if ((((id) == -1) && !scsi_device_present(id, dev->current_lun))) { + if ((!scsi_device_present(id, dev->current_lun))) { ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command); return; } @@ -673,7 +681,7 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) dev->command_complete = 0; sd = &SCSIDevices[id][dev->current_lun]; - if (((id == -1) || !scsi_device_present(id, dev->current_lun))) { + if (!scsi_device_present(id, dev->current_lun)) { ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]); ncr53c810_bad_selection(dev, id); return 0; @@ -747,7 +755,7 @@ ncr53c810_do_status(ncr53c810_t *dev) static void ncr53c810_do_msgin(ncr53c810_t *dev) { - int len; + uint32_t len; ncr53c810_log("Message in len=%d/%d\n", dev->dbc, dev->msg_len); dev->sfbr = dev->msg[0]; len = dev->msg_len; @@ -1067,7 +1075,7 @@ again: } dev->sstat0 |= NCR_SSTAT0_WOA; dev->scntl1 &= ~NCR_SCNTL1_IARB; - if (((id == -1) || !scsi_device_present(id, 0))) { + if (!scsi_device_present(id, 0)) { ncr53c810_bad_selection(dev, id); break; } diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c index 10f27249f..13f8e37f4 100644 --- a/src/scsi/scsi_x54x.c +++ b/src/scsi/scsi_x54x.c @@ -11,7 +11,7 @@ * series of SCSI Host Adapters made by Mylex. * These controllers were designed for various buses. * - * Version: @(#)scsi_x54x.c 1.0.20 2018/03/18 + * Version: @(#)scsi_x54x.c 1.0.21 2018/03/28 * * Authors: TheCollector1995, * Miran Grca, @@ -36,8 +36,8 @@ #include "../mca.h" #include "../mem.h" #include "../rom.h" -#include "../nvr.h" #include "../device.h" +#include "../nvr.h" #include "../timer.h" #include "../plat.h" #include "../cpu/cpu.h" @@ -720,8 +720,7 @@ x54x_get_length(Req_t *req, int Is24bit) uint32_t DataPointer, DataLength; uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); SGE32 SGBuffer; - uint32_t DataToTransfer = 0; - int i = 0; + uint32_t DataToTransfer = 0, i = 0; if (Is24bit) { DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); @@ -793,8 +792,7 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) { uint32_t DataPointer, DataLength; uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - uint32_t Address; - int i = 0; + uint32_t Address, i; int32_t BufLen = SCSIDevices[req->TargetID][req->LUN].BufferLength; uint8_t read_from_host = (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))); uint8_t write_to_host = (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))); @@ -823,7 +821,7 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) x54x_rd_sge(Is24bit, DataPointer + i, &SGBuffer); Address = SGBuffer.SegmentPointer; - DataToTransfer = MIN(SGBuffer.Segment, BufLen); + DataToTransfer = MIN((int) SGBuffer.Segment, BufLen); if (read_from_host && DataToTransfer) { x54x_log("Reading S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); @@ -851,9 +849,9 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) if ((DataLength > 0) && (BufLen > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { if (read_from_host) - DMAPageRead(Address, SCSIDevices[req->TargetID][req->LUN].CmdBuffer, MIN(BufLen, DataLength)); + DMAPageRead(Address, SCSIDevices[req->TargetID][req->LUN].CmdBuffer, MIN(BufLen, (int) DataLength)); else if (write_to_host) - DMAPageWrite(Address, SCSIDevices[req->TargetID][req->LUN].CmdBuffer, MIN(BufLen, DataLength)); + DMAPageWrite(Address, SCSIDevices[req->TargetID][req->LUN].CmdBuffer, MIN(BufLen, (int) DataLength)); } } } @@ -1061,7 +1059,6 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) { Req_t *req = &dev->Req; uint8_t id, lun; - uint8_t max_id = SCSI_ID_MAX-1; /* Fetch data from the Command Control Block. */ DMAPageRead(CCBPointer, (uint8_t *)&req->CmdBlock, sizeof(CCB32)); @@ -1074,7 +1071,7 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) id = req->TargetID; lun = req->LUN; - if ((id > max_id) || (lun > 7)) { + if ((id > dev->max_id) || (lun > 7)) { x54x_log("SCSI Target ID %i or LUN %i is not valid\n",id,lun); x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, MBI_ERROR); @@ -1110,12 +1107,14 @@ x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) } if (req->CmdBlock.common.Opcode == 0x81) { x54x_log("Bus reset opcode\n"); + scsi_device_reset(id, lun); x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); x54x_notify(dev); return; } + if (req->CmdBlock.common.ControlByte > 0x03) { x54x_log("Invalid control byte: %02X\n", req->CmdBlock.common.ControlByte); @@ -1276,7 +1275,12 @@ x54x_cmd_callback(void *priv) double period; x54x_t *dev = (x54x_t *) x54x_dev; - if ((dev->Status & STAT_INIT) || (!dev->MailboxInit && !dev->BIOSMailboxInit) || (!dev->MailboxReq && !dev->BIOSMailboxReq)) { + int mailboxes_present, bios_mailboxes_present; + + mailboxes_present = (!(dev->Status & STAT_INIT) && dev->MailboxInit && dev->MailboxReq); + bios_mailboxes_present = (dev->ven_callback && dev->BIOSMailboxInit && dev->BIOSMailboxReq); + + if (!mailboxes_present && !bios_mailboxes_present) { /* If we did not get anything, do nothing and wait 10 us. */ dev->timer_period = 10LL * TIMER_USEC; return; @@ -1284,11 +1288,21 @@ x54x_cmd_callback(void *priv) dev->temp_period = dev->media_period = 0LL; - if (!(x54x_dev->Status & STAT_INIT) && x54x_dev->MailboxInit && dev->MailboxReq) - x54x_do_mail(dev); - - if (dev->ven_callback) + if (!mailboxes_present) { + /* Do only BIOS mailboxes. */ dev->ven_callback(dev); + } else if (!bios_mailboxes_present) { + /* Do only normal mailboxes. */ + x54x_do_mail(dev); + } else { + /* Do both kinds of mailboxes. */ + if (dev->callback_phase) + dev->ven_callback(dev); + else + x54x_do_mail(dev); + + dev->callback_phase = (dev->callback_phase + 1) & 0x01; + } period = (1000000.0 / x54x_dev->ha_bps) * ((double) TIMER_USEC) * ((double) dev->temp_period); dev->timer_period = dev->media_period + ((int64_t) period) + (40LL * TIMER_USEC); @@ -1319,7 +1333,10 @@ x54x_in(uint16_t port, void *priv) break; case 2: - ret = dev->Interrupt; + if (dev->int_geom_writable) + ret = dev->Interrupt; + else + ret = dev->Interrupt & ~0x70; break; case 3: @@ -1406,11 +1423,14 @@ x54x_reset_poll(void *priv) static void x54x_reset(x54x_t *dev) { + int i, j; + clear_irq(dev); if (dev->int_geom_writable) dev->Geometry = 0x80; else dev->Geometry = 0x00; + dev->callback_phase = 0; dev->Command = 0xFF; dev->CmdParam = 0; dev->CmdParamLeft = 0; @@ -1422,9 +1442,14 @@ x54x_reset(x54x_t *dev) dev->MailboxCount = 0; dev->MailboxOutPosCur = 0; - if (dev->ven_reset) { - dev->ven_reset(dev); + /* Reset all devices on controller reset. */ + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) + scsi_device_reset(i, j); } + + if (dev->ven_reset) + dev->ven_reset(dev); } @@ -1476,6 +1501,14 @@ x54x_out(uint16_t port, uint8_t val, void *priv) break; } + if (val & CTRL_SCRST) { + /* Reset all devices on SCSI bus reset. */ + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) + scsi_device_reset(i, j); + } + } + if (val & CTRL_IRST) { clear_irq(dev); x54x_log("Interrupt reset: "); @@ -1643,7 +1676,7 @@ x54x_out(uint16_t port, uint8_t val, void *priv) if (dev->ven_get_host_id) host_id = dev->ven_get_host_id(dev); - for (i=0; iDataBuf[i] = 0x00; /* Skip the HA .. */ @@ -1902,6 +1935,7 @@ x54x_init(const device_t *info) dev->type = info->local; dev->bus = info->flags; + dev->callback_phase = 0; timer_add(x54x_reset_poll, &dev->ResetCB, &dev->ResetCB, dev); dev->timer_period = 10LL * TIMER_USEC; diff --git a/src/scsi/scsi_x54x.h b/src/scsi/scsi_x54x.h index a35932169..d2e7cb60b 100644 --- a/src/scsi/scsi_x54x.h +++ b/src/scsi/scsi_x54x.h @@ -11,7 +11,7 @@ * of SCSI Host Adapters made by Mylex. * These controllers were designed for various buses. * - * Version: @(#)scsi_x54x.h 1.0.6 2018/03/18 + * Version: @(#)scsi_x54x.h 1.0.7 2018/04/06 * * Authors: TheCollector1995, * Miran Grca, @@ -333,6 +333,7 @@ typedef struct { char name[16]; /* name of device */ int64_t timer_period, temp_period; + uint8_t callback_phase; int64_t media_period; double ha_bps; /* bytes per second */ diff --git a/src/sio_fdc37c669.c b/src/sio_fdc37c669.c index ea5398020..81d9d700f 100644 --- a/src/sio_fdc37c669.c +++ b/src/sio_fdc37c669.c @@ -8,7 +8,7 @@ * * Implementation of the SMC FDC37C669 Super I/O Chip. * - * Version: @(#)sio_fdc37c669.c 1.0.7 2018/01/16 + * Version: @(#)sio_fdc37c669.c 1.0.8 2018/04/04 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -125,7 +125,7 @@ process_value: if (valxor & 3) { ide_pri_disable(); - if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable_ex(); + if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable(); break; } #endif @@ -206,7 +206,7 @@ process_value: ide_set_side(0, make_port(0x22)); break; } - if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable_ex(); + if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable(); } #endif break; @@ -345,6 +345,4 @@ void fdc37c669_init() io_sethandler(0x3f0, 0x0002, fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, NULL); fdc37c669_reset(); - - pci_reset_handler.super_io_reset = fdc37c669_reset; } diff --git a/src/sio_fdc37c66x.c b/src/sio_fdc37c66x.c index 222233db4..a97ee26e9 100644 --- a/src/sio_fdc37c66x.c +++ b/src/sio_fdc37c66x.c @@ -9,7 +9,7 @@ * Implementation of the SMC FDC37C663 and FDC37C665 Super * I/O Chips. * - * Version: @(#)sio_fdc37c66x.c 1.0.10 2018/01/16 + * Version: @(#)sio_fdc37c66x.c 1.0.11 2018/04/04 * * Authors: Sarah Walker, * Miran Grca, @@ -73,7 +73,7 @@ static void ide_handler() } ide_set_base(0, 0x170 | or_value); ide_set_side(0, 0x376 | or_value); - ide_pri_enable_ex(); + ide_pri_enable(); } #endif } @@ -319,8 +319,6 @@ void fdc37c663_init() io_sethandler(0x03f0, 0x0002, fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, NULL); fdc37c663_reset(); - - pci_reset_handler.super_io_reset = fdc37c663_reset; } void fdc37c665_init() @@ -330,6 +328,4 @@ void fdc37c665_init() io_sethandler(0x03f0, 0x0002, fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, NULL); fdc37c665_reset(); - - pci_reset_handler.super_io_reset = fdc37c665_reset; } diff --git a/src/sio_fdc37c93x.c b/src/sio_fdc37c93x.c index 0d4076ade..07183803b 100644 --- a/src/sio_fdc37c93x.c +++ b/src/sio_fdc37c93x.c @@ -9,7 +9,7 @@ * Implementation of the SMC FDC37C932FR and FDC37C935 Super * I/O Chips. * - * Version: @(#)sio_fdc37c93x.c 1.0.11 2018/03/14 + * Version: @(#)sio_fdc37c93x.c 1.0.12 2018/04/04 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -566,14 +566,10 @@ void fdc37c932fr_init(void) { fdc37c93x_init(); fdc37c932fr_reset(); - - pci_reset_handler.super_io_reset = fdc37c932fr_reset; } void fdc37c935_init(void) { fdc37c93x_init(); fdc37c935_reset(); - - pci_reset_handler.super_io_reset = fdc37c935_reset; } diff --git a/src/sio_pc87306.c b/src/sio_pc87306.c index 9dfe881b1..be9339beb 100644 --- a/src/sio_pc87306.c +++ b/src/sio_pc87306.c @@ -8,7 +8,7 @@ * * Emulation of the NatSemi PC87306 Super I/O chip. * - * Version: @(#)sio_pc87306.c 1.0.9 2018/01/17 + * Version: @(#)sio_pc87306.c 1.0.10 2018/04/04 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -256,7 +256,7 @@ process_value: ide_set_side(0, 0x376 | or_value); if (val & 0x40) { - ide_pri_enable_ex(); + ide_pri_enable(); } #endif } @@ -476,6 +476,4 @@ void pc87306_init() pc87306_reset(); io_sethandler(0x02e, 0x0002, pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, NULL); - - pci_reset_handler.super_io_reset = pc87306_reset; } diff --git a/src/sio_um8669f.c b/src/sio_um8669f.c index 1f2dccf11..5b027580e 100644 --- a/src/sio_um8669f.c +++ b/src/sio_um8669f.c @@ -299,6 +299,4 @@ void um8669f_init(void) io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, &um8669f_global); um8669f_reset(); - - pci_reset_handler.super_io_reset = um8669f_reset; } diff --git a/src/sio_w83877f.c b/src/sio_w83877f.c index fe6edc20d..2725cd354 100644 --- a/src/sio_w83877f.c +++ b/src/sio_w83877f.c @@ -11,7 +11,7 @@ * Winbond W83877F Super I/O Chip * Used by the Award 430HX * - * Version: @(#)sio_w83877f.c 1.0.9 2018/01/20 + * Version: @(#)sio_w83877f.c 1.0.10 2018/04/04 * * Author: Miran Grca, * Copyright 2016-2018 Miran Grca. @@ -538,6 +538,4 @@ void w83877f_init(void) lpt2_remove(); w83877f_reset(); - - pci_reset_handler.super_io_reset = w83877f_reset; } diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index 6fff49a1f..f14409f2e 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -243,7 +243,7 @@ void* fluidsynth_init(const device_t *info) /* Try loading the DLL. */ #ifdef _WIN32 - fluidsynth_handle = dynld_module("libfluidsynth.dll", fluidsynth_imports); + fluidsynth_handle = dynld_module("libfluidsynth-1.dll", fluidsynth_imports); #else fluidsynth_handle = dynld_module("libfluidsynth.so", fluidsynth_imports); #endif diff --git a/src/sound/nukedopl.cpp b/src/sound/nukedopl.cpp index 538a4411b..0039a63bc 100644 --- a/src/sound/nukedopl.cpp +++ b/src/sound/nukedopl.cpp @@ -1,7 +1,16 @@ -/* Copyright holders: Alexey Khokholov (Nuke.YKT) - see COPYING for more details -*/ - +// +// Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// // // Nuked OPL3 emulator. // Thanks: @@ -11,8 +20,10 @@ // Tremolo and phase generator calculation information. // OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): // OPL2 ROMs. +// siliconpr0n.org(John McMaster, digshadow): +// YMF262 and VRC VII decaps and die shots. // -// version: 1.7.4 +// version: 1.8 // #include @@ -83,38 +94,38 @@ static const Bit16u logsinrom[256] = { // static const Bit16u exprom[256] = { - 0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014, - 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a, - 0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042, - 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a, - 0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072, - 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b, - 0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4, - 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be, - 0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9, - 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4, - 0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110, - 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c, - 0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149, - 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167, - 0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185, - 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4, - 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4, - 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4, - 0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205, - 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227, - 0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249, - 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d, - 0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291, - 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5, - 0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db, - 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302, - 0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329, - 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351, - 0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a, - 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4, - 0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf, - 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa + 0x7fa, 0x7f5, 0x7ef, 0x7ea, 0x7e4, 0x7df, 0x7da, 0x7d4, + 0x7cf, 0x7c9, 0x7c4, 0x7bf, 0x7b9, 0x7b4, 0x7ae, 0x7a9, + 0x7a4, 0x79f, 0x799, 0x794, 0x78f, 0x78a, 0x784, 0x77f, + 0x77a, 0x775, 0x770, 0x76a, 0x765, 0x760, 0x75b, 0x756, + 0x751, 0x74c, 0x747, 0x742, 0x73d, 0x738, 0x733, 0x72e, + 0x729, 0x724, 0x71f, 0x71a, 0x715, 0x710, 0x70b, 0x706, + 0x702, 0x6fd, 0x6f8, 0x6f3, 0x6ee, 0x6e9, 0x6e5, 0x6e0, + 0x6db, 0x6d6, 0x6d2, 0x6cd, 0x6c8, 0x6c4, 0x6bf, 0x6ba, + 0x6b5, 0x6b1, 0x6ac, 0x6a8, 0x6a3, 0x69e, 0x69a, 0x695, + 0x691, 0x68c, 0x688, 0x683, 0x67f, 0x67a, 0x676, 0x671, + 0x66d, 0x668, 0x664, 0x65f, 0x65b, 0x657, 0x652, 0x64e, + 0x649, 0x645, 0x641, 0x63c, 0x638, 0x634, 0x630, 0x62b, + 0x627, 0x623, 0x61e, 0x61a, 0x616, 0x612, 0x60e, 0x609, + 0x605, 0x601, 0x5fd, 0x5f9, 0x5f5, 0x5f0, 0x5ec, 0x5e8, + 0x5e4, 0x5e0, 0x5dc, 0x5d8, 0x5d4, 0x5d0, 0x5cc, 0x5c8, + 0x5c4, 0x5c0, 0x5bc, 0x5b8, 0x5b4, 0x5b0, 0x5ac, 0x5a8, + 0x5a4, 0x5a0, 0x59c, 0x599, 0x595, 0x591, 0x58d, 0x589, + 0x585, 0x581, 0x57e, 0x57a, 0x576, 0x572, 0x56f, 0x56b, + 0x567, 0x563, 0x560, 0x55c, 0x558, 0x554, 0x551, 0x54d, + 0x549, 0x546, 0x542, 0x53e, 0x53b, 0x537, 0x534, 0x530, + 0x52c, 0x529, 0x525, 0x522, 0x51e, 0x51b, 0x517, 0x514, + 0x510, 0x50c, 0x509, 0x506, 0x502, 0x4ff, 0x4fb, 0x4f8, + 0x4f4, 0x4f1, 0x4ed, 0x4ea, 0x4e7, 0x4e3, 0x4e0, 0x4dc, + 0x4d9, 0x4d6, 0x4d2, 0x4cf, 0x4cc, 0x4c8, 0x4c5, 0x4c2, + 0x4be, 0x4bb, 0x4b8, 0x4b5, 0x4b1, 0x4ae, 0x4ab, 0x4a8, + 0x4a4, 0x4a1, 0x49e, 0x49b, 0x498, 0x494, 0x491, 0x48e, + 0x48b, 0x488, 0x485, 0x482, 0x47e, 0x47b, 0x478, 0x475, + 0x472, 0x46f, 0x46c, 0x469, 0x466, 0x463, 0x460, 0x45d, + 0x45a, 0x457, 0x454, 0x451, 0x44e, 0x44b, 0x448, 0x445, + 0x442, 0x43f, 0x43c, 0x439, 0x436, 0x433, 0x430, 0x42d, + 0x42a, 0x428, 0x425, 0x422, 0x41f, 0x41c, 0x419, 0x416, + 0x414, 0x411, 0x40e, 0x40b, 0x408, 0x406, 0x403, 0x400 }; // @@ -143,33 +154,11 @@ static const Bit8u kslshift[4] = { // envelope generator constants // -static const Bit8u eg_incstep[3][4][8] = { - { - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0, 0, 0, 0, 0, 0, 0 } - }, - { - { 0, 1, 0, 1, 0, 1, 0, 1 }, - { 0, 1, 0, 1, 1, 1, 0, 1 }, - { 0, 1, 1, 1, 0, 1, 1, 1 }, - { 0, 1, 1, 1, 1, 1, 1, 1 } - }, - { - { 1, 1, 1, 1, 1, 1, 1, 1 }, - { 2, 2, 1, 1, 1, 1, 1, 1 }, - { 2, 2, 1, 1, 2, 2, 1, 1 }, - { 2, 2, 2, 2, 2, 2, 1, 1 } - } -}; - -static const Bit8u eg_incdesc[16] = { - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2 -}; - -static const Bit8s eg_incsh[16] = { - 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2 +static const Bit8u eg_incstep[4][4] = { + { 0, 0, 0, 0 }, + { 1, 0, 0, 0 }, + { 1, 0, 1, 0 }, + { 1, 1, 1, 0 } }; // @@ -198,7 +187,7 @@ static Bit16s OPL3_EnvelopeCalcExp(Bit32u level) { level = 0x1fff; } - return ((exprom[(level & 0xff) ^ 0xff] | 0x400) << 1) >> (level >> 8); + return (exprom[level & 0xff] << 1) >> (level >> 8); } static Bit16s OPL3_EnvelopeCalcSin0(Bit16u phase, Bit16u envelope) @@ -208,7 +197,7 @@ static Bit16s OPL3_EnvelopeCalcSin0(Bit16u phase, Bit16u envelope) phase &= 0x3ff; if (phase & 0x200) { - neg = ~0; + neg = 0xffff; } if (phase & 0x100) { @@ -277,7 +266,7 @@ static Bit16s OPL3_EnvelopeCalcSin4(Bit16u phase, Bit16u envelope) phase &= 0x3ff; if ((phase & 0x300) == 0x100) { - neg = ~0; + neg = 0xffff; } if (phase & 0x200) { @@ -319,7 +308,7 @@ static Bit16s OPL3_EnvelopeCalcSin6(Bit16u phase, Bit16u envelope) phase &= 0x3ff; if (phase & 0x200) { - neg = ~0; + neg = 0xffff; } return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg; } @@ -331,7 +320,7 @@ static Bit16s OPL3_EnvelopeCalcSin7(Bit16u phase, Bit16u envelope) phase &= 0x3ff; if (phase & 0x200) { - neg = ~0; + neg = 0xffff; phase = (phase & 0x1ff) ^ 0x1ff; } out = phase << 3; @@ -349,45 +338,14 @@ static const envelope_sinfunc envelope_sin[8] = { OPL3_EnvelopeCalcSin7 }; -static void OPL3_EnvelopeGenOff(opl3_slot *slot); -static void OPL3_EnvelopeGenAttack(opl3_slot *slot); -static void OPL3_EnvelopeGenDecay(opl3_slot *slot); -static void OPL3_EnvelopeGenSustain(opl3_slot *slot); -static void OPL3_EnvelopeGenRelease(opl3_slot *slot); - -envelope_genfunc envelope_gen[5] = { - OPL3_EnvelopeGenOff, - OPL3_EnvelopeGenAttack, - OPL3_EnvelopeGenDecay, - OPL3_EnvelopeGenSustain, - OPL3_EnvelopeGenRelease -}; - enum envelope_gen_num { - envelope_gen_num_off = 0, - envelope_gen_num_attack = 1, - envelope_gen_num_decay = 2, - envelope_gen_num_sustain = 3, - envelope_gen_num_release = 4 + envelope_gen_num_attack = 0, + envelope_gen_num_decay = 1, + envelope_gen_num_sustain = 2, + envelope_gen_num_release = 3 }; -static Bit8u OPL3_EnvelopeCalcRate(opl3_slot *slot, Bit8u reg_rate) -{ - Bit8u rate; - if (reg_rate == 0x00) - { - return 0x00; - } - rate = (reg_rate << 2) - + (slot->reg_ksr ? slot->channel->ksv : (slot->channel->ksv >> 2)); - if (rate > 0x3c) - { - rate = 0x3c; - } - return rate; -} - static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) { Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) @@ -399,128 +357,161 @@ static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) slot->eg_ksl = (Bit8u)ksl; } -static void OPL3_EnvelopeUpdateRate(opl3_slot *slot) -{ - switch (slot->eg_gen) - { - case envelope_gen_num_off: - case envelope_gen_num_attack: - slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_ar); - break; - case envelope_gen_num_decay: - slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_dr); - break; - case envelope_gen_num_sustain: - case envelope_gen_num_release: - slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_rr); - break; - } -} - -static void OPL3_EnvelopeGenOff(opl3_slot *slot) -{ - slot->eg_rout = 0x1ff; -} - -static void OPL3_EnvelopeGenAttack(opl3_slot *slot) -{ - if (slot->eg_rout == 0x00) - { - slot->eg_gen = envelope_gen_num_decay; - OPL3_EnvelopeUpdateRate(slot); - return; - } - slot->eg_rout += ((~slot->eg_rout) * slot->eg_inc) >> 3; - if (slot->eg_rout < 0x00) - { - slot->eg_rout = 0x00; - } -} - -static void OPL3_EnvelopeGenDecay(opl3_slot *slot) -{ - if (slot->eg_rout >= slot->reg_sl << 4) - { - slot->eg_gen = envelope_gen_num_sustain; - OPL3_EnvelopeUpdateRate(slot); - return; - } - slot->eg_rout += slot->eg_inc; -} - -static void OPL3_EnvelopeGenSustain(opl3_slot *slot) -{ - if (!slot->reg_type) - { - OPL3_EnvelopeGenRelease(slot); - } -} - -static void OPL3_EnvelopeGenRelease(opl3_slot *slot) -{ - if (slot->eg_rout >= 0x1ff) - { - slot->eg_gen = envelope_gen_num_off; - slot->eg_rout = 0x1ff; - OPL3_EnvelopeUpdateRate(slot); - return; - } - slot->eg_rout += slot->eg_inc; -} - static void OPL3_EnvelopeCalc(opl3_slot *slot) { - Bit8u rate_h, rate_l; - Bit8u inc = 0; - rate_h = slot->eg_rate >> 2; - rate_l = slot->eg_rate & 3; - if (eg_incsh[rate_h] > 0) + Bit8u nonzero; + Bit8u rate; + Bit8u rate_hi; + Bit8u rate_lo; + Bit8u reg_rate = 0; + Bit8u ks; + Bit8u eg_shift, shift; + Bit16u eg_rout; + Bit16s eg_inc; + Bit8u eg_off; + Bit8u reset = 0; + slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; + if (slot->key && slot->eg_gen == envelope_gen_num_release) { - if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) - { - inc = eg_incstep[eg_incdesc[rate_h]][rate_l] - [((slot->chip->timer)>> eg_incsh[rate_h]) & 0x07]; - } + reset = 1; + reg_rate = slot->reg_ar; } else { - inc = eg_incstep[eg_incdesc[rate_h]][rate_l] - [slot->chip->timer & 0x07] << (-eg_incsh[rate_h]); + switch (slot->eg_gen) + { + case envelope_gen_num_attack: + reg_rate = slot->reg_ar; + break; + case envelope_gen_num_decay: + reg_rate = slot->reg_dr; + break; + case envelope_gen_num_sustain: + if (!slot->reg_type) + { + reg_rate = slot->reg_rr; + } + break; + case envelope_gen_num_release: + reg_rate = slot->reg_rr; + break; + } + } + slot->pg_reset = reset; + ks = slot->channel->ksv >> ((slot->reg_ksr ^ 1) << 1); + nonzero = (reg_rate != 0); + rate = ks + (reg_rate << 2); + rate_hi = rate >> 2; + rate_lo = rate & 0x03; + if (rate_hi & 0x10) + { + rate_hi = 0x0f; + } + eg_shift = rate_hi + slot->chip->eg_add; + shift = 0; + if (nonzero) + { + if (rate_hi < 12) + { + if (slot->chip->eg_state) + { + switch (eg_shift) + { + case 12: + shift = 1; + break; + case 13: + shift = (rate_lo >> 1) & 0x01; + break; + case 14: + shift = rate_lo & 0x01; + break; + default: + break; + } + } + } + else + { + shift = (rate_hi & 0x03) + eg_incstep[rate_lo][slot->chip->timer & 0x03]; + if (shift & 0x04) + { + shift = 0x03; + } + if (!shift) + { + shift = slot->chip->eg_state; + } + } + } + eg_rout = slot->eg_rout; + eg_inc = 0; + eg_off = 0; + // Instant attack + if (reset && rate_hi == 0x0f) + { + eg_rout = 0x00; + } + // Envelope off + if ((slot->eg_rout & 0x1f8) == 0x1f8) + { + eg_off = 1; + } + if (slot->eg_gen != envelope_gen_num_attack && !reset && eg_off) + { + eg_rout = 0x1ff; + } + switch (slot->eg_gen) + { + case envelope_gen_num_attack: + if (!slot->eg_rout) + { + slot->eg_gen = envelope_gen_num_decay; + } + else if (slot->key && shift > 0 && rate_hi != 0x0f) + { + eg_inc = ((~slot->eg_rout) << shift) >> 4; + } + break; + case envelope_gen_num_decay: + if ((slot->eg_rout >> 4) == slot->reg_sl) + { + slot->eg_gen = envelope_gen_num_sustain; + } + else if (!eg_off && !reset && shift > 0) + { + eg_inc = 1 << (shift - 1); + } + break; + case envelope_gen_num_sustain: + case envelope_gen_num_release: + if (!eg_off && !reset && shift > 0) + { + eg_inc = 1 << (shift - 1); + } + break; + } + slot->eg_rout = (eg_rout + eg_inc) & 0x1ff; + // Key off + if (reset) + { + slot->eg_gen = envelope_gen_num_attack; + } + if (!slot->key) + { + slot->eg_gen = envelope_gen_num_release; } - slot->eg_inc = inc; - slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) - + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; - envelope_gen[slot->eg_gen](slot); } static void OPL3_EnvelopeKeyOn(opl3_slot *slot, Bit8u type) { - if (!slot->key) - { - slot->eg_gen = envelope_gen_num_attack; - OPL3_EnvelopeUpdateRate(slot); - if ((slot->eg_rate >> 2) == 0x0f) - { - slot->eg_gen = envelope_gen_num_decay; - OPL3_EnvelopeUpdateRate(slot); - slot->eg_rout = 0x00; - } - slot->pg_phase = 0x00; - } slot->key |= type; } static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type) { - if (slot->key) - { - slot->key &= (~type); - if (!slot->key) - { - slot->eg_gen = envelope_gen_num_release; - OPL3_EnvelopeUpdateRate(slot); - } - } + slot->key &= ~type; } // @@ -529,9 +520,14 @@ static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type) static void OPL3_PhaseGenerate(opl3_slot *slot) { + opl3_chip *chip; Bit16u f_num; Bit32u basefreq; + Bit8u rm_xor, n_bit; + Bit32u noise; + Bit16u phase; + chip = slot->chip; f_num = slot->channel->f_num; if (slot->reg_vib) { @@ -558,20 +554,58 @@ static void OPL3_PhaseGenerate(opl3_slot *slot) f_num += range; } basefreq = (f_num << slot->channel->block) >> 1; - slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1; -} - -// -// Noise Generator -// - -static void OPL3_NoiseGenerate(opl3_chip *chip) -{ - if (chip->noise & 0x01) + phase = (Bit16u)(slot->pg_phase >> 9); + if (slot->pg_reset) { - chip->noise ^= 0x800302; + slot->pg_phase = 0; } - chip->noise >>= 1; + slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1; + // Rhythm mode + noise = chip->noise; + slot->pg_phase_out = phase; + if (slot->slot_num == 13) // hh + { + chip->rm_hh_bit2 = (phase >> 2) & 1; + chip->rm_hh_bit3 = (phase >> 3) & 1; + chip->rm_hh_bit7 = (phase >> 7) & 1; + chip->rm_hh_bit8 = (phase >> 8) & 1; + } + if (slot->slot_num == 17 && (chip->rhy & 0x20)) // tc + { + chip->rm_tc_bit3 = (phase >> 3) & 1; + chip->rm_tc_bit5 = (phase >> 5) & 1; + } + if (chip->rhy & 0x20) + { + rm_xor = (chip->rm_hh_bit2 ^ chip->rm_hh_bit7) + | (chip->rm_hh_bit3 ^ chip->rm_tc_bit5) + | (chip->rm_tc_bit3 ^ chip->rm_tc_bit5); + switch (slot->slot_num) + { + case 13: // hh + slot->pg_phase_out = rm_xor << 9; + if (rm_xor ^ (noise & 1)) + { + slot->pg_phase_out |= 0xd0; + } + else + { + slot->pg_phase_out |= 0x34; + } + break; + case 16: // sd + slot->pg_phase_out = (chip->rm_hh_bit8 << 9) + | ((chip->rm_hh_bit8 ^ (noise & 1)) << 8); + break; + case 17: // tc + slot->pg_phase_out = (rm_xor << 9) | 0x80; + break; + default: + break; + } + } + n_bit = ((noise >> 14) ^ noise) & 0x01; + chip->noise = (noise >> 1) | (n_bit << 22); } // @@ -592,7 +626,6 @@ static void OPL3_SlotWrite20(opl3_slot *slot, Bit8u data) slot->reg_type = (data >> 5) & 0x01; slot->reg_ksr = (data >> 4) & 0x01; slot->reg_mult = data & 0x0f; - OPL3_EnvelopeUpdateRate(slot); } static void OPL3_SlotWrite40(opl3_slot *slot, Bit8u data) @@ -606,7 +639,6 @@ static void OPL3_SlotWrite60(opl3_slot *slot, Bit8u data) { slot->reg_ar = (data >> 4) & 0x0f; slot->reg_dr = data & 0x0f; - OPL3_EnvelopeUpdateRate(slot); } static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data) @@ -617,7 +649,6 @@ static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data) slot->reg_sl = 0x1f; } slot->reg_rr = data & 0x0f; - OPL3_EnvelopeUpdateRate(slot); } static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data) @@ -629,19 +660,9 @@ static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data) } } -static void OPL3_SlotGeneratePhase(opl3_slot *slot, Bit16u phase) -{ - slot->out = envelope_sin[slot->reg_wf](phase, slot->eg_out); -} - static void OPL3_SlotGenerate(opl3_slot *slot) { - OPL3_SlotGeneratePhase(slot, (Bit16u)(slot->pg_phase >> 9) + *slot->mod); -} - -static void OPL3_SlotGenerateZM(opl3_slot *slot) -{ - OPL3_SlotGeneratePhase(slot, (Bit16u)(slot->pg_phase >> 9)); + slot->out = envelope_sin[slot->reg_wf](slot->pg_phase_out + *slot->mod, slot->eg_out); } static void OPL3_SlotCalcFB(opl3_slot *slot) @@ -693,6 +714,8 @@ static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data) chip->channel[chnum].chtype = ch_drum; } OPL3_ChannelSetupAlg(channel6); + OPL3_ChannelSetupAlg(channel7); + OPL3_ChannelSetupAlg(channel8); //hh if (chip->rhy & 0x01) { @@ -764,16 +787,12 @@ static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); OPL3_EnvelopeUpdateKSL(channel->slots[0]); OPL3_EnvelopeUpdateKSL(channel->slots[1]); - OPL3_EnvelopeUpdateRate(channel->slots[0]); - OPL3_EnvelopeUpdateRate(channel->slots[1]); if (channel->chip->newm && channel->chtype == ch_4op) { channel->pair->f_num = channel->f_num; channel->pair->ksv = channel->ksv; OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); - OPL3_EnvelopeUpdateRate(channel->pair->slots[0]); - OPL3_EnvelopeUpdateRate(channel->pair->slots[1]); } } @@ -789,8 +808,6 @@ static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data) | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); OPL3_EnvelopeUpdateKSL(channel->slots[0]); OPL3_EnvelopeUpdateKSL(channel->slots[1]); - OPL3_EnvelopeUpdateRate(channel->slots[0]); - OPL3_EnvelopeUpdateRate(channel->slots[1]); if (channel->chip->newm && channel->chtype == ch_4op) { channel->pair->f_num = channel->f_num; @@ -798,8 +815,6 @@ static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data) channel->pair->ksv = channel->ksv; OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); - OPL3_EnvelopeUpdateRate(channel->pair->slots[0]); - OPL3_EnvelopeUpdateRate(channel->pair->slots[1]); } } @@ -807,6 +822,12 @@ static void OPL3_ChannelSetupAlg(opl3_channel *channel) { if (channel->chtype == ch_drum) { + if (channel->ch_num == 7 || channel->ch_num == 8) + { + channel->slots[0]->mod = &channel->chip->zeromod; + channel->slots[1]->mod = &channel->chip->zeromod; + return; + } switch (channel->alg & 0x01) { case 0x00: @@ -933,7 +954,7 @@ static void OPL3_ChannelWriteC0(opl3_channel *channel, Bit8u data) } else { - channel->cha = channel->chb = ~0; + channel->cha = channel->chb = (Bit16u)~0; } } @@ -1022,96 +1043,23 @@ static Bit16s OPL3_ClipSample(Bit32s sample) return (Bit16s)sample; } -static void OPL3_GenerateRhythm1(opl3_chip *chip) -{ - opl3_channel *channel6; - opl3_channel *channel7; - opl3_channel *channel8; - Bit16u phase14; - Bit16u phase17; - Bit16u phase; - Bit16u phasebit; - - channel6 = &chip->channel[6]; - channel7 = &chip->channel[7]; - channel8 = &chip->channel[8]; - OPL3_SlotGenerate(channel6->slots[0]); - phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; - phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; - phase = 0x00; - //hh tc phase bit - phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) - | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - //hh - phase = (phasebit << 9) - | (0x34 << ((phasebit ^ (chip->noise & 0x01)) << 1)); - OPL3_SlotGeneratePhase(channel7->slots[0], phase); - //tt - OPL3_SlotGenerateZM(channel8->slots[0]); -} - -static void OPL3_GenerateRhythm2(opl3_chip *chip) -{ - opl3_channel *channel6; - opl3_channel *channel7; - opl3_channel *channel8; - Bit16u phase14; - Bit16u phase17; - Bit16u phase; - Bit16u phasebit; - - channel6 = &chip->channel[6]; - channel7 = &chip->channel[7]; - channel8 = &chip->channel[8]; - OPL3_SlotGenerate(channel6->slots[1]); - phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; - phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; - phase = 0x00; - //hh tc phase bit - phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) - | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; - //sd - phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); - OPL3_SlotGeneratePhase(channel7->slots[1], phase); - //tc - phase = 0x100 | (phasebit << 9); - OPL3_SlotGeneratePhase(channel8->slots[1], phase); -} - void OPL3_Generate(opl3_chip *chip, Bit16s *buf) { Bit8u ii; Bit8u jj; Bit16s accm; + Bit8u shift = 0; buf[1] = OPL3_ClipSample(chip->mixbuff[1]); - for (ii = 0; ii < 12; ii++) + for (ii = 0; ii < 15; ii++) { OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); OPL3_SlotGenerate(&chip->slot[ii]); } - for (ii = 12; ii < 15; ii++) - { - OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); - OPL3_EnvelopeCalc(&chip->slot[ii]); - } - - if (chip->rhy & 0x20) - { - OPL3_GenerateRhythm1(chip); - } - else - { - OPL3_SlotGenerate(&chip->slot[12]); - OPL3_SlotGenerate(&chip->slot[13]); - OPL3_SlotGenerate(&chip->slot[14]); - } - chip->mixbuff[0] = 0; for (ii = 0; ii < 18; ii++) { @@ -1126,19 +1074,9 @@ void OPL3_Generate(opl3_chip *chip, Bit16s *buf) for (ii = 15; ii < 18; ii++) { OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); OPL3_EnvelopeCalc(&chip->slot[ii]); - } - - if (chip->rhy & 0x20) - { - OPL3_GenerateRhythm2(chip); - } - else - { - OPL3_SlotGenerate(&chip->slot[15]); - OPL3_SlotGenerate(&chip->slot[16]); - OPL3_SlotGenerate(&chip->slot[17]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_SlotGenerate(&chip->slot[ii]); } buf[0] = OPL3_ClipSample(chip->mixbuff[0]); @@ -1146,8 +1084,8 @@ void OPL3_Generate(opl3_chip *chip, Bit16s *buf) for (ii = 18; ii < 33; ii++) { OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); OPL3_SlotGenerate(&chip->slot[ii]); } @@ -1165,13 +1103,11 @@ void OPL3_Generate(opl3_chip *chip, Bit16s *buf) for (ii = 33; ii < 36; ii++) { OPL3_SlotCalcFB(&chip->slot[ii]); - OPL3_PhaseGenerate(&chip->slot[ii]); OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); OPL3_SlotGenerate(&chip->slot[ii]); } - OPL3_NoiseGenerate(chip); - if ((chip->timer & 0x3f) == 0x3f) { chip->tremolopos = (chip->tremolopos + 1) % 210; @@ -1191,6 +1127,52 @@ void OPL3_Generate(opl3_chip *chip, Bit16s *buf) } chip->timer++; + + chip->eg_add = 0; + if (chip->eg_timer) + { + while (shift < 36 && ((chip->eg_timer >> shift) & 1) == 0) + { + shift++; + } + if (shift > 12) + { + chip->eg_add = 0; + } + else + { + chip->eg_add = shift + 1; + } + } + + if (chip->eg_timerrem || chip->eg_state) + { + if (chip->eg_timer == 0xfffffffff) + { + chip->eg_timer = 0; + chip->eg_timerrem = 1; + } + else + { + chip->eg_timer++; + chip->eg_timerrem = 0; + } + } + + chip->eg_state ^= 1; + + while (chip->writebuf[chip->writebuf_cur].time <= chip->writebuf_samplecnt) + { + if (!(chip->writebuf[chip->writebuf_cur].reg & 0x200)) + { + break; + } + chip->writebuf[chip->writebuf_cur].reg &= 0x1ff; + OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_cur].reg, + chip->writebuf[chip->writebuf_cur].data); + chip->writebuf_cur = (chip->writebuf_cur + 1) % OPL_WRITEBUF_SIZE; + } + chip->writebuf_samplecnt++; } void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf) @@ -1221,8 +1203,9 @@ void OPL3_Reset(opl3_chip *chip, Bit32u samplerate) chip->slot[slotnum].mod = &chip->zeromod; chip->slot[slotnum].eg_rout = 0x1ff; chip->slot[slotnum].eg_out = 0x1ff; - chip->slot[slotnum].eg_gen = envelope_gen_num_off; + chip->slot[slotnum].eg_gen = envelope_gen_num_release; chip->slot[slotnum].trem = (Bit8u*)&chip->zeromod; + chip->slot[slotnum].slot_num = slotnum; } for (channum = 0; channum < 18; channum++) { @@ -1244,11 +1227,12 @@ void OPL3_Reset(opl3_chip *chip, Bit32u samplerate) chip->channel[channum].out[2] = &chip->zeromod; chip->channel[channum].out[3] = &chip->zeromod; chip->channel[channum].chtype = ch_2op; - chip->channel[channum].cha = ~0; - chip->channel[channum].chb = ~0; + chip->channel[channum].cha = 0xffff; + chip->channel[channum].chb = 0xffff; + chip->channel[channum].ch_num = channum; OPL3_ChannelSetupAlg(&chip->channel[channum]); } - chip->noise = 0x306600; + chip->noise = 1; chip->rateratio = (samplerate << RSM_FRAC) / 49716; chip->tremoloshift = 4; chip->vibshift = 1; @@ -1363,6 +1347,34 @@ void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) } } +void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v) +{ + Bit64u time1, time2; + + if (chip->writebuf[chip->writebuf_last].reg & 0x200) + { + OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_last].reg & 0x1ff, + chip->writebuf[chip->writebuf_last].data); + + chip->writebuf_cur = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; + chip->writebuf_samplecnt = chip->writebuf[chip->writebuf_last].time; + } + + chip->writebuf[chip->writebuf_last].reg = reg | 0x200; + chip->writebuf[chip->writebuf_last].data = v; + time1 = chip->writebuf_lasttime + OPL_WRITEBUF_DELAY; + time2 = chip->writebuf_samplecnt; + + if (time1 < time2) + { + time1 = time2; + } + + chip->writebuf[chip->writebuf_last].time = time1; + chip->writebuf_lasttime = time1; + chip->writebuf_last = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; +} + void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples) { Bit32u i; diff --git a/src/sound/nukedopl.h b/src/sound/nukedopl.h index aa389feb0..9570298fb 100644 --- a/src/sound/nukedopl.h +++ b/src/sound/nukedopl.h @@ -1,7 +1,16 @@ -/* Copyright holders: Alexey Khokholov (Nuke.YKT) - see COPYING for more details -*/ - +// +// Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT) +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// // // Nuked OPL3 emulator. // Thanks: @@ -11,10 +20,16 @@ // Tremolo and phase generator calculation information. // OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): // OPL2 ROMs. +// siliconpr0n.org(John McMaster, digshadow): +// YMF262 and VRC VII decaps and die shots. +// +// version: 1.8 // #ifndef NUKEDOPL_H #define NUKEDOPL_H +#define OPL_WRITEBUF_SIZE 1024 +#define OPL_WRITEBUF_DELAY 1 //#include "dosbox.h" #include @@ -26,10 +41,12 @@ typedef int16_t Bit16s; typedef uint16_t Bit16u; typedef int32_t Bit32s; typedef uint32_t Bit32u; +typedef int64_t Bit64s; +typedef uint64_t Bit64u; -struct opl3_chip; struct opl3_slot; struct opl3_channel; +struct opl3_chip; struct opl3_slot { opl3_channel *channel; @@ -57,8 +74,10 @@ struct opl3_slot { Bit8u reg_rr; Bit8u reg_wf; Bit8u key; + Bit32u pg_reset; Bit32u pg_phase; - Bit32u timer; + Bit16u pg_phase_out; + Bit8u slot_num; }; struct opl3_channel { @@ -74,12 +93,23 @@ struct opl3_channel { Bit8u alg; Bit8u ksv; Bit16u cha, chb; + Bit8u ch_num; +}; + +struct opl3_writebuf { + Bit64u time; + Bit16u reg; + Bit8u data; }; struct opl3_chip { opl3_channel channel[18]; opl3_slot slot[36]; Bit16u timer; + Bit64u eg_timer; + Bit8u eg_timerrem; + Bit8u eg_state; + Bit8u eg_add; Bit8u newm; Bit8u nts; Bit8u rhy; @@ -91,11 +121,23 @@ struct opl3_chip { Bit32u noise; Bit16s zeromod; Bit32s mixbuff[2]; - + Bit8u rm_hh_bit2; + Bit8u rm_hh_bit3; + Bit8u rm_hh_bit7; + Bit8u rm_hh_bit8; + Bit8u rm_tc_bit3; + Bit8u rm_tc_bit5; + //OPL3L Bit32s rateratio; Bit32s samplecnt; Bit16s oldsamples[2]; Bit16s samples[2]; + + Bit64u writebuf_samplecnt; + Bit32u writebuf_cur; + Bit32u writebuf_last; + Bit64u writebuf_lasttime; + opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; }; void OPL3_Generate(opl3_chip *chip, Bit16s *buf); @@ -103,5 +145,6 @@ void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf); void OPL3_Reset(opl3_chip *chip, Bit32u samplerate); Bit32u OPL3_WriteAddr(opl3_chip *chip, Bit32u port, Bit8u val); void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v); +void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v); void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); #endif diff --git a/src/sound/openal.c b/src/sound/openal.c index 9483d1648..319623816 100644 --- a/src/sound/openal.c +++ b/src/sound/openal.c @@ -8,7 +8,7 @@ * * Interface to the OpenAL sound processing library. * - * Version: @(#)openal.c 1.0.5 2018/02/19 + * Version: @(#)openal.c 1.0.6 2018/04/23 * * Authors: Sarah Walker, * Miran Grca, @@ -22,7 +22,6 @@ #include #include #include -#ifdef USE_OPENAL # undef AL_API # undef ALC_API # define AL_LIBTYPE_STATIC @@ -30,7 +29,6 @@ # include # include # include -#endif #include "../86box.h" #include "sound.h" #include "midi.h" @@ -40,12 +38,10 @@ #define BUFLEN SOUNDBUFLEN -#ifdef USE_OPENAL ALuint buffers[4]; /* front and back buffers */ ALuint buffers_cd[4]; /* front and back buffers */ ALuint buffers_midi[4]; /* front and back buffers */ static ALuint source[3]; /* audio source */ -#endif static int midi_freq = 44100; @@ -61,7 +57,6 @@ al_set_midi(int freq, int buf_size) } -#ifdef USE_OPENAL void closeal(void); ALvoid alutInit(ALint *argc,ALbyte **argv) { @@ -104,27 +99,15 @@ alutExit(ALvoid) alcDestroyContext(Context); } } -#endif void closeal(void) { -#ifdef USE_OPENAL + if (!initialized) return; + alutExit(); -#endif -} - -void -initalmain(int argc, char *argv[]) -{ - if (! initialized) return; - -#ifdef USE_OPENAL - alutInit(0,0); - atexit(closeal); -#endif initialized = 0; } @@ -141,13 +124,14 @@ inital(void) if (initialized) return; + alutInit(0, 0); + atexit(closeal); + mdn = midi_device_get_internal_name(midi_device_current); if (strcmp(mdn, "none") && strcmp(mdn, SYSTEM_MIDI_INTERNAL_NAME)) init_midi = 1; /* If the device is neither none, nor system MIDI, initialize the MIDI buffer and source, otherwise, do not. */ -#ifdef USE_OPENAL - if (sound_is_float) { buf = (float *) malloc((BUFLEN << 1) * sizeof(float)); cd_buf = (float *) malloc((CD_BUFLEN << 1) * sizeof(float)); @@ -236,14 +220,12 @@ inital(void) } initialized = 1; -#endif } void givealbuffer_common(void *buf, uint8_t src, int size, int freq) { -#ifdef USE_OPENAL int processed; int state; ALuint buffer; @@ -270,7 +252,6 @@ givealbuffer_common(void *buf, uint8_t src, int size, int freq) alSourceQueueBuffers(source[src], 1, &buffer); } -#endif } diff --git a/src/sound/snd_adlibgold.c b/src/sound/snd_adlibgold.c index 02e692491..b79244bbc 100644 --- a/src/sound/snd_adlibgold.c +++ b/src/sound/snd_adlibgold.c @@ -10,9 +10,9 @@ #include "../pit.h" #include "../mem.h" #include "../rom.h" +#include "../device.h" #include "../nvr.h" #include "../timer.h" -#include "../device.h" #include "sound.h" #include "filters.h" #include "snd_opl.h" diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index a7e0257a9..ad5513466 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -1217,6 +1217,8 @@ static void generate_es1371_filter() for (n = 0; n < ES1371_NCoef; n++) gain += low_fir_es1371_coef[n] / (float)N; + gain /= 0.95; + /*Normalise filter, to produce unity gain*/ for (n = 0; n < ES1371_NCoef; n++) low_fir_es1371_coef[n] /= gain; diff --git a/src/sound/snd_dbopl.cc b/src/sound/snd_dbopl.cc index 94480ad4f..78840f4a6 100644 --- a/src/sound/snd_dbopl.cc +++ b/src/sound/snd_dbopl.cc @@ -3,23 +3,24 @@ */ #include "dbopl.h" #include "nukedopl.h" +#include "sound.h" #include "snd_dbopl.h" -int opl3_type = 0; +int opl_type = 0; static struct { DBOPL::Chip chip; - struct opl3_chip opl3chip; + opl3_chip opl3chip; int addr; int timer[2]; uint8_t timer_ctrl; uint8_t status_mask; uint8_t status; int is_opl3; - + void (*timer_callback)(void *param, int timer, int64_t period); void *timer_param; } opl[2]; @@ -42,20 +43,19 @@ enum void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3) { - if (!is_opl3 || !opl3_type) + opl[nr].timer_callback = timer_callback; + opl[nr].timer_param = timer_param; + opl[nr].is_opl3 = is_opl3; + + if (!opl_type) { - DBOPL::InitTables(); - opl[nr].chip.Setup(48000, is_opl3); - opl[nr].timer_callback = timer_callback; - opl[nr].timer_param = timer_param; - opl[nr].is_opl3 = is_opl3; + DBOPL::InitTables(); + opl[nr].chip.Setup(48000, is_opl3); } else { - OPL3_Reset(&opl[nr].opl3chip, 48000); - opl[nr].timer_callback = timer_callback; - opl[nr].timer_param = timer_param; - opl[nr].is_opl3 = is_opl3; + opl[nr].opl3chip.newm = 0; + OPL3_Reset(&opl[nr].opl3chip, 48000); } } @@ -87,17 +87,22 @@ void opl_write(int nr, uint16_t addr, uint8_t val) { if (!(addr & 1)) { - if (!opl[nr].is_opl3 || !opl3_type) - opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & (opl[nr].is_opl3 ? 0x1ff : 0xff); + if (!opl_type) + opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & 0x1ff; else opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff; + if (!opl[nr].is_opl3) + opl[nr].addr &= 0xff; } else { - if (!opl[nr].is_opl3 || !opl3_type) + if (!opl_type) opl[nr].chip.WriteReg(opl[nr].addr, val); - else - OPL3_WriteReg(&opl[nr].opl3chip, opl[nr].addr, val); + else { + OPL3_WriteRegBuffered(&opl[nr].opl3chip, (uint16_t) opl[nr].addr, val); + if (opl[nr].addr == 0x105) + opl[nr].opl3chip.newm = opl[nr].addr & 0x01; + } switch (opl[nr].addr) { @@ -148,20 +153,27 @@ uint8_t opl_read(int nr, uint16_t addr) void opl2_update(int nr, int16_t *buffer, int samples) { int c; - Bit32s buffer_32[samples]; - - opl[nr].chip.GenerateBlock2(samples, buffer_32); - - for (c = 0; c < samples; c++) - buffer[c*2] = (int16_t)buffer_32[c]; + Bit32s buffer_32[SOUNDBUFLEN]; + + if (opl_type) + { + OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); + } + else + { + opl[nr].chip.GenerateBlock2(samples, buffer_32); + + for (c = 0; c < samples; c++) + buffer[c*2] = (int16_t)buffer_32[c]; + } } void opl3_update(int nr, int16_t *buffer, int samples) { int c; - Bit32s buffer_32[samples*2]; + Bit32s buffer_32[SOUNDBUFLEN*2]; - if (opl3_type) + if (opl_type) { OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); } diff --git a/src/sound/snd_dbopl.h b/src/sound/snd_dbopl.h index 6fd536f39..ca6299724 100644 --- a/src/sound/snd_dbopl.h +++ b/src/sound/snd_dbopl.h @@ -11,7 +11,7 @@ extern "C" { void opl2_update(int nr, int16_t *buffer, int samples); void opl3_update(int nr, int16_t *buffer, int samples); - extern int opl3_type; + extern int opl_type; #ifdef __cplusplus } #endif diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index c4c4ff255..50a9da711 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -8,7 +8,7 @@ * * Sound Blaster emulation. * - * Version: @(#)sound_sb.c 1.0.6 2018/03/18 + * Version: @(#)sound_sb.c 1.0.7 2018/04/18 * * Authors: Sarah Walker, * Miran Grca, @@ -134,6 +134,9 @@ typedef struct sb_t }; mpu_t mpu; emu8k_t emu8k; +#if 0 + sb_ct1745_mixer_t temp_mixer_sb16; +#endif int pos; @@ -272,10 +275,12 @@ static void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) sb->dsp.pos = 0; } +// FIXME: See why this causes weird audio glitches in some situations. +#if 0 static void sb_process_buffer_sb16(int32_t *buffer, int len, void *p) { sb_t *sb = (sb_t *)p; - sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + sb_ct1745_mixer_t *mixer = &sb->temp_mixer_sb16; int c; @@ -283,8 +288,8 @@ static void sb_process_buffer_sb16(int32_t *buffer, int len, void *p) { int32_t out_l = 0, out_r = 0; - out_l = ((int32_t)(buffer[c] * mixer->cd_l) / 3) >> 15; - out_r = ((int32_t)(buffer[c + 1] * mixer->cd_r) / 3) >> 15; + out_l = ((int32_t)(low_fir_sb16(0, (float)buffer[c]) * mixer->cd_l) / 3) >> 15; + out_r = ((int32_t)(low_fir_sb16(1, (float)buffer[c + 1]) * mixer->cd_r) / 3) >> 15; out_l = (out_l * mixer->master_l) >> 15; out_r = (out_r * mixer->master_r) >> 15; @@ -306,6 +311,7 @@ static void sb_process_buffer_sb16(int32_t *buffer, int len, void *p) buffer[c + 1] = (out_r << mixer->output_gain_R); } } +#endif static void sb_get_buffer_sb16(int32_t *buffer, int len, void *p) { @@ -378,6 +384,9 @@ static void sb_get_buffer_sb16(int32_t *buffer, int len, void *p) sb->pos = 0; sb->opl.pos = 0; sb->dsp.pos = 0; +#if 0 + memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); +#endif } #ifdef SB_DSP_RECORD_DEBUG int old_dsp_rec_pos=0; @@ -488,6 +497,9 @@ static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) sb->opl.pos = 0; sb->dsp.pos = 0; sb->emu8k.pos = 0; +#if 0 + memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); +#endif } @@ -1103,6 +1115,12 @@ void *sb_2_init() "CD version" also uses 250h or 260h for 2x0 to 2x3 -> CDROM interface 2x4 to 2x5 -> Mixer interface*/ + /*My SB 2.0 mirrors the OPL2 at ports 2x0/2x1. Presumably this mirror is + disabled when the CMS chips are present. + This mirror may also exist on SB 1.5 & MCV, however I am unable to + test this. It shouldn't exist on SB 1.0 as the CMS chips are always + present there. + Syndicate requires this mirror for music to play.*/ sb_t *sb = malloc(sizeof(sb_t)); uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); @@ -1119,6 +1137,8 @@ void *sb_2_init() /* CMS I/O handler is activated on the dedicated sound_cms module DSP I/O handler is activated in sb_dsp_setaddr */ if (sb->opl_enabled) { + if (!GAMEBLASTER) + io_sethandler(addr, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); } @@ -1249,9 +1269,14 @@ void *sb_16_init() } io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_sb16, sb); +#if 0 sound_add_process_handler(sb_process_buffer_sb16, sb); +#endif mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq401"), device_get_config_int("mode401")); sb_dsp_set_mpu(&sb->mpu); +#if 0 + memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); +#endif return sb; } @@ -1288,10 +1313,15 @@ void *sb_awe32_init() } io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_emu8k, sb); +#if 0 sound_add_process_handler(sb_process_buffer_sb16, sb); +#endif mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq401"), device_get_config_int("mode401")); sb_dsp_set_mpu(&sb->mpu); emu8k_init(&sb->emu8k, emu_addr, onboard_ram); +#if 0 + memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); +#endif return sb; } diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index fd71a697d..3e5bd5be0 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -346,7 +346,7 @@ void sb_8_write_dma(sb_dsp_t *dsp, uint8_t val) fwrite(&val,1,1,soundf); #endif } -uint16_t sb_16_read_dma(sb_dsp_t *dsp) +int sb_16_read_dma(sb_dsp_t *dsp) { return dma_channel_read(dsp->sb_16_dmanum); } @@ -522,19 +522,19 @@ void sb_exec_command(sb_dsp_t *dsp) timer_update_outstanding(); break; case 0x90: /*High speed 8-bit autoinit DMA output*/ - if (dsp->sb_type < SB2 || dsp->sb_type > SBPRO2) break; + if (dsp->sb_type < SB2) break; sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); break; case 0x91: /*High speed 8-bit single cycle DMA output*/ - if (dsp->sb_type < SB2 || dsp->sb_type > SBPRO2) break; + if (dsp->sb_type < SB2) break; sb_start_dma(dsp, 1, 0, 0, dsp->sb_8_autolen); break; case 0x98: /*High speed 8-bit autoinit DMA input*/ - if (dsp->sb_type < SB2 || dsp->sb_type > SBPRO2) break; + if (dsp->sb_type < SB2) break; sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_8_autolen); break; case 0x99: /*High speed 8-bit single cycle DMA input*/ - if (dsp->sb_type < SB2 || dsp->sb_type > SBPRO2) break; + if (dsp->sb_type < SB2) break; sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen); break; case 0xA0: /*Set input mode to mono*/ @@ -767,11 +767,11 @@ uint8_t sb_read(uint16_t a, void *priv) // pclog("SB read %02X\n",sbreaddat); return dsp->sbreaddat; case 0xC: /*Write data ready*/ - if (dsp->sb_8_enable || dsp->sb_type >= SB16 ) - dsp->busy_count = (dsp->busy_count + 1) & 15; + if (dsp->sb_8_enable || dsp->sb_type >= SB16) + dsp->busy_count = (dsp->busy_count + 1) & 3; else dsp->busy_count = 0; - if (dsp->wb_full || (dsp->busy_count & 8)) + if (dsp->wb_full || (dsp->busy_count & 2)) { dsp->wb_full = dsp->wb_time; return 0xff; @@ -1016,26 +1016,42 @@ void pollsb(void *p) } if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0LL && dsp->sb_16_output) { + int data[2]; + sb_dsp_update(dsp); switch (dsp->sb_16_format) { case 0x00: /*Mono unsigned*/ - dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000; + data[0] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA) + break; + dsp->sbdatl = dsp->sbdatr = data[0] ^ 0x8000; dsp->sb_16_length--; break; case 0x10: /*Mono signed*/ - dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp); + data[0] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA) + break; + dsp->sbdatl = dsp->sbdatr = data[0]; dsp->sb_16_length--; break; case 0x20: /*Stereo unsigned*/ - dsp->sbdatl = sb_16_read_dma(dsp) ^ 0x8000; - dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000; + data[0] = sb_16_read_dma(dsp); + data[1] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = data[0] ^ 0x8000; + dsp->sbdatr = data[1] ^ 0x8000; dsp->sb_16_length -= 2; break; case 0x30: /*Stereo signed*/ - dsp->sbdatl = sb_16_read_dma(dsp); - dsp->sbdatr = sb_16_read_dma(dsp); + data[0] = sb_16_read_dma(dsp); + data[1] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = data[0]; + dsp->sbdatr = data[1]; dsp->sb_16_length -= 2; break; // default: diff --git a/src/sound/sound.c b/src/sound/sound.c index 66f8a0c87..086598c28 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -8,7 +8,7 @@ * * Sound emulation core. * - * Version: @(#)sound.c 1.0.15 2018/03/18 + * Version: @(#)sound.c 1.0.16 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, @@ -24,20 +24,24 @@ #include "../86box.h" #include "../device.h" #include "../timer.h" +#include "../scsi/scsi.h" #include "../cdrom/cdrom.h" #include "../plat.h" #include "sound.h" #include "midi.h" #include "snd_opl.h" +#include "snd_cms.h" #include "snd_adlib.h" #include "snd_adlibgold.h" #include "snd_audiopci.h" +#include "snd_gus.h" #include "snd_mpu401.h" #if defined(DEV_BRANCH) && defined(USE_PAS16) # include "snd_pas16.h" #endif #include "snd_sb.h" #include "snd_sb_dsp.h" +#include "snd_ssi2001.h" #include "snd_wss.h" #include "filters.h" @@ -169,7 +173,7 @@ static void sound_cd_thread(void *param) int32_t cd_buffer_temp4[2] = {0, 0}; int c, has_audio; - int d; + int d, r; thread_set_event(sound_cd_start_event); @@ -195,22 +199,40 @@ static void sound_cd_thread(void *param) for (i = 0; i < CDROM_NUM; i++) { has_audio = 0; - if (cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) + if ((cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) || !cdrom[i] || !cdrom[i]->handler) continue; - if (cdrom_drives[i].handler->audio_callback) + if (cdrom[i]->handler->audio_callback) { - cdrom_drives[i].handler->audio_callback(i, cd_buffer[i], CD_BUFLEN*2); - has_audio = (cdrom_drives[i].bus_type && cdrom_drives[i].sound_on); + r = cdrom[i]->handler->audio_callback(i, cd_buffer[i], CD_BUFLEN*2); + has_audio = (cdrom_drives[i].bus_type && cdrom_drives[i].sound_on/* && r*/); } else continue; if (soundon && has_audio) { - int32_t audio_vol_l = cdrom_mode_sense_get_volume(i, 0); - int32_t audio_vol_r = cdrom_mode_sense_get_volume(i, 1); + int32_t audio_vol_l = cdrom_mode_sense_get_volume(cdrom[i], 0); + int32_t audio_vol_r = cdrom_mode_sense_get_volume(cdrom[i], 1); int channel_select[2]; - channel_select[0] = cdrom_mode_sense_get_channel(i, 0); - channel_select[1] = cdrom_mode_sense_get_channel(i, 1); + channel_select[0] = cdrom_mode_sense_get_channel(cdrom[i], 0); + channel_select[1] = cdrom_mode_sense_get_channel(cdrom[i], 1); + + if (!r) + { + for (c = 0; c < CD_BUFLEN*2; c += 2) + { + if (sound_is_float) + { + cd_out_buffer[c] += 0.0; + cd_out_buffer[c+1] += 0.0; + } + else + { + cd_out_buffer_int16[c] += 0; + cd_out_buffer_int16[c+1] += 0; + } + } + continue; + } for (c = 0; c < CD_BUFLEN*2; c += 2) { @@ -299,7 +321,7 @@ static int16_t *outbuffer_ex_int16; static int cd_thread_enable = 0; -void sound_realloc_buffers(void) +static void sound_realloc_buffers(void) { if (outbuffer_ex != NULL) { @@ -326,15 +348,10 @@ void sound_init(void) int i = 0; int available_cdrom_drives = 0; - initalmain(0,NULL); - inital(); - outbuffer_ex = NULL; outbuffer_ex_int16 = NULL; - outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int32_t)); - - sound_realloc_buffers(); + outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int32_t)); for (i = 0; i < CDROM_NUM; i++) { @@ -445,7 +462,10 @@ void sound_speed_changed(void) void sound_reset(void) { - int i = 0; + sound_realloc_buffers(); + + midi_device_init(); + inital(); timer_add(sound_poll, &sound_poll_time, TIMER_ALWAYS_ENABLED, NULL); @@ -453,14 +473,19 @@ void sound_reset(void) sound_process_handlers_num = 0; sound_set_cd_volume(65535, 65535); +} - for (i = 0; i < CDROM_NUM; i++) - { - if (cdrom_drives[i].handler->audio_stop) - { - cdrom_drives[i].handler->audio_stop(i); - } - } +void sound_card_reset(void) +{ + sound_card_init(); + if (mpu401_standalone_enable) + mpu401_device_add(); + if (GUS) + device_add(&gus_device); + if (GAMEBLASTER) + device_add(&cms_device); + if (SSI2001) + device_add(&ssi2001_device); } void sound_cd_thread_end(void) @@ -494,7 +519,12 @@ void sound_cd_thread_reset(void) for (i = 0; i < CDROM_NUM; i++) { - if (cdrom_drives[i].bus_type != CDROM_BUS_DISABLED) + if (cdrom[i] && cdrom[i]->handler && cdrom[i]->handler->audio_stop) + { + cdrom[i]->handler->audio_stop(i); + } + + if ((cdrom_drives[i].bus_type != CDROM_BUS_DISABLED) && cdrom[i]) { available_cdrom_drives++; } diff --git a/src/sound/sound.h b/src/sound/sound.h index 05bfe4959..cf49dbf1c 100644 --- a/src/sound/sound.h +++ b/src/sound/sound.h @@ -8,7 +8,7 @@ * * Sound emulation core. * - * Version: @(#)sound.h 1.0.6 2018/03/18 + * Version: @(#)sound.h 1.0.7 2018/04/23 * * Authors: Sarah Walker, * Miran Grca, @@ -55,16 +55,15 @@ extern void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r); extern void sound_speed_changed(void); -extern void sound_realloc_buffers(void); - extern void sound_init(void); extern void sound_reset(void); +extern void sound_card_reset(void); + extern void sound_cd_thread_end(void); extern void sound_cd_thread_reset(void); extern void closeal(void); -extern void initalmain(int argc, char *argv[]); extern void inital(void); extern void givealbuffer(void *buf); extern void givealbuffer_cd(void *buf); diff --git a/src/ui.h b/src/ui.h index fd2f83abc..1e9077cdf 100644 --- a/src/ui.h +++ b/src/ui.h @@ -8,7 +8,7 @@ * * Define the various UI functions. * - * Version: @(#)ui.h 1.0.13 2018/02/06 + * Version: @(#)ui.h 1.0.14 2018/04/24 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -45,11 +45,10 @@ extern void ui_check_menu_item(int id, int checked); #define SB_FLOPPY 0x00 #define SB_CDROM 0x10 #define SB_ZIP 0x20 -#define SB_RDISK 0x30 -#define SB_HDD 0x50 -#define SB_NETWORK 0x60 -#define SB_SOUND 0x70 -#define SB_TEXT 0x80 +#define SB_HDD 0x40 +#define SB_NETWORK 0x50 +#define SB_SOUND 0x60 +#define SB_TEXT 0x70 extern wchar_t *ui_window_title(wchar_t *s); extern void ui_status_update(void); diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index d879ab937..21839465c 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -8,7 +8,7 @@ * * ATI 18800 emulation (VGA Edge-16) * - * Version: @(#)vid_ati18800.c 1.0.9 2018/03/24 + * Version: @(#)vid_ati18800.c 1.0.10 2018/04/09 * * Authors: Sarah Walker, * Miran Grca, @@ -34,14 +34,21 @@ #include "vid_svga_render.h" +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) #define BIOS_ROM_PATH_WONDER L"roms/video/ati18800/VGA_Wonder_V3-1.02.bin" +#endif #define BIOS_ROM_PATH_VGA88 L"roms/video/ati18800/vga88.bin" #define BIOS_ROM_PATH_EDGE16 L"roms/video/ati18800/vgaedge16.vbi" enum { +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) ATI18800_WONDER = 0, ATI18800_VGA88, ATI18800_EDGE16 +#else + ATI18800_VGA88 = 0, + ATI18800_EDGE16 +#endif }; @@ -73,7 +80,7 @@ static void ati18800_out(uint16_t addr, uint8_t val, void *p) break; case 0x1cf: ati18800->regs[ati18800->index] = val; - pclog("ATI 18800 ATI register write %02x %02x\n", ati18800->index, val); + /* pclog("ATI 18800 ATI register write %02x %02x\n", ati18800->index, val); */ switch (ati18800->index) { case 0xb0: @@ -154,9 +161,7 @@ static uint8_t ati18800_in(uint16_t addr, void *p) temp = svga_in(addr, svga); break; } -#ifndef RELEASE_BUILD - if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); -#endif + /* if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); */ return temp; } @@ -188,10 +193,14 @@ static void *ati18800_init(const device_t *info) memset(ati18800, 0, sizeof(ati18800_t)); switch (info->local) { +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) case ATI18800_WONDER: +#endif default: +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_WONDER, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); break; +#endif case ATI18800_VGA88: rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_VGA88, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); break; @@ -216,10 +225,12 @@ static void *ati18800_init(const device_t *info) return ati18800; } +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) static int ati18800_wonder_available(void) { return rom_present(BIOS_ROM_PATH_WONDER); } +#endif static int ati18800_vga88_available(void) { @@ -261,6 +272,7 @@ static void ati18800_add_status_info(char *s, int max_len, void *p) svga_add_status_info(s, max_len, &ati18800->svga); } +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) const device_t ati18800_wonder_device = { "ATI-18800", @@ -274,6 +286,7 @@ const device_t ati18800_wonder_device = ati18800_add_status_info, NULL }; +#endif const device_t ati18800_vga88_device = { diff --git a/src/video/vid_ati_eeprom.c b/src/video/vid_ati_eeprom.c index 6ce2ac238..4bcd9d702 100644 --- a/src/video/vid_ati_eeprom.c +++ b/src/video/vid_ati_eeprom.c @@ -8,19 +8,20 @@ * * Emulation of the EEPROM on select ATI cards. * - * Version: @(#)vid_ati_eeprom.c 1.0.2 2017/11/04 + * Version: @(#)vid_ati_eeprom.c 1.0.2 2018/04/11 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ #include #include #include #include #include "../86box.h" +#include "../device.h" #include "../mem.h" #include "../nvr.h" #include "vid_ati_eeprom.h" diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index b6aa66f97..404c32668 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -8,7 +8,7 @@ * * ATi Mach64 graphics card emulation. * - * Version: @(#)vid_ati_mach64.c 1.0.18 2018/03/24 + * Version: @(#)vid_ati_mach64.c 1.0.19 2018/04/02 * * Authors: Sarah Walker, * Miran Grca, @@ -94,7 +94,7 @@ typedef struct mach64_t uint8_t regs[256]; int index; - int type; + int type, pci; uint8_t pci_regs[256]; uint8_t int_line; @@ -567,7 +567,6 @@ void mach64_updatemapping(mach64_t *mach64) mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000); mem_mapping_set_addr(&mach64->mmio_linear_mapping_2, mach64->linear_base + ((16 << 20) - 0x4000), 0x4000); } - svga->linear_base = mach64->linear_base; } else { @@ -579,6 +578,11 @@ void mach64_updatemapping(mach64_t *mach64) static void mach64_update_irqs(mach64_t *mach64) { + if (!mach64->pci) + { + return; + } + if ((mach64->crtc_int_cntl & 0xaa0024) & ((mach64->crtc_int_cntl << 1) & 0xaa0024)) pci_set_irq(mach64->card, PCI_INTA); else @@ -3434,6 +3438,7 @@ static void *mach64gx_init(const device_t *info) mach64_t *mach64 = mach64_common_init(info); mach64->type = MACH64_GX; + mach64->pci = !!(info->flags & DEVICE_PCI); mach64->pci_id = (int)'X' | ((int)'G' << 8); mach64->config_chip_id = 0x020000d7; mach64->dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/ @@ -3460,6 +3465,7 @@ static void *mach64vt2_init(const device_t *info) svga_t *svga = &mach64->svga; mach64->type = MACH64_VT2; + mach64->pci = 1; mach64->pci_id = 0x5654; mach64->config_chip_id = 0x40005654; mach64->dac_cntl = 1 << 16; /*Internal 24-bit DAC*/ diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 81960c350..01018d118 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -9,7 +9,7 @@ * Emulation of select Cirrus Logic cards (CL-GD 5428, * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). * - * Version: @(#)vid_cl_54xx.c 1.0.16 2018/03/23 + * Version: @(#)vid_cl_54xx.c 1.0.17 2018/04/02 * * Authors: Sarah Walker, * Barry Rodewald, @@ -718,7 +718,6 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) mem_mapping_disable(&svga->mapping); mem_mapping_set_addr(&gd54xx->linear_mapping, base, size); - svga->linear_base = base; if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) { if (size >= (4 * 1024 * 1024)) @@ -745,85 +744,72 @@ gd54xx_recalctimings(svga_t *svga) svga->interlace = (svga->crtc[0x1a] & 0x01); + if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) + svga->render = svga_render_8bpp_highres; + else if (svga->gdcreg[5] & 0x40) + svga->render = svga_render_8bpp_lowres; + svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); - if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) - { - svga->bpp = 8; - svga->render = svga_render_8bpp_highres; - } - else if (svga->gdcreg[5] & 0x40) - { - svga->bpp = 8; - svga->render = svga_render_8bpp_lowres; - } - - if (gd54xx->ramdac.ctrl & 0x80) - { - if (gd54xx->ramdac.ctrl & 0x40) - { - switch (gd54xx->ramdac.ctrl & 0xf) - { - case 0: - svga->bpp = 15; - svga->render = svga_render_15bpp_highres; - break; - - case 1: - svga->bpp = 16; - svga->render = svga_render_16bpp_highres; - break; - - case 5: - if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) && (svga->seqregs[7] & CIRRUS_SR7_BPP_32)) - { + svga->bpp = 8; + + if (gd54xx->ramdac.ctrl & 0x80) { + if (gd54xx->ramdac.ctrl & 0x40) { + switch (gd54xx->ramdac.ctrl & 0xf) { + case 0: + svga->bpp = 15; + svga->render = svga_render_15bpp_highres; + break; + + case 1: + svga->bpp = 16; + svga->render = svga_render_16bpp_highres; + break; + + case 5: + if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) && (svga->seqregs[7] & CIRRUS_SR7_BPP_32)) { + svga->bpp = 32; + svga->render = svga_render_32bpp_highres; + if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) + svga->rowoffset *= 2; + } else { + svga->bpp = 24; + svga->render = svga_render_24bpp_highres; + } + break; + + case 0xf: + switch (svga->seqregs[7] & CIRRUS_SR7_BPP_MASK) { + case CIRRUS_SR7_BPP_32: svga->bpp = 32; svga->render = svga_render_32bpp_highres; - if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) - svga->rowoffset *= 2; - } - else - { + svga->rowoffset *= 2; + break; + + case CIRRUS_SR7_BPP_24: svga->bpp = 24; svga->render = svga_render_24bpp_highres; - } - break; - - case 0xf: - switch (svga->seqregs[7] & CIRRUS_SR7_BPP_MASK) - { - case CIRRUS_SR7_BPP_32: - svga->bpp = 32; - svga->render = svga_render_32bpp_highres; - svga->rowoffset *= 2; - break; - - case CIRRUS_SR7_BPP_24: - svga->bpp = 24; - svga->render = svga_render_24bpp_highres; - break; - - case CIRRUS_SR7_BPP_16: - case CIRRUS_SR7_BPP_16_DOUBLEVCLK: - svga->bpp = 16; - svga->render = svga_render_16bpp_highres; - break; - - case CIRRUS_SR7_BPP_8: - svga->bpp = 8; - svga->render = svga_render_8bpp_highres; - break; - } - break; - } - } - else - { - svga->bpp = 15; - svga->render = svga_render_15bpp_highres; + break; + + case CIRRUS_SR7_BPP_16: + case CIRRUS_SR7_BPP_16_DOUBLEVCLK: + svga->bpp = 16; + svga->render = svga_render_16bpp_highres; + break; + + case CIRRUS_SR7_BPP_8: + svga->bpp = 8; + svga->render = svga_render_8bpp_highres; + break; + } + break; } + } else { + svga->bpp = 15; + svga->render = svga_render_15bpp_highres; } - + } + clocksel = (svga->miscout >> 2) & 3; if (!gd54xx->vclk_n[clocksel] || !gd54xx->vclk_d[clocksel]) @@ -994,9 +980,6 @@ gd54xx_blt_write_l(uint32_t addr, uint32_t val, void *p) } -static void gd54xx_write_linear(uint32_t addr, uint8_t val, gd54xx_t *gd54xx); - - static void gd54xx_write(uint32_t addr, uint8_t val, void *p) { @@ -1018,7 +1001,8 @@ gd54xx_write(uint32_t addr, uint8_t val, void *p) addr &= svga->banked_mask; addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; - gd54xx_write_linear(addr, val, gd54xx); + + svga_write_linear(addr, val, svga); } @@ -1037,12 +1021,12 @@ gd54xx_writew(uint32_t addr, uint16_t val, void *p) addr &= svga->banked_mask; addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; - - if (svga->writemode < 4) - svga_writew_linear(addr, val, svga); + + if (svga->writemode < 4) + svga_writew_linear(addr, val, svga); else { - gd54xx_write_linear(addr, val, gd54xx); - gd54xx_write_linear(addr+1, val >> 8, gd54xx); + svga_write_linear(addr, val, svga); + svga_write_linear(addr + 1, val >> 8, svga); } } @@ -1068,52 +1052,24 @@ gd54xx_writel(uint32_t addr, uint32_t val, void *p) if (svga->writemode < 4) svga_writel_linear(addr, val, svga); else { - gd54xx_write_linear(addr, val, gd54xx); - gd54xx_write_linear(addr+1, val >> 8, gd54xx); - gd54xx_write_linear(addr+2, val >> 16, gd54xx); - gd54xx_write_linear(addr+3, val >> 24, gd54xx); + svga_write_linear(addr, val, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); } } +/* This adds write modes 4 and 5 to SVGA. */ static void -gd54xx_write_linear(uint32_t addr, uint8_t val, gd54xx_t *gd54xx) +gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) { - svga_t *svga = &gd54xx->svga; - uint8_t vala, valb, valc, vald, wm = svga->writemask; - int writemask2 = svga->writemask; - int i; - uint8_t j; - - cycles -= video_timing_write_b; - cycles_lost += video_timing_write_b; - - egawrites++; - - if (!(svga->gdcreg[6] & 1)) - svga->fullchange = 2; - if ((svga->chain4 || svga->fb_only) && (svga->writemode < 4)) { - writemask2 = 1 << (addr & 3); - addr &= ~3; - } else if (svga->chain2_write) { - writemask2 &= ~0xa; - if (addr & 1) - writemask2 <<= 1; - addr &= ~1; - addr <<= 2; - } else - addr <<= 2; - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return; - addr &= svga->vram_mask; - svga->changedvram[addr >> 12]=changeframecount; + uint32_t i, j; switch (svga->writemode) { case 4: if (svga->gdcreg[0xb] & 0x10) { addr <<= 2; - svga->changedvram[addr >> 12] = changeframecount; for (i = 0; i < 8; i++) { if (val & svga->seqregs[2] & (0x80 >> i)) { @@ -1122,173 +1078,41 @@ gd54xx_write_linear(uint32_t addr, uint8_t val, gd54xx_t *gd54xx) } } } else { - addr <<= 1; - svga->changedvram[addr >> 12] = changeframecount; + addr <<= 1; for (i = 0; i < 8; i++) { - if (val & svga->seqregs[2] & (0x80 >> i)) - svga->vram[addr + i] = svga->gdcreg[1]; + if (val & svga->seqregs[2] & (0x80 >> i)) + svga->vram[addr + i] = svga->gdcreg[1]; } - } - break; - - case 5: - if (svga->gdcreg[0xb] & 0x10) - { - addr <<= 2; - svga->changedvram[addr >> 12] = changeframecount; + } + break; + + case 5: + if (svga->gdcreg[0xb] & 0x10) { + addr <<= 2; for (i = 0; i < 8; i++) { j = (0x80 >> i); if (svga->seqregs[2] & j) { - svga->vram[addr + (i << 1)] = (val & j) ? svga->gdcreg[1] : svga->gdcreg[0]; - svga->vram[addr + (i << 1) + 1] = (val & j) ? svga->gdcreg[0x11] : svga->gdcreg[0x10]; + svga->vram[addr + (i << 1)] = (val & j) ? + svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + (i << 1) + 1] = (val & j) ? + svga->gdcreg[0x11] : svga->gdcreg[0x10]; } } - } - else - { - addr <<= 1; - svga->changedvram[addr >> 12] = changeframecount; + } else { + addr <<= 1; for (i = 0; i < 8; i++) { j = (0x80 >> i); if (svga->seqregs[2] & j) svga->vram[addr + i] = (val & j) ? svga->gdcreg[1] : svga->gdcreg[0]; } - } - break; - - case 1: - if (writemask2 & 1) svga->vram[addr] = svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld; - break; - case 0: - if (svga->gdcreg[3] & 7) - val = svga_rotate[svga->gdcreg[3] & 7][val]; - if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { - if (writemask2 & 1) svga->vram[addr] = val; - if (writemask2 & 2) svga->vram[addr | 0x1] = val; - if (writemask2 & 4) svga->vram[addr | 0x2] = val; - if (writemask2 & 8) svga->vram[addr | 0x3] = val; - } else { - if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; - else vala = val; - if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; - else valb = val; - if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; - else valc = val; - if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; - else vald = val; - - switch (svga->gdcreg[3] & 0x18) { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; - break; - } } break; - case 2: - if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) { - if (writemask2 & 1) svga->vram[addr] = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - } else { - vala = ((val & 1) ? 0xff : 0); - valb = ((val & 2) ? 0xff : 0); - valc = ((val & 4) ? 0xff : 0); - vald = ((val & 8) ? 0xff : 0); - switch (svga->gdcreg[3] & 0x18) { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; - break; - } - } - break; - case 3: - if (svga->gdcreg[3] & 7) - val = svga_rotate[svga->gdcreg[3] & 7][val]; - wm = svga->gdcreg[8]; - svga->gdcreg[8] &= val; - - vala = (svga->gdcreg[0] & 1) ? 0xff : 0; - valb = (svga->gdcreg[0] & 2) ? 0xff : 0; - valc = (svga->gdcreg[0] & 4) ? 0xff : 0; - vald = (svga->gdcreg[0] & 8) ? 0xff : 0; - switch (svga->gdcreg[3] & 0x18) { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; - break; - } - svga->gdcreg[8] = wm; - break; } + + svga->changedvram[addr >> 12] = changeframecount; } @@ -1506,10 +1330,7 @@ gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) return; } - if (svga->writemode < 4) - svga_write_linear(addr, val, svga); - else - gd54xx_write_linear(addr, val & 0xff, gd54xx); + svga_write_linear(addr, val, svga); } @@ -1572,14 +1393,14 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) switch(ap) { case 0: default: - gd54xx_write_linear(addr, val & 0xff, gd54xx); - gd54xx_write_linear(addr + 1, val >> 8, gd54xx); + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr + 1, val >> 8, svga); return; case 2: addr ^= 0x00000002; case 1: - gd54xx_write_linear(addr + 1, val & 0xff, gd54xx); - gd54xx_write_linear(addr, val >> 8, gd54xx); + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); case 3: return; } @@ -1662,22 +1483,22 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) switch(ap) { case 0: default: - gd54xx_write_linear(addr, val & 0xff, gd54xx); - gd54xx_write_linear(addr+1, val >> 8, gd54xx); - gd54xx_write_linear(addr+2, val >> 16, gd54xx); - gd54xx_write_linear(addr+3, val >> 24, gd54xx); + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); return; case 1: - gd54xx_write_linear(addr + 1, val & 0xff, gd54xx); - gd54xx_write_linear(addr, val >> 8, gd54xx); - gd54xx_write_linear(addr + 3, val >> 16, gd54xx); - gd54xx_write_linear(addr + 2, val >> 24, gd54xx); + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); + svga_write_linear(addr + 3, val >> 16, svga); + svga_write_linear(addr + 2, val >> 24, svga); return; case 2: - gd54xx_write_linear(addr + 3, val & 0xff, gd54xx); - gd54xx_write_linear(addr + 2, val >> 8, gd54xx); - gd54xx_write_linear(addr + 1, val >> 16, gd54xx); - gd54xx_write_linear(addr, val >> 24, gd54xx); + svga_write_linear(addr + 3, val & 0xff, svga); + svga_write_linear(addr + 2, val >> 8, svga); + svga_write_linear(addr + 1, val >> 16, svga); + svga_write_linear(addr, val >> 24, svga); case 3: return; } @@ -2399,6 +2220,7 @@ static void svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size << 20, gd54xx_recalctimings, gd54xx_in, gd54xx_out, gd54xx_hwcursor_draw, NULL); + svga_set_ven_write(&gd54xx->svga, gd54xx_write_modes45); mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); mem_mapping_set_p(&svga->mapping, gd54xx); diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index defe6a586..af859da47 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -10,7 +10,7 @@ * * Known bugs: Accelerator doesn't work in planar modes * - * Version: @(#)vid_et4000w32.c 1.0.7 2018/03/18 + * Version: @(#)vid_et4000w32.c 1.0.8 2018/04/02 * * Authors: Sarah Walker, * Miran Grca, @@ -360,7 +360,6 @@ void et4000w32p_recalcmapping(et4000w32p_t *et4000) if (svga->crtc[0x36] & 0x10) /*Linear frame buffer*/ { mem_mapping_set_addr(&et4000->linear_mapping, et4000->linearbase, 0x200000); - svga->linear_base = et4000->linearbase; mem_mapping_disable(&svga->mapping); mem_mapping_disable(&et4000->mmu_mapping); } diff --git a/src/video/vid_oak_oti.c b/src/video/vid_oak_oti.c index c3d2ff522..ba24af74c 100644 --- a/src/video/vid_oak_oti.c +++ b/src/video/vid_oak_oti.c @@ -8,7 +8,7 @@ * * Oak OTI037C/67/077 emulation. * - * Version: @(#)vid_oak_oti.c 1.0.10 2018/03/24 + * Version: @(#)vid_oak_oti.c 1.0.11 2018/04/12 * * Authors: Sarah Walker, * Miran Grca, @@ -77,6 +77,8 @@ oti_out(uint16_t addr, uint8_t val, void *p) return; case 0x3D5: + if (svga->crtcreg & 0x20) + return; if (((svga->crtcreg & 31) < 7) && (svga->crtc[0x11] & 0x80)) return; if (((svga->crtcreg & 31) == 7) && (svga->crtc[0x11] & 0x80)) @@ -154,9 +156,12 @@ oti_in(uint16_t addr, void *p) break; case 0x3D5: - temp = svga->crtc[svga->crtcreg & 31]; + if (svga->crtcreg & 0x20) + temp = 0xff; + else + temp = svga->crtc[svga->crtcreg & 31]; break; - + case 0x3DA: svga->attrff = 0; svga->attrff = 0; diff --git a/src/video/vid_paradise.c b/src/video/vid_paradise.c index dda19b26d..b06cc9021 100644 --- a/src/video/vid_paradise.c +++ b/src/video/vid_paradise.c @@ -10,7 +10,7 @@ * PC2086, PC3086 use PVGA1A * MegaPC uses W90C11A * - * Version: @(#)vid_paradise.c 1.0.5 2018/03/18 + * Version: @(#)vid_paradise.c 1.0.6 2018/04/02 * * Authors: Sarah Walker, * Miran Grca, @@ -124,12 +124,11 @@ void paradise_out(uint16_t addr, uint8_t val, void *p) break; case 0x3D4: - if (paradise->type == PVGA1A) - svga->crtcreg = val & 0x1f; - else - svga->crtcreg = val & 0x3f; + svga->crtcreg = val & 0x3f; return; case 0x3D5: + if ((paradise->type == PVGA1A) && (svga->crtcreg & 0x20)) + return; if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -194,6 +193,8 @@ uint8_t paradise_in(uint16_t addr, void *p) case 0x3D4: return svga->crtcreg; case 0x3D5: + if ((paradise->type == PVGA1A) && (svga->crtcreg & 0x20)) + return 0xff; if (svga->crtcreg > 0x29 && svga->crtcreg < 0x30 && (svga->crtc[0x29] & 0x88) != 0x80) return 0xff; return svga->crtc[svga->crtcreg]; @@ -305,8 +306,6 @@ void *paradise_pvga1a_init(const device_t *info, uint32_t memsize) svga->bpp = 8; svga->miscout = 1; - svga->linear_base = 0; - paradise->type = PVGA1A; return paradise; @@ -339,9 +338,7 @@ void *paradise_wd90c11_init(const device_t *info) svga->bpp = 8; svga->miscout = 1; - - svga->linear_base = 0; - + paradise->type = WD90C11; return paradise; @@ -374,9 +371,7 @@ void *paradise_wd90c30_init(const device_t *info, uint32_t memsize) svga->bpp = 8; svga->miscout = 1; - - svga->linear_base = 0; - + paradise->type = WD90C11; return paradise; diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 1df6e8eb3..0fb2e1b2c 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -8,7 +8,7 @@ * * S3 emulation. * - * Version: @(#)vid_s3.c 1.0.8 2018/03/21 + * Version: @(#)vid_s3.c 1.0.9 2018/04/02 * * Authors: Sarah Walker, * Miran Grca, @@ -94,7 +94,7 @@ typedef struct s3_t int width; int bpp; - int chip; + int chip, pci; uint8_t id, id_ext, id_ext_pci; @@ -118,12 +118,13 @@ typedef struct s3_t uint16_t subsys_cntl; uint16_t setup_md; uint8_t advfunc_cntl; - uint16_t cur_y; - uint16_t cur_x; - int16_t desty_axstp; + uint16_t cur_y, cur_y2; + uint16_t cur_x, cur_x2; + uint16_t x2; + int16_t desty_axstp, desty_axstp2; int16_t destx_distp; - int16_t err_term; - int16_t maj_axis_pcnt; + int16_t err_term, err_term2; + int16_t maj_axis_pcnt, maj_axis_pcnt2; uint16_t cmd; uint16_t short_stroke; uint32_t bkgd_color; @@ -142,7 +143,13 @@ typedef struct s3_t int dx, dy; uint32_t src, dest, pattern; int pix_trans_count; - + + int poly_cx, poly_cx2; + int poly_cy, poly_cy2; + int point_1_updated, point_2_updated; + int poly_dx1, poly_dx2; + int poly_x; + uint32_t dat_buf; int dat_count; } accel; @@ -193,6 +200,11 @@ static void s3_wait_fifo_idle(s3_t *s3) static void s3_update_irqs(s3_t *s3) { + if (!s3->pci) + { + return; + } + if (s3->subsys_cntl & s3->subsys_stat & INT_MASK) pci_set_irq(s3->card, PCI_INTA); else @@ -215,34 +227,78 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) { case 0x82e8: s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val; + s3->accel.poly_cy = s3->accel.cur_y; break; case 0x82e9: s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cy = s3->accel.cur_y; + break; + case 0x82ea: + s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xf00) | val; + s3->accel.poly_cy2 = s3->accel.cur_y2; + break; + case 0x82eb: + s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cy2 = s3->accel.cur_y2; break; case 0x86e8: s3->accel.cur_x = (s3->accel.cur_x & 0xf00) | val; + s3->accel.poly_cx = s3->accel.cur_x << 20; + s3->accel.poly_x = s3->accel.poly_cx >> 20; break; case 0x86e9: s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cx = s3->accel.poly_x = s3->accel.cur_x << 20; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + break; + case 0x86ea: + s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xf00) | val; + s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; + break; + case 0x86eb: + s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; break; case 0x8ae8: s3->accel.desty_axstp = (s3->accel.desty_axstp & 0x3f00) | val; + s3->accel.point_1_updated = 1; break; case 0x8ae9: s3->accel.desty_axstp = (s3->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) - s3->accel.desty_axstp |= ~0x3fff; + s3->accel.desty_axstp |= ~0x3fff; + s3->accel.point_1_updated = 1; + break; + case 0x8aea: + s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0x3f00) | val; + s3->accel.point_2_updated = 1; + break; + case 0x8aeb: + s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.desty_axstp2 |= ~0x3fff; + s3->accel.point_2_updated = 1; break; case 0x8ee8: s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val; + s3->accel.point_1_updated = 1; break; case 0x8ee9: s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) - s3->accel.destx_distp |= ~0x3fff; + s3->accel.destx_distp |= ~0x3fff; + s3->accel.point_1_updated = 1; + break; + case 0x8eea: + s3->accel.x2 = (s3->accel.x2 & 0xf00) | val; + s3->accel.point_2_updated = 1; + break; + case 0x8eeb: + s3->accel.x2 = (s3->accel.x2 & 0xff) | ((val & 0xf) << 8); + s3->accel.point_2_updated = 1; break; case 0x92e8: @@ -253,6 +309,14 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (val & 0x20) s3->accel.err_term |= ~0x3fff; break; + case 0x92ea: + s3->accel.err_term2 = (s3->accel.err_term2 & 0x3f00) | val; + break; + case 0x92eb: + s3->accel.err_term2 = (s3->accel.err_term2 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.err_term2 |= ~0x3fff; + break; case 0x96e8: s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0x3f00) | val; @@ -262,6 +326,14 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (val & 0x08) s3->accel.maj_axis_pcnt |= ~0x0fff; break; + case 0x96ea: + s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xf00) | val; + break; + case 0x96eb: + s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xff) | ((val & 0x0f) << 8); + if (val & 0x08) + s3->accel.maj_axis_pcnt2 |= ~0x0fff; + break; case 0x9ae8: s3->accel.cmd = (s3->accel.cmd & 0xff00) | val; @@ -297,10 +369,25 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xa2ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; + } break; case 0xa2eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } break; case 0xa6e8: @@ -320,10 +407,25 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xa6ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; + } break; case 0xa6eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } break; case 0xaae8: @@ -343,10 +445,25 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xaaea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; + } break; case 0xaaeb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } break; case 0xaee8: @@ -366,10 +483,25 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xaeea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; + } break; case 0xaeeb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } break; case 0xb2e8: @@ -389,10 +521,25 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xb2ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; + } break; case 0xb2eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } break; case 0xb6e8: @@ -436,7 +583,14 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) break; case 0xe2eb: s3->accel.pix_trans[3] = val; - if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x600 && (s3->accel.cmd & 0x100) && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, s3->accel.pix_trans[3], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[2], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + } + else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x400) == 0x400 && (s3->accel.cmd & 0x100)) s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); else if ((s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); @@ -452,6 +606,11 @@ static void s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) { if (s3->accel.cmd & 0x1000) val = (val >> 8) | (val << 8); + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } if ((s3->accel.cmd & 0x600) == 0x000) s3_accel_start(8, 1, val | (val << 16), 0, s3); else @@ -473,7 +632,16 @@ static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) { if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) { - if (s3->accel.cmd & 0x400) + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if (s3->accel.cmd & 0x400) { if (s3->accel.cmd & 0x1000) val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); @@ -632,7 +800,12 @@ static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) { if (s3->accel.cmd & 0x1000) val = (val >> 8) | (val << 8); - if ((s3->accel.cmd & 0x600) == 0x000) + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x000) s3_accel_start(8, 1, val | (val << 16), 0, s3); else s3_accel_start(16, 1, val | (val << 16), 0, s3); @@ -663,7 +836,16 @@ static void s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) { if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) { - if (s3->accel.cmd & 0x400) + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if (s3->accel.cmd & 0x400) { if (s3->accel.cmd & 0x1000) val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); @@ -1137,7 +1319,6 @@ void s3_updatemapping(s3_t *s3) break; } s3->linear_base &= ~(s3->linear_size - 1); - svga->linear_base = s3->linear_base; if (s3->linear_base == 0xa0000) { mem_mapping_disable(&s3->linear_mapping); @@ -1428,29 +1609,80 @@ uint8_t s3_accel_read(uint32_t addr, void *p) return 0; } -#define READ(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ - else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ - else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; +static void polygon_setup(s3_t *s3) +{ + if (s3->accel.point_1_updated) + { + int start_x = s3->accel.poly_cx; + int start_y = s3->accel.poly_cy; + int end_x = s3->accel.destx_distp << 20; + int end_y = s3->accel.desty_axstp; + + if (end_y - start_y) + s3->accel.poly_dx1 = (end_x - start_x) / (end_y - start_y); + else + s3->accel.poly_dx1 = 0; + + s3->accel.point_1_updated = 0; -#define MIX switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \ - { \ - case 0x0: dest_dat = ~dest_dat; break; \ - case 0x1: dest_dat = 0; break; \ - case 0x2: dest_dat = ~0; break; \ - case 0x3: dest_dat = dest_dat; break; \ - case 0x4: dest_dat = ~src_dat; break; \ - case 0x5: dest_dat = src_dat ^ dest_dat; break; \ - case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ - case 0x7: dest_dat = src_dat; break; \ - case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ - case 0x9: dest_dat = ~src_dat | dest_dat; break; \ - case 0xa: dest_dat = src_dat | ~dest_dat; break; \ - case 0xb: dest_dat = src_dat | dest_dat; break; \ - case 0xc: dest_dat = src_dat & dest_dat; break; \ - case 0xd: dest_dat = src_dat & ~dest_dat; break; \ - case 0xe: dest_dat = ~src_dat & dest_dat; break; \ - case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + if (end_y == s3->accel.poly_cy) + { + s3->accel.poly_cx = end_x; + s3->accel.poly_x = end_x >> 20; } + } + if (s3->accel.point_2_updated) + { + int start_x = s3->accel.poly_cx2; + int start_y = s3->accel.poly_cy2; + int end_x = s3->accel.x2 << 20; + int end_y = s3->accel.desty_axstp2; + + if (end_y - start_y) + s3->accel.poly_dx2 = (end_x - start_x) / (end_y - start_y); + else + s3->accel.poly_dx2 = 0; + + s3->accel.point_2_updated = 0; + + if (end_y == s3->accel.poly_cy) + s3->accel.poly_cx2 = end_x; + } +} + +#define READ_SRC(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; \ + if (vram_mask) \ + dat = ((dat & rd_mask) == rd_mask); + +#define READ_DST(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; + +#define MIX { \ + uint32_t old_dest_dat = dest_dat; \ + switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = ~0; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } \ + dest_dat = (dest_dat & s3->accel.wrt_mask) | (old_dest_dat & ~s3->accel.wrt_mask); \ + } #define WRITE(addr) if (s3->bpp == 0) \ @@ -1484,6 +1716,11 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat uint32_t *vram_l = (uint32_t *)svga->vram; uint32_t compare = s3->accel.color_cmp; int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; + uint32_t rd_mask = s3->accel.rd_mask; + int cmd = s3->accel.cmd >> 13; + + if ((s3->chip == S3_TRIO64) && (s3->accel.cmd & (1 << 11))) + cmd |= 8; if (!cpu_input) s3->accel.dat_count = 0; if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80) @@ -1505,18 +1742,23 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->bpp == 1) count >>= 1; if (s3->bpp == 3) count >>= 2; } - + + if (s3->bpp == 0) + rd_mask &= 0xff; + else if (s3->bpp == 1) + rd_mask &= 0xffff; + switch (s3->accel.cmd & 0x600) { case 0x000: mix_mask = 0x80; break; case 0x200: mix_mask = 0x8000; break; case 0x400: mix_mask = 0x80000000; break; - case 0x600: mix_mask = 0x80000000; break; + case 0x600: mix_mask = (s3->chip == S3_TRIO32) ? 0x80 : 0x80000000; break; } if (s3->bpp == 0) compare &= 0xff; if (s3->bpp == 1) compare &= 0xffff; - switch (s3->accel.cmd >> 13) + switch (cmd) { case 1: /*Draw line*/ if (!cpu_input) /*!cpu_input is trigger to start operation*/ @@ -1528,6 +1770,15 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.sy = s3->accel.maj_axis_pcnt; } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ frgd_mix = (s3->accel.frgd_mix >> 5) & 3; @@ -1552,7 +1803,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); MIX @@ -1602,7 +1853,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); MIX @@ -1669,14 +1920,14 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.dest = s3->accel.cy * s3->width; } - s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } - if ((s3->accel.cmd & 0x100) && !cpu_input) - { - s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ - return; /*Wait for data from CPU*/ - } - if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ frgd_mix = (s3->accel.frgd_mix >> 5) & 3; @@ -1699,7 +1950,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ(s3->accel.dest + s3->accel.cx, dest_dat); + READ_DST(s3->accel.dest + s3->accel.cx, dest_dat); MIX @@ -1730,8 +1981,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; if (s3->accel.sy < 0) { - s3->accel.cur_x = s3->accel.cx; - s3->accel.cur_y = s3->accel.cy; + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; return; } } @@ -1757,6 +2008,15 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.src = s3->accel.cy * s3->width; s3->accel.dest = s3->accel.dy * s3->width; } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ if (s3->accel.sy < 0) @@ -1774,10 +2034,11 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) { - READ(s3->accel.src + s3->accel.cx, src_dat); - - dest_dat = src_dat; - + READ_SRC(s3->accel.src + s3->accel.cx, src_dat); + READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); + + dest_dat = (src_dat & s3->accel.wrt_mask) | (dest_dat & ~s3->accel.wrt_mask); + WRITE(s3->accel.dest + s3->accel.dx); } @@ -1814,7 +2075,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { if (vram_mask) { - READ(s3->accel.src + s3->accel.cx, mix_dat) + READ_SRC(s3->accel.src + s3->accel.cx, mix_dat) mix_dat = mix_dat ? mix_mask : 0; } switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) @@ -1822,14 +2083,14 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat case 0: src_dat = s3->accel.bkgd_color; break; case 1: src_dat = s3->accel.frgd_color; break; case 2: src_dat = cpu_dat; break; - case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break; + case 3: READ_SRC(s3->accel.src + s3->accel.cx, src_dat); break; } if ((compare_mode == 2 && src_dat != compare) || (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ(s3->accel.dest + s3->accel.dx, dest_dat); + READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); MIX @@ -1918,6 +2179,15 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ frgd_mix = (s3->accel.frgd_mix >> 5) & 3; @@ -1930,7 +2200,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { if (vram_mask) { - READ(s3->accel.src + s3->accel.cx, mix_dat) + READ_SRC(s3->accel.src + s3->accel.cx, mix_dat) mix_dat = mix_dat ? mix_mask : 0; } switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) @@ -1938,14 +2208,14 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat case 0: src_dat = s3->accel.bkgd_color; break; case 1: src_dat = s3->accel.frgd_color; break; case 2: src_dat = cpu_dat; break; - case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break; + case 3: READ_SRC(s3->accel.src + s3->accel.cx, src_dat); break; } if ((compare_mode == 2 && src_dat != compare) || (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ(s3->accel.dest + s3->accel.dx, dest_dat); + READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); MIX @@ -2005,6 +2275,182 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } } break; + + case 3: /*Polygon Fill Solid (Trio64 only)*/ + { + int end_y1, end_y2; + + if (s3->chip != S3_TRIO64) + break; + + polygon_setup(s3); + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + end_y1 = s3->accel.desty_axstp; + end_y2 = s3->accel.desty_axstp2; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + + while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) + { + int y = s3->accel.poly_cy; + int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; + + s3->accel.dest = y * s3->width; + + while (x_count-- && count--) + { + if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && + s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b) + { + switch (frgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; /*Nor supported?*/ break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.poly_x); + } + } + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) + s3->accel.poly_x++; + else + s3->accel.poly_x--; + } + + s3->accel.poly_cx += s3->accel.poly_dx1; + s3->accel.poly_cx2 += s3->accel.poly_dx2; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + + s3->accel.poly_cy++; + s3->accel.poly_cy2++; + + if (!count) + break; + } + + s3->accel.cur_x = s3->accel.poly_cx & 0xfff; + s3->accel.cur_y = s3->accel.poly_cy & 0xfff; + s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; + s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; + } + break; + + case 11: /*Polygon Fill Pattern (Trio64 only)*/ + { + int end_y1, end_y2; + + if (s3->chip != S3_TRIO64) + break; + + polygon_setup(s3); + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + end_y1 = s3->accel.desty_axstp; + end_y2 = s3->accel.desty_axstp2; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) + { + int y = s3->accel.poly_cy; + int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; + + s3->accel.src = s3->accel.pattern + ((y & 7) * s3->width); + s3->accel.dest = y * s3->width; + + while (x_count-- && count--) + { + int pat_x = s3->accel.poly_x & 7; + + if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && + s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b) + { + if (vram_mask) + { + READ_SRC(s3->accel.src + pat_x, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ_SRC(s3->accel.src + pat_x, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.poly_x); + } + } + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + mix_dat <<= 1; + mix_dat |= 1; + + if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) + s3->accel.poly_x++; + else + s3->accel.poly_x--; + } + + s3->accel.poly_cx += s3->accel.poly_dx1; + s3->accel.poly_cx2 += s3->accel.poly_dx2; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + + s3->accel.poly_cy++; + s3->accel.poly_cy2++; + + if (!count) + break; + } + + s3->accel.cur_x = s3->accel.poly_cx & 0xfff; + s3->accel.cur_y = s3->accel.poly_cy & 0xfff; + s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; + s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; + } + break; } } @@ -2086,12 +2532,24 @@ static void s3_io_remove(s3_t *s3) io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); - io_removehandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip == S3_TRIO64) + { + io_sethandler(0x82e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + else + { + io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); @@ -2254,6 +2712,8 @@ static void *s3_init(const device_t *info, wchar_t *bios_fn, int chip) mem_mapping_disable(&s3->bios_rom.mapping); } + s3->pci = !!(info->flags & DEVICE_PCI); + mem_mapping_add(&s3->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &s3->svga); mem_mapping_add(&s3->mmio_mapping, 0xa0000, 0x10000, s3_accel_read, NULL, NULL, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3); mem_mapping_disable(&s3->mmio_mapping); diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index bb104c921..6bedd3655 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -8,7 +8,7 @@ * * S3 ViRGE emulation. * - * Version: @(#)vid_s3_virge.c 1.0.8 2018/03/22 + * Version: @(#)vid_s3_virge.c 1.0.9 2018/04/02 * * Authors: Sarah Walker, * Miran Grca, @@ -701,7 +701,6 @@ static void s3_virge_updatemapping(virge_t *virge) break; } virge->linear_base &= ~(virge->linear_size - 1); - svga->linear_base = virge->linear_base; //pclog("Linear framebuffer at %08X size %08X\n", virge->linear_base, virge->linear_size); if (virge->linear_base == 0xa0000) { diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index cb03307a2..d5c69504d 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -11,7 +11,7 @@ * This is intended to be used by another SVGA driver, * and not as a card in it's own right. * - * Version: @(#)vid_svga.c 1.0.27 2018/03/23 + * Version: @(#)vid_svga.c 1.0.28 2018/04/01 * * Authors: Sarah Walker, * Miran Grca, @@ -42,1512 +42,1318 @@ void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); -extern uint8_t edatlookup[4][4]; +extern int cyc_total; +extern uint8_t edatlookup[4][4]; -uint8_t svga_rotate[8][256]; +uint8_t svga_rotate[8][256]; + +static const uint32_t mask16[16] = { + 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, + 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, + 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, + 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff +}; /*Primary SVGA device. As multiple video cards are not yet supported this is the only SVGA device.*/ -static svga_t *svga_pri; +static svga_t *svga_pri; -svga_t *svga_get_pri() + +svga_t +*svga_get_pri() { - return svga_pri; -} -void svga_set_override(svga_t *svga, int val) -{ - if (svga->override && !val) - svga->fullchange = changeframecount; - svga->override = val; + return svga_pri; } -void svga_out(uint16_t addr, uint8_t val, void *p) + +void +svga_set_override(svga_t *svga, int val) { - svga_t *svga = (svga_t *)p; - int c; - uint8_t o; - switch (addr) - { - case 0x3C0: - case 0x3C1: - if (!svga->attrff) - { - svga->attraddr = val & 31; - if ((val & 0x20) != svga->attr_palette_enable) - { - svga->fullchange = 3; - svga->attr_palette_enable = val & 0x20; - svga_recalctimings(svga); - } - } - else - { + if (svga->override && !val) + svga->fullchange = changeframecount; + svga->override = val; +} + + +/* Used to add custom write modes, eg. by the CL-GD 54xx to add write modes 4 and 5. */ +void +svga_set_ven_write(svga_t *svga, void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr)) +{ + svga->ven_write = ven_write; +} + + +void +svga_out(uint16_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + int c; + uint8_t o; + + switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { o = svga->attrregs[svga->attraddr & 31]; - svga->attrregs[svga->attraddr & 31] = val; - if (svga->attraddr < 16) - svga->fullchange = changeframecount; - if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) - { - for (c = 0; c < 16; c++) - { - if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); - else svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4); - } - } - /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ - if (svga->attraddr == 0x10) - { - if (o != val) svga_recalctimings(svga); - } - else if (svga->attraddr == 0x11) - { - svga->overscan_color = svga->pallook[svga->overscan_color]; - if (o != val) svga_recalctimings(svga); - } - else if (svga->attraddr == 0x12) - { - if ((val & 0xf) != svga->plane_mask) - svga->fullchange = changeframecount; - svga->plane_mask = val & 0xf; - } - } - svga->attrff ^= 1; - break; - case 0x3C2: - svga->miscout = val; - svga->vidclock = val & 4; - io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); - if (!(val & 1)) - io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); - svga_recalctimings(svga); - break; - case 0x3C4: - svga->seqaddr = val; - break; - case 0x3C5: - if (svga->seqaddr > 0xf) return; - o = svga->seqregs[svga->seqaddr & 0xf]; - svga->seqregs[svga->seqaddr & 0xf] = val; - if (o != val && (svga->seqaddr & 0xf) == 1) - svga_recalctimings(svga); - switch (svga->seqaddr & 0xf) - { - case 1: - if (svga->scrblank && !(val & 0x20)) - svga->fullchange = 3; - svga->scrblank = (svga->scrblank & ~0x20) | (val & 0x20); - svga_recalctimings(svga); - break; - case 2: - svga->writemask = val & 0xf; - break; - case 3: - svga->charsetb = (((val >> 2) & 3) * 0x10000) + 2; - svga->charseta = ((val & 3) * 0x10000) + 2; - if (val & 0x10) - svga->charseta += 0x8000; - if (val & 0x20) - svga->charsetb += 0x8000; - break; - case 4: - svga->chain2_write = !(val & 4); - svga->chain4 = val & 8; - svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4; - break; - } - break; - case 0x3c6: - svga->dac_mask = val; - break; - case 0x3C7: - svga->dac_read = val; - svga->dac_pos = 0; - break; - case 0x3C8: - svga->dac_write = val; - svga->dac_read = val - 1; - svga->dac_pos = 0; - break; - case 0x3C9: - svga->dac_status = 0; - svga->fullchange = changeframecount; - switch (svga->dac_pos) - { - case 0: - svga->dac_r = val; - svga->dac_pos++; - break; - case 1: - svga->dac_g = val; - svga->dac_pos++; - break; - case 2: - svga->vgapal[svga->dac_write].r = svga->dac_r; - svga->vgapal[svga->dac_write].g = svga->dac_g; - svga->vgapal[svga->dac_write].b = val; - if (svga->ramdac_type == RAMDAC_8BIT) - svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); - else - svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); - svga->dac_pos = 0; - svga->dac_write = (svga->dac_write + 1) & 255; - break; - } - break; - case 0x3CE: - svga->gdcaddr = val; - break; - case 0x3CF: - o = svga->gdcreg[svga->gdcaddr & 15]; - switch (svga->gdcaddr & 15) - { - case 2: svga->colourcompare=val; break; - case 4: svga->readplane=val&3; break; - case 5: - svga->writemode = val & 3; - svga->readmode = val & 8; - svga->chain2_read = val & 0x10; - break; - case 6: - if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) - { - switch (val&0xC) - { - case 0x0: /*128k at A0000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); - svga->banked_mask = 0xffff; - break; - case 0x4: /*64k at A0000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); - svga->banked_mask = 0xffff; - break; - case 0x8: /*32k at B0000*/ - mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); - svga->banked_mask = 0x7fff; - break; - case 0xC: /*32k at B8000*/ - mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); - svga->banked_mask = 0x7fff; - break; - } - } - break; - case 7: svga->colournocare=val; break; - } - svga->gdcreg[svga->gdcaddr & 15] = val; - svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4; - if (((svga->gdcaddr & 15) == 5 && (val ^ o) & 0x70) || ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) - svga_recalctimings(svga); - break; - } -} - -uint8_t svga_in(uint16_t addr, void *p) -{ - svga_t *svga = (svga_t *)p; - uint8_t temp; - switch (addr) - { - case 0x3C0: - return svga->attraddr | svga->attr_palette_enable; - case 0x3C1: - return svga->attrregs[svga->attraddr]; - case 0x3c2: - if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) - temp = 0; - else - temp = 0x10; - return temp; - case 0x3C4: - return svga->seqaddr; - case 0x3C5: - return svga->seqregs[svga->seqaddr & 0xF]; - case 0x3c6: return svga->dac_mask; - case 0x3c7: return svga->dac_status; - case 0x3c8: return svga->dac_write; - case 0x3c9: - svga->dac_status = 3; - switch (svga->dac_pos) - { - case 0: - svga->dac_pos++; - if (svga->ramdac_type == RAMDAC_8BIT) - return svga->vgapal[svga->dac_read].r; - return svga->vgapal[svga->dac_read].r & 0x3f; - case 1: - svga->dac_pos++; - if (svga->ramdac_type == RAMDAC_8BIT) - return svga->vgapal[svga->dac_read].g; - return svga->vgapal[svga->dac_read].g & 0x3f; - case 2: - svga->dac_pos=0; - svga->dac_read = (svga->dac_read + 1) & 255; - if (svga->ramdac_type == RAMDAC_8BIT) - return svga->vgapal[(svga->dac_read - 1) & 255].b; - return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; - } - break; - case 0x3CC: - return svga->miscout; - case 0x3CE: - return svga->gdcaddr; - case 0x3CF: - /* The spec says GDC addresses 0xF8 to 0xFB return the latch. */ - if (svga->gdcaddr == 0xF8) return svga->la; - if (svga->gdcaddr == 0xF9) return svga->lb; - if (svga->gdcaddr == 0xFA) return svga->lc; - if (svga->gdcaddr == 0xFB) return svga->ld; - return svga->gdcreg[svga->gdcaddr & 0xf]; - case 0x3DA: - svga->attrff = 0; - svga->attrff = 0; - - if (svga->cgastat & 0x01) - svga->cgastat &= ~0x30; - else - svga->cgastat ^= 0x30; - return svga->cgastat; - } - return 0xFF; -} - -void svga_set_ramdac_type(svga_t *svga, int type) -{ - int c; - - if (svga->ramdac_type != type) - { - svga->ramdac_type = type; - - for (c = 0; c < 256; c++) - { - if (svga->ramdac_type == RAMDAC_8BIT) - svga->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b); - else - svga->pallook[c] = makecol32((svga->vgapal[c].r & 0x3f) * 4, (svga->vgapal[c].g & 0x3f) * 4, (svga->vgapal[c].b & 0x3f) * 4); - } - } -} - -void svga_recalctimings(svga_t *svga) -{ - double crtcconst; - double _dispontime, _dispofftime, disptime; - - svga->vtotal = svga->crtc[6]; - svga->dispend = svga->crtc[0x12]; - svga->vsyncstart = svga->crtc[0x10]; - svga->split = svga->crtc[0x18]; - svga->vblankstart = svga->crtc[0x15]; - - if (svga->crtc[7] & 1) svga->vtotal |= 0x100; - if (svga->crtc[7] & 32) svga->vtotal |= 0x200; - svga->vtotal += 2; - - if (svga->crtc[7] & 2) svga->dispend |= 0x100; - if (svga->crtc[7] & 64) svga->dispend |= 0x200; - svga->dispend++; - - if (svga->crtc[7] & 4) svga->vsyncstart |= 0x100; - if (svga->crtc[7] & 128) svga->vsyncstart |= 0x200; - svga->vsyncstart++; - - if (svga->crtc[7] & 0x10) svga->split|=0x100; - if (svga->crtc[9] & 0x40) svga->split|=0x200; - svga->split++; - - if (svga->crtc[7] & 0x08) svga->vblankstart |= 0x100; - if (svga->crtc[9] & 0x20) svga->vblankstart |= 0x200; - svga->vblankstart++; - - svga->hdisp = svga->crtc[1]; - svga->hdisp++; - - svga->htotal = svga->crtc[0]; - svga->htotal += 6; /*+6 is required for Tyrian*/ - - svga->rowoffset = svga->crtc[0x13]; - - svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; - - svga->lowres = svga->attrregs[0x10] & 0x40; - - svga->interlace = 0; - - svga->ma_latch = (svga->crtc[0xc] << 8) | svga->crtc[0xd]; - - svga->hdisp_time = svga->hdisp; - svga->render = svga_render_blank; - if (!svga->scrblank && svga->attr_palette_enable) { - if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - if (svga->seqregs[1] & 8) /*40 column*/ { - svga->render = svga_render_text_40; - svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; - } else { - svga->render = svga_render_text_80; - svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; - } - svga->hdisp_old = svga->hdisp; - } else { - svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; - svga->hdisp_old = svga->hdisp; - - switch (svga->gdcreg[5] & 0x60) { - case 0x00: - if (svga->seqregs[1] & 8) /*Low res (320)*/ - svga->render = svga_render_4bpp_lowres; - else - svga->render = svga_render_4bpp_highres; - break; - case 0x20: /*4 colours*/ - if (svga->seqregs[1] & 8) /*Low res (320)*/ - svga->render = svga_render_2bpp_lowres; - else - svga->render = svga_render_2bpp_highres; - break; - case 0x40: case 0x60: /*256+ colours*/ - switch (svga->bpp) { - case 8: - if (svga->lowres) - svga->render = svga_render_8bpp_lowres; - else - svga->render = svga_render_8bpp_highres; - break; - case 15: - if (svga->lowres) - svga->render = svga_render_15bpp_lowres; - else - svga->render = svga_render_15bpp_highres; - break; - case 16: - if (svga->lowres) - svga->render = svga_render_16bpp_lowres; - else - svga->render = svga_render_16bpp_highres; - break; - case 24: - if (svga->lowres) - svga->render = svga_render_24bpp_lowres; - else - svga->render = svga_render_24bpp_highres; - break; - case 32: - if (svga->lowres) - svga->render = svga_render_32bpp_lowres; - else - svga->render = svga_render_32bpp_highres; - break; - } - break; - } - } - } - - svga->linedbl = svga->crtc[9] & 0x80; - svga->rowcount = svga->crtc[9] & 31; - if (enable_overscan) { - overscan_y = (svga->rowcount + 1) << 1; - if (svga->seqregs[1] & 8) /*Low res (320)*/ - overscan_y <<= 1; - if (overscan_y < 16) - overscan_y = 16; - } - if (svga->recalctimings_ex) - svga->recalctimings_ex(svga); - - if (svga->vblankstart < svga->dispend) - svga->dispend = svga->vblankstart; - - crtcconst = (svga->seqregs[1] & 1) ? (svga->clock * 8.0) : (svga->clock * 9.0); - - disptime = svga->htotal; - _dispontime = svga->hdisp_time; - - if (svga->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } - _dispofftime = disptime - _dispontime; - _dispontime *= crtcconst; - _dispofftime *= crtcconst; - - svga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - svga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); -} - -extern int cyc_total; -void svga_poll(void *p) -{ - svga_t *svga = (svga_t *)p; - int x; - - if (!svga->linepos) { - if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { - svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; - svga->hwcursor_oddeven = 0; - } - - if (svga->displine == svga->hwcursor_latch.y+1 && svga->hwcursor_latch.ena && svga->interlace) { - svga->hwcursor_on = 64 - (svga->hwcursor_latch.yoff + 1); - svga->hwcursor_oddeven = 1; - } - - if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { - svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; - svga->overlay_oddeven = 0; - } - if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace) { - svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; - svga->overlay_oddeven = 1; - } - - svga->vidtime += svga->dispofftime; - svga->cgastat |= 1; - svga->linepos = 1; - - if (svga->dispon) { - svga->hdisp_on=1; - - svga->ma &= svga->vram_display_mask; - if (svga->firstline == 2000) { - svga->firstline = svga->displine; - video_wait_for_buffer(); - } - - if (svga->hwcursor_on || svga->overlay_on) - svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = svga->interlace ? 3 : 2; - - if (!svga->override) - svga->render(svga); - - if (svga->overlay_on) { - if (!svga->override) - svga->overlay_draw(svga, svga->displine); - svga->overlay_on--; - if (svga->overlay_on && svga->interlace) - svga->overlay_on--; - } - - if (svga->hwcursor_on) { - if (!svga->override) - svga->hwcursor_draw(svga, svga->displine); - svga->hwcursor_on--; - if (svga->hwcursor_on && svga->interlace) - svga->hwcursor_on--; - } - - if (svga->lastline < svga->displine) - svga->lastline = svga->displine; - } - - svga->displine++; - if (svga->interlace) - svga->displine++; - if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) - svga->cgastat &= ~8; - svga->vslines++; - if (svga->displine > 1500) - svga->displine = 0; - } else { - svga->vidtime += svga->dispontime; - - if (svga->dispon) - svga->cgastat &= ~1; - svga->hdisp_on = 0; - - svga->linepos = 0; - if (svga->sc == (svga->crtc[11] & 31)) - svga->con = 0; - if (svga->dispon) { - if (svga->linedbl && !svga->linecountff) { - svga->linecountff = 1; - svga->ma = svga->maback; - } else if (svga->sc == svga->rowcount) { - svga->linecountff = 0; - svga->sc = 0; - - svga->maback += (svga->rowoffset << 3); - if (svga->interlace) - svga->maback += (svga->rowoffset << 3); - svga->maback &= svga->vram_display_mask; - svga->ma = svga->maback; - } else { - svga->linecountff = 0; - svga->sc++; - svga->sc &= 31; - svga->ma = svga->maback; - } - } - svga->vc++; - svga->vc &= 2047; - - if (svga->vc == svga->split) { - svga->ma = svga->maback = 0; - if (svga->attrregs[0x10] & 0x20) - svga->scrollcache = 0; - } - if (svga->vc == svga->dispend) { - if (svga->vblank_start) - svga->vblank_start(svga); - svga->dispon=0; - if (svga->crtc[10] & 0x20) svga->cursoron = 0; - else svga->cursoron = svga->blink & 16; - if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) - svga->fullchange = 2; - svga->blink++; - - for (x = 0; x < ((svga->vram_mask+1) >> 12); x++) { - if (svga->changedvram[x]) - svga->changedvram[x]--; - } - if (svga->fullchange) - svga->fullchange--; - } - if (svga->vc == svga->vsyncstart) { - int wx, wy; - svga->dispon=0; - svga->cgastat |= 8; - x = svga->hdisp; - - if (svga->interlace && !svga->oddeven) svga->lastline++; - if (svga->interlace && svga->oddeven) svga->firstline--; - - wx = x; - wy = svga->lastline - svga->firstline; - - if (!svga->override) - svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga); - - svga->firstline = 2000; - svga->lastline = 0; - - svga->firstline_draw = 2000; - svga->lastline_draw = 0; - - svga->oddeven ^= 1; - - changeframecount = svga->interlace ? 3 : 2; - svga->vslines = 0; - - if (svga->interlace && svga->oddeven) svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1); - else svga->ma = svga->maback = svga->ma_latch; - svga->ca = (svga->crtc[0xe] << 8) | svga->crtc[0xf]; - - svga->ma <<= 2; - svga->maback <<= 2; - svga->ca <<= 2; - - svga->video_res_x = wx; - svga->video_res_y = wy + 1; - if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ - svga->video_res_x /= (svga->seqregs[1] & 1) ? 8 : 9; - svga->video_res_y /= (svga->crtc[9] & 31) + 1; - svga->video_bpp = 0; - } else { - if (svga->crtc[9] & 0x80) - svga->video_res_y /= 2; - if (!(svga->crtc[0x17] & 2)) - svga->video_res_y *= 4; - else if (!(svga->crtc[0x17] & 1)) - svga->video_res_y *= 2; - svga->video_res_y /= (svga->crtc[9] & 31) + 1; - if (svga->lowres) - svga->video_res_x /= 2; - - svga->video_bpp = svga->bpp; - } - } - if (svga->vc == svga->vtotal) { - svga->vc = 0; - svga->sc = svga->crtc[8] & 0x1f; - svga->dispon = 1; - svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; - svga->scrollcache = svga->attrregs[0x13] & 7; - svga->linecountff = 0; - - svga->hwcursor_on = 0; - svga->hwcursor_latch = svga->hwcursor; - - svga->overlay_on = 0; - svga->overlay_latch = svga->overlay; - } - if (svga->sc == (svga->crtc[10] & 31)) - svga->con = 1; - } -} - -int svga_init(svga_t *svga, void *p, int memsize, - void (*recalctimings_ex)(struct svga_t *svga), - uint8_t (*video_in) (uint16_t addr, void *p), - void (*video_out)(uint16_t addr, uint8_t val, void *p), - void (*hwcursor_draw)(struct svga_t *svga, int displine), - void (*overlay_draw)(struct svga_t *svga, int displine)) -{ - int c, d, e; - - svga->p = p; - - for (c = 0; c < 256; c++) { - e = c; - for (d = 0; d < 8; d++) { - svga_rotate[d][c] = e; - e = (e >> 1) | ((e & 1) ? 0x80 : 0); - } - } - svga->readmode = 0; - - svga->attrregs[0x11] = 0; - svga->overscan_color = 0x000000; - - overscan_x = 16; - overscan_y = 32; - - svga->crtc[0] = 63; - svga->crtc[6] = 255; - svga->dispontime = 1000 * (1 << TIMER_SHIFT); - svga->dispofftime = 1000 * (1 << TIMER_SHIFT); - svga->bpp = 8; - svga->vram = malloc(memsize); - svga->vram_max = memsize; - svga->vram_display_mask = memsize - 1; - svga->vram_mask = memsize - 1; - svga->decode_mask = 0x7fffff; - svga->changedvram = malloc(/*(memsize >> 12) << 1*/0x800000 >> 12); - svga->recalctimings_ex = recalctimings_ex; - svga->video_in = video_in; - svga->video_out = video_out; - svga->hwcursor_draw = hwcursor_draw; - svga->overlay_draw = overlay_draw; - - mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); - - timer_add(svga_poll, &svga->vidtime, TIMER_ALWAYS_ENABLED, svga); - - svga_pri = svga; - - svga->ramdac_type = RAMDAC_6BIT; - - return 0; -} - -void svga_close(svga_t *svga) -{ - free(svga->changedvram); - free(svga->vram); - - svga_pri = NULL; -} - -void svga_write(uint32_t addr, uint8_t val, void *p) -{ - svga_t *svga = (svga_t *)p; - uint8_t vala, valb, valc, vald, wm = svga->writemask; - int writemask2 = svga->writemask; - - egawrites++; - - cycles -= video_timing_write_b; - cycles_lost += video_timing_write_b; - - if (svga_output) pclog("Writeega %06X ",addr); - addr &= svga->banked_mask; - addr += svga->write_bank; - - if (!(svga->gdcreg[6] & 1)) svga->fullchange=2; - if (svga->chain4 || svga->fb_only) - { - writemask2=1<<(addr&3); - addr&=~3; - } - else if (svga->chain2_write) - { - writemask2 &= ~0xa; - if (addr & 1) - writemask2 <<= 1; - addr &= ~1; - addr <<= 2; - } - else - { - addr<<=2; - } - addr &= svga->decode_mask; - - if (addr >= svga->vram_max) - return; - - addr &= svga->vram_mask; - - if (svga_output) pclog("%08X (%i, %i) %02X %i %i %i %02X\n", addr, addr & 1023, addr >> 10, val, writemask2, svga->writemode, svga->chain4, svga->gdcreg[8]); - svga->changedvram[addr >> 12] = changeframecount; - - switch (svga->writemode) - { - case 1: - if (writemask2 & 1) svga->vram[addr] = svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld; - break; - case 0: - if (svga->gdcreg[3] & 7) - val = svga_rotate[svga->gdcreg[3] & 7][val]; - if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) - { - if (writemask2 & 1) svga->vram[addr] = val; - if (writemask2 & 2) svga->vram[addr | 0x1] = val; - if (writemask2 & 4) svga->vram[addr | 0x2] = val; - if (writemask2 & 8) svga->vram[addr | 0x3] = val; - } - else - { - if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; - else vala = val; - if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; - else valb = val; - if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; - else valc = val; - if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; - else vald = val; - - switch (svga->gdcreg[3] & 0x18) - { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; - break; - } -// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); - } - break; - case 2: - if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) - { - if (writemask2 & 1) svga->vram[addr] = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - } - else - { - vala = ((val & 1) ? 0xff : 0); - valb = ((val & 2) ? 0xff : 0); - valc = ((val & 4) ? 0xff : 0); - vald = ((val & 8) ? 0xff : 0); - switch (svga->gdcreg[3] & 0x18) - { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; - break; - } - } - break; - case 3: - if (svga->gdcreg[3] & 7) - val = svga_rotate[svga->gdcreg[3] & 7][val]; - wm = svga->gdcreg[8]; - svga->gdcreg[8] &= val; - - vala = (svga->gdcreg[0] & 1) ? 0xff : 0; - valb = (svga->gdcreg[0] & 2) ? 0xff : 0; - valc = (svga->gdcreg[0] & 4) ? 0xff : 0; - vald = (svga->gdcreg[0] & 8) ? 0xff : 0; - switch (svga->gdcreg[3] & 0x18) - { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; - break; - } - svga->gdcreg[8] = wm; - break; - } -} - -uint8_t svga_read(uint32_t addr, void *p) -{ - svga_t *svga = (svga_t *)p; - uint8_t temp, temp2, temp3, temp4; - uint32_t latch_addr; - int readplane = svga->readplane; - - cycles -= video_timing_read_b; - cycles_lost += video_timing_read_b; - - egareads++; -// pclog("Readega %06X ",addr); - - addr &= svga->banked_mask; - addr += svga->read_bank; - - latch_addr = (addr << 2) & svga->decode_mask; - -// pclog("%05X %i %04X:%04X %02X %02X %i\n",addr,svga->chain4,CS,pc, vram[addr & 0x7fffff], vram[(addr << 2) & 0x7fffff], svga->readmode); -// pclog("%i\n", svga->readmode); - if (svga->chain4 || svga->fb_only) - { - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return 0xff; - return svga->vram[addr & svga->vram_mask]; - } - else if (svga->chain2_read) - { - readplane = (readplane & 2) | (addr & 1); - addr &= ~1; - addr <<= 2; - } - else - addr<<=2; - - addr &= svga->decode_mask; - - if (latch_addr >= svga->vram_max) - { - svga->la = svga->lb = svga->lc = svga->ld = 0xff; - } - else - { - latch_addr &= svga->vram_mask; - svga->la = svga->vram[latch_addr]; - svga->lb = svga->vram[latch_addr | 0x1]; - svga->lc = svga->vram[latch_addr | 0x2]; - svga->ld = svga->vram[latch_addr | 0x3]; - } - - if (addr >= svga->vram_max) - return 0xff; - - addr &= svga->vram_mask; - - if (svga->readmode) - { - temp = svga->la; - temp ^= (svga->colourcompare & 1) ? 0xff : 0; - temp &= (svga->colournocare & 1) ? 0xff : 0; - temp2 = svga->lb; - temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; - temp2 &= (svga->colournocare & 2) ? 0xff : 0; - temp3 = svga->lc; - temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; - temp3 &= (svga->colournocare & 4) ? 0xff : 0; - temp4 = svga->ld; - temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; - temp4 &= (svga->colournocare & 8) ? 0xff : 0; - return ~(temp | temp2 | temp3 | temp4); - } -//pclog("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane); - - return svga->vram[addr | readplane]; -} - -void svga_write_linear(uint32_t addr, uint8_t val, void *p) -{ - svga_t *svga = (svga_t *)p; - uint8_t vala, valb, valc, vald, wm = svga->writemask; - int writemask2 = svga->writemask; - - cycles -= video_timing_write_b; - cycles_lost += video_timing_write_b; - - egawrites++; - - if (svga_output) pclog("Write LFB %08X %02X ", addr, val); - if (!(svga->gdcreg[6] & 1)) - svga->fullchange = 2; - if (svga->chain4 || svga->fb_only) - { - writemask2=1<<(addr&3); - addr&=~3; - } - else if (svga->chain2_write) - { - writemask2 &= ~0xa; - if (addr & 1) - writemask2 <<= 1; - addr &= ~1; - addr <<= 2; - } - else - { - addr<<=2; - } - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return; - addr &= svga->vram_mask; - if (svga_output) pclog("%08X\n", addr); - svga->changedvram[addr >> 12]=changeframecount; - - switch (svga->writemode) - { - case 1: - if (writemask2 & 1) svga->vram[addr] = svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld; - break; - case 0: - if (svga->gdcreg[3] & 7) - val = svga_rotate[svga->gdcreg[3] & 7][val]; - if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) - { - if (writemask2 & 1) svga->vram[addr] = val; - if (writemask2 & 2) svga->vram[addr | 0x1] = val; - if (writemask2 & 4) svga->vram[addr | 0x2] = val; - if (writemask2 & 8) svga->vram[addr | 0x3] = val; - } - else - { - if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; - else vala = val; - if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; - else valb = val; - if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; - else valc = val; - if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; - else vald = val; - - switch (svga->gdcreg[3] & 0x18) - { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; - break; - } -// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); - } - break; - case 2: - if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) - { - if (writemask2 & 1) svga->vram[addr] = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - } - else - { - vala = ((val & 1) ? 0xff : 0); - valb = ((val & 2) ? 0xff : 0); - valc = ((val & 4) ? 0xff : 0); - vald = ((val & 8) ? 0xff : 0); - switch (svga->gdcreg[3] & 0x18) - { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; - break; - } - } - break; - case 3: - if (svga->gdcreg[3] & 7) - val = svga_rotate[svga->gdcreg[3] & 7][val]; - wm = svga->gdcreg[8]; - svga->gdcreg[8] &= val; - - vala = (svga->gdcreg[0] & 1) ? 0xff : 0; - valb = (svga->gdcreg[0] & 2) ? 0xff : 0; - valc = (svga->gdcreg[0] & 4) ? 0xff : 0; - vald = (svga->gdcreg[0] & 8) ? 0xff : 0; - switch (svga->gdcreg[3] & 0x18) - { - case 0: /*Set*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); - break; - case 8: /*AND*/ - if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; - break; - case 0x10: /*OR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; - break; - case 0x18: /*XOR*/ - if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; - if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; - if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; - if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; - break; - } - svga->gdcreg[8] = wm; - break; - } -} - -uint8_t svga_read_linear(uint32_t addr, void *p) -{ - svga_t *svga = (svga_t *)p; - uint8_t temp, temp2, temp3, temp4; - int readplane = svga->readplane; - - cycles -= video_timing_read_b; - cycles_lost += video_timing_read_b; - - egareads++; - - if (svga->chain4 || svga->fb_only) - { - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return 0xff; - return svga->vram[addr & svga->vram_mask]; - } - else if (svga->chain2_read) - { - readplane = (readplane & 2) | (addr & 1); - addr &= ~1; - addr <<= 2; - } - else - addr<<=2; - - addr &= svga->decode_mask; - - if (addr >= svga->vram_max) - return 0xff; - - addr &= svga->vram_mask; - - svga->la = svga->vram[addr]; - svga->lb = svga->vram[addr | 0x1]; - svga->lc = svga->vram[addr | 0x2]; - svga->ld = svga->vram[addr | 0x3]; - if (svga->readmode) - { - temp = svga->la; - temp ^= (svga->colourcompare & 1) ? 0xff : 0; - temp &= (svga->colournocare & 1) ? 0xff : 0; - temp2 = svga->lb; - temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; - temp2 &= (svga->colournocare & 2) ? 0xff : 0; - temp3 = svga->lc; - temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; - temp3 &= (svga->colournocare & 4) ? 0xff : 0; - temp4 = svga->ld; - temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; - temp4 &= (svga->colournocare & 8) ? 0xff : 0; - return ~(temp | temp2 | temp3 | temp4); - } - return svga->vram[addr | readplane]; -} - -void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) -{ - int y_add = (enable_overscan) ? overscan_y : 0; - int x_add = (enable_overscan) ? 16 : 0; - uint32_t *p, i, j; - - svga->frames++; - - if ((xsize > 2032) || (ysize > 2032)) { - x_add = 0; - y_add = 0; - suppress_overscan = 1; - } else - suppress_overscan = 0; - - if (y1 > y2) { - video_blit_memtoscreen(32, 0, 0, 0, xsize + x_add, ysize + y_add); - return; - } - - if ((wx != xsize) || ((wy + 1) != ysize) || video_force_resize_get()) { - /* Screen res has changed.. fix up, and let them know. */ - xsize = wx; - ysize = wy+1; - if (xsize<64) xsize = 640; - if (ysize<32) ysize = 200; - - set_screen_size(xsize+x_add,ysize+y_add); - - if (video_force_resize_get()) - video_force_resize_set(0); - } - - if (enable_overscan && !suppress_overscan) { - if ((wx >= 160) && ((wy + 1) >= 120)) { - /* Draw (overscan_size - scroll size) lines of overscan on top. */ - for (i = 0; i < (y_add >> 1); i++) { - p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; - - for (j = 0; j < (xsize + x_add); j++) - p[j] = svga_color_transform(svga->overscan_color); - } - - /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ - for (i = 0; i < (y_add >> 1); i++) { - p = &((uint32_t *)buffer32->line[(ysize + (y_add >> 1) + i) & 0x7ff])[32]; - - for (j = 0; j < (xsize + x_add); j++) - p[j] = svga_color_transform(svga->overscan_color); - } - - for (i = (y_add >> 1); i < (ysize + (y_add >> 1)); i ++) { - p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; - - for (j = 0; j < 8; j++) { - p[j] = svga->pallook[svga->overscan_color]; - p[xsize + (x_add >> 1) + j] = svga_color_transform(svga->overscan_color); + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (svga->attrregs[0x10] & 0x80) { + svga->egapal[c] = (svga->attrregs[c] & 0xf) | + ((svga->attrregs[0x14] & 0xf) << 4); + } else { + svga->egapal[c] = (svga->attrregs[c] & 0x3f) | + ((svga->attrregs[0x14] & 0xc) << 4); + } } } + /* Recalculate timings on change of attribute register 0x11 + (overscan border color) too. */ + if (svga->attraddr == 0x10) { + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + break; + case 0x3c2: + svga->miscout = val; + svga->vidclock = val & 4; + io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); + if (!(val & 1)) + io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); + svga_recalctimings(svga); + break; + case 0x3c4: + svga->seqaddr = val; + break; + case 0x3c5: + if (svga->seqaddr > 0xf) + return; + o = svga->seqregs[svga->seqaddr & 0xf]; + svga->seqregs[svga->seqaddr & 0xf] = val; + if (o != val && (svga->seqaddr & 0xf) == 1) + svga_recalctimings(svga); + switch (svga->seqaddr & 0xf) { + case 1: + if (svga->scrblank && !(val & 0x20)) + svga->fullchange = 3; + svga->scrblank = (svga->scrblank & ~0x20) | (val & 0x20); + svga_recalctimings(svga); + break; + case 2: + svga->writemask = val & 0xf; + break; + case 3: + svga->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + svga->charseta = ((val & 3) * 0x10000) + 2; + if (val & 0x10) + svga->charseta += 0x8000; + if (val & 0x20) + svga->charsetb += 0x8000; + break; + case 4: + svga->chain2_write = !(val & 4); + svga->chain4 = val & 8; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4; + break; + } + break; + case 0x3c6: + svga->dac_mask = val; + break; + case 0x3C7: + svga->dac_read = val; + svga->dac_pos = 0; + break; + case 0x3c8: + svga->dac_write = val; + svga->dac_read = val - 1; + svga->dac_pos = 0; + break; + case 0x3c9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); + else + svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + svga->dac_pos = 0; + svga->dac_write = (svga->dac_write + 1) & 255; + break; + } + break; + case 0x3ce: + svga->gdcaddr = val; + break; + case 0x3cf: + o = svga->gdcreg[svga->gdcaddr & 15]; + switch (svga->gdcaddr & 15) { + case 2: + svga->colourcompare=val; + break; + case 4: + svga->readplane = val & 3; + break; + case 5: + svga->writemode = val & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + break; + case 6: + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { + switch (val&0xC) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + break; + case 7: + svga->colournocare=val; + break; + } + svga->gdcreg[svga->gdcaddr & 15] = val; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4; + if (((svga->gdcaddr & 15) == 5 && (val ^ o) & 0x70) || + ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) + svga_recalctimings(svga); + break; + } +} + + +uint8_t +svga_in(uint16_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3c0: + ret = svga->attraddr | svga->attr_palette_enable; + break; + case 0x3c1: + ret = svga->attrregs[svga->attraddr]; + break; + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) + ret = 0; + else + ret = 0x10; + break; + case 0x3c4: + ret = svga->seqaddr; + break; + case 0x3c5: + ret = svga->seqregs[svga->seqaddr & 0x0f]; + break; + case 0x3c6: + ret = svga->dac_mask; + break; + case 0x3c7: + ret = svga->dac_status; + break; + case 0x3c8: + ret = svga->dac_write; + break; + case 0x3c9: + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[svga->dac_read].r; + else + ret = svga->vgapal[svga->dac_read].r & 0x3f; + break; + case 1: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[svga->dac_read].g; + else + ret = svga->vgapal[svga->dac_read].g & 0x3f; + break; + case 2: + svga->dac_pos=0; + svga->dac_read = (svga->dac_read + 1) & 255; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[(svga->dac_read - 1) & 255].b; + else + ret = svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + break; + } + break; + case 0x3cc: + ret = svga->miscout; + break; + case 0x3ce: + ret = svga->gdcaddr; + break; + case 0x3cf: + /* The spec says GDC addresses 0xF8 to 0xFB return the latch. */ + switch(svga->gdcaddr) { + case 0xf8: + ret = (svga->latch & 0xFF); + break; + case 0xf9: + ret = ((svga->latch & 0xFF00) >> 8); + break; + case 0xfa: + ret = ((svga->latch & 0xFF0000) >> 16); + break; + case 0xfb: + ret = ((svga->latch & 0xFF000000) >> 24); + break; + default: + ret = svga->gdcreg[svga->gdcaddr & 0xf]; + break; + } + break; + case 0x3da: + svga->attrff = 0; + svga->attrff = 0; + + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x30; + else + svga->cgastat ^= 0x30; + ret = svga->cgastat; + break; + } + + return(ret); +} + + +void +svga_set_ramdac_type(svga_t *svga, int type) +{ + int c; + + if (svga->ramdac_type != type) { + svga->ramdac_type = type; + + for (c = 0; c < 256; c++) { + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b); + else + svga->pallook[c] = makecol32((svga->vgapal[c].r & 0x3f) * 4, + (svga->vgapal[c].g & 0x3f) * 4, + (svga->vgapal[c].b & 0x3f) * 4); + } + } +} + + +void +svga_recalctimings(svga_t *svga) +{ + double crtcconst, _dispontime, _dispofftime, disptime; + + svga->vtotal = svga->crtc[6]; + svga->dispend = svga->crtc[0x12]; + svga->vsyncstart = svga->crtc[0x10]; + svga->split = svga->crtc[0x18]; + svga->vblankstart = svga->crtc[0x15]; + + if (svga->crtc[7] & 1) + svga->vtotal |= 0x100; + if (svga->crtc[7] & 32) + svga->vtotal |= 0x200; + svga->vtotal += 2; + + if (svga->crtc[7] & 2) + svga->dispend |= 0x100; + if (svga->crtc[7] & 64) + svga->dispend |= 0x200; + svga->dispend++; + + if (svga->crtc[7] & 4) + svga->vsyncstart |= 0x100; + if (svga->crtc[7] & 128) + svga->vsyncstart |= 0x200; + svga->vsyncstart++; + + if (svga->crtc[7] & 0x10) + svga->split|=0x100; + if (svga->crtc[9] & 0x40) + svga->split|=0x200; + svga->split++; + + if (svga->crtc[7] & 0x08) + svga->vblankstart |= 0x100; + if (svga->crtc[9] & 0x20) + svga->vblankstart |= 0x200; + svga->vblankstart++; + + svga->hdisp = svga->crtc[1]; + svga->hdisp++; + + svga->htotal = svga->crtc[0]; + svga->htotal += 6; /*+6 is required for Tyrian*/ + + svga->rowoffset = svga->crtc[0x13]; + + svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; + + svga->lowres = svga->attrregs[0x10] & 0x40; + + svga->interlace = 0; + + svga->ma_latch = (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + + svga->hdisp_time = svga->hdisp; + svga->render = svga_render_blank; + if (!svga->scrblank && svga->attr_palette_enable) { + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + if (svga->seqregs[1] & 8) /*40 column*/ { + svga->render = svga_render_text_40; + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + } else { + svga->render = svga_render_text_80; + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + } + svga->hdisp_old = svga->hdisp; + } else { + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + svga->hdisp_old = svga->hdisp; + + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: case 0x60: /*256+ colours*/ + switch (svga->bpp) { + case 8: + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + break; + case 15: + if (svga->lowres) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; + break; + case 16: + if (svga->lowres) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; + case 24: + if (svga->lowres) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; + case 32: + if (svga->lowres) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + break; + } + break; + } + } + } + + svga->linedbl = svga->crtc[9] & 0x80; + svga->rowcount = svga->crtc[9] & 31; + if (enable_overscan) { + overscan_y = (svga->rowcount + 1) << 1; + if (svga->seqregs[1] & 8) /*Low res (320)*/ + overscan_y <<= 1; + if (overscan_y < 16) + overscan_y = 16; + } + if (svga->recalctimings_ex) + svga->recalctimings_ex(svga); + + if (svga->vblankstart < svga->dispend) + svga->dispend = svga->vblankstart; + + crtcconst = (svga->seqregs[1] & 1) ? (svga->clock * 8.0) : (svga->clock * 9.0); + + disptime = svga->htotal; + _dispontime = svga->hdisp_time; + + if (svga->seqregs[1] & 8) { + disptime *= 2; + _dispontime *= 2; + } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + svga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + svga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +void +svga_poll(void *p) +{ + svga_t *svga = (svga_t *)p; + uint32_t x; + int wx, wy; + + if (!svga->linepos) { + if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { + svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; + svga->hwcursor_oddeven = 0; + } + + if (svga->displine == (svga->hwcursor_latch.y + 1) && svga->hwcursor_latch.ena && + svga->interlace) { + svga->hwcursor_on = 64 - (svga->hwcursor_latch.yoff + 1); + svga->hwcursor_oddeven = 1; + } + + if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 0; + } + + if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace) { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 1; + } + + svga->vidtime += svga->dispofftime; + svga->cgastat |= 1; + svga->linepos = 1; + + if (svga->dispon) { + svga->hdisp_on=1; + + svga->ma &= svga->vram_display_mask; + if (svga->firstline == 2000) { + svga->firstline = svga->displine; + video_wait_for_buffer(); + } + + if (svga->hwcursor_on || svga->overlay_on) { + svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = + svga->interlace ? 3 : 2; + } + + if (!svga->override) + svga->render(svga); + + if (svga->overlay_on) { + if (!svga->override) + svga->overlay_draw(svga, svga->displine); + svga->overlay_on--; + if (svga->overlay_on && svga->interlace) + svga->overlay_on--; + } + + if (svga->hwcursor_on) { + if (!svga->override) + svga->hwcursor_draw(svga, svga->displine); + svga->hwcursor_on--; + if (svga->hwcursor_on && svga->interlace) + svga->hwcursor_on--; + } + + if (svga->lastline < svga->displine) + svga->lastline = svga->displine; + } + + svga->displine++; + if (svga->interlace) + svga->displine++; + if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) + svga->cgastat &= ~8; + svga->vslines++; + if (svga->displine > 1500) + svga->displine = 0; + } else { + svga->vidtime += svga->dispontime; + + if (svga->dispon) + svga->cgastat &= ~1; + svga->hdisp_on = 0; + + svga->linepos = 0; + if (svga->sc == (svga->crtc[11] & 31)) + svga->con = 0; + if (svga->dispon) { + if (svga->linedbl && !svga->linecountff) { + svga->linecountff = 1; + svga->ma = svga->maback; + } else if (svga->sc == svga->rowcount) { + svga->linecountff = 0; + svga->sc = 0; + + svga->maback += (svga->rowoffset << 3); + if (svga->interlace) + svga->maback += (svga->rowoffset << 3); + svga->maback &= svga->vram_display_mask; + svga->ma = svga->maback; + } else { + svga->linecountff = 0; + svga->sc++; + svga->sc &= 31; + svga->ma = svga->maback; + } + } + svga->vc++; + svga->vc &= 2047; + + if (svga->vc == svga->split) { + svga->ma = svga->maback = 0; + if (svga->attrregs[0x10] & 0x20) + svga->scrollcache = 0; + } + if (svga->vc == svga->dispend) { + if (svga->vblank_start) + svga->vblank_start(svga); + svga->dispon=0; + if (svga->crtc[10] & 0x20) + svga->cursoron = 0; + else + svga->cursoron = svga->blink & 16; + + if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) + svga->fullchange = 2; + svga->blink++; + + for (x = 0; x < ((svga->vram_mask + 1) >> 12); x++) { + if (svga->changedvram[x]) + svga->changedvram[x]--; + } + if (svga->fullchange) + svga->fullchange--; + } + if (svga->vc == svga->vsyncstart) { + svga->dispon = 0; + svga->cgastat |= 8; + x = svga->hdisp; + + if (svga->interlace && !svga->oddeven) + svga->lastline++; + if (svga->interlace && svga->oddeven) + svga->firstline--; + + wx = x; + wy = svga->lastline - svga->firstline; + + if (!svga->override) + svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga); + + svga->firstline = 2000; + svga->lastline = 0; + + svga->firstline_draw = 2000; + svga->lastline_draw = 0; + + svga->oddeven ^= 1; + + changeframecount = svga->interlace ? 3 : 2; + svga->vslines = 0; + + if (svga->interlace && svga->oddeven) + svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1); + else + svga->ma = svga->maback = svga->ma_latch; + svga->ca = (svga->crtc[0xe] << 8) | svga->crtc[0xf]; + + svga->ma <<= 2; + svga->maback <<= 2; + svga->ca <<= 2; + + svga->video_res_x = wx; + svga->video_res_y = wy + 1; + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + svga->video_res_x /= (svga->seqregs[1] & 1) ? 8 : 9; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + svga->video_bpp = 0; + } else { + if (svga->crtc[9] & 0x80) + svga->video_res_y /= 2; + if (!(svga->crtc[0x17] & 2)) + svga->video_res_y *= 4; + else if (!(svga->crtc[0x17] & 1)) + svga->video_res_y *= 2; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + if (svga->lowres) + svga->video_res_x /= 2; + + svga->video_bpp = svga->bpp; + } + } + if (svga->vc == svga->vtotal) { + svga->vc = 0; + svga->sc = svga->crtc[8] & 0x1f; + svga->dispon = 1; + svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; + svga->scrollcache = svga->attrregs[0x13] & 7; + svga->linecountff = 0; + + svga->hwcursor_on = 0; + svga->hwcursor_latch = svga->hwcursor; + + svga->overlay_on = 0; + svga->overlay_latch = svga->overlay; + } + if (svga->sc == (svga->crtc[10] & 31)) + svga->con = 1; + } +} + + +int +svga_init(svga_t *svga, void *p, int memsize, + void (*recalctimings_ex)(struct svga_t *svga), + uint8_t (*video_in) (uint16_t addr, void *p), + void (*video_out)(uint16_t addr, uint8_t val, void *p), + void (*hwcursor_draw)(struct svga_t *svga, int displine), + void (*overlay_draw)(struct svga_t *svga, int displine)) +{ + int c, d, e; + + svga->p = p; + + for (c = 0; c < 256; c++) { + e = c; + for (d = 0; d < 8; d++) { + svga_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + svga->readmode = 0; + + svga->attrregs[0x11] = 0; + svga->overscan_color = 0x000000; + + overscan_x = 16; + overscan_y = 32; + + svga->crtc[0] = 63; + svga->crtc[6] = 255; + svga->dispontime = svga->dispofftime = 1000 * (1 << TIMER_SHIFT); + svga->bpp = 8; + svga->vram = malloc(memsize); + svga->vram_max = memsize; + svga->vram_display_mask = svga->vram_mask = memsize - 1; + svga->decode_mask = 0x7fffff; + svga->changedvram = malloc(0x800000 >> 12); + svga->recalctimings_ex = recalctimings_ex; + svga->video_in = video_in; + svga->video_out = video_out; + svga->hwcursor_draw = hwcursor_draw; + svga->overlay_draw = overlay_draw; + + mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, + svga_read, svga_readw, svga_readl, + svga_write, svga_writew, svga_writel, + NULL, MEM_MAPPING_EXTERNAL, svga); + + timer_add(svga_poll, &svga->vidtime, TIMER_ALWAYS_ENABLED, svga); + + svga_pri = svga; + + svga->ramdac_type = RAMDAC_6BIT; + + return 0; +} + + +void +svga_close(svga_t *svga) +{ + free(svga->changedvram); + free(svga->vram); + + svga_pri = NULL; +} + + +void +svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + int func_select, writemask2 = svga->writemask; + uint32_t write_mask, bit_mask, set_mask, val32 = (uint32_t) val; + + egawrites++; + + cycles -= video_timing_write_b; + cycles_lost += video_timing_write_b; + + if (!linear) { + addr &= svga->banked_mask; + addr += svga->write_bank; + } + + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + + if ((svga->chain4 || svga->fb_only) && (svga->writemode < 4)) { + writemask2 = 1 << (addr & 3); + addr &= ~3; + } else if (svga->chain2_write) { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + addr <<= 2; + } else + addr <<= 2; + addr &= svga->decode_mask; + + if (addr >= svga->vram_max) + return; + + addr &= svga->vram_mask; + + svga->changedvram[addr >> 12] = changeframecount; + + /* standard VGA latched access */ + func_select = (svga->gdcreg[3] >> 3) & 3; + + switch (svga->writemode) { + case 0: + /* rotate */ + if (svga->gdcreg[3] & 7) + val32 = svga_rotate[svga->gdcreg[3] & 7][val32]; + + /* apply set/reset mask */ + bit_mask = svga->gdcreg[8]; + + val32 |= (val32 << 8); + val32 |= (val32 << 16); + + if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + (!svga->gdcreg[1] || svga->set_reset_disabled)) { + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] &= ~write_mask; + ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); + return; + } + + set_mask = mask16[svga->gdcreg[1] & 0x0f]; + val32 = (val32 & ~set_mask) | (mask16[svga->gdcreg[0] & 0x0f] & set_mask); + break; + case 1: + val32 = svga->latch; + + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] &= ~write_mask; + ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); + return; + case 2: + val32 = mask16[val32 & 0x0f]; + bit_mask = svga->gdcreg[8]; + + if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) + func_select = 0; + break; + case 3: + /* rotate */ + if (svga->gdcreg[3] & 7) + val32 = svga_rotate[svga->gdcreg[3] & 7][val]; + + bit_mask = svga->gdcreg[8] & val32; + val32 = mask16[svga->gdcreg[0] & 0x0f]; + break; + default: + if (svga->ven_write) + svga->ven_write(svga, val, addr); + return; + } + + /* apply bit mask */ + bit_mask |= bit_mask << 8; + bit_mask |= bit_mask << 16; + + /* apply logical operation */ + switch(func_select) { + case 0: + default: + /* set */ + val32 &= bit_mask; + val32 |= (svga->latch & ~bit_mask); + break; + case 1: + /* and */ + val32 |= ~bit_mask; + val32 &= svga->latch; + break; + case 2: + /* or */ + val32 &= bit_mask; + val32 |= svga->latch; + break; + case 3: + /* xor */ + val32 &= bit_mask; + val32 ^= svga->latch; + break; + } + + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] = (((uint32_t *)(svga->vram))[addr] & ~write_mask) | (val32 & write_mask); +} + + +uint8_t +svga_read_common(uint32_t addr, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + uint32_t latch_addr, ret; + int readplane = svga->readplane; + uint8_t ret8; + + cycles -= video_timing_read_b; + cycles_lost += video_timing_read_b; + + egareads++; + + if (!linear) { + addr &= svga->banked_mask; + addr += svga->read_bank; + + latch_addr = (addr << 2) & svga->decode_mask; + } + + if (svga->chain4 || svga->fb_only) { + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + return svga->vram[addr & svga->vram_mask]; + } else if (svga->chain2_read) { + readplane = (readplane & 2) | (addr & 1); + addr &= ~1; + addr <<= 2; + } else + addr <<= 2; + + addr &= svga->decode_mask; + + /* standard VGA latched access */ + if (linear) { + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + + svga->latch = ((uint32_t *)(svga->vram))[addr >> 2]; + } else { + if (latch_addr > svga->vram_max) + svga->latch = 0xffffffff; + else { + latch_addr &= svga->vram_mask; + svga->latch = ((uint32_t *)(svga->vram))[latch_addr >> 2]; + } + + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + } + + if (!(svga->gdcreg[5] & 8)) { + /* read mode 0 */ + return svga->vram[addr | readplane]; + } else { + /* read mode 1 */ + ret = (svga->latch ^ mask16[svga->colourcompare & 0x0f]) & mask16[svga->colournocare & 0x0f]; + ret8 = (ret & 0xff); + ret8 |= ((ret >> 24) & 0xff); + ret8 |= ((ret >> 16) & 0xff); + ret8 |= ((ret >> 8) & 0xff); + return(~ret8); + } +} + + +void +svga_write(uint32_t addr, uint8_t val, void *p) +{ + svga_write_common(addr, val, 0, p); +} + + +void +svga_write_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_write_common(addr, val, 1, p); +} + + +uint8_t +svga_read(uint32_t addr, void *p) +{ + return svga_read_common(addr, 0, p); +} + + +uint8_t +svga_read_linear(uint32_t addr, void *p) +{ + return svga_read_common(addr, 1, p); +} + + +void +svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) +{ + int y_add = (enable_overscan) ? overscan_y : 0; + int x_add = (enable_overscan) ? 16 : 0; + uint32_t *p; + int i, j; + + svga->frames++; + + if ((xsize > 2032) || (ysize > 2032)) { + x_add = 0; + y_add = 0; + suppress_overscan = 1; + } else + suppress_overscan = 0; + + if (y1 > y2) { + video_blit_memtoscreen(32, 0, 0, 0, xsize + x_add, ysize + y_add); + return; + } + + if ((wx != xsize) || ((wy + 1) != ysize) || video_force_resize_get()) { + /* Screen res has changed.. fix up, and let them know. */ + xsize = wx; + ysize = wy + 1; + if (xsize < 64) + xsize = 640; + if (ysize < 32) + ysize = 200; + + set_screen_size(xsize+x_add,ysize+y_add); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan && !suppress_overscan) { + if ((wx >= 160) && ((wy + 1) >= 120)) { + /* Draw (overscan_size - scroll size) lines of overscan on top. */ + for (i = 0; i < (y_add >> 1); i++) { + p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga_color_transform(svga->overscan_color); + } + + /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ + for (i = 0; i < (y_add >> 1); i++) { + p = &((uint32_t *)buffer32->line[(ysize + (y_add >> 1) + i) & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga_color_transform(svga->overscan_color); + } + + for (i = (y_add >> 1); i < (ysize + (y_add >> 1)); i ++) { + p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + + for (j = 0; j < 8; j++) { + p[j] = svga->pallook[svga->overscan_color]; + p[xsize + (x_add >> 1) + j] = svga_color_transform(svga->overscan_color); + } } } + } - video_blit_memtoscreen(32, 0, y1, y2 + y_add, xsize + x_add, ysize + y_add); + video_blit_memtoscreen(32, 0, y1, y2 + y_add, xsize + x_add, ysize + y_add); } -void svga_writew(uint32_t addr, uint16_t val, void *p) + +void +svga_writeb_linear(uint32_t addr, uint8_t val, void *p) { - svga_t *svga = (svga_t *)p; - if (!svga->fast) - { - svga_write(addr, val, p); - svga_write(addr + 1, val >> 8, p); - return; - } - - egawrites += 2; + svga_t *svga = (svga_t *)p; - cycles -= video_timing_write_w; - cycles_lost += video_timing_write_w; + if (!svga->fast) { + svga_write_linear(addr, val, p); + return; + } - if (svga_output) pclog("svga_writew: %05X ", addr); - addr = (addr & svga->banked_mask) + svga->write_bank; - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return; - addr &= svga->vram_mask; - if (svga_output) pclog("%08X (%i, %i) %04X\n", addr, addr & 1023, addr >> 10, val); - svga->changedvram[addr >> 12] = changeframecount; - *(uint16_t *)&svga->vram[addr] = val; + egawrites++; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint8_t *)&svga->vram[addr] = val; } -void svga_writel(uint32_t addr, uint32_t val, void *p) + +void +svga_writew_common(uint32_t addr, uint16_t val, uint8_t linear, void *p) { - svga_t *svga = (svga_t *)p; - - if (!svga->fast) - { - svga_write(addr, val, p); - svga_write(addr + 1, val >> 8, p); - svga_write(addr + 2, val >> 16, p); - svga_write(addr + 3, val >> 24, p); - return; - } - - egawrites += 4; + svga_t *svga = (svga_t *)p; - cycles -= video_timing_write_l; - cycles_lost += video_timing_write_l; + if (!svga->fast) { + svga_write_common(addr, val, linear, p); + svga_write_common(addr + 1, val >> 8, linear, p); + return; + } - if (svga_output) pclog("svga_writel: %05X ", addr); - addr = (addr & svga->banked_mask) + svga->write_bank; - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return; - addr &= svga->vram_mask; - if (svga_output) pclog("%08X (%i, %i) %08X\n", addr, addr & 1023, addr >> 10, val); - - svga->changedvram[addr >> 12] = changeframecount; - *(uint32_t *)&svga->vram[addr] = val; + egawrites += 2; + + cycles -= video_timing_write_w; + cycles_lost += video_timing_write_w; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr] = val; } -uint16_t svga_readw(uint32_t addr, void *p) + +void +svga_writew(uint32_t addr, uint16_t val, void *p) { - svga_t *svga = (svga_t *)p; - - if (!svga->fast) - return svga_read(addr, p) | (svga_read(addr + 1, p) << 8); - - egareads += 2; - - cycles -= video_timing_read_w; - cycles_lost += video_timing_read_w; - -// pclog("Readw %05X ", addr); - addr = (addr & svga->banked_mask) + svga->read_bank; - addr &= svga->decode_mask; -// pclog("%08X %04X\n", addr, *(uint16_t *)&vram[addr]); - if (addr >= svga->vram_max) - return 0xffff; - - return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; + svga_writew_common(addr, val, 0, p); } -uint32_t svga_readl(uint32_t addr, void *p) + +void +svga_writew_linear(uint32_t addr, uint16_t val, void *p) { - svga_t *svga = (svga_t *)p; - - if (!svga->fast) - return svga_read(addr, p) | (svga_read(addr + 1, p) << 8) | (svga_read(addr + 2, p) << 16) | (svga_read(addr + 3, p) << 24); - - egareads += 4; - - cycles -= video_timing_read_l; - cycles_lost += video_timing_read_l; - -// pclog("Readl %05X ", addr); - addr = (addr & svga->banked_mask) + svga->read_bank; - addr &= svga->decode_mask; -// pclog("%08X %08X\n", addr, *(uint32_t *)&vram[addr]); - if (addr >= svga->vram_max) - return 0xffffffff; - - return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; + svga_writew_common(addr, val, 1, p); } -void svga_writeb_linear(uint32_t addr, uint8_t val, void *p) + +void +svga_writel_common(uint32_t addr, uint32_t val, uint8_t linear, void *p) { - svga_t *svga = (svga_t *)p; - - if (!svga->fast) - { - svga_write_linear(addr, val, p); - return; - } - - egawrites++; + svga_t *svga = (svga_t *)p; - if (svga_output) pclog("Write LFBb %08X %04X\n", addr, val); - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return; - addr &= svga->vram_mask; - svga->changedvram[addr >> 12] = changeframecount; - *(uint8_t *)&svga->vram[addr] = val; + if (!svga->fast) { + svga_write(addr, val, p); + svga_write(addr + 1, val >> 8, p); + svga_write(addr + 2, val >> 16, p); + svga_write(addr + 3, val >> 24, p); + return; + } + + egawrites += 4; + + cycles -= video_timing_write_l; + cycles_lost += video_timing_write_l; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr] = val; } -void svga_writew_linear(uint32_t addr, uint16_t val, void *p) + +void +svga_writel(uint32_t addr, uint32_t val, void *p) { - svga_t *svga = (svga_t *)p; - - if (!svga->fast) - { - svga_write_linear(addr, val, p); - svga_write_linear(addr + 1, val >> 8, p); - return; - } - - egawrites += 2; - - cycles -= video_timing_write_w; - cycles_lost += video_timing_write_w; - - if (svga_output) pclog("Write LFBw %08X %04X\n", addr, val); - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return; - addr &= svga->vram_mask; - svga->changedvram[addr >> 12] = changeframecount; - *(uint16_t *)&svga->vram[addr] = val; + svga_writel_common(addr, val, 0, p); } -void svga_writel_linear(uint32_t addr, uint32_t val, void *p) + +void +svga_writel_linear(uint32_t addr, uint32_t val, void *p) { - svga_t *svga = (svga_t *)p; - - if (!svga->fast) - { - svga_write_linear(addr, val, p); - svga_write_linear(addr + 1, val >> 8, p); - svga_write_linear(addr + 2, val >> 16, p); - svga_write_linear(addr + 3, val >> 24, p); - return; - } - - egawrites += 4; - - cycles -= video_timing_write_l; - cycles_lost += video_timing_write_l; - - if (svga_output) pclog("Write LFBl %08X %08X\n", addr, val); - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return; - addr &= svga->vram_mask; - svga->changedvram[addr >> 12] = changeframecount; - *(uint32_t *)&svga->vram[addr] = val; + svga_writel_common(addr, val, 1, p); } -uint8_t svga_readb_linear(uint32_t addr, void *p) + +uint8_t +svga_readb_linear(uint32_t addr, void *p) { - svga_t *svga = (svga_t *)p; - - if (!svga->fast) - return svga_read_linear(addr, p); - - egareads++; + svga_t *svga = (svga_t *)p; - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return 0xff; - - return *(uint8_t *)&svga->vram[addr & svga->vram_mask]; + if (!svga->fast) + return svga_read_linear(addr, p); + + egareads++; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + return *(uint8_t *)&svga->vram[addr & svga->vram_mask]; } -uint16_t svga_readw_linear(uint32_t addr, void *p) + +uint16_t +svga_readw_common(uint32_t addr, uint8_t linear, void *p) { - svga_t *svga = (svga_t *)p; - - if (!svga->fast) - return svga_read_linear(addr, p) | (svga_read_linear(addr + 1, p) << 8); - - egareads += 2; + svga_t *svga = (svga_t *)p; - cycles -= video_timing_read_w; - cycles_lost += video_timing_read_w; + if (!svga->fast) + return svga_read_common(addr, linear, p) | (svga_read_common(addr + 1, linear, p) << 8); - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return 0xffff; - - return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; + egareads += 2; + + cycles -= video_timing_read_w; + cycles_lost += video_timing_read_w; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffff; + + return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; } -uint32_t svga_readl_linear(uint32_t addr, void *p) + +uint16_t +svga_readw(uint32_t addr, void *p) { - svga_t *svga = (svga_t *)p; - - if (!svga->fast) - return svga_read_linear(addr, p) | (svga_read_linear(addr + 1, p) << 8) | (svga_read_linear(addr + 2, p) << 16) | (svga_read_linear(addr + 3, p) << 24); - - egareads += 4; - - cycles -= video_timing_read_l; - cycles_lost += video_timing_read_l; - - addr &= svga->decode_mask; - if (addr >= svga->vram_max) - return 0xffffffff; - - return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; + return svga_readw_common(addr, 0, p); } -void svga_add_status_info(char *s, int max_len, void *p) +uint16_t +svga_readw_linear(uint32_t addr, void *p) { - svga_t *svga = (svga_t *)p; - char temps[128]; - - if (svga->chain4) strcpy(temps, "SVGA chained (possibly mode 13h)\n"); - else strcpy(temps, "SVGA unchained (possibly mode-X)\n"); - strncat(s, temps, max_len); - - if (!svga->video_bpp) strcpy(temps, "SVGA in text mode\n"); - else sprintf(temps, "SVGA colour depth : %i bpp\n", svga->video_bpp); - strncat(s, temps, max_len); - - sprintf(temps, "SVGA resolution : %i x %i\n", svga->video_res_x, svga->video_res_y); - strncat(s, temps, max_len); - - sprintf(temps, "SVGA refresh rate : %i Hz\n\n", svga->frames); - svga->frames = 0; - strncat(s, temps, max_len); + return svga_readw_common(addr, 1, p); +} + + +uint32_t +svga_readl_common(uint32_t addr, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + return svga_read_common(addr, linear, p) | (svga_read_common(addr + 1, linear, p) << 8) | + (svga_read_common(addr + 2, linear, p) << 16) | (svga_read_common(addr + 3, linear, p) << 24); + } + + egareads += 4; + + cycles -= video_timing_read_l; + cycles_lost += video_timing_read_l; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffffffff; + + return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; +} + + +uint32_t +svga_readl(uint32_t addr, void *p) +{ + return svga_readl_common(addr, 0, p); +} + + +uint32_t +svga_readl_linear(uint32_t addr, void *p) +{ + return svga_readl_common(addr, 1, p); +} + + +void +svga_add_status_info(char *s, int max_len, void *p) +{ + svga_t *svga = (svga_t *)p; + char temps[128]; + + if (svga->chain4) + strcpy(temps, "SVGA chained (possibly mode 13h)\n"); + else + strcpy(temps, "SVGA unchained (possibly mode-X)\n"); + strncat(s, temps, max_len); + + if (!svga->video_bpp) + strcpy(temps, "SVGA in text mode\n"); + else + sprintf(temps, "SVGA colour depth : %i bpp\n", svga->video_bpp); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA resolution : %i x %i\n", svga->video_res_x, svga->video_res_y); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA refresh rate : %i Hz\n\n", svga->frames); + svga->frames = 0; + strncat(s, temps, max_len); } diff --git a/src/video/vid_svga.h b/src/video/vid_svga.h index b2811995b..1711af4cc 100644 --- a/src/video/vid_svga.h +++ b/src/video/vid_svga.h @@ -8,7 +8,7 @@ * * Generic SVGA handling. * - * Version: @(#)vid_svga.h 1.0.10 2018/03/23 + * Version: @(#)vid_svga.h 1.0.11 2018/04/01 * * Authors: Sarah Walker, * Miran Grca, @@ -17,228 +17,189 @@ * Copyright 2016-2018 Miran Grca. */ +typedef struct { + int ena, + x, y, xoff, yoff, xsize, ysize, + v_acc, h_acc; + uint32_t addr, pitch; +} hwcursor_t; + typedef struct svga_t { - mem_mapping_t mapping; + mem_mapping_t mapping; - int enabled; + int enabled; - - uint8_t crtcreg; - uint8_t crtc[128]; - uint8_t gdcreg[64]; - int gdcaddr; - uint8_t attrregs[32]; - int attraddr, attrff; - int attr_palette_enable; - uint8_t seqregs[64]; - int seqaddr; - - uint8_t miscout; - int vidclock; + uint8_t crtcreg, crtc[128], + gdcaddr, gdcreg[64], + attrff, attr_palette_enable, + attraddr, attrregs[32], + seqaddr, seqregs[64], + miscout, cgastat, + plane_mask, writemask, + colourcompare, colournocare, + scrblank, egapal[16], + *vram, *changedvram; - /*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 : - 0MB-1MB - VRAM - 1MB-2MB - VRAM mirror - 2MB-4MB - open bus - 4MB-xMB - mirror of above - - For the example memory map, decode_mask would be 4MB-1 (4MB address space), vram_max would be 2MB - (present video memory only responds to first 2MB), vram_mask would be 1MB-1 (video memory wraps at 1MB) - */ - uint32_t decode_mask; - uint32_t vram_max; - uint32_t vram_mask; + int vidclock, fb_only, + fast; - uint8_t la, lb, lc, ld; - - uint8_t dac_mask, dac_status; - int dac_read, dac_write, dac_pos; - int dac_r, dac_g; - - uint8_t cgastat; - - uint8_t plane_mask; - - int fb_only; - - int fast; - uint8_t colourcompare, colournocare; - int readmode, writemode, readplane; - int chain4, chain2_write, chain2_read; - int oddeven_page, oddeven_chain; - int extvram; - uint8_t writemask; - uint32_t charseta, charsetb; - - int set_reset_disabled; - - uint8_t egapal[16]; - uint32_t pallook[256]; - PALETTE vgapal; - - int ramdac_type; + /*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 : + 0MB-1MB - VRAM + 1MB-2MB - VRAM mirror + 2MB-4MB - open bus + 4MB-xMB - mirror of above - int vtotal, dispend, vsyncstart, split, vblankstart; - int hdisp, hdisp_old, htotal, hdisp_time, rowoffset; - int lowres, interlace; - int linedbl, rowcount; - double clock; - uint32_t ma_latch; - int bpp; - - int64_t dispontime, dispofftime; - int64_t vidtime; - - uint8_t scrblank; - - int dispon; - int hdisp_on; + For the example memory map, decode_mask would be 4MB-1 (4MB address space), vram_max would be 2MB + (present video memory only responds to first 2MB), vram_mask would be 1MB-1 (video memory wraps at 1MB) + */ + uint32_t decode_mask; + uint32_t vram_max; + uint32_t vram_mask; - uint32_t ma, maback, ca; - int vc; - int sc; - int linepos, vslines, linecountff, oddeven; - int con, cursoron, blink; - int scrollcache; - - int firstline, lastline; - int firstline_draw, lastline_draw; - int displine; - - uint8_t *vram; - uint8_t *changedvram; - int vram_display_mask; - uint32_t banked_mask; + uint8_t dac_mask, dac_status; + int dac_read, dac_write, + dac_pos, ramdac_type, + dac_r, dac_g; - uint32_t write_bank, read_bank; - - int fullchange; - - int video_res_x, video_res_y, video_bpp; - int frames, fps; + int readmode, writemode, + readplane, extvram, + chain4, chain2_write, chain2_read, + oddeven_page, oddeven_chain, + set_reset_disabled; - struct - { - int ena; - int x, y; - int xoff, yoff; - int xsize, ysize; - uint32_t addr; - uint32_t pitch; - int v_acc, h_acc; - } hwcursor, hwcursor_latch, overlay, overlay_latch; - - int hwcursor_on; - int overlay_on; - - int hwcursor_oddeven; - int overlay_oddeven; - - void (*render)(struct svga_t *svga); - void (*recalctimings_ex)(struct svga_t *svga); + uint32_t charseta, charsetb, + latch, ma_latch, + ma, maback, + write_bank, read_bank, + banked_mask, + ca, overscan_color, + pallook[256]; - void (*video_out)(uint16_t addr, uint8_t val, void *p); - uint8_t (*video_in) (uint16_t addr, void *p); + PALETTE vgapal; - void (*hwcursor_draw)(struct svga_t *svga, int displine); + int vtotal, dispend, vsyncstart, split, vblankstart, + hdisp, hdisp_old, htotal, hdisp_time, rowoffset, + lowres, interlace, linedbl, rowcount, bpp, + dispon, hdisp_on, + vc, sc, linepos, vslines, linecountff, oddeven, + con, cursoron, blink, scrollcache, + firstline, lastline, firstline_draw, lastline_draw, + displine, fullchange, + video_res_x, video_res_y, video_bpp, frames, fps, + vram_display_mask, + hwcursor_on, overlay_on, + hwcursor_oddeven, overlay_oddeven; - void (*overlay_draw)(struct svga_t *svga, int displine); - - void (*vblank_start)(struct svga_t *svga); + double clock; - /*If set then another device is driving the monitor output and the SVGA - card should not attempt to display anything */ - int override; - void *p; + int64_t dispontime, dispofftime, + vidtime; - uint32_t linear_base; - uint32_t overscan_color; + hwcursor_t hwcursor, hwcursor_latch, + overlay, overlay_latch; + + void (*render)(struct svga_t *svga); + void (*recalctimings_ex)(struct svga_t *svga); + + void (*video_out)(uint16_t addr, uint8_t val, void *p); + uint8_t (*video_in) (uint16_t addr, void *p); + + void (*hwcursor_draw)(struct svga_t *svga, int displine); + + void (*overlay_draw)(struct svga_t *svga, int displine); + + void (*vblank_start)(struct svga_t *svga); + + void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr); + + /*If set then another device is driving the monitor output and the SVGA + card should not attempt to display anything */ + int override; + void *p; } svga_t; -extern int svga_init(svga_t *svga, void *p, int memsize, - void (*recalctimings_ex)(struct svga_t *svga), - uint8_t (*video_in) (uint16_t addr, void *p), - void (*video_out)(uint16_t addr, uint8_t val, void *p), - void (*hwcursor_draw)(struct svga_t *svga, int displine), - void (*overlay_draw)(struct svga_t *svga, int displine)); -extern void svga_recalctimings(svga_t *svga); -extern void svga_close(svga_t *svga); + +extern int svga_init(svga_t *svga, void *p, int memsize, + void (*recalctimings_ex)(struct svga_t *svga), + uint8_t (*video_in) (uint16_t addr, void *p), + void (*video_out)(uint16_t addr, uint8_t val, void *p), + void (*hwcursor_draw)(struct svga_t *svga, int displine), + void (*overlay_draw)(struct svga_t *svga, int displine)); +extern void svga_recalctimings(svga_t *svga); +extern void svga_close(svga_t *svga); + +uint8_t svga_read(uint32_t addr, void *p); +uint16_t svga_readw(uint32_t addr, void *p); +uint32_t svga_readl(uint32_t addr, void *p); +void svga_write(uint32_t addr, uint8_t val, void *p); +void svga_writew(uint32_t addr, uint16_t val, void *p); +void svga_writel(uint32_t addr, uint32_t val, void *p); +uint8_t svga_read_linear(uint32_t addr, void *p); +uint8_t svga_readb_linear(uint32_t addr, void *p); +uint16_t svga_readw_linear(uint32_t addr, void *p); +uint32_t svga_readl_linear(uint32_t addr, void *p); +void svga_write_linear(uint32_t addr, uint8_t val, void *p); +void svga_writeb_linear(uint32_t addr, uint8_t val, void *p); +void svga_writew_linear(uint32_t addr, uint16_t val, void *p); +void svga_writel_linear(uint32_t addr, uint32_t val, void *p); + +void svga_add_status_info(char *s, int max_len, void *p); + +extern uint8_t svga_rotate[8][256]; + +void svga_out(uint16_t addr, uint8_t val, void *p); +uint8_t svga_in(uint16_t addr, void *p); + +svga_t *svga_get_pri(); +void svga_set_override(svga_t *svga, int val); + +void svga_set_ven_write(svga_t *svga, + void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr)); + +void svga_set_ramdac_type(svga_t *svga, int type); +void svga_close(svga_t *svga); + +uint32_t svga_mask_addr(uint32_t addr, svga_t *svga); +uint32_t svga_mask_changedaddr(uint32_t addr, svga_t *svga); + +void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); -uint8_t svga_read(uint32_t addr, void *p); -uint16_t svga_readw(uint32_t addr, void *p); -uint32_t svga_readl(uint32_t addr, void *p); -void svga_write(uint32_t addr, uint8_t val, void *p); -void svga_writew(uint32_t addr, uint16_t val, void *p); -void svga_writel(uint32_t addr, uint32_t val, void *p); -uint8_t svga_read_linear(uint32_t addr, void *p); -uint8_t svga_readb_linear(uint32_t addr, void *p); -uint16_t svga_readw_linear(uint32_t addr, void *p); -uint32_t svga_readl_linear(uint32_t addr, void *p); -void svga_write_linear(uint32_t addr, uint8_t val, void *p); -void svga_writeb_linear(uint32_t addr, uint8_t val, void *p); -void svga_writew_linear(uint32_t addr, uint16_t val, void *p); -void svga_writel_linear(uint32_t addr, uint32_t val, void *p); - -void svga_add_status_info(char *s, int max_len, void *p); - -extern uint8_t svga_rotate[8][256]; - -void svga_out(uint16_t addr, uint8_t val, void *p); -uint8_t svga_in(uint16_t addr, void *p); - -svga_t *svga_get_pri(); -void svga_set_override(svga_t *svga, int val); - -#define RAMDAC_6BIT 0 -#define RAMDAC_8BIT 1 -void svga_set_ramdac_type(svga_t *svga, int type); - -void svga_close(svga_t *svga); - -uint32_t svga_mask_addr(uint32_t addr, svga_t *svga); -uint32_t svga_mask_changedaddr(uint32_t addr, svga_t *svga); +enum { + RAMDAC_6BIT = 0, + RAMDAC_8BIT +}; extern uint32_t shade[5][256]; -static __inline__ uint32_t svga_color_transform(uint32_t color) -{ - uint8_t *clr8 = (uint8_t *) &color; - if (!video_grayscale && !invert_display) - return color; - if (video_grayscale) - { - if (video_graytype) - { - if (video_graytype == 1) - color = ((54 * (uint32_t)clr8[2]) + (183 * (uint32_t)clr8[1]) + (18 * (uint32_t)clr8[0])) / 255; - else - color = ((uint32_t)clr8[2] + (uint32_t)clr8[1] + (uint32_t)clr8[0]) / 3; - } - else - color = ((76 * (uint32_t)clr8[2]) + (150 * (uint32_t)clr8[1]) + (29 * (uint32_t)clr8[0])) / 255; - switch (video_grayscale) - { - case 2: - case 3: - case 4: - color = shade[video_grayscale][color]; - break; - default: - clr8[3] = 0; - clr8[0] = color; - clr8[1] = clr8[2] = clr8[0]; - break; - } - } - if (invert_display) - { - clr8[0] ^= 0xff; - clr8[1] ^= 0xff; - clr8[2] ^= 0xff; - } - return color; -} -void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); +static __inline__ uint32_t +svga_color_transform(uint32_t color) +{ + uint8_t *clr8 = (uint8_t *) &color; + if (!video_grayscale && !invert_display) + return color; + if (video_grayscale) { + if (video_graytype) { + if (video_graytype == 1) + color = ((54 * (uint32_t)clr8[2]) + (183 * (uint32_t)clr8[1]) + (18 * (uint32_t)clr8[0])) / 255; + else + color = ((uint32_t)clr8[2] + (uint32_t)clr8[1] + (uint32_t)clr8[0]) / 3; + } else + color = ((76 * (uint32_t)clr8[2]) + (150 * (uint32_t)clr8[1]) + (29 * (uint32_t)clr8[0])) / 255; + switch (video_grayscale) { + case 2: case 3: case 4: + color = shade[video_grayscale][color]; + break; + default: + clr8[3] = 0; + clr8[0] = color; + clr8[1] = clr8[2] = clr8[0]; + break; + } + } + if (invert_display) + color ^= 0x00ffffff; + return color; +} diff --git a/src/video/vid_table.c b/src/video/vid_table.c index fcb8ff503..84e3a282e 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -8,7 +8,7 @@ * * Define all known video cards. * - * Version: @(#)vid_table.c 1.0.26 2018/03/20 + * Version: @(#)vid_table.c 1.0.27 2018/04/09 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -92,7 +92,9 @@ video_cards[] = { { "[ISA] ATI VGA-88 (ATI-18800-1)", "ati18800v", &ati18800_vga88_device, GFX_VGA88, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, { "[ISA] ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device, GFX_VGACHARGER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, { "[ISA] ATI VGA Edge-16 (ATI-18800-5)", "ati18800", &ati18800_device, GFX_VGAEDGE16, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) { "[ISA] ATI VGA Wonder (ATI-18800)", "ati18800w", &ati18800_wonder_device, GFX_VGAWONDER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, +#endif #if defined(DEV_BRANCH) && defined(USE_XL24) { "[ISA] ATI VGA Wonder XL24 (ATI-28800-6)", "ati28800w", &ati28800_wonderxl24_device, GFX_VGAWONDERXL24, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, #endif @@ -189,18 +191,19 @@ video_reset(int card) cga_palette = 0; cgapal_rebuild(); - /* Do not initialize internal cards here. */ - if ((card == GFX_NONE) || \ - (card == GFX_INTERNAL) || machines[machine].fixed_gfxcard) return; - if (fontdatksc5601) { free(fontdatksc5601); fontdatksc5601 = NULL; } -pclog("VIDEO: initializing '%s'\n", video_cards[video_old_to_new(card)].name); - /* Initialize the video card. */ - device_add(video_cards[video_old_to_new(card)].device); + /* Do not initialize internal cards here. */ + if (!(card == GFX_NONE) && \ + !(card == GFX_INTERNAL) && !machines[machine].fixed_gfxcard) { + pclog("VIDEO: initializing '%s'\n", video_cards[video_old_to_new(card)].name); + + /* Initialize the video card. */ + device_add(video_cards[video_old_to_new(card)].device); + } /* Enable the Voodoo if configured. */ if (voodoo_enabled) diff --git a/src/video/vid_ti_cf62011.c b/src/video/vid_ti_cf62011.c index cbf3c48b7..f407693e4 100644 --- a/src/video/vid_ti_cf62011.c +++ b/src/video/vid_ti_cf62011.c @@ -42,7 +42,7 @@ * which are the same as the XGA. It supports up to 1MB of VRAM, * but we lock it down to 512K. The PS/1 2122 had 256K. * - * Version: @(#)vid_ti_cf62011.c 1.0.4 2018/03/18 + * Version: @(#)vid_ti_cf62011.c 1.0.5 2018/04/12 * * Authors: Sarah Walker, * Miran Grca, @@ -103,10 +103,12 @@ vid_out(uint16_t addr, uint8_t val, void *priv) return; case 0x03d4: - svga->crtcreg = val & 0x1f; + svga->crtcreg = val & 0x3f; return; case 0x03d5: + if (svga->crtcreg & 0x20) + return; if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -174,7 +176,10 @@ vid_in(uint16_t addr, void *priv) break; case 0x03d5: - ret = svga->crtc[svga->crtcreg]; + if (svga->crtcreg & 0x20) + ret = 0xff; + else + ret = svga->crtc[svga->crtcreg]; break; case 0x2100: diff --git a/src/video/vid_vga.c b/src/video/vid_vga.c index 2311f5a00..113b2e06f 100644 --- a/src/video/vid_vga.c +++ b/src/video/vid_vga.c @@ -50,9 +50,11 @@ void vga_out(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x3D4: - svga->crtcreg = val & 0x1f; + svga->crtcreg = val & 0x3f; return; case 0x3D5: + if (svga->crtcreg & 0x20) + return; if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -87,7 +89,10 @@ uint8_t vga_in(uint16_t addr, void *p) temp = svga->crtcreg; break; case 0x3D5: - temp = svga->crtc[svga->crtcreg]; + if (svga->crtcreg & 0x20) + temp = 0xff; + else + temp = svga->crtc[svga->crtcreg]; break; default: temp = svga_in(addr, svga); diff --git a/src/video/vid_voodoo.c b/src/video/vid_voodoo.c index 608708bd1..efa8aee73 100644 --- a/src/video/vid_voodoo.c +++ b/src/video/vid_voodoo.c @@ -8,7 +8,7 @@ * * Emulation of the 3DFX Voodoo Graphics controller. * - * Version: @(#)vid_voodoo.c 1.0.12 2018/03/18 + * Version: @(#)vid_voodoo.c 1.0.13 2018/04/13 * * Authors: Sarah Walker, * leilei @@ -37,18 +37,10 @@ #include "vid_voodoo.h" #include "vid_voodoo_dither.h" -#ifdef MIN -#undef MIN -#endif -#ifdef ABS -#undef ABS -#endif #ifdef CLAMP #undef CLAMP #endif -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - #define CLAMP(x) (((x) < 0) ? 0 : (((x) > 0xff) ? 0xff : (x))) #define CLAMP16(x) (((x) < 0) ? 0 : (((x) > 0xffff) ? 0xffff : (x))) @@ -4007,8 +3999,6 @@ enum case 0xf: dst_dat = 0xffff; break; \ } -#define ABS(x) ((x) > 0 ? (x) : -(x)) - static void blit_start(voodoo_t *voodoo) { uint64_t dat64; @@ -4179,15 +4169,29 @@ static void blit_data(voodoo_t *voodoo, uint32_t data) { int src_bits = 32; uint32_t base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); + uint32_t addr; uint16_t *dst; - + if ((voodoo->bltCommand & BLIT_COMMAND_MASK) != BLIT_COMMAND_CPU_TO_SCREEN) return; if (SLI_ENABLED) - dst = (uint16_t *)&voodoo->fb_mem[base_addr + (voodoo->blt.dst_y >> 1) * voodoo->blt.dst_stride]; + { + addr = base_addr + (voodoo->blt.dst_y >> 1) * voodoo->blt.dst_stride; + dst = (uint16_t *)&voodoo->fb_mem[addr]; + } else - dst = (uint16_t *)&voodoo->fb_mem[base_addr + voodoo->blt.dst_y*voodoo->blt.dst_stride]; + { + addr = base_addr + voodoo->blt.dst_y*voodoo->blt.dst_stride; + dst = (uint16_t *)&voodoo->fb_mem[addr]; + } + + if (addr >= voodoo->front_offset && voodoo->row_width) + { + int y = (addr - voodoo->front_offset) / voodoo->row_width; + if (y < voodoo->v_disp) + voodoo->dirty_line[y] = 2; + } while (src_bits && voodoo->blt.cur_x <= voodoo->blt.size_x) { diff --git a/src/video/video.h b/src/video/video.h index 99b54a66f..ce7889c50 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -8,7 +8,7 @@ * * Definitions for the video controller module. * - * Version: @(#)video.h 1.0.25 2018/03/20 + * Version: @(#)video.h 1.0.26 2018/04/09 * * Authors: Sarah Walker, * Miran Grca, @@ -65,7 +65,9 @@ enum { GFX_VGA88, /* ATI VGA-88 (18800-1) */ GFX_VGAEDGE16, /* ATI VGA Edge-16 (18800-1) */ GFX_VGACHARGER, /* ATI VGA Charger (28800-5) */ +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) GFX_VGAWONDER, /* Compaq ATI VGA Wonder (18800) */ +#endif GFX_VGAWONDERXL, /* Compaq ATI VGA Wonder XL (28800-5) */ #if defined(DEV_BRANCH) && defined(USE_XL24) GFX_VGAWONDERXL24, /* Compaq ATI VGA Wonder XL24 (28800-6) */ diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 7122bf0f5..4865b77f0 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -8,7 +8,7 @@ * * Application resource script for Windows. * - * Version: @(#)86Box.rc 1.0.31 2018/03/06 + * Version: @(#)86Box.rc 1.0.32 2018/03/26 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -445,16 +445,17 @@ BEGIN PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI,214,7,46,12 LTEXT "HD Controller:",IDT_1717,7,26,61,10 - COMBOBOX IDC_COMBO_HDC,71,25,189,120,CBS_DROPDOWNLIST | + COMBOBOX IDC_COMBO_HDC,71,25,149,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_HDC,214,25,46,12 - LTEXT "Tertiary IDE:",IDT_1718,7,44,61,10 - COMBOBOX IDC_COMBO_IDE_TER,71,43,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP + CONTROL "Tertiary IDE Controller",IDC_CHECK_IDE_TER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,44,199,10 + PUSHBUTTON "Configure",IDC_BUTTON_IDE_TER,214,43,46,12 - LTEXT "Quaternary IDE:",IDT_1719,7,62,61,10 - COMBOBOX IDC_COMBO_IDE_QUA,71,61,189,120,CBS_DROPDOWNLIST | - WS_VSCROLL | WS_TABSTOP + CONTROL "Quaternary IDE Controller",IDC_CHECK_IDE_QUA,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,62,199,10 + PUSHBUTTON "Configure",IDC_BUTTON_IDE_QUA,214,61,46,12 CONTROL "ISABugger device",IDC_CHECK_BUGGER,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,7,80,94,10 @@ -570,7 +571,7 @@ BEGIN CONTROL "List1",IDC_LIST_ZIP_DRIVES,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,137,253,60 - LTEXT "ZIP drives:",IDT_1739,7,127,50,8 + LTEXT "ZIP drives:",IDT_1759,7,127,50,8 COMBOBOX IDC_COMBO_ZIP_BUS,73,204,90,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP LTEXT "Bus:",IDT_1753,57,206,14,8 @@ -617,12 +618,10 @@ END 161 ICON DISCARDABLE "win/icons/cdrom_active.ico" 176 ICON DISCARDABLE "win/icons/zip.ico" 177 ICON DISCARDABLE "win/icons/zip_active.ico" -192 ICON DISCARDABLE "win/icons/removable_disk.ico" -193 ICON DISCARDABLE "win/icons/removable_disk_active.ico" -208 ICON DISCARDABLE "win/icons/hard_disk.ico" -209 ICON DISCARDABLE "win/icons/hard_disk_active.ico" -224 ICON DISCARDABLE "win/icons/network.ico" -225 ICON DISCARDABLE "win/icons/network_active.ico" +192 ICON DISCARDABLE "win/icons/hard_disk.ico" +193 ICON DISCARDABLE "win/icons/hard_disk_active.ico" +208 ICON DISCARDABLE "win/icons/network.ico" +209 ICON DISCARDABLE "win/icons/network_active.ico" 256 ICON DISCARDABLE "win/icons/machine.ico" 257 ICON DISCARDABLE "win/icons/display.ico" 258 ICON DISCARDABLE "win/icons/input_devices.ico" @@ -641,8 +640,6 @@ END 417 ICON DISCARDABLE "win/icons/cdrom_empty_active.ico" 432 ICON DISCARDABLE "win/icons/zip_empty.ico" 433 ICON DISCARDABLE "win/icons/zip_empty_active.ico" -448 ICON DISCARDABLE "win/icons/removable_disk_empty.ico" -449 ICON DISCARDABLE "win/icons/removable_disk_empty_active.ico" 512 ICON DISCARDABLE "win/icons/floppy_disabled.ico" 514 ICON DISCARDABLE "win/icons/cdrom_disabled.ico" 515 ICON DISCARDABLE "win/icons/zip_disabled.ico" @@ -936,8 +933,8 @@ BEGIN IDS_2153 "Unable to load Keyboard Accelerators!" IDS_2154 "Unable to register Raw Input!" IDS_2155 "IRQ %i" - IDS_2156 "%" PRIu64 - IDS_2157 "%" PRIu64 " MB (CHS: %" PRIu64 ", %" PRIu64 ", %" PRIu64 ")" + IDS_2156 "%u" + IDS_2157 "%u MB (CHS: %i, %i, %i)" IDS_2158 "Floppy %i (%s): %ls" IDS_2159 "All images (*.0??;*.1??;*.360;*.720;*.86F;*.BIN;*.CQ?;*.DSK;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.XDF)\0*.0??;*.1??;*.360;*.720;*.86F;*.BIN;*.CQ?;*.DSK;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.360;*.720;*.BIN;*.CQ?;*.DSK;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.360;*.720;*.BIN;*.CQ?;*.DSK;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F)\0*.86F\0All files (*.*)\0*.*\0" IDS_2160 "Configuration files (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0" @@ -957,7 +954,7 @@ BEGIN IDS_2174 "All images (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Basic sector images (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Surface images (*.86F)\0*.86F\0" IDS_2175 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0All files (*.*)\0*.*\0" IDS_2176 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" - IDS_2177 "ZIP %i (%03i): %ls" + IDS_2177 "ZIP %03i %i (%s): %ls" IDS_2178 "Speed" IDS_4096 "Hard disk (%s)" @@ -979,23 +976,18 @@ BEGIN IDS_4112 "Please enter a valid file name" IDS_4113 "Remember to partition and format the new drive" IDS_4114 "MFM/RLL or ESDI CD-ROM drives never existed" - IDS_4115 "Removable disk %i (SCSI): %ls" IDS_4352 "MFM/RLL" - IDS_4353 "XT IDE" + IDS_4353 "XTA" IDS_4354 "ESDI" - IDS_4355 "IDE (PIO-only)" - IDS_4356 "IDE (PIO+DMA)" - IDS_4357 "SCSI" - IDS_4358 "SCSI (removable)" + IDS_4355 "IDE" + IDS_4356 "SCSI" IDS_4608 "MFM/RLL (%01i:%01i)" - IDS_4609 "XT IDE (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" IDS_4610 "ESDI (%01i:%01i)" - IDS_4611 "IDE (PIO-only) (%01i:%01i)" - IDS_4612 "IDE (PIO+DMA) (%01i:%01i)" - IDS_4613 "SCSI (%02i:%02i)" - IDS_4614 "SCSI (removable) (%02i:%02i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "SCSI (%02i:%02i)" IDS_5120 "CD-ROM %i (%s): %s" @@ -1003,17 +995,15 @@ BEGIN IDS_5377 "" IDS_5378 "" IDS_5379 "" - IDS_5380 "ATAPI (PIO-only)" - IDS_5381 "ATAPI (PIO and DMA)" - IDS_5382 "SCSI" + IDS_5380 "ATAPI" + IDS_5381 "SCSI" IDS_5632 "Disabled" IDS_5633 "" IDS_5634 "" IDS_5635 "" - IDS_5636 "ATAPI (PIO-only) (%01i:%01i)" - IDS_5637 "ATAPI (PIO and DMA) (%01i:%01i)" - IDS_5638 "SCSI (%02i:%02i)" + IDS_5636 "ATAPI (%01i:%01i)" + IDS_5637 "SCSI (%02i:%02i)" IDS_5888 "160 kB" IDS_5889 "180 kB" diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index d0a3383df..4880fc948 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -8,7 +8,7 @@ # # Makefile for Win32 (MinGW32) environment. # -# Version: @(#)Makefile.mingw 1.0.113 2018/03/18 +# Version: @(#)Makefile.mingw 1.0.114 2018/03/31 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -108,6 +108,9 @@ else ifndef STEALTH32 STEALTH32 := n endif + ifndef VGAWONDER + VGAWONDER := n + endif ifndef VNC VNC := n endif @@ -391,6 +394,10 @@ OPTS += -DUSE_STEALTH32 DEVBROBJ += vid_icd2061.o endif +ifeq ($(VGAWONDER), y) +OPTS += -DUSE_VGAWONDER +endif + ifeq ($(XL24), y) OPTS += -DUSE_XL24 endif @@ -433,13 +440,13 @@ MCHOBJ := machine.o machine_table.o \ m_xt_xi8088.o \ m_pcjr.o \ m_amstrad.o \ - m_europc.o m_europc_hdc.o \ + m_europc.o \ m_olivetti_m24.o m_tandy.o \ m_at.o \ m_at_ali1429.o m_at_commodore.o \ m_at_neat.o m_at_headland.o \ m_at_t3100e.o m_at_t3100e_vid.o \ - m_ps1.o \ + m_ps1.o m_ps1_hdc.o \ m_ps2_isa.o m_ps2_mca.o \ m_at_opti495.o m_at_scat.o \ m_at_compaq.o m_at_wd76c10.o \ @@ -467,10 +474,10 @@ FDDOBJ := fdd.o fdc.o fdi2raw.o \ HDDOBJ := hdd.o \ hdd_image.o hdd_table.o \ hdc.o \ - hdc_mfm_xt.o hdc_xtide.o \ - hdc_mfm_at.o \ + hdc_mfm_xt.o hdc_mfm_at.o \ + hdc_xta.o \ hdc_esdi_at.o hdc_esdi_mca.o \ - hdc_ide.o + hdc_xtide.o hdc_ide.o CDROMOBJ := cdrom.o \ cdrom_dosbox.o cdrom_image.o cdrom_null.o @@ -549,7 +556,7 @@ VIDOBJ := video.o \ PLATOBJ := win.o \ win_dynld.o win_thread.o \ - win_cdrom.o win_cdrom_ioctl.o win_keyboard.o \ + win_cdrom.o win_keyboard.o \ win_mouse.o win_joystick.o win_midi.o OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(MCHOBJ) $(DEVOBJ) \ diff --git a/src/win/icons/removable_disk.ico b/src/win/icons/removable_disk.ico deleted file mode 100644 index 6f67d6a5652497b9f58fda44f637fa3b49d4f04f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmd6k&2AD=6vr=WqDxjrcWg|$awV_e3-AVRG_i?3fvIuPq)8<%jKvfvRrl4jR7T9<7$qtYc4ZFm{_U zHbzj1DuX%&#^_ynNPqpGOgf!TYyJ4)ZCVo3vXW6bk|L{OW{51QA|Xhkni7Sq-SK0^ zU@+VtwtwyO(xM}?tst$)2*sk8;#~J&VR;chLq7aUCF^><{tkWP)>b0k=AIyn2*x6P z_&SkJ^+`(Uer-JxfWzy?@~R#2WCAZH{X|I62< zPlZYeeDr!fbUGchkB-o6wNP&~uwSd8QmrCi*h4nA13{7C4fqA_@?o-?pR0TMfq!yx zslQt+U^}0Kn3eHu<@>_GW^B@E)X{mi`uktu7fMB_yE#Z%1@EoaXCt4-@J2+s$}dy@ zg>s4Z-$5k4bzn3a@1FNv9*_NRe7?Wi=Z&3rd2XIFKP(oD_1|=U-EJ4h{0!S|G!GBa zXf{zhsH3u9g``L=i_OOG{lYMrOk;EN^G|1OmhllL%k21wca*=LnR#$Q{D%dAG0ueM W&n6~l$!jBAl)J7E$le?{+&cw$l`&KR diff --git a/src/win/icons/removable_disk_active.ico b/src/win/icons/removable_disk_active.ico deleted file mode 100644 index bfbc3707ffc93eeb9b5d4b8ffb7f59c02aa1f0b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmc(b-A__s9LImBz`W79xwYkuIZWDFPolj2yVfr3@8s9rW&H^hw7d)>pHqg3sfeFP(_#%%Iy!@ zZ}WesRH`Q9=*Y9M7zszEl{iO~qVdQ|g;q;zk=)EZLE~8CGSknETPCJgRwaa`D7?YI zZwR9T=p8|6RifTn4~0b`*L9}44D;*f7eaaNEk`5p1pP9+UI;JAs75ZMZK4gGuFe`Q z<1J`@-Yha-_#6u5Y%T|89Cl3GZ8B3VPR`EA+12^c>3|mIaJg<)m-8JTdQR(v9k@nN~IDCg#z+N zN66-K*w19JySIm(bQ&9pEyUK>uq=six7$sQBgbU;WKw0;?PAh{U3J zKl$NJ)qkYbs=h2O=H&UO_=)W#;+yLbV-j8(jd!X(kG?s-c$%ML=TD@z+59#5L-Pk( zt@hG!-{x?9Jd4lg+g;A!ahK=%Vg0paGP(ba-Cwa-#8-ZY`8=|Rhsb2J*gM$A&Tbl_ zB<2hzQ};=q*E*d}J#04j44DkQRdj}--YPFx{$z0Q>Yv>I)x#_i`iR*3%i?vP@Dm%$ NZRab*E-(ibz5~3eC(8f; diff --git a/src/win/icons/removable_disk_empty.ico b/src/win/icons/removable_disk_empty.ico deleted file mode 100644 index 09229f56670a27b0d46ac11438a4d77a09d6e060..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmd6ky>8P`6o79iDock7B-EioNDS}-eTfc8mGThX(g$GZf|Q|xH|UZIiSDf;SdKty zR5QeloleF1^}iEe|HRF|dyZX4fvSZKY<>6Kd+hJt<738hc(1QB9AC2C$BaE^jJ-iH zg_$&ufiZk$-;%8Vlc7*3tVx&kJv7ct{MtxrVc%~e^M+KpW+^?cF*}jp6hWiFcP%xaW|pQ)4XOGKzlUW zEpYlhfbZYlqMx%Jr`*+5=%_?Dp^dTK?JUUh6gATT)3)I3{Cu0fK{t&n9t`ho6TT4ox)@?fzfyj!_f$?heHUX0r+76 zuFpX;^b)yriBc^e48qjMJ?`@dQ3OF4CVg(Uo9|Pbu`@x~zPO||*EG-bFi=B)r&V_3A^&RmaCgPYeVn6q55&O8LTn6AAR#KWz HQir@7Uj98h diff --git a/src/win/icons/removable_disk_empty_active.ico b/src/win/icons/removable_disk_empty_active.ico deleted file mode 100644 index 4fcd2ebbcd6ca0651d99432f2bb1a3faad1f8c64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1150 zcmc(bOKTHR6oAiYV!E)UAcPXENH?ZGz&}xn5a>efA5dJxA0Sed?gAxCK_m9z!kuVC z5R~i2kWrFpCaD!{8q%bB%*0G)CX@GE&z&(bjjy`$&V2XWbB6EUI|qQnXL=fNz6duQ z0B!*AB3QzTUB>``-=yzY`M*q$!N0;OK|4= zgZZ0m55M1kR@_bBRupBkuGXJ36h_^~6ZWVOLwAg+t*OtbpZb!?tkpG@phL=X1cz&ajhCgeRzD+hOIdr!EcsGg4K4&AeJ&Atj6qmRFUU#q7pxbMDm~U5qXc@x1U* z_apZ%`kW-ok$ka04hxLDMGj*we`s;}fCSm*!2H<*v-D5^>XQCu4MES9Cpv%mWIj~d>;B1>VO=g*D$`9dLZA|KB$6puoq zE?Xy4$;)`Z?Lq%Wd(g4^X!lT2m57*1T^aXTE(pSfR66b3Nr^)QamP0xfondIxb!Rc df7R$a0J;Kz@3F!1748QF*W|QK)`bqW`3A*-Em8mg diff --git a/src/win/resource.h b/src/win/resource.h index af9d94b77..6bf1d7956 100644 --- a/src/win/resource.h +++ b/src/win/resource.h @@ -8,7 +8,7 @@ * * Windows resource defines. * - * Version: @(#)resource.h 1.0.22 2018/03/06 + * Version: @(#)resource.h 1.0.23 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, @@ -58,8 +58,7 @@ #define IDT_1715 1715 /* Network adapter: */ #define IDT_1716 1716 /* SCSI Controller: */ #define IDT_1717 1717 /* HD Controller: */ -#define IDT_1718 1718 /* Tertiary IDE: */ -#define IDT_1719 1719 /* Quaternary IDE: */ +#define IDT_1718 1718 #define IDT_1720 1720 /* Hard disks: */ #define IDT_1721 1721 /* Bus: */ #define IDT_1722 1722 /* Channel: */ @@ -91,6 +90,7 @@ #define IDT_1756 1756 /* Channel: */ #define IDT_1757 1757 /* Progress: */ #define IDT_1758 1758 /* Speed: */ +#define IDT_1759 1759 /* ZIP drives: */ /* @@ -157,9 +157,12 @@ #define IDC_COMBO_SCSI 1121 #define IDC_CONFIGURE_SCSI 1122 #define IDC_COMBO_HDC 1123 -#define IDC_COMBO_IDE_TER 1124 -#define IDC_COMBO_IDE_QUA 1125 -#define IDC_CHECK_BUGGER 1126 +#define IDC_CONFIGURE_HDC 1124 +#define IDC_CHECK_IDE_TER 1125 +#define IDC_BUTTON_IDE_TER 1126 +#define IDC_CHECK_IDE_QUA 1127 +#define IDC_BUTTON_IDE_QUA 1128 +#define IDC_CHECK_BUGGER 1129 #define IDC_HARD_DISKS 1130 /* hard disk config */ #define IDC_LIST_HARD_DISKS 1131 diff --git a/src/win/win.c b/src/win/win.c index d4ca6e66b..938d73614 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -8,7 +8,7 @@ * * Platform main support module for Windows. * - * Version: @(#)win.c 1.0.46 2018/03/16 + * Version: @(#)win.c 1.0.47 2018/03/28 * * Authors: Sarah Walker, * Miran Grca, @@ -75,6 +75,7 @@ static rc_str_t *lpRCstr2048, *lpRCstr5888, *lpRCstr6144, *lpRCstr7168; +static int vid_api_inited = 0; static struct { @@ -202,27 +203,26 @@ plat_get_string(int i) { LPTSTR str; - if ((i >= 2048) && (i <= 3071)) { + if ((i >= 2048) && (i <= 3071)) str = lpRCstr2048[i-2048].str; - } else if ((i >= 4096) && (i <= 4351)) { + else if ((i >= 4096) && (i <= 4351)) str = lpRCstr4096[i-4096].str; - } else if ((i >= 4352) && (i <= 4607)) { + else if ((i >= 4352) && (i <= 4607)) str = lpRCstr4352[i-4352].str; - } else if ((i >= 4608) && (i <= 5119)) { + else if ((i >= 4608) && (i <= 5119)) str = lpRCstr4608[i-4608].str; - } else if ((i >= 5120) && (i <= 5375)) { + else if ((i >= 5120) && (i <= 5375)) str = lpRCstr5120[i-5120].str; - } else if ((i >= 5376) && (i <= 5631)) { + else if ((i >= 5376) && (i <= 5631)) str = lpRCstr5376[i-5376].str; - } else if ((i >= 5632) && (i <= 5887)) { + else if ((i >= 5632) && (i <= 5887)) str = lpRCstr5632[i-5632].str; - } else if ((i >= 5888) && (i <= 6143)) { + else if ((i >= 5888) && (i <= 6143)) str = lpRCstr5888[i-5888].str; - } else if ((i >= 6144) && (i <= 7167)) { + else if ((i >= 6144) && (i <= 7167)) str = lpRCstr6144[i-6144].str; - } else { + else str = lpRCstr7168[i-7168].str; - } return((wchar_t *)str); } @@ -251,29 +251,24 @@ CreateConsole(int init) /* Not logging to file, attach to console. */ if (! AttachConsole(ATTACH_PARENT_PROCESS)) { /* Parent has no console, create one. */ - AllocConsole(); + if (! AllocConsole()) { + /* Cannot create console, just give up. */ + return; + } + } + fp = NULL; + if ((h = GetStdHandle(STD_OUTPUT_HANDLE)) != NULL) { + /* We got the handle, now open a file descriptor. */ + if ((i = _open_osfhandle((intptr_t)h, _O_TEXT)) != -1) { + /* We got a file descriptor, now allocate a new stream. */ + if ((fp = _fdopen(i, "w")) != NULL) { + /* Got the stream, re-initialize stdout without it. */ + (void)freopen("CONOUT$", "w", stdout); + setvbuf(stdout, NULL, _IONBF, 0); + fflush(stdout); + } + } } - - h = GetStdHandle(STD_OUTPUT_HANDLE); - i = _open_osfhandle((intptr_t)h, _O_TEXT); - fp = _fdopen(i, "w"); - setvbuf(fp, NULL, _IONBF, 1); - *stdout = *fp; - - h = GetStdHandle(STD_ERROR_HANDLE); - i = _open_osfhandle((intptr_t)h, _O_TEXT); - fp = _fdopen(i, "w"); - setvbuf(fp, NULL, _IONBF, 1); - *stderr = *fp; - -#if 0 - /* Set up stdin as well. */ - h = GetStdHandle(STD_INPUT_HANDLE); - i = _open_osfhandle((intptr_t)h, _O_TEXT); - fp = _fdopen(i, "r"); - setvbuf(fp, NULL, _IONBF, 128); - *stdin = *fp; -#endif } @@ -588,7 +583,7 @@ plat_vidapi(char *name) { int i; - if (!strcasecmp(name, "default") || !strcasecmp(name, "system")) return(1); + if (!strcasecmp(name, "default") || !strcasecmp(name, "system")) return(0); for (i=0; i<4; i++) { if (vid_apis[0][i].name && @@ -596,7 +591,7 @@ plat_vidapi(char *name) } /* Default value. */ - return(1); + return(0); } @@ -607,25 +602,16 @@ plat_vidapi_name(int api) char *name = "default"; switch(api) { -#if USE_WX case 0: - break; - - case 1: - name = "wxwidgets"; - break; -#else - case 0: - name = "ddraw"; - break; - - case 1: #if 0 - /* Direct3D is default. */ - name = "d3d"; + /* DirectDraw is default. */ + name = "ddraw"; #endif break; -#endif + + case 1: + name = "d3d"; + break; #ifdef USE_VNC case 2: @@ -679,6 +665,8 @@ plat_setvid(int api) device_force_redraw(); + vid_api_inited = 1; + return(1); } @@ -687,7 +675,7 @@ plat_setvid(int api) void plat_vidsize(int x, int y) { - if (! vid_apis[video_fullscreen][vid_api].resize) return; + if (!vid_api_inited || !vid_apis[video_fullscreen][vid_api].resize) return; startblit(); video_wait_for_blit(); @@ -798,6 +786,16 @@ take_screenshot(void) } +/* LPARAM interface to plat_get_string(). */ +LPARAM win_get_string(int id) +{ + wchar_t *ret; + + ret = plat_get_string(id); + return ((LPARAM) ret); +} + + void /* plat_ */ startblit(void) { diff --git a/src/win/win.h b/src/win/win.h index c909b0829..0abf4d7dd 100644 --- a/src/win/win.h +++ b/src/win/win.h @@ -8,7 +8,7 @@ * * Platform support defintions for Win32. * - * Version: @(#)win.h 1.0.15 2018/03/18 + * Version: @(#)win.h 1.0.16 2018/03/28 * * Authors: Sarah Walker, * Miran Grca, @@ -91,6 +91,8 @@ extern void keyboard_handle(LPARAM lParam, int infocus); extern void win_mouse_init(void); extern void win_mouse_close(void); +extern LPARAM win_get_string(int id); + extern intptr_t fdd_type_to_icon(int type); #ifdef EMU_DEVICE_H diff --git a/src/win/win_about.c b/src/win/win_about.c index 9e83d7a5c..37389dfab 100644 --- a/src/win/win_about.c +++ b/src/win/win_about.c @@ -8,13 +8,13 @@ * * Handle the About dialog. * - * Version: @(#)win_about.c 1.0.5 2017/12/13 + * Version: @(#)win_about.c 1.0.6 2018/03/28 * * Authors: Miran Grca, * Fred N. van Kempen, * - * Copyright 2016,2017 Miran Grca. - * Copyright 2017 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. */ #define UNICODE #define BITMAP WINDOWS_BITMAP @@ -39,13 +39,15 @@ static BOOL CALLBACK AboutDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h; + HANDLE ih; switch (message) { case WM_INITDIALOG: plat_pause(1); h = GetDlgItem(hdlg, IDC_ABOUT_ICON); + ih = LoadImage(hinstance,(PCTSTR)100,IMAGE_ICON,64,64,0); SendMessage(h, STM_SETIMAGE, (WPARAM)IMAGE_ICON, - (LPARAM)LoadImage(hinstance,(PCTSTR)100,IMAGE_ICON,64,64,0)); + (LPARAM)ih); break; case WM_COMMAND: diff --git a/src/win/win_cdrom.c b/src/win/win_cdrom.c index 0741bfc5e..666ac7ccf 100644 --- a/src/win/win_cdrom.c +++ b/src/win/win_cdrom.c @@ -8,7 +8,7 @@ * * Handle the platform-side of CDROM drives. * - * Version: @(#)win_cdrom.c 1.0.6 2018/03/17 + * Version: @(#)win_cdrom.c 1.0.7 2018/03/26 * * Authors: Sarah Walker, * Miran Grca, @@ -28,43 +28,18 @@ #include #include #include "../config.h" -#include "../cdrom/cdrom.h" -#include "../cdrom/cdrom_image.h" -#include "../cdrom/cdrom_null.h" #include "../disk/hdd.h" #include "../disk/zip.h" #include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../cdrom/cdrom_image.h" +#include "../cdrom/cdrom_null.h" #include "../scsi/scsi_disk.h" #include "../plat.h" #include "../ui.h" #include "win.h" -uint8_t host_cdrom_drive_available[26]; -uint8_t host_cdrom_drive_available_num = 0; - - -void -cdrom_init_host_drives(void) -{ - WCHAR s[64]; - int i = 0; - - host_cdrom_drive_available_num = 0; - for (i='A'; i<='Z'; i++) { - _swprintf(s, L"%c:\\", i); - - if (GetDriveType(s)==DRIVE_CDROM) { - host_cdrom_drive_available[i - 'A'] = 1; - - host_cdrom_drive_available_num++; - } else { - host_cdrom_drive_available[i - 'A'] = 0; - } - } -} - - void cdrom_eject(uint8_t id) { @@ -73,12 +48,6 @@ cdrom_eject(uint8_t id) return; } - if ((cdrom_drives[id].host_drive >= 'A') && - (cdrom_drives[id].host_drive <= 'Z')) { - ui_sb_check_menu_item(SB_CDROM|id, - IDM_CDROM_HOST_DRIVE | id | ((cdrom_drives[id].host_drive - 'A') << 3), MF_UNCHECKED); - } - if (cdrom_image[id].prev_image_path) { free(cdrom_image[id].prev_image_path); cdrom_image[id].prev_image_path = NULL; @@ -89,12 +58,13 @@ cdrom_eject(uint8_t id) wcscpy(cdrom_image[id].prev_image_path, cdrom_image[id].image_path); } cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; - cdrom_drives[id].handler->exit(id); - cdrom_close(id); - cdrom_null_open(id, 0); + cdrom[id]->handler->exit(id); + cdrom_close_handler(id); + memset(cdrom_image[id].image_path, 0, 2048); + cdrom_null_open(id); if (cdrom_drives[id].bus_type) { /* Signal disc change to the emulated machine. */ - cdrom_insert(id); + cdrom_insert(cdrom[id]); } ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_UNCHECKED); @@ -111,14 +81,13 @@ cdrom_eject(uint8_t id) void cdrom_reload(uint8_t id) { - int new_cdrom_drive; - if ((cdrom_drives[id].host_drive == cdrom_drives[id].prev_host_drive) || (cdrom_drives[id].prev_host_drive == 0) || (cdrom_drives[id].host_drive != 0)) { /* Switch from empty to empty. Do nothing. */ return; } - cdrom_close(id); + cdrom_close_handler(id); + memset(cdrom_image[id].image_path, 0, 2048); if (cdrom_drives[id].prev_host_drive == 200) { wcscpy(cdrom_image[id].image_path, cdrom_image[id].prev_image_path); @@ -127,7 +96,7 @@ cdrom_reload(uint8_t id) image_open(id, cdrom_image[id].image_path); if (cdrom_drives[id].bus_type) { /* Signal disc change to the emulated machine. */ - cdrom_insert(id); + cdrom_insert(cdrom[id]); } if (wcslen(cdrom_image[id].image_path) == 0) { ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_CHECKED); @@ -140,17 +109,6 @@ cdrom_reload(uint8_t id) ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_CHECKED); ui_sb_update_icon_state(SB_CDROM|id, 0); } - } else { - new_cdrom_drive = cdrom_drives[id].prev_host_drive; - ioctl_open(id, new_cdrom_drive); - if (cdrom_drives[id].bus_type) { - /* Signal disc change to the emulated machine. */ - cdrom_insert(id); - } - ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_UNCHECKED); - cdrom_drives[id].host_drive = new_cdrom_drive; - ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_HOST_DRIVE | id | ((cdrom_drives[id].host_drive - 'A') << 3), MF_CHECKED); - ui_sb_update_icon_state(SB_CDROM|id, 0); } ui_sb_enable_menu_item(SB_CDROM|id, IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); @@ -194,56 +152,3 @@ zip_reload(uint8_t id) config_save(); } - - -void -removable_disk_unload(uint8_t id) -{ - if (wcslen(hdd[id].fn) == 0) { - /* Switch from empty to empty. Do nothing. */ - return; - } - - scsi_unloadhd(hdd[id].scsi_id, hdd[id].scsi_lun, id); - scsi_disk_insert(id); -} - - -void -removable_disk_eject(uint8_t id) -{ - removable_disk_unload(id); - ui_sb_update_icon_state(SB_RDISK|id, 1); - ui_sb_enable_menu_item(SB_RDISK|id, IDM_RDISK_EJECT | id, MF_BYCOMMAND | MF_GRAYED); - ui_sb_enable_menu_item(SB_RDISK|id, IDM_RDISK_RELOAD | id, MF_BYCOMMAND | MF_ENABLED); - ui_sb_enable_menu_item(SB_RDISK|id, IDM_RDISK_SEND_CHANGE | id, MF_BYCOMMAND | MF_GRAYED); - - ui_sb_update_tip(SB_RDISK|id); - - config_save(); -} - - -void -removable_disk_reload(uint8_t id) -{ - if (wcslen(hdd[id].fn) != 0) { - /* Attempting to reload while an image is already loaded. Do nothing. */ - return; - } - - scsi_reloadhd(id); -#if 0 - scsi_disk_insert(id); -#endif - - ui_sb_update_icon_state(SB_RDISK|id, wcslen(hdd[id].fn) ? 0 : 1); - - ui_sb_enable_menu_item(SB_RDISK|id, IDM_RDISK_EJECT | id, MF_BYCOMMAND | (wcslen(hdd[id].fn) ? MF_ENABLED : MF_GRAYED)); - ui_sb_enable_menu_item(SB_RDISK|id, IDM_RDISK_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); - ui_sb_enable_menu_item(SB_RDISK|id, IDM_RDISK_SEND_CHANGE | id, MF_BYCOMMAND | (wcslen(hdd[id].fn) ? MF_ENABLED : MF_GRAYED)); - - ui_sb_update_tip(SB_RDISK|id); - - config_save(); -} diff --git a/src/win/win_cdrom_ioctl.c b/src/win/win_cdrom_ioctl.c deleted file mode 100644 index 3261fc441..000000000 --- a/src/win/win_cdrom_ioctl.c +++ /dev/null @@ -1,1341 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * Implementation of the CD-ROM host drive IOCTL interface for - * Windows using SCSI Passthrough Direct. - * - * Version: @(#)cdrom_ioctl.c 1.0.15 2018/03/20 - * - * Authors: Sarah Walker, - * Miran Grca, - * - * Copyright 2008-2018 Sarah Walker. - * Copyright 2016-2018 Miran Grca. - */ -#define WINVER 0x0600 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include "../86box.h" -#include "../device.h" -#include "../scsi/scsi.h" -#include "../cdrom/cdrom.h" -#include "../plat.h" - - -#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) - - -enum { - CD_STOPPED = 0, - CD_PLAYING, - CD_PAUSED -}; - - -typedef struct { - HANDLE hIOCTL; - CDROM_TOC toc; - int is_playing; -} cdrom_ioctl_windows_t; - - -cdrom_ioctl_windows_t cdrom_ioctl_windows[CDROM_NUM]; - -#ifdef ENABLE_CDROM_IOCTL_LOG -int cdrom_ioctl_do_log = ENABLE_CDROM_IOCTL_LOG; -#endif - - -static CDROM ioctl_cdrom; - - -static void -cdrom_ioctl_log(const char *format, ...) -{ -#ifdef ENABLE_CDROM_IOCTL_LOG - va_list ap; - - if (cdrom_ioctl_do_log) { - va_start(ap, format); - pclog_ex(format, ap); - va_end(ap); - } -#endif -} - -static int ioctl_hopen(uint8_t id); - -void ioctl_audio_callback(uint8_t id, int16_t *output, int len) -{ - cdrom_t *dev = cdrom[id]; - - RAW_READ_INFO in; - DWORD count; - - if (!cdrom_drives[id].sound_on || (dev->cd_state != CD_PLAYING)) - { - if (dev->cd_state == CD_PLAYING) - { - dev->seek_pos += (len >> 11); - cdrom_ioctl_log("ioctl_audio_callback(): playing but mute\n"); - } else - cdrom_ioctl_log("ioctl_audio_callback(): not playing\n"); - cdrom_ioctl_windows[id].is_playing = 0; - memset(output, 0, len * 2); - return; - } - cdrom_ioctl_log("ioctl_audio_callback(): dev->cd_buflen = %i, len = %i\n", dev->cd_buflen, len); - while (dev->cd_buflen < len) - { - if (dev->seek_pos < dev->cd_end) - { - in.DiskOffset.LowPart = dev->seek_pos * 2048; - in.DiskOffset.HighPart = 0; - in.SectorCount = 1; - in.TrackMode = CDDA; - if (!DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &(dev->cd_buffer[dev->cd_buflen]), 2352, &count, NULL)) - { - memset(&(dev->cd_buffer[dev->cd_buflen]), 0, (BUF_SIZE - dev->cd_buflen) * 2); - cdrom_ioctl_windows[id].is_playing = 0; - ioctl_close(id); - dev->cd_state = CD_STOPPED; - dev->cd_buflen = len; - cdrom_ioctl_log("ioctl_audio_callback(): read sector error, stopped\n"); - } - else - { - dev->seek_pos++; - dev->cd_buflen += (2352 / 2); - cdrom_ioctl_log("ioctl_audio_callback(): dev->seek_pos = %i\n", dev->seek_pos); - } - } - else - { - memset(&(dev->cd_buffer[dev->cd_buflen]), 0, (BUF_SIZE - dev->cd_buflen) * 2); - cdrom_ioctl_windows[id].is_playing = 0; - ioctl_close(id); - dev->cd_state = CD_STOPPED; - dev->cd_buflen = len; - cdrom_ioctl_log("ioctl_audio_callback(): reached the end\n"); - } - } - memcpy(output, dev->cd_buffer, len * 2); - memcpy(&dev->cd_buffer[0], &(dev->cd_buffer[len]), (BUF_SIZE - len) * 2); - dev->cd_buflen -= len; -} - -void ioctl_audio_stop(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - cdrom_ioctl_windows[id].is_playing = 0; - ioctl_close(id); - dev->cd_state = CD_STOPPED; -} - -static int get_track_nr(uint8_t id, uint32_t pos) -{ - cdrom_t *dev = cdrom[id]; - - int c; - int track = 0; - - if (dev->disc_changed) - { - return 0; - cdrom_ioctl_log("get_track_nr(): disc changed\n"); - } - - if (cdrom_ioctl[id].last_track_pos == pos) - { - cdrom_ioctl_log("get_track_nr(): cdrom_ioctl[id].last_track_pos == pos\n"); - return cdrom_ioctl[id].last_track_nr; - } - - /* for (c = cdrom_ioctl_windows[id].toc.FirstTrack; c < cdrom_ioctl_windows[id].toc.LastTrack; c++) */ - for (c = 0; c < cdrom_ioctl_windows[id].toc.LastTrack; c++) - { - uint32_t track_address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1], - cdrom_ioctl_windows[id].toc.TrackData[c].Address[2], - cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]) - 150; - - if (track_address <= pos) - { - cdrom_ioctl_log("get_track_nr(): track = %i\n", c); - track = c; - } - } - cdrom_ioctl[id].last_track_pos = pos; - cdrom_ioctl[id].last_track_nr = track; - - cdrom_ioctl_log("get_track_nr(): return %i\n", track); - return track; -} - -static uint32_t get_track_msf(uint8_t id, uint32_t track_no) -{ - cdrom_t *dev = cdrom[id]; - int c; - - if (dev->disc_changed) - { - return 0; - } - - for (c = cdrom_ioctl_windows[id].toc.FirstTrack; c < cdrom_ioctl_windows[id].toc.LastTrack; c++) - { - if (c == track_no) - { - return cdrom_ioctl_windows[id].toc.TrackData[c].Address[3] + (cdrom_ioctl_windows[id].toc.TrackData[c].Address[2] << 8) + (cdrom_ioctl_windows[id].toc.TrackData[c].Address[1] << 16); - } - } - return 0xffffffff; -} - -static void ioctl_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) -{ - cdrom_t *dev = cdrom[id]; - int m = 0, s = 0, f = 0; - uint32_t start_msf = 0, end_msf = 0; - if (!cdrom_drives[id].host_drive) - { - return; - } - cdrom_ioctl_log("Play audio - %08X %08X %i\n", pos, len, ismsf); - if (ismsf == 2) - { - start_msf = get_track_msf(id, pos); - end_msf = get_track_msf(id, len); - if (start_msf == 0xffffffff) - { - return; - } - if (end_msf == 0xffffffff) - { - return; - } - m = (start_msf >> 16) & 0xff; - s = (start_msf >> 8) & 0xff; - f = start_msf & 0xff; - pos = MSFtoLBA(m, s, f) - 150; - m = (end_msf >> 16) & 0xff; - s = (end_msf >> 8) & 0xff; - f = end_msf & 0xff; - len = MSFtoLBA(m, s, f) - 150; - } - else if (ismsf == 1) - { - m = (pos >> 16) & 0xff; - s = (pos >> 8) & 0xff; - f = pos & 0xff; - - if (pos == 0xffffff) - { - cdrom_ioctl_log("Playing from current position (MSF)\n"); - pos = dev->seek_pos; - } - else - { - pos = MSFtoLBA(m, s, f) - 150; - } - - m = (len >> 16) & 0xff; - s = (len >> 8) & 0xff; - f = len & 0xff; - len = MSFtoLBA(m, s, f) - 150; - } - else if (ismsf == 0) - { - if (pos == 0xffffffff) - { - cdrom_ioctl_log("Playing from current position\n"); - pos = dev->seek_pos; - } - len += pos; - } - dev->seek_pos = pos; - dev->cd_end = len; - - if (!cdrom_ioctl_windows[id].is_playing) - { - ioctl_hopen(id); - cdrom_ioctl_windows[id].is_playing = 1; - } - dev->cd_state = CD_PLAYING; -} - -static void ioctl_pause(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - if (!cdrom_drives[id].host_drive) - { - return; - } - if (dev->cd_state == CD_PLAYING) - { - dev->cd_state = CD_PAUSED; - } -} - -static void ioctl_resume(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - if (!cdrom_drives[id].host_drive) - { - return; - } - if (dev->cd_state == CD_PAUSED) - { - dev->cd_state = CD_PLAYING; - } -} - -static void ioctl_stop(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - if (!cdrom_drives[id].host_drive) - { - return; - } - if (cdrom_ioctl_windows[id].is_playing) - { - cdrom_ioctl_windows[id].is_playing = 0; - ioctl_close(id); - } - dev->cd_state = CD_STOPPED; -} - -static int ioctl_ready(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - unsigned long size; - int temp; - CDROM_TOC ltoc; - if (!cdrom_drives[id].host_drive) - { - return 0; - } - if (cdrom_ioctl_windows[id].hIOCTL == NULL) - { - ioctl_hopen(id); - temp = DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), &size, NULL); - ioctl_close(id); - } - else - { - temp = DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), &size, NULL); - } - if (!temp) - { - return 0; - } - if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[1]) || - (ltoc.TrackData[ltoc.LastTrack].Address[2] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[2]) || - (ltoc.TrackData[ltoc.LastTrack].Address[3] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[3]) || - dev->disc_changed || (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive)) - { - dev->cd_state = CD_STOPPED; - if (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive) - { - cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; - } - return 1; - } - return 1; -} - -static int ioctl_get_last_block(uint8_t id, unsigned char starttrack, int msf, int maxlen, int single) -{ - cdrom_t *dev = cdrom[id]; - unsigned long size; - int c, d = 0; - CDROM_TOC lbtoc; - int lb = 0; - if (!cdrom_drives[id].host_drive) - { - return 0; - } - dev->cd_state = CD_STOPPED; - ioctl_hopen(id); - DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, &lbtoc, sizeof(lbtoc), &size, NULL); - ioctl_close(id); - dev->disc_changed = 0; - for (c=d; c <= lbtoc.LastTrack; c++) - { - uint32_t address; - address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1], cdrom_ioctl_windows[id].toc.TrackData[c].Address[2], cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]); - if (address > lb) - { - lb = address; - } - } - return lb; -} - -static void ioctl_read_capacity(uint8_t id, uint8_t *b); - -static int ioctl_medium_changed(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - unsigned long size; - int temp; - CDROM_TOC ltoc; - if (!cdrom_drives[id].host_drive) - { - return 0; /* This will be handled by the not ready handler instead. */ - } - ioctl_hopen(id); - temp = DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc,sizeof(ltoc), &size, NULL); - ioctl_close(id); - if (!temp) - { - return 0; /* Drive empty, a not ready handler matter, not disc change. */ - } - if (dev->disc_changed || (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive)) - { - dev->cd_state = CD_STOPPED; - cdrom_ioctl_windows[id].toc = ltoc; - dev->disc_changed = 0; - if (cdrom_drives[id].host_drive != cdrom_drives[id].prev_host_drive) - { - cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; - } - ioctl_hopen(id); - cdrom_ioctl[id].capacity_read=0; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */ - ioctl_read_capacity(id, NULL); - ioctl_close(id); - dev->cdrom_capacity = ioctl_get_last_block(id, 0, 0, 4096, 0); - return 1; - } - else - { - if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[1]) || - (ltoc.TrackData[ltoc.LastTrack].Address[2] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[2]) || - (ltoc.TrackData[ltoc.LastTrack].Address[3] != cdrom_ioctl_windows[id].toc.TrackData[cdrom_ioctl_windows[id].toc.LastTrack].Address[3])) - { - dev->cd_state = CD_STOPPED; - cdrom_ioctl_log("Setting TOC...\n"); - cdrom_ioctl_windows[id].toc = ltoc; - ioctl_hopen(id); - cdrom_ioctl[id].capacity_read=0; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */ - ioctl_read_capacity(id, NULL); - ioctl_close(id); - dev->cdrom_capacity = ioctl_get_last_block(id, 0, 0, 4096, 0); - return 1; /* TOC mismatches. */ - } - } - return 0; /* None of the above, return 0. */ -} - -static uint8_t ioctl_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) -{ - cdrom_t *dev = cdrom[id]; - CDROM_SUB_Q_DATA_FORMAT insub; - SUB_Q_CHANNEL_DATA sub; - unsigned long size; - int pos = 0, track; - uint32_t cdpos, track_address, dat; - - if (!cdrom_drives[id].host_drive) return 0; - - cdpos = dev->seek_pos; - - if (dev->last_subchannel_pos == cdpos) - { - memcpy(&insub, dev->sub_q_data_format, sizeof(insub)); - memcpy(&sub, dev->sub_q_channel_data, sizeof(sub)); - } - else - { - insub.Format = IOCTL_CDROM_CURRENT_POSITION; - ioctl_hopen(id); - DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL,&insub,sizeof(insub),&sub,sizeof(sub),&size,NULL); - ioctl_close(id); - memset(dev->sub_q_data_format, 0, 16); - memcpy(dev->sub_q_data_format, &insub, sizeof(insub)); - memset(dev->sub_q_channel_data, 0, 256); - memcpy(dev->sub_q_channel_data, &sub, sizeof(sub)); - dev->last_subchannel_pos = cdpos; - } - - if (dev->cd_state == CD_PLAYING || dev->cd_state == CD_PAUSED) - { - track = get_track_nr(id, cdpos); - track_address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[track].Address[1], - cdrom_ioctl_windows[id].toc.TrackData[track].Address[2], - cdrom_ioctl_windows[id].toc.TrackData[track].Address[3]) - 150; - - cdrom_ioctl_log("ioctl_getcurrentsubchannel(): cdpos = %i, track = %i, track_address = %i\n", cdpos, track, track_address); - - b[pos++] = sub.CurrentPosition.Control; - b[pos++] = track + 1; - b[pos++] = sub.CurrentPosition.IndexNumber; - - if (msf) - { - dat = cdpos + 150; - b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; - b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; - b[pos + 1] = (uint8_t)dat; - b[pos] = 0; - pos += 4; - dat = cdpos - track_address; - b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; - b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; - b[pos + 1] = (uint8_t)dat; - b[pos] = 0; - pos += 4; - } - else - { - b[pos++] = (cdpos >> 24) & 0xff; - b[pos++] = (cdpos >> 16) & 0xff; - b[pos++] = (cdpos >> 8) & 0xff; - b[pos++] = cdpos & 0xff; - cdpos -= track_address; - b[pos++] = (cdpos >> 24) & 0xff; - b[pos++] = (cdpos >> 16) & 0xff; - b[pos++] = (cdpos >> 8) & 0xff; - b[pos++] = cdpos & 0xff; - } - - if (dev->cd_state == CD_PLAYING) return 0x11; - return 0x12; - } - - b[pos++]=sub.CurrentPosition.Control; - b[pos++]=sub.CurrentPosition.TrackNumber; - b[pos++]=sub.CurrentPosition.IndexNumber; - - cdrom_ioctl_log("cdpos = %i, track_address = %i\n", MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]), MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3])); - - if (msf) - { - int c; - for (c = 0; c < 4; c++) - { - b[pos++] = sub.CurrentPosition.AbsoluteAddress[c]; - } - for (c = 0; c < 4; c++) - { - b[pos++] = sub.CurrentPosition.TrackRelativeAddress[c]; - } - } - else - { - uint32_t temp = MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]) - 150; - b[pos++] = temp >> 24; - b[pos++] = temp >> 16; - b[pos++] = temp >> 8; - b[pos++] = temp; - temp = MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3]) - 150; - b[pos++] = temp >> 24; - b[pos++] = temp >> 16; - b[pos++] = temp >> 8; - b[pos++] = temp; - } - - return 0x13; -} - -static void ioctl_eject(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - unsigned long size; - if (!cdrom_drives[id].host_drive) - { - return; - } - if (cdrom_ioctl_windows[id].is_playing) - { - cdrom_ioctl_windows[id].is_playing = 0; - ioctl_stop(id); - } - dev->cd_state = CD_STOPPED; - ioctl_hopen(id); - DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&size,NULL); - ioctl_close(id); -} - -static void ioctl_load(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - unsigned long size; - if (!cdrom_drives[id].host_drive) - { - return; - } - if (cdrom_ioctl_windows[id].is_playing) - { - cdrom_ioctl_windows[id].is_playing = 0; - ioctl_stop(id); - } - dev->cd_state = CD_STOPPED; - ioctl_hopen(id); - DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_STORAGE_LOAD_MEDIA,NULL,0,NULL,0,&size,NULL); - cdrom_ioctl[id].capacity_read=0; /* With this two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */ - ioctl_read_capacity(id, NULL); - ioctl_close(id); - dev->cdrom_capacity = ioctl_get_last_block(id, 0, 0, 4096, 0); -} - -static int ioctl_is_track_audio(uint8_t id, uint32_t pos, int ismsf) -{ - cdrom_t *dev = cdrom[id]; - - int c; - int control = 0; - - uint32_t track_address = 0; - - if (dev->disc_changed) - { - return 0; - } - - for (c = 0; cdrom_ioctl_windows[id].toc.TrackData[c].TrackNumber != 0xaa; c++) - { - if (ismsf) { - track_address = cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]; - track_address |= (cdrom_ioctl_windows[id].toc.TrackData[c].Address[2] << 8); - track_address |= (cdrom_ioctl_windows[id].toc.TrackData[c].Address[1] << 16); - } else { - track_address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1],cdrom_ioctl_windows[id].toc.TrackData[c].Address[2],cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]); - track_address -= 150; - } - - if (cdrom_ioctl_windows[id].toc.TrackData[c].TrackNumber >= cdrom_ioctl_windows[id].toc.FirstTrack && - cdrom_ioctl_windows[id].toc.TrackData[c].TrackNumber <= cdrom_ioctl_windows[id].toc.LastTrack && - track_address <= pos) - control = cdrom_ioctl_windows[id].toc.TrackData[c].Control; - } - - if ((control & 0xd) <= 1) - return 1; - else - return 0; -} - -/* 00, 08, 10, 18, 20, 28, 30, 38 */ -int flags_to_size[5][32] = { { 0, 0, 2352, 2352, 2352, 2352, 2352, 2352, /* 00-38 (CD-DA) */ - 2352, 2352, 2352, 2352, 2352, 2352, 2352, 2352, /* 40-78 */ - 2352, 2352, 2352, 2352, 2352, 2352, 2352, 2352, /* 80-B8 */ - 2352, 2352, 2352, 2352, 2352, 2352, 2352, 2352 }, /* C0-F8 */ - { 0, 0, 2048, 2336, 4, -296, 2052, 2344, /* 00-38 (Mode 1) */ - 8, -296, 2048, 2048, 12, -296, 2052, 2052, /* 40-78 */ - -296, -296, -296, -296, 16, -296, 2064, 2344, /* 80-B8 */ - -296, -296, 2048, 2048, 24, -296, 2064, 2352 }, /* C0-F8 */ - { 0, 0, 2336, 2336, 4, -296, 2340, 2340, /* 00-38 (Mode 2 non-XA) */ - 8, -296, 2336, 2336, 12, -296, 2340, 2340, /* 40-78 */ - -296, -296, -296, -296, 16, -296, 2352, 2340, /* 80-B8 */ - -296, -296, 2336, 2336, 24, -296, 2352, 2352 }, /* C0-F8 */ - { 0, 0, 2048, 2336, 4, -296, -296, -296, /* 00-38 (Mode 2 Form 1) */ - 8, -296, 2056, 2344, 12, -296, 2060, 2340, /* 40-78 */ - -296, -296, -296, -296, 16, -296, -296, -296, /* 80-B8 */ - -296, -296, -296, -296, 24, -296, 2072, 2352 }, /* C0-F8 */ - { 0, 0, 2328, 2328, 4, -296, -296, -296, /* 00-38 (Mode 2 Form 2) */ - 8, -296, 2336, 2336, 12, -296, 2340, 2340, /* 40-78 */ - -296, -296, -296, -296, 16, -296, -296, -296, /* 80-B8 */ - -296, -296, -296, -296, 24, -296, 2352, 2352 } /* C0-F8 */ - }; - -static int ioctl_get_sector_data_type(uint8_t id, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, int ismsf); - -static void cdrom_illegal_mode(uint8_t id) -{ - cdrom_sense_key = SENSE_ILLEGAL_REQUEST; - cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; - cdrom_ascq = 0; -} - -struct sptd_with_sense -{ - SCSI_PASS_THROUGH s; - ULONG Filler; - UCHAR sense[32]; - UCHAR data[65536]; -} sptd; - -static int ioctl_get_block_length(uint8_t id, const UCHAR *cdb, int number_of_blocks, int no_length_check) -{ - cdrom_t *dev = cdrom[id]; - - int sector_type = 0; - int temp_len = 0; - - if (no_length_check) - { - switch (cdb[0]) - { - case 0x25: /* READ CAPACITY */ - case 0x44: /* READ HEADER */ - return 8; - case 0x42: /* READ SUBCHANNEL */ - case 0x43: /* READ TOC */ - case 0x51: /* READ DISC INFORMATION */ - case 0x52: /* READ TRACK INFORMATION */ - case 0x5A: /* MODE SENSE (10) */ - return (((uint32_t) cdb[7]) << 8) | ((uint32_t) cdb[8]); - case 0xAD: /* READ DVD STRUCTURE */ - return (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - default: - return 65534; - } - } - - switch (cdb[0]) - { - case 0x25: /* READ CAPACITY */ - case 0x44: /* READ HEADER */ - return 8; - case 0x42: /* READ SUBCHANNEL */ - case 0x43: /* READ TOC */ - case 0x51: /* READ DISC INFORMATION */ - case 0x52: /* READ TRACK INFORMATION */ - case 0x5A: /* MODE SENSE (10) */ - return (((uint32_t) cdb[7]) << 8) | ((uint32_t) cdb[8]); - case 0xAD: /* READ DVD STRUCTURE */ - return (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - case 0x08: - case 0x28: - case 0xa8: - /* READ (6), READ (10), READ (12) */ - return 2048 * number_of_blocks; - break; - case 0xb9: - sector_type = (cdb[1] >> 2) & 7; - if (sector_type == 0) - { - sector_type = ioctl_get_sector_data_type(id, 0, cdb[3], cdb[4], cdb[5], 1); - if (sector_type == 0) - { - cdrom_illegal_mode(id); - return -1; - } - } - goto common_handler; - case 0xbe: - /* READ CD MSF, READ CD */ - sector_type = (cdb[1] >> 2) & 7; - if (sector_type == 0) - { - sector_type = ioctl_get_sector_data_type(id, cdb[2], cdb[3], cdb[4], cdb[5], 0); - if (sector_type == 0) - { - cdrom_illegal_mode(id); - return -1; - } - } -common_handler: - temp_len = flags_to_size[sector_type - 1][cdb[9] >> 3]; - if ((cdb[9] & 6) == 2) - { - temp_len += 294; - } - else if ((cdb[9] & 6) == 4) - { - temp_len += 296; - } - if ((cdb[10] & 7) == 1) - { - temp_len += 96; - } - else if ((cdb[10] & 7) == 2) - { - temp_len += 16; - } - else if ((cdb[10] & 7) == 4) - { - temp_len += 96; - } - if (temp_len <= 0) - { - cdrom_illegal_mode(id); - return -1; - } - return temp_len * dev->requested_blocks; - break; - default: - /* Other commands */ - return 65534; - break; - } - -} - -static int SCSICommand(uint8_t id, const UCHAR *cdb, UCHAR *buf, uint32_t *len, int no_length_check) -{ - DWORD ioctl_bytes; - int ioctl_rv = 0; - - SCSISense.SenseKey = 0; - SCSISense.Asc = 0; - SCSISense.Ascq = 0; - - *len = 0; - memset(&sptd, 0, sizeof(sptd)); - sptd.s.Length = sizeof(SCSI_PASS_THROUGH); - sptd.s.CdbLength = 12; - sptd.s.DataIn = SCSI_IOCTL_DATA_IN; - sptd.s.TimeOutValue = 80 * 60; - sptd.s.DataTransferLength = ioctl_get_block_length(id, cdb, cdrom_ioctl[id].actual_requested_blocks, no_length_check); - sptd.s.SenseInfoOffset = (uintptr_t)&sptd.sense - (uintptr_t)&sptd; - sptd.s.SenseInfoLength = 32; - sptd.s.DataBufferOffset = (uintptr_t)&sptd.data - (uintptr_t)&sptd; - - memcpy(sptd.s.Cdb, cdb, 12); - ioctl_rv = DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_SCSI_PASS_THROUGH, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); - - if (sptd.s.SenseInfoLength) - { - cdrom_sense_key = sptd.sense[2]; - cdrom_asc = sptd.sense[12]; - cdrom_ascq = sptd.sense[13]; - } - - cdrom_ioctl_log("Transferred length: %i (command: %02X)\n", sptd.s.DataTransferLength, cdb[0]); - cdrom_ioctl_log("Sense length: %i (%02X %02X %02X %02X %02X)\n", sptd.s.SenseInfoLength, sptd.sense[0], sptd.sense[1], sptd.sense[2], sptd.sense[12], sptd.sense[13]); - cdrom_ioctl_log("IOCTL bytes: %i; SCSI status: %i, status: %i, LastError: %08X\n", ioctl_bytes, sptd.s.ScsiStatus, ioctl_rv, GetLastError()); - cdrom_ioctl_log("DATA: %02X %02X %02X %02X %02X %02X\n", sptd.data[0], sptd.data[1], sptd.data[2], sptd.data[3], sptd.data[4], sptd.data[5]); - cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.data[6], sptd.data[7], sptd.data[8], sptd.data[9], sptd.data[10], sptd.data[11]); - cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.data[12], sptd.data[13], sptd.data[14], sptd.data[15], sptd.data[16], sptd.data[17]); - cdrom_ioctl_log("SENSE: %02X %02X %02X %02X %02X %02X\n", sptd.sense[0], sptd.sense[1], sptd.sense[2], sptd.sense[3], sptd.sense[4], sptd.sense[5]); - cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.sense[6], sptd.sense[7], sptd.sense[8], sptd.sense[9], sptd.sense[10], sptd.sense[11]); - cdrom_ioctl_log(" %02X %02X %02X %02X %02X %02X\n", sptd.sense[12], sptd.sense[13], sptd.sense[14], sptd.sense[15], sptd.sense[16], sptd.sense[17]); - *len = sptd.s.DataTransferLength; - if (sptd.s.DataTransferLength != 0) - { - memcpy(buf, sptd.data, sptd.s.DataTransferLength); - } - - return ioctl_rv; -} - -static void ioctl_read_capacity(uint8_t id, uint8_t *b) -{ - cdrom_t *dev = cdrom[id]; - uint32_t len = 0; - - const UCHAR cdb[] = { 0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - UCHAR buf[16]; - - if (!cdrom_ioctl[id].capacity_read || (b == NULL)) - { - SCSICommand(id, cdb, buf, &len, 1); - - memcpy(dev->rcbuf, buf, len); - cdrom_ioctl[id].capacity_read = 1; - } - else - { - memcpy(b, dev->rcbuf, 16); - } -} - -static int ioctl_media_type_id(uint8_t id) -{ - uint8_t old_sense[3] = { 0, 0, 0 }; - - UCHAR msbuf[28]; - uint32_t len = 0; - int sense = 0; - - const UCHAR cdb[] = { 0x5A, 0x00, 0x2A, 0, 0, 0, 0, 0, 28, 0, 0, 0 }; - - old_sense[0] = cdrom_sense_key; - old_sense[1] = cdrom_asc; - old_sense[2] = cdrom_asc; - - ioctl_hopen(id); - - SCSICommand(id, cdb, msbuf, &len, 1); - - ioctl_close(id); - - sense = cdrom_sense_key; - cdrom_sense_key = old_sense[0]; - cdrom_asc = old_sense[1]; - cdrom_asc = old_sense[2]; - - if (sense == 0) - { - return msbuf[2]; - } - else - { - return 3; - } -} - -static uint32_t msf_to_lba32(int lba) -{ - int m = (lba >> 16) & 0xff; - int s = (lba >> 8) & 0xff; - int f = lba & 0xff; - return (m * 60 * 75) + (s * 75) + f; -} - -static int ioctl_get_type(uint8_t id, UCHAR *cdb, UCHAR *buf) -{ - int i = 0; - int ioctl_rv = 0; - - uint32_t len = 0; - - for (i = 2; i <= 5; i++) - { - cdb[1] = i << 2; - ioctl_rv = SCSICommand(id, cdb, buf, &len, 1); /* Bypass length check so we don't risk calling this again and getting stuck in an endless up. */ - if (ioctl_rv) - { - return i; - } - } - return 0; -} - -static int ioctl_sector_data_type(uint8_t id, int sector, int ismsf) -{ - int ioctl_rv = 0; - UCHAR cdb_lba[] = { 0xBE, 0, 0, 0, 0, 0, 0, 0, 1, 0x10, 0, 0 }; - UCHAR cdb_msf[] = { 0xB9, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0 }; - UCHAR buf[2352]; - - cdb_lba[2] = (sector >> 24); - cdb_lba[3] = ((sector >> 16) & 0xff); - cdb_lba[4] = ((sector >> 8) & 0xff); - cdb_lba[5] = (sector & 0xff); - - cdb_msf[3] = cdb_msf[6] = ((sector >> 16) & 0xff); - cdb_msf[4] = cdb_msf[7] = ((sector >> 8) & 0xff); - cdb_msf[5] = cdb_msf[8] = (sector & 0xff); - - ioctl_hopen(id); - - if (ioctl_is_track_audio(id, sector, ismsf)) - { - return 1; - } - - if (ismsf) - { - ioctl_rv = ioctl_get_type(id, cdb_msf, buf); - } - else - { - ioctl_rv = ioctl_get_type(id, cdb_lba, buf); - } - - if (ioctl_rv) - { - ioctl_close(id); - return ioctl_rv; - } - - if (ismsf) - { - sector = msf_to_lba32(sector); - if (sector < 150) - { - ioctl_close(id); - return 0; - } - sector -= 150; - ioctl_rv = ioctl_get_type(id, (UCHAR *) cdb_lba, buf); - } - - ioctl_close(id); - return ioctl_rv; -} - -static int ioctl_get_sector_data_type(uint8_t id, uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3, int ismsf) -{ - int sector = b3; - sector |= ((uint32_t) b2) << 8; - sector |= ((uint32_t) b1) << 16; - sector |= ((uint32_t) b0) << 24; - return ioctl_sector_data_type(id, sector, ismsf); -} - -static void ioctl_validate_toc(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - unsigned long size; - if (!cdrom_drives[id].host_drive) - { - return; - } - dev->cd_state = CD_STOPPED; - ioctl_hopen(id); - cdrom_ioctl_log("Validating TOC...\n"); - DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&cdrom_ioctl_windows[id].toc,sizeof(cdrom_ioctl_windows[id].toc),&size,NULL); - ioctl_close(id); - dev->disc_changed = 0; -} - -UCHAR buf[262144]; - -static int ioctl_pass_through(uint8_t id, uint8_t *in_cdb, uint8_t *b, uint32_t *len) -{ - cdrom_t *dev = cdrom[id]; - - const UCHAR cdb[12]; - - int ret = 0; - - int temp_block_length = 0; - int buffer_pos = 0; - - uint32_t temp_len = 0; - - int i = 0; - - if (in_cdb[0] == 0x43) - { - /* This is a read TOC, so we have to validate the TOC to make the rest of the emulator happy. */ - ioctl_validate_toc(id); - } - - ioctl_hopen(id); - - memcpy((void *) cdb, in_cdb, 12); - - temp_len = 0; - temp_block_length = ioctl_get_block_length(id, cdb, dev->requested_blocks, 0); - if (temp_block_length != -1) { - cdrom_ioctl[id].actual_requested_blocks = 1; - if ((cdb[0] == 0x08) || (cdb[0] == 0x28) || (cdb[0] == 0xA8) || (cdb[0] == 0xB9) || (cdb[0] == 0xBE)) { - buffer_pos = 0; - temp_len = 0; - - for (i = 0; i < dev->requested_blocks; i++) - { - cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Transferring block...\n", id, cdrom_ioctl[id].actual_requested_blocks); - cdrom_update_cdb((uint8_t *) cdb, dev->sector_pos + i, 1); - ret = SCSICommand(id, cdb, b + buffer_pos, &temp_len, 0); - buffer_pos += temp_len; - } - *len = buffer_pos; - } else { - cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Expected transfer length %i is smaller than 65534, transferring all at once...\n", id, temp_block_length); - ret = SCSICommand(id, cdb, b, len, 0); - cdrom_ioctl_log("CD-ROM %i: ioctl_pass_through(): Single transfer done\n", id); - } - } - - cdrom_ioctl_log("IOCTL DATA: %02X %02X %02X %02X %02X %02X %02X %02X\n", b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); - - ioctl_close(id); - - cdrom_ioctl_log("IOCTL Returned value: %i\n", ret); - - return ret; -} - -static int ioctl_readtoc(uint8_t id, unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) -{ - cdrom_t *dev = cdrom[id]; - int len=4; - DWORD size; - int c,d; - uint32_t temp; - uint32_t last_block; - if (!cdrom_drives[id].host_drive) - { - return 0; - } - dev->cd_state = CD_STOPPED; - ioctl_hopen(id); - DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&cdrom_ioctl_windows[id].toc,sizeof(cdrom_ioctl_windows[id].toc),&size,NULL); - ioctl_close(id); - dev->disc_changed = 0; - b[2]=cdrom_ioctl_windows[id].toc.FirstTrack; - b[3]=cdrom_ioctl_windows[id].toc.LastTrack; - d=0; - for (c=0;c<=cdrom_ioctl_windows[id].toc.LastTrack;c++) - { - if (cdrom_ioctl_windows[id].toc.TrackData[c].TrackNumber>=starttrack) - { - d=c; - break; - } - } - last_block = 0; - for (c=d;c<=cdrom_ioctl_windows[id].toc.LastTrack;c++) - { - uint32_t address; - if ((len+8)>maxlen) break; - b[len++]=0; /*Reserved*/ - b[len++]=(cdrom_ioctl_windows[id].toc.TrackData[c].Adr<<4)|cdrom_ioctl_windows[id].toc.TrackData[c].Control; - b[len++]=cdrom_ioctl_windows[id].toc.TrackData[c].TrackNumber; - b[len++]=0; /*Reserved*/ - address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1],cdrom_ioctl_windows[id].toc.TrackData[c].Address[2],cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]); - if (address > last_block) - last_block = address; - - if (msf) - { - b[len++]=cdrom_ioctl_windows[id].toc.TrackData[c].Address[0]; - b[len++]=cdrom_ioctl_windows[id].toc.TrackData[c].Address[1]; - b[len++]=cdrom_ioctl_windows[id].toc.TrackData[c].Address[2]; - b[len++]=cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]; - } - else - { - temp=MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1],cdrom_ioctl_windows[id].toc.TrackData[c].Address[2],cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]) - 150; - b[len++]=temp>>24; - b[len++]=temp>>16; - b[len++]=temp>>8; - b[len++]=temp; - } - if (single) break; - } - b[0] = (uint8_t)(((len-2) >> 8) & 0xff); - b[1] = (uint8_t)((len-2) & 0xff); - return len; -} - -static int ioctl_readtoc_session(uint8_t id, unsigned char *b, int msf, int maxlen) -{ - cdrom_t *dev = cdrom[id]; - int len=4; - int size; - uint32_t temp; - CDROM_READ_TOC_EX toc_ex; - CDROM_TOC_SESSION_DATA toc; - if (!cdrom_drives[id].host_drive) - { - return 0; - } - dev->cd_state = CD_STOPPED; - memset(&toc_ex,0,sizeof(toc_ex)); - memset(&toc,0,sizeof(toc)); - toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_SESSION; - toc_ex.Msf=msf; - toc_ex.SessionTrack=0; - ioctl_hopen(id); - DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL); - ioctl_close(id); - b[2]=toc.FirstCompleteSession; - b[3]=toc.LastCompleteSession; - b[len++]=0; /*Reserved*/ - b[len++]=(toc.TrackData[0].Adr<<4)|toc.TrackData[0].Control; - b[len++]=toc.TrackData[0].TrackNumber; - b[len++]=0; /*Reserved*/ - if (msf) - { - b[len++]=toc.TrackData[0].Address[0]; - b[len++]=toc.TrackData[0].Address[1]; - b[len++]=toc.TrackData[0].Address[2]; - b[len++]=toc.TrackData[0].Address[3]; - } - else - { - temp=MSFtoLBA(toc.TrackData[0].Address[1],toc.TrackData[0].Address[2],toc.TrackData[0].Address[3]) - 150; - b[len++]=temp>>24; - b[len++]=temp>>16; - b[len++]=temp>>8; - b[len++]=temp; - } - - return len; -} - -static int ioctl_readtoc_raw(uint8_t id, uint8_t *b, int maxlen) -{ - cdrom_t *dev = cdrom[id]; - int len=4; - int size; - int i; - CDROM_READ_TOC_EX toc_ex; - CDROM_TOC_FULL_TOC_DATA toc; - if (!cdrom_drives[id].host_drive) - { - return 0; - } - dev->cd_state = CD_STOPPED; - memset(&toc_ex,0,sizeof(toc_ex)); - memset(&toc,0,sizeof(toc)); - toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_FULL_TOC; - toc_ex.Msf=1; - toc_ex.SessionTrack=0; - ioctl_hopen(id); - DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL); - ioctl_close(id); - if (maxlen >= 3) b[2]=toc.FirstCompleteSession; - if (maxlen >= 4) b[3]=toc.LastCompleteSession; - - if (len >= maxlen) return len; - - size -= sizeof(CDROM_TOC_FULL_TOC_DATA); - size /= sizeof(toc.Descriptors[0]); - - for (i = 0; i <= size; i++) - { - b[len++]=toc.Descriptors[i].SessionNumber; - if (len == maxlen) return len; - b[len++]=(toc.Descriptors[i].Adr<<4)|toc.Descriptors[i].Control; - if (len == maxlen) return len; - b[len++]=0; - if (len == maxlen) return len; - b[len++]=toc.Descriptors[i].Reserved1; /*Reserved*/ - if (len == maxlen) return len; - b[len++]=toc.Descriptors[i].MsfExtra[0]; - if (len == maxlen) return len; - b[len++]=toc.Descriptors[i].MsfExtra[1]; - if (len == maxlen) return len; - b[len++]=toc.Descriptors[i].MsfExtra[2]; - if (len == maxlen) return len; - b[len++]=toc.Descriptors[i].Zero; - if (len == maxlen) return len; - b[len++]=toc.Descriptors[i].Msf[0]; - if (len == maxlen) return len; - b[len++]=toc.Descriptors[i].Msf[1]; - if (len == maxlen) return len; - b[len++]=toc.Descriptors[i].Msf[2]; - if (len == maxlen) return len; - } - - return len; -} - -static uint32_t ioctl_size(uint8_t id) -{ - uint8_t capacity_buffer[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - uint32_t capacity = 0; - - ioctl_read_capacity(id, capacity_buffer); - capacity = ((uint32_t) capacity_buffer[0]) << 24; - capacity |= ((uint32_t) capacity_buffer[1]) << 16; - capacity |= ((uint32_t) capacity_buffer[2]) << 8; - capacity |= (uint32_t) capacity_buffer[3]; - return capacity + 1; -} - -static int ioctl_status(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - if (!(ioctl_ready(id)) && (cdrom_drives[id].host_drive <= 0)) - { - return CD_STATUS_EMPTY; - } - - switch(dev->cd_state) - { - case CD_PLAYING: - return CD_STATUS_PLAYING; - case CD_PAUSED: - return CD_STATUS_PAUSED; - case CD_STOPPED: - return CD_STATUS_STOPPED; - default: - return CD_STATUS_EMPTY; - } -} - -void ioctl_reset(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - - CDROM_TOC ltoc; - unsigned long size; - - if (!cdrom_drives[id].host_drive) - { - dev->disc_changed = 1; - return; - } - - ioctl_hopen(id); - DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), &size, NULL); - ioctl_close(id); - - cdrom_ioctl_windows[id].toc = ltoc; - dev->disc_changed = 0; -} - -int ioctl_hopen(uint8_t id) -{ - if (cdrom_ioctl_windows[id].is_playing) return 0; - cdrom_ioctl_windows[id].hIOCTL = CreateFile(cdrom_ioctl[id].ioctl_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - return 0; -} - -#define rcs "Read capacity: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n" -#define drb dev->rcbuf - -int ioctl_open(uint8_t id, char d) -{ - cdrom_t *dev = cdrom[id]; - sprintf(cdrom_ioctl[id].ioctl_path,"\\\\.\\%c:",d); - pclog("IOCTL path: %s\n", cdrom_ioctl[id].ioctl_path); - dev->disc_changed = 1; - cdrom_ioctl_windows[id].hIOCTL = CreateFile(cdrom_ioctl[id].ioctl_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - cdrom_drives[id].handler = &ioctl_cdrom; - dev->handler_inited=1; - cdrom_ioctl_windows[id].is_playing = 0; - cdrom_ioctl[id].capacity_read=0; /* With these two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */ - ioctl_read_capacity(id, NULL); - pclog(rcs, drb[0], drb[1], drb[2], drb[3], drb[4], drb[5], drb[6], drb[7], - drb[8], drb[9], drb[10], drb[11], drb[12], drb[13], drb[14], drb[15]); - CloseHandle(cdrom_ioctl_windows[id].hIOCTL); - cdrom_ioctl_windows[id].hIOCTL = NULL; - return 0; -} - -void ioctl_close(uint8_t id) -{ - if (cdrom_ioctl_windows[id].is_playing) return; - if (cdrom_ioctl_windows[id].hIOCTL) - { - CloseHandle(cdrom_ioctl_windows[id].hIOCTL); - cdrom_ioctl_windows[id].hIOCTL = NULL; - } -} - -static void ioctl_exit(uint8_t id) -{ - cdrom_t *dev = cdrom[id]; - cdrom_ioctl_windows[id].is_playing = 0; - ioctl_stop(id); - dev->handler_inited=0; - dev->disc_changed = 1; -} - -static CDROM ioctl_cdrom= -{ - ioctl_ready, - ioctl_medium_changed, - ioctl_media_type_id, - ioctl_audio_callback, - ioctl_audio_stop, - ioctl_readtoc, - ioctl_readtoc_session, - ioctl_readtoc_raw, - ioctl_getcurrentsubchannel, - ioctl_pass_through, - NULL, - ioctl_playaudio, - ioctl_load, - ioctl_eject, - ioctl_pause, - ioctl_resume, - ioctl_size, - ioctl_status, - ioctl_is_track_audio, - ioctl_stop, - ioctl_exit -}; diff --git a/src/win/win_ddraw.cpp b/src/win/win_ddraw.cpp index b211a6766..14b89a45c 100644 --- a/src/win/win_ddraw.cpp +++ b/src/win/win_ddraw.cpp @@ -11,7 +11,7 @@ * NOTES: This code should be re-merged into a single init() with a * 'fullscreen' argument, indicating FS mode is requested. * - * Version: @(#)win_ddraw.cpp 1.0.6 2018/03/16 + * Version: @(#)win_ddraw.cpp 1.0.7 2018/03/28 * * Authors: Sarah Walker, * Miran Grca, @@ -110,7 +110,6 @@ DoubleLines(uint8_t *dst, uint8_t *src) static void SavePNG(wchar_t *szFilename, HBITMAP hBitmap) { - BITMAPFILEHEADER bmpFileHeader; BITMAPINFO bmpInfo; HDC hdc; LPVOID pBuf = NULL; diff --git a/src/win/win_devconf.c b/src/win/win_devconf.c index 5b1e80535..203fd2f32 100644 --- a/src/win/win_devconf.c +++ b/src/win/win_devconf.c @@ -8,7 +8,7 @@ * * Windows device configuration dialog implementation. * - * Version: @(#)win_devconf.c 1.0.17 2018/03/20 + * Version: @(#)win_devconf.c 1.0.18 2018/04/01 * * Authors: Sarah Walker, * Miran Grca, @@ -468,7 +468,7 @@ uint8_t deviceconfig_open(HWND hwnd, const device_t *device) deviceconfig_changed = 0; - memset(data_block, 0, 4096); + memset(data_block, 0, 16384); dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU; dlg->x = 10; @@ -480,10 +480,10 @@ uint8_t deviceconfig_open(HWND hwnd, const device_t *device) *data++ = 0; /*no menu*/ *data++ = 0; /*predefined dialog box class*/ - data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 50); + data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 120); *data++ = 9; /*Point*/ - data += MultiByteToWideChar(CP_ACP, 0, "Segoe UI", -1, data, 50); + data += MultiByteToWideChar(CP_ACP, 0, "Segoe UI", -1, data, 120); if (((uintptr_t)data) & 2) data++; diff --git a/src/win/win_dialog.c b/src/win/win_dialog.c index d578f7aa4..e0fb0072d 100644 --- a/src/win/win_dialog.c +++ b/src/win/win_dialog.c @@ -8,7 +8,7 @@ * * Several dialogs for the application. * - * Version: @(#)win_dialog.c 1.0.8 2018/01/21 + * Version: @(#)win_dialog.c 1.0.9 2018/04/01 * * Author: Miran Grca, * Fred N. van Kempen, @@ -32,53 +32,11 @@ #include "win.h" -WCHAR path[MAX_PATH]; WCHAR wopenfilestring[260]; char openfilestring[260]; uint8_t filterindex = 0; -static int CALLBACK -BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) -{ - if (uMsg == BFFM_INITIALIZED) - SendMessage(hwnd, BFFM_SETSELECTION, TRUE, lpData); - - return(0); -} - - -wchar_t * -BrowseFolder(wchar_t *saved_path, wchar_t *title) -{ - BROWSEINFO bi = { 0 }; - LPITEMIDLIST pidl; - IMalloc *imalloc; - - bi.lpszTitle = title; - bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE; - bi.lpfn = BrowseCallbackProc; - bi.lParam = (LPARAM) saved_path; - - pidl = SHBrowseForFolder(&bi); - if (pidl != 0) { - /* Get the name of the folder and put it in path. */ - SHGetPathFromIDList(pidl, path); - - /* Free memory used. */ - imalloc = 0; - if (SUCCEEDED(SHGetMalloc(&imalloc))) { - imalloc->lpVtbl->Free(imalloc, pidl); - imalloc->lpVtbl->Release(imalloc); - } - - return(path); - } - - return(L""); -} - - int ui_msgbox(int flags, void *arg) { diff --git a/src/win/win_new_floppy.c b/src/win/win_new_floppy.c index d00d492e3..c42b1ac34 100644 --- a/src/win/win_new_floppy.c +++ b/src/win/win_new_floppy.c @@ -8,7 +8,7 @@ * * Handle the New Floppy Image dialog. * - * Version: @(#)win_new_floppy.c 1.0.5 2018/03/19 + * Version: @(#)win_new_floppy.c 1.0.6 2018/03/28 * * Authors: Miran Grca, * @@ -65,7 +65,7 @@ disk_size_t disk_sizes[14] = { { 0, 1, 2, 1, 0, 40, 8, 2, 0xFE, 2, 2, 1, 112 { 0, 64, 0, 0, 0, 96, 32, 2, 0, 0, 0, 0, 0 }, /* ZIP 100 */ { 0, 64, 0, 0, 0, 239, 32, 2, 0, 0, 0, 0, 0 } }; /* ZIP 250 */ -static char *empty; +static unsigned char *empty; static int @@ -137,7 +137,7 @@ create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) if (array_size2 & 15) array_size += 2; - empty = (char *) malloc(array_size); + empty = (unsigned char *) malloc(array_size); memset(tarray, 0, 2048); memset(empty, 0, array_size); @@ -209,7 +209,7 @@ create_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_fdi) zero_bytes = fat2_offs + fat_size + root_dir_bytes; if (!is_zip && is_fdi) { - empty = (char *) malloc(base); + empty = (unsigned char *) malloc(base); memset(empty, 0, base); *(uint32_t *) &(empty[0x08]) = (uint32_t) base; @@ -223,7 +223,7 @@ create_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_fdi) free(empty); } - empty = (char *) malloc(total_size); + empty = (unsigned char *) malloc(total_size); memset(empty, 0x00, zero_bytes); if (!is_zip) { @@ -344,7 +344,7 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, pbar_max++; if (is_zdi) { - empty = (char *) malloc(base); + empty = (unsigned char *) malloc(base); memset(empty, 0, base); *(uint32_t *) &(empty[0x08]) = (uint32_t) base; @@ -364,7 +364,7 @@ create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, pbar_max -= 2; } - empty = (char *) malloc(total_size); + empty = (unsigned char *) malloc(total_size); memset(empty, 0x00, zero_bytes); if (total_sectors == ZIP_SECTORS) { @@ -566,16 +566,16 @@ NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) if (is_zip) { zip_types = zip_drives[fdd_id].is_250 ? 2 : 1; for (i = 0; i < zip_types; i++) - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) plat_get_string(IDS_5900 + i)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5900 + i)); } else { for (i = 0; i < 12; i++) - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) plat_get_string(IDS_5888 + i)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5888 + i)); } SendMessage(h, CB_SETCURSEL, 0, 0); EnableWindow(h, FALSE); h = GetDlgItem(hdlg, IDC_COMBO_RPM_MODE); for (i = 0; i < 4; i++) - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) plat_get_string(IDS_6144 + i)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_6144 + i)); SendMessage(h, CB_SETCURSEL, 0, 0); EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 6544035b6..7f07aff08 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -8,7 +8,7 @@ * * Windows 86Box Settings dialog handler. * - * Version: @(#)win_settings.c 1.0.46 2018/03/19 + * Version: @(#)win_settings.c 1.0.47 2018/03/26 * * Author: Miran Grca, * @@ -36,13 +36,13 @@ #include "../game/gameport.h" #include "../lpt.h" #include "../mouse.h" +#include "../scsi/scsi.h" #include "../cdrom/cdrom.h" #include "../disk/hdd.h" #include "../disk/hdc.h" #include "../disk/hdc_ide.h" #include "../disk/zip.h" #include "../floppy/fdd.h" -#include "../scsi/scsi.h" #include "../network/network.h" #include "../sound/sound.h" #include "../sound/midi.h" @@ -57,7 +57,8 @@ /* Machine category */ -static int temp_machine, temp_cpu_m, temp_cpu, temp_wait_states, temp_mem_size, temp_fpu, temp_sync; +static int temp_machine, temp_cpu_m, temp_cpu, temp_wait_states, temp_fpu, temp_sync; +static uint32_t temp_mem_size; #ifdef USE_DYNAREC static int temp_dynarec; #endif @@ -69,7 +70,7 @@ static int temp_gfxcard, temp_video_speed, temp_voodoo; static int temp_mouse, temp_joystick; /* Sound category */ -static int temp_sound_card, temp_midi_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS, temp_opl3_type; +static int temp_sound_card, temp_midi_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS, temp_opl_type; static int temp_float; /* Network category */ @@ -81,9 +82,9 @@ static char temp_lpt_device_names[3][16]; static int temp_serial[2], temp_lpt; /* Other peripherals category */ -static int temp_scsi_card, temp_ide_ter, temp_ide_ter_irq, temp_ide_qua, temp_ide_qua_irq; -static char temp_hdc_name[16]; -static char *hdc_names[16]; +static int temp_scsi_card, temp_ide_ter, temp_ide_qua; +static char temp_hdc_name[32]; +static char *hdc_names[32]; static int temp_bugger; static uint8_t temp_deviceconfig; @@ -102,7 +103,7 @@ static zip_drive_t temp_zip_drives[ZIP_NUM]; static HWND hwndParentDialog, hwndChildDialog; -static int displayed_category = 0; +static uint32_t displayed_category = 0; extern int is486; static int romstolist[ROM_MAX], listtomachine[ROM_MAX], romstomachine[ROM_MAX], machinetolist[ROM_MAX]; @@ -112,7 +113,7 @@ static int settings_mouse_to_list[20], settings_list_to_mouse[20]; static int settings_scsi_to_list[20], settings_list_to_scsi[20]; static int settings_network_to_list[20], settings_list_to_network[20]; -static uint64_t mfm_tracking, esdi_tracking, xtide_tracking, ide_tracking, scsi_tracking[16]; +static uint64_t mfm_tracking, esdi_tracking, xta_tracking, ide_tracking, scsi_tracking[16]; @@ -167,7 +168,7 @@ static void win_settings_init(void) temp_SSI2001 = SSI2001; temp_GAMEBLASTER = GAMEBLASTER; temp_GUS = GUS; - temp_opl3_type = opl3_type; + temp_opl_type = opl_type; temp_float = sound_is_float; /* Network category */ @@ -186,13 +187,11 @@ static void win_settings_init(void) /* Other peripherals category */ temp_scsi_card = scsi_card_current; strncpy(temp_hdc_name, hdc_name, sizeof(temp_hdc_name) - 1); - temp_ide_ter = ide_enable[2]; - temp_ide_ter_irq = ide_irq[2]; - temp_ide_qua = ide_enable[3]; - temp_ide_qua_irq = ide_irq[3]; + temp_ide_ter = ide_ter_enabled; + temp_ide_qua = ide_qua_enabled; temp_bugger = bugger_enabled; - mfm_tracking = xtide_tracking = esdi_tracking = ide_tracking = 0; + mfm_tracking = xta_tracking = esdi_tracking = ide_tracking = 0; for (i = 0; i < 16; i++) scsi_tracking[i] = 0; @@ -202,18 +201,14 @@ static void win_settings_init(void) { if (hdd[i].bus == HDD_BUS_MFM) mfm_tracking |= (1 << (hdd[i].mfm_channel << 3)); - else if (hdd[i].bus == HDD_BUS_XTIDE) - xtide_tracking |= (1 << (hdd[i].xtide_channel << 3)); + else if (hdd[i].bus == HDD_BUS_XTA) + xta_tracking |= (1 << (hdd[i].xta_channel << 3)); else if (hdd[i].bus == HDD_BUS_ESDI) esdi_tracking |= (1 << (hdd[i].esdi_channel << 3)); - else if (hdd[i].bus == HDD_BUS_IDE_PIO_ONLY) - ide_tracking |= (1 << (hdd[i].ide_channel << 3)); - else if (hdd[i].bus == HDD_BUS_IDE_PIO_AND_DMA) + else if (hdd[i].bus == HDD_BUS_IDE) ide_tracking |= (1 << (hdd[i].ide_channel << 3)); else if (hdd[i].bus == HDD_BUS_SCSI) scsi_tracking[hdd[i].scsi_id] |= (1 << (hdd[i].scsi_lun << 3)); - else if (hdd[i].bus == HDD_BUS_SCSI_REMOVABLE) - scsi_tracking[hdd[i].scsi_id] |= (1 << (hdd[i].scsi_lun << 3)); } /* Floppy drives category */ @@ -228,9 +223,7 @@ static void win_settings_init(void) memcpy(temp_cdrom_drives, cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); for (i = 0; i < CDROM_NUM; i++) { - if (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI_PIO_ONLY) - ide_tracking |= (2 << (cdrom_drives[i].ide_channel << 3)); - else if (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA) + if (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) ide_tracking |= (2 << (cdrom_drives[i].ide_channel << 3)); else if (cdrom_drives[i].bus_type == CDROM_BUS_SCSI) scsi_tracking[cdrom_drives[i].scsi_device_id] |= (2 << (cdrom_drives[i].scsi_device_lun << 3)); @@ -238,9 +231,7 @@ static void win_settings_init(void) memcpy(temp_zip_drives, zip_drives, ZIP_NUM * sizeof(zip_drive_t)); for (i = 0; i < ZIP_NUM; i++) { - if (zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_ONLY) - ide_tracking |= (4 << (zip_drives[i].ide_channel << 3)); - else if (zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA) + if (zip_drives[i].bus_type == ZIP_BUS_ATAPI) ide_tracking |= (4 << (zip_drives[i].ide_channel << 3)); else if (zip_drives[i].bus_type == ZIP_BUS_SCSI) scsi_tracking[zip_drives[i].scsi_device_id] |= (4 << (zip_drives[i].scsi_device_lun << 3)); @@ -284,7 +275,7 @@ static int win_settings_changed(void) i = i || (SSI2001 != temp_SSI2001); i = i || (GAMEBLASTER != temp_GAMEBLASTER); i = i || (GUS != temp_GUS); - i = i || (opl3_type != temp_opl3_type); + i = i || (opl_type != temp_opl_type); i = i || (sound_is_float != temp_float); /* Network category */ @@ -302,10 +293,8 @@ static int win_settings_changed(void) /* Peripherals category */ i = i || (scsi_card_current != temp_scsi_card); i = i || strncmp(temp_hdc_name, hdc_name, sizeof(temp_hdc_name) - 1); - i = i || (temp_ide_ter != ide_enable[2]); - i = i || (temp_ide_ter_irq != ide_irq[2]); - i = i || (temp_ide_qua != ide_enable[3]); - i = i || (temp_ide_qua_irq != ide_irq[3]); + i = i || (temp_ide_ter != ide_ter_enabled); + i = i || (temp_ide_qua != ide_qua_enabled); i = i || (temp_bugger != bugger_enabled); /* Hard disks category */ @@ -387,7 +376,7 @@ static void win_settings_save(void) SSI2001 = temp_SSI2001; GAMEBLASTER = temp_GAMEBLASTER; GUS = temp_GUS; - opl3_type = temp_opl3_type; + opl_type = temp_opl_type; sound_is_float = temp_float; /* Network category */ @@ -412,10 +401,8 @@ static void win_settings_save(void) hdc_name = (char *) malloc(sizeof(temp_hdc_name)); strncpy(hdc_name, temp_hdc_name, sizeof(temp_hdc_name) - 1); hdc_init(hdc_name); - ide_enable[2] = temp_ide_ter; - ide_irq[2] = temp_ide_ter_irq; - ide_enable[3] = temp_ide_qua; - ide_irq[3] = temp_ide_qua_irq; + ide_ter_enabled = temp_ide_ter; + ide_qua_enabled = temp_ide_qua; bugger_enabled = temp_bugger; /* Hard disks category */ @@ -600,13 +587,13 @@ static void win_settings_machine_recalc_machine(HWND hdlg) { SendMessage(h, UDM_SETPOS, 0, temp_mem_size); h = GetDlgItem(hdlg, IDC_TEXT_MB); - SendMessage(h, WM_SETTEXT, 0, (LPARAM) plat_get_string(IDS_2094)); + SendMessage(h, WM_SETTEXT, 0, win_get_string(IDS_2094)); } else { SendMessage(h, UDM_SETPOS, 0, temp_mem_size / 1024); h = GetDlgItem(hdlg, IDC_TEXT_MB); - SendMessage(h, WM_SETTEXT, 0, (LPARAM) plat_get_string(IDS_2087)); + SendMessage(h, WM_SETTEXT, 0, win_get_string(IDS_2087)); } free(lptsTemp); @@ -620,7 +607,7 @@ static BOOL CALLBACK #endif win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { - HWND h; + HWND h, h2; int c = 0; int d = 0; LPTSTR lptsTemp; @@ -655,7 +642,7 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(h, CB_SETCURSEL, machinetolist[temp_machine], 0); h = GetDlgItem(hdlg, IDC_COMBO_WS); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) plat_get_string(IDS_2131)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2131)); for (c = 0; c < 8; c++) { @@ -671,7 +658,8 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) #endif h = GetDlgItem(hdlg, IDC_MEMSPIN); - SendMessage(h, UDM_SETBUDDY, (WPARAM)GetDlgItem(hdlg, IDC_MEMTEXT), 0); + h2 = GetDlgItem(hdlg, IDC_MEMTEXT); + SendMessage(h, UDM_SETBUDDY, (WPARAM)h2, 0); h=GetDlgItem(hdlg, IDC_CHECK_SYNC); SendMessage(h, BM_SETCHECK, temp_sync, 0); @@ -744,7 +732,7 @@ win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h = GetDlgItem(hdlg, IDC_MEMTEXT); SendMessage(h, WM_GETTEXT, 255, (LPARAM) lptsTemp); wcstombs(stransi, lptsTemp, 512); - sscanf(stransi, "%i", &temp_mem_size); + sscanf(stransi, "%u", &temp_mem_size); temp_mem_size &= ~(machines[temp_machine].ram_granularity - 1); if (temp_mem_size < machines[temp_machine].min_ram) { @@ -846,13 +834,13 @@ win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) recalc_vid_list(hdlg); h = GetDlgItem(hdlg, IDC_COMBO_VIDEO_SPEED); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_2131)); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_2133)); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_2134)); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_2135)); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_2136)); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_2137)); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_2138)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2131)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2133)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2134)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2135)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2136)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2137)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2138)); SendMessage(h, CB_SETCURSEL, temp_video_speed + 1, 0); h=GetDlgItem(hdlg, IDC_CHECK_VOODOO); @@ -1016,7 +1004,7 @@ win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) c = 0; while (joystick_get_name(c)) { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(2144 + c)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(2144 + c)); c++; } EnableWindow(h, TRUE); @@ -1192,7 +1180,7 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { if (c == 0) { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) plat_get_string(IDS_2152)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2152)); } else { @@ -1237,7 +1225,7 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { if (c == 0) { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_2152)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2152)); } else { @@ -1279,7 +1267,7 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) SendMessage(h, BM_SETCHECK, temp_SSI2001, 0); h=GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); - SendMessage(h, BM_SETCHECK, temp_opl3_type, 0); + SendMessage(h, BM_SETCHECK, temp_opl_type, 0); h=GetDlgItem(hdlg, IDC_CHECK_FLOAT); SendMessage(h, BM_SETCHECK, temp_float, 0); @@ -1383,7 +1371,7 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0); h = GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); - temp_opl3_type = SendMessage(h, BM_GETCHECK, 0, 0); + temp_opl_type = SendMessage(h, BM_GETCHECK, 0, 0); h = GetDlgItem(hdlg, IDC_CHECK_FLOAT); temp_float = SendMessage(h, BM_GETCHECK, 0, 0); @@ -1424,7 +1412,7 @@ win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) break; if (c == 0) { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) plat_get_string(IDS_2152)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2152)); } else { mbstowcs(lptsTemp, s, strlen(s) + 1); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); @@ -1480,7 +1468,7 @@ static void recalc_hdc_list(HWND hdlg, int machine, int use_selected_hdc) char *s; int valid = 0; - char old_name[16]; + char old_name[32]; int c, d; LPTSTR lptsTemp; @@ -1553,25 +1541,6 @@ static void recalc_hdc_list(HWND hdlg, int machine, int use_selected_hdc) } -int valid_ide_irqs[11] = { 2, 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 }; - - -int find_irq_in_array(int irq, int def) -{ - int i = 0; - - for (i = 0; i < 11; i++) - { - if (valid_ide_irqs[i] == irq) - { - return i + 1; - } - } - - return 7 + def; -} - - #ifdef __amd64__ static LRESULT CALLBACK #else @@ -1584,6 +1553,7 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa int d = 0; LPTSTR lptsTemp; const device_t *scsi_dev; + int temp_hdc_type; switch (message) { @@ -1613,7 +1583,7 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa { if (c == 0) { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) plat_get_string(IDS_2152)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2152)); } else { @@ -1643,41 +1613,29 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa recalc_hdc_list(hdlg, temp_machine, 0); - h=GetDlgItem(hdlg, IDC_COMBO_IDE_TER); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_5376)); - - for (c = 0; c < 11; c++) - { - wsprintf(lptsTemp, plat_get_string(IDS_2155), valid_ide_irqs[c]); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - } - - if (temp_ide_ter) - { - SendMessage(h, CB_SETCURSEL, find_irq_in_array(temp_ide_ter_irq, 0), 0); - } + h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); + if (hdc_has_config(hdc_get_from_internal_name(temp_hdc_name))) + EnableWindow(h, TRUE); else - { - SendMessage(h, CB_SETCURSEL, 0, 0); - } + EnableWindow(h, FALSE); - h=GetDlgItem(hdlg, IDC_COMBO_IDE_QUA); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_5376)); + h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + EnableWindow(h, (machines[temp_machine].flags & MACHINE_AT) ? TRUE : FALSE); - for (c = 0; c < 11; c++) - { - wsprintf(lptsTemp, plat_get_string(IDS_2155), valid_ide_irqs[c]); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); - } + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_TER); + EnableWindow(h, ((machines[temp_machine].flags & MACHINE_AT) && temp_ide_ter) ? TRUE : FALSE); - if (temp_ide_qua) - { - SendMessage(h, CB_SETCURSEL, find_irq_in_array(temp_ide_qua_irq, 1), 0); - } - else - { - SendMessage(h, CB_SETCURSEL, 0, 0); - } + h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + EnableWindow(h, (machines[temp_machine].flags & MACHINE_AT) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_QUA); + EnableWindow(h, ((machines[temp_machine].flags & MACHINE_AT) && temp_ide_qua) ? TRUE : FALSE); + + h=GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + SendMessage(h, BM_SETCHECK, temp_ide_ter, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + SendMessage(h, BM_SETCHECK, temp_ide_qua, 0); h=GetDlgItem(hdlg, IDC_CHECK_BUGGER); SendMessage(h, BM_SETCHECK, temp_bugger, 0); @@ -1689,7 +1647,25 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa case WM_COMMAND: switch (LOWORD(wParam)) { - case IDC_CONFIGURE_SCSI: + case IDC_COMBO_HDC: + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + temp_hdc_type = hdc_get_from_internal_name(hdc_names[SendMessage(h, CB_GETCURSEL, 0, 0)]); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); + if (hdc_has_config(temp_hdc_type)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CONFIGURE_HDC: + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + temp_hdc_type = hdc_get_from_internal_name(hdc_names[SendMessage(h, CB_GETCURSEL, 0, 0)]); + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)hdc_get_device(temp_hdc_type)); + break; + + case IDC_CONFIGURE_SCSI: h = GetDlgItem(hdlg, IDC_COMBO_SCSI); temp_scsi_card = settings_list_to_scsi[SendMessage(h, CB_GETCURSEL, 0, 0)]; @@ -1710,6 +1686,30 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa EnableWindow(h, FALSE); } break; + + case IDC_CHECK_IDE_TER: + h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + temp_ide_ter = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_TER); + EnableWindow(h, temp_ide_ter ? TRUE : FALSE); + break; + + case IDC_BUTTON_IDE_TER: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&ide_ter_device); + break; + + case IDC_CHECK_IDE_QUA: + h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + temp_ide_qua = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_QUA); + EnableWindow(h, temp_ide_qua ? TRUE : FALSE); + break; + + case IDC_BUTTON_IDE_QUA: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&ide_qua_device); + break; } return FALSE; @@ -1728,21 +1728,11 @@ win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPa h = GetDlgItem(hdlg, IDC_COMBO_SCSI); temp_scsi_card = settings_list_to_scsi[SendMessage(h, CB_GETCURSEL, 0, 0)]; - h = GetDlgItem(hdlg, IDC_COMBO_IDE_TER); - temp_ide_ter = SendMessage(h, CB_GETCURSEL, 0, 0); - if (temp_ide_ter > 1) - { - temp_ide_ter_irq = valid_ide_irqs[temp_ide_ter - 1]; - temp_ide_ter = 1; - } + h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + temp_ide_ter = SendMessage(h, BM_GETCHECK, 0, 0); - h = GetDlgItem(hdlg, IDC_COMBO_IDE_QUA); - temp_ide_qua = SendMessage(h, CB_GETCURSEL, 0, 0); - if (temp_ide_qua > 1) - { - temp_ide_qua_irq = valid_ide_irqs[temp_ide_qua - 1]; - temp_ide_qua = 1; - } + h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + temp_ide_qua = SendMessage(h, BM_GETCHECK, 0, 0); h = GetDlgItem(hdlg, IDC_CHECK_BUGGER); temp_bugger = SendMessage(h, BM_GETCHECK, 0, 0); @@ -1866,7 +1856,7 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { if (c == 0) { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM) plat_get_string(2152)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(2152)); } else { @@ -1970,10 +1960,6 @@ static BOOL win_settings_hard_disks_image_list_init(HWND hwndList) GetSystemMetrics(SM_CYSMICON), ILC_MASK | ILC_COLOR32, 1, 1); - hiconItem = LoadIcon(hinstance, (LPCWSTR) 208); - ImageList_AddIcon(hSmall, hiconItem); - DestroyIcon(hiconItem); - hiconItem = LoadIcon(hinstance, (LPCWSTR) 192); ImageList_AddIcon(hSmall, hiconItem); DestroyIcon(hiconItem); @@ -2044,9 +2030,9 @@ static void add_locations(HWND hdlg) lptsTemp = (LPTSTR) malloc(512); h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - for (i = 0; i < 7; i++) + for (i = 0; i < 5; i++) { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_4352 + i)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4352 + i)); } h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); @@ -2172,7 +2158,7 @@ static void recalc_location_controls(HWND hdlg, int is_add_dlg, int assign_id) temp_hdd[hdlv_current_sel].mfm_channel = next_free_binary_channel(&mfm_tracking); SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.mfm_channel : temp_hdd[hdlv_current_sel].mfm_channel, 0); break; - case HDD_BUS_XTIDE: /* XT IDE */ + case HDD_BUS_XTA: /* XTA */ h = GetDlgItem(hdlg, IDT_1722); ShowWindow(h, SW_SHOW); EnableWindow(h, TRUE); @@ -2181,8 +2167,8 @@ static void recalc_location_controls(HWND hdlg, int is_add_dlg, int assign_id) ShowWindow(h, SW_SHOW); EnableWindow(h, TRUE); if (assign_id) - temp_hdd[hdlv_current_sel].xtide_channel = next_free_binary_channel(&xtide_tracking); - SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.xtide_channel : temp_hdd[hdlv_current_sel].xtide_channel, 0); + temp_hdd[hdlv_current_sel].xta_channel = next_free_binary_channel(&xta_tracking); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.xta_channel : temp_hdd[hdlv_current_sel].xta_channel, 0); break; case HDD_BUS_ESDI: /* ESDI */ h = GetDlgItem(hdlg, IDT_1722); @@ -2196,8 +2182,7 @@ static void recalc_location_controls(HWND hdlg, int is_add_dlg, int assign_id) temp_hdd[hdlv_current_sel].esdi_channel = next_free_binary_channel(&esdi_tracking); SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.esdi_channel : temp_hdd[hdlv_current_sel].esdi_channel, 0); break; - case HDD_BUS_IDE_PIO_ONLY: /* IDE (PIO-only) */ - case HDD_BUS_IDE_PIO_AND_DMA: /* IDE (PIO and DMA) */ + case HDD_BUS_IDE: /* IDE */ h = GetDlgItem(hdlg, IDT_1722); ShowWindow(h, SW_SHOW); EnableWindow(h, TRUE); @@ -2210,7 +2195,6 @@ static void recalc_location_controls(HWND hdlg, int is_add_dlg, int assign_id) SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.ide_channel : temp_hdd[hdlv_current_sel].ide_channel, 0); break; case HDD_BUS_SCSI: /* SCSI */ - case HDD_BUS_SCSI_REMOVABLE: /* SCSI (removable) */ h = GetDlgItem(hdlg, IDT_1723); ShowWindow(h, SW_SHOW); EnableWindow(h, TRUE); @@ -2284,9 +2268,8 @@ static void recalc_next_free_id(HWND hdlg) int c_mfm = 0; int c_esdi = 0; - int c_xtide = 0; - int c_ide_pio = 0; - int c_ide_dma = 0; + int c_xta = 0; + int c_ide = 0; int c_scsi = 0; int enable_add = 0; @@ -2302,26 +2285,18 @@ static void recalc_next_free_id(HWND hdlg) { c_esdi++; } - else if (temp_hdd[i].bus == HDD_BUS_XTIDE) + else if (temp_hdd[i].bus == HDD_BUS_XTA) { - c_xtide++; + c_xta++; } - else if (temp_hdd[i].bus == HDD_BUS_IDE_PIO_ONLY) + else if (temp_hdd[i].bus == HDD_BUS_IDE) { - c_ide_pio++; - } - else if (temp_hdd[i].bus == HDD_BUS_IDE_PIO_AND_DMA) - { - c_ide_dma++; + c_ide++; } else if (temp_hdd[i].bus == HDD_BUS_SCSI) { c_scsi++; } - else if (temp_hdd[i].bus == HDD_BUS_SCSI_REMOVABLE) - { - c_scsi++; - } } for (i = 0; i < HDD_NUM; i++) @@ -2334,10 +2309,11 @@ static void recalc_next_free_id(HWND hdlg) } enable_add = enable_add || (next_free_id >= 0); - enable_add = enable_add && ((c_mfm < MFM_NUM) || (c_esdi < ESDI_NUM) || (c_xtide < XTIDE_NUM) || (c_ide_pio < IDE_NUM) || (c_ide_dma < IDE_NUM) || (c_scsi < SCSI_NUM)); + enable_add = enable_add && ((c_mfm < MFM_NUM) || (c_esdi < ESDI_NUM) || (c_xta < XTA_NUM) || + (c_ide < IDE_NUM) || (c_scsi < SCSI_NUM)); enable_add = enable_add && !bus_full(&mfm_tracking, 2); enable_add = enable_add && !bus_full(&esdi_tracking, 2); - enable_add = enable_add && !bus_full(&xtide_tracking, 2); + enable_add = enable_add && !bus_full(&xta_tracking, 2); enable_add = enable_add && !bus_full(&ide_tracking, 8); for (i = 0; i < 16; i++) enable_add = enable_add && !bus_full(&(scsi_tracking[i]), 8); @@ -2366,7 +2342,7 @@ static void recalc_next_free_id(HWND hdlg) h = GetDlgItem(hdlg, IDC_BUTTON_HDD_REMOVE); - if ((c_mfm == 0) && (c_esdi == 0) && (c_xtide == 0) && (c_ide_pio == 0) && (c_ide_dma == 0) && (c_scsi == 0)) + if ((c_mfm == 0) && (c_esdi == 0) && (c_xta == 0) && (c_ide == 0) && (c_scsi == 0)) { EnableWindow(h, FALSE); } @@ -2394,27 +2370,21 @@ static void win_settings_hard_disks_update_item(HWND hwndList, int i, int column case HDD_BUS_MFM: wsprintf(szText, plat_get_string(IDS_4608), temp_hdd[i].mfm_channel >> 1, temp_hdd[i].mfm_channel & 1); break; - case HDD_BUS_XTIDE: - wsprintf(szText, plat_get_string(IDS_4609), temp_hdd[i].xtide_channel >> 1, temp_hdd[i].xtide_channel & 1); + case HDD_BUS_XTA: + wsprintf(szText, plat_get_string(IDS_4609), temp_hdd[i].xta_channel >> 1, temp_hdd[i].xta_channel & 1); break; case HDD_BUS_ESDI: wsprintf(szText, plat_get_string(IDS_4610), temp_hdd[i].esdi_channel >> 1, temp_hdd[i].esdi_channel & 1); break; - case HDD_BUS_IDE_PIO_ONLY: + case HDD_BUS_IDE: wsprintf(szText, plat_get_string(IDS_4611), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); break; - case HDD_BUS_IDE_PIO_AND_DMA: - wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); - break; case HDD_BUS_SCSI: - wsprintf(szText, plat_get_string(IDS_4613), temp_hdd[i].scsi_id, temp_hdd[i].scsi_lun); - break; - case HDD_BUS_SCSI_REMOVABLE: - wsprintf(szText, plat_get_string(IDS_4614), temp_hdd[i].scsi_id, temp_hdd[i].scsi_lun); + wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].scsi_id, temp_hdd[i].scsi_lun); break; } lvI.pszText = szText; - lvI.iImage = (temp_hdd[i].bus == HDD_BUS_SCSI_REMOVABLE) ? 1 : 0; + lvI.iImage = 0; } else if (column == 1) { @@ -2478,28 +2448,22 @@ static BOOL win_settings_hard_disks_recalc_list(HWND hwndList) case HDD_BUS_MFM: wsprintf(szText, plat_get_string(IDS_4608), temp_hdd[i].mfm_channel >> 1, temp_hdd[i].mfm_channel & 1); break; - case HDD_BUS_XTIDE: - wsprintf(szText, plat_get_string(IDS_4609), temp_hdd[i].xtide_channel >> 1, temp_hdd[i].xtide_channel & 1); + case HDD_BUS_XTA: + wsprintf(szText, plat_get_string(IDS_4609), temp_hdd[i].xta_channel >> 1, temp_hdd[i].xta_channel & 1); break; case HDD_BUS_ESDI: wsprintf(szText, plat_get_string(IDS_4610), temp_hdd[i].esdi_channel >> 1, temp_hdd[i].esdi_channel & 1); break; - case HDD_BUS_IDE_PIO_ONLY: + case HDD_BUS_IDE: wsprintf(szText, plat_get_string(IDS_4611), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); break; - case HDD_BUS_IDE_PIO_AND_DMA: - wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); - break; case HDD_BUS_SCSI: - wsprintf(szText, plat_get_string(IDS_4613), temp_hdd[i].scsi_id, temp_hdd[i].scsi_lun); - break; - case HDD_BUS_SCSI_REMOVABLE: - wsprintf(szText, plat_get_string(IDS_4614), temp_hdd[i].scsi_id, temp_hdd[i].scsi_lun); + wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].scsi_id, temp_hdd[i].scsi_lun); break; } lvI.pszText = szText; lvI.iItem = j; - lvI.iImage = (temp_hdd[i].bus == HDD_BUS_SCSI_REMOVABLE) ? 1 : 0; + lvI.iImage = 0; if (ListView_InsertItem(hwndList, &lvI) == -1) { @@ -2623,7 +2587,7 @@ static BOOL win_settings_hard_disks_init_columns(HWND hwndList) return TRUE; } -static void get_edit_box_contents(HWND hdlg, int id, uint64_t *val) +static void get_edit_box_contents(HWND hdlg, int id, uint32_t *val) { HWND h; WCHAR szText[256]; @@ -2632,10 +2596,10 @@ static void get_edit_box_contents(HWND hdlg, int id, uint64_t *val) h = GetDlgItem(hdlg, id); SendMessage(h, WM_GETTEXT, 255, (LPARAM) szText); wcstombs(stransi, szText, 256); - sscanf(stransi, "%" PRIu64, val); + sscanf(stransi, "%u", val); } -static void get_combo_box_selection(HWND hdlg, int id, uint64_t *val) +static void get_combo_box_selection(HWND hdlg, int id, uint32_t *val) { HWND h; @@ -2643,7 +2607,7 @@ static void get_combo_box_selection(HWND hdlg, int id, uint64_t *val) *val = SendMessage(h, CB_GETCURSEL, 0, 0); } -static void set_edit_box_contents(HWND hdlg, int id, uint64_t val) +static void set_edit_box_contents(HWND hdlg, int id, uint32_t val) { HWND h; WCHAR szText[256]; @@ -2654,17 +2618,19 @@ static void set_edit_box_contents(HWND hdlg, int id, uint64_t val) } int hard_disk_added = 0; -int max_spt = 63; -int max_hpc = 255; -int max_tracks = 266305; + +int64_t max_spt = 63, max_hpc = 255, + max_tracks = 266305; int no_update = 0; int existing = 0; uint64_t selection = 127; -uint64_t spt, hpc, tracks, size; -wchar_t hd_file_name[512]; +static int spt, hpc, + tracks; +static uint64_t size; +static wchar_t hd_file_name[512]; static hard_disk_t *hdd_ptr; @@ -2673,7 +2639,7 @@ static int hdconf_initialize_hdt_combo(HWND hdlg) HWND h; int i = 0; uint64_t temp_size = 0; - uint64_t size_mb = 0; + uint32_t size_mb = 0; WCHAR szText[256]; selection = 127; @@ -2682,16 +2648,18 @@ static int hdconf_initialize_hdt_combo(HWND hdlg) for (i = 0; i < 127; i++) { temp_size = hdd_table[i][0] * hdd_table[i][1] * hdd_table[i][2]; - size_mb = temp_size >> 11; + size_mb = (uint32_t) (temp_size >> 11LL); wsprintf(szText, plat_get_string(IDS_2157), size_mb, hdd_table[i][0], hdd_table[i][1], hdd_table[i][2]); SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); - if ((tracks == hdd_table[i][0]) && (hpc == hdd_table[i][1]) && (spt == hdd_table[i][2])) + if ((tracks == (int) hdd_table[i][0]) && + (hpc == (int) hdd_table[i][1]) && + (spt == (int) hdd_table[i][2])) { selection = i; } } - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_4100)); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_4101)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4100)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4101)); SendMessage(h, CB_SETCURSEL, selection, 0); return selection; } @@ -2705,7 +2673,9 @@ static void recalc_selection(HWND hdlg) h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); for (i = 0; i < 127; i++) { - if ((tracks == hdd_table[i][0]) && (hpc == hdd_table[i][1]) && (spt == hdd_table[i][2])) + if ((tracks == (int) hdd_table[i][0]) && + (hpc == (int) hdd_table[i][1]) && + (spt == (int) hdd_table[i][2])) { selection = i; } @@ -2727,8 +2697,7 @@ static BOOL CALLBACK win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND h; - int64_t i = 0; - uint64_t temp; + uint32_t temp, i = 0; FILE *f; uint32_t sector_size = 512; uint32_t zero = 0; @@ -2747,15 +2716,7 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM case WM_INITDIALOG: memset(hd_file_name, 0, sizeof(hd_file_name)); - if (existing & 2) - { - next_free_id = (existing >> 3) & 0x1f; - hdd_ptr = &(hdd[next_free_id]); - } - else - { - hdd_ptr = &(temp_hdd[next_free_id]); - } + hdd_ptr = &(temp_hdd[next_free_id]); SetWindowText(hdlg, plat_get_string((existing & 1) ? IDS_4103 : IDS_4102)); @@ -2767,7 +2728,7 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM tracks = (existing & 1) ? 0 : 1023; set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); size = (tracks * hpc * spt) << 9; - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20LL)); hdconf_initialize_hdt_combo(hdlg); if (existing & 1) { @@ -2789,65 +2750,31 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM } add_locations(hdlg); h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - if (existing & 2) - { - hdd_ptr->bus = HDD_BUS_SCSI_REMOVABLE; - max_spt = 99; - max_hpc = 255; - } - else - { - hdd_ptr->bus = HDD_BUS_IDE_PIO_ONLY; - max_spt = 63; - max_hpc = 255; - } + hdd_ptr->bus = HDD_BUS_IDE; + max_spt = 63; + max_hpc = 255; SendMessage(h, CB_SETCURSEL, hdd_ptr->bus, 0); max_tracks = 266305; recalc_location_controls(hdlg, 1, 0); - if (existing & 2) - { - /* We're functioning as a load image dialog for a removable SCSI hard disk, - called from win.c, so let's hide the bus selection as we should not - allow it at this point. */ - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - h = GetDlgItem(hdlg, 1798); - ShowWindow(h, SW_HIDE); + channel = next_free_ide_channel(); + next_free_scsi_id_and_lun(&id, &lun); + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + SendMessage(h, CB_SETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + SendMessage(h, CB_SETCURSEL, id, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + SendMessage(h, CB_SETCURSEL, lun, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + SendMessage(h, CB_SETCURSEL, channel, 0); - /* Disable and hide the SCSI ID and LUN combo boxes. */ - h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); + new_hdd.mfm_channel = next_free_binary_channel(&mfm_tracking); + new_hdd.esdi_channel = next_free_binary_channel(&esdi_tracking); + new_hdd.xta_channel = next_free_binary_channel(&xta_tracking); + new_hdd.ide_channel = channel; + new_hdd.scsi_id = id; + new_hdd.scsi_lun = lun; - h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); - EnableWindow(h, FALSE); - ShowWindow(h, SW_HIDE); - - /* Set the file name edit box contents to our existing parameters. */ - h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); - SendMessage(h, WM_SETTEXT, 0, (LPARAM) hdd[next_free_id].fn); - } - else - { - channel = next_free_ide_channel(); - next_free_scsi_id_and_lun(&id, &lun); - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - SendMessage(h, CB_SETCURSEL, 0, 0); - h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); - SendMessage(h, CB_SETCURSEL, id, 0); - h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); - SendMessage(h, CB_SETCURSEL, lun, 0); - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); - SendMessage(h, CB_SETCURSEL, channel, 0); - - new_hdd.mfm_channel = next_free_binary_channel(&mfm_tracking); - new_hdd.esdi_channel = next_free_binary_channel(&esdi_tracking); - new_hdd.xtide_channel = next_free_binary_channel(&xtide_tracking); - new_hdd.ide_channel = channel; - new_hdd.scsi_id = id; - new_hdd.scsi_lun = lun; - } h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); EnableWindow(h, FALSE); @@ -2866,27 +2793,16 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM switch (LOWORD(wParam)) { case IDOK: - if (!(existing & 2)) - { - h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); - hdd_ptr->bus = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; - } + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + hdd_ptr->bus = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; /* Make sure no file name is allowed with removable SCSI hard disks. */ - if ((wcslen(hd_file_name) == 0) && (hdd_ptr->bus != HDD_BUS_SCSI_REMOVABLE)) + if (wcslen(hd_file_name) == 0) { hdd_ptr->bus = HDD_BUS_DISABLED; settings_msgbox(MBX_ERROR, (wchar_t *)IDS_4112); return TRUE; } - else if ((wcslen(hd_file_name) == 0) && (hdd_ptr->bus == HDD_BUS_SCSI_REMOVABLE)) - { - /* Mark hard disk added but return empty - it will signify the disk was ejected. */ - hdd_ptr->spt = hdd_ptr->hpc = hdd_ptr->tracks = 0; - memset(hdd_ptr->fn, 0, sizeof(hdd_ptr->fn)); - - goto hd_add_ok_common; - } get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &(hdd_ptr->spt)); get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &(hdd_ptr->hpc)); @@ -2895,43 +2811,30 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM hpc = hdd_ptr->hpc; tracks = hdd_ptr->tracks; - if (existing & 2) + switch(hdd_ptr->bus) { - if (hdd_ptr->bus == HDD_BUS_SCSI_REMOVABLE) - { - memset(hdd_ptr->prev_fn, 0, sizeof(hdd_ptr->prev_fn)); - wcscpy(hdd_ptr->prev_fn, hdd_ptr->fn); - } - } - else - { - switch(hdd_ptr->bus) - { - case HDD_BUS_MFM: - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - hdd_ptr->mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); - break; - case HDD_BUS_ESDI: - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - hdd_ptr->esdi_channel = SendMessage(h, CB_GETCURSEL, 0, 0); - break; - case HDD_BUS_XTIDE: - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); - hdd_ptr->xtide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); - break; - case HDD_BUS_IDE_PIO_ONLY: - case HDD_BUS_IDE_PIO_AND_DMA: - h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); - hdd_ptr->ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); - break; - case HDD_BUS_SCSI: - case HDD_BUS_SCSI_REMOVABLE: - h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); - hdd_ptr->scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); - h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); - hdd_ptr->scsi_lun = SendMessage(h, CB_GETCURSEL, 0, 0); - break; - } + case HDD_BUS_MFM: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdd_ptr->mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_ESDI: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdd_ptr->esdi_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_XTA: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdd_ptr->xta_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_IDE: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + hdd_ptr->ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_SCSI: + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + hdd_ptr->scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + hdd_ptr->scsi_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + break; } memset(hdd_ptr->fn, 0, sizeof(hdd_ptr->fn)); @@ -3036,17 +2939,13 @@ win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM settings_msgbox(MBX_INFO, (wchar_t *)IDS_4113); } -hd_add_ok_common: hard_disk_added = 1; EndDialog(hdlg, 0); return TRUE; case IDCANCEL: hard_disk_added = 0; - if (!(existing & 2)) - { - hdd_ptr->bus = HDD_BUS_DISABLED; - } + hdd_ptr->bus = HDD_BUS_DISABLED; EndDialog(hdlg, 0); return TRUE; @@ -3189,20 +3088,20 @@ hdd_add_file_open_error: no_update = 1; get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &temp); - if (temp != tracks) + if (tracks != (int64_t) temp) { tracks = temp; - size = (tracks * hpc * spt) << 9; - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (tracks > max_tracks) { tracks = max_tracks; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } @@ -3217,20 +3116,20 @@ hdd_add_file_open_error: no_update = 1; get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &temp); - if (temp != hpc) + if (hpc != (int64_t) temp) { hpc = temp; - size = (tracks * hpc * spt) << 9; - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (hpc > max_hpc) { hpc = max_hpc; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } @@ -3245,20 +3144,20 @@ hdd_add_file_open_error: no_update = 1; get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &temp); - if (temp != spt) + if (spt != (int64_t) temp) { spt = temp; - size = (tracks * hpc * spt) << 9; - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (spt > max_spt) { spt = max_spt; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } @@ -3273,10 +3172,10 @@ hdd_add_file_open_error: no_update = 1; get_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, &temp); - if (temp != (size >> 20)) + if (temp != (uint32_t) (size >> 20)) { - size = temp << 20; - tracks = ((size >> 9) / hpc) / spt; + size = ((uint64_t) temp) << 20LL; + tracks = (((uint32_t) (size >> 9)) / hpc) / spt; set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); recalc_selection(hdlg); } @@ -3284,9 +3183,9 @@ hdd_add_file_open_error: if (tracks > max_tracks) { tracks = max_tracks; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } @@ -3307,11 +3206,11 @@ hdd_add_file_open_error: tracks = hdd_table[selection][0]; hpc = hdd_table[selection][1]; spt = hdd_table[selection][2]; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); } else if ((temp != selection) && (temp == 127)) { @@ -3322,36 +3221,36 @@ hdd_add_file_open_error: selection = temp; hpc = 16; spt = 63; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); } if (spt > max_spt) { spt = max_spt; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (hpc > max_hpc) { hpc = max_hpc; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (tracks > max_tracks) { tracks = max_tracks; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } @@ -3387,39 +3286,16 @@ hdd_add_file_open_error: max_tracks = 1023; break; case HDD_BUS_ESDI: - case HDD_BUS_XTIDE: + case HDD_BUS_XTA: max_spt = 63; max_hpc = 16; max_tracks = 1023; break; - case HDD_BUS_IDE_PIO_ONLY: - case HDD_BUS_IDE_PIO_AND_DMA: + case HDD_BUS_IDE: max_spt = 63; max_hpc = 255; max_tracks = 266305; break; - case HDD_BUS_SCSI_REMOVABLE: - if (spt == 0) - { - spt = 63; - size = (tracks * hpc * spt) << 9; - set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); - } - if (hpc == 0) - { - hpc = 16; - size = (tracks * hpc * spt) << 9; - set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); - } - if (tracks == 0) - { - tracks = 1023; - size = (tracks * hpc * spt) << 9; - set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); - } case HDD_BUS_SCSI: max_spt = 99; max_hpc = 255; @@ -3427,20 +3303,7 @@ hdd_add_file_open_error: break; } - if ((hdd_ptr->bus == HDD_BUS_SCSI_REMOVABLE) && !chs_enabled) - { - h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); - EnableWindow(h, TRUE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); - EnableWindow(h, TRUE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); - EnableWindow(h, TRUE); - h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); - EnableWindow(h, TRUE); - h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); - EnableWindow(h, TRUE); - } - else if ((hdd_ptr->bus != HDD_BUS_SCSI_REMOVABLE) && !chs_enabled) + if (!chs_enabled) { h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); EnableWindow(h, FALSE); @@ -3457,27 +3320,27 @@ hdd_add_file_open_error: if (spt > max_spt) { spt = max_spt; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (hpc > max_hpc) { hpc = max_hpc; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } if (tracks > max_tracks) { tracks = max_tracks; - size = (tracks * hpc * spt) << 9; + size = (tracks * hpc * spt) << 9LL; set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); - set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (size >> 20)); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); recalc_selection(hdlg); } @@ -3513,15 +3376,13 @@ static void hard_disk_track(uint8_t id) case HDD_BUS_ESDI: esdi_tracking |= (1 << (temp_hdd[id].esdi_channel << 3)); break; - case HDD_BUS_XTIDE: - xtide_tracking |= (1 << (temp_hdd[id].xtide_channel << 3)); + case HDD_BUS_XTA: + xta_tracking |= (1 << (temp_hdd[id].xta_channel << 3)); break; - case HDD_BUS_IDE_PIO_ONLY: - case HDD_BUS_IDE_PIO_AND_DMA: + case HDD_BUS_IDE: ide_tracking |= (1 << (temp_hdd[id].ide_channel << 3)); break; case HDD_BUS_SCSI: - case HDD_BUS_SCSI_REMOVABLE: scsi_tracking[temp_hdd[id].scsi_id] |= (1 << (temp_hdd[id].scsi_lun << 3)); break; } @@ -3536,15 +3397,13 @@ static void hard_disk_untrack(uint8_t id) case HDD_BUS_ESDI: esdi_tracking &= ~(1 << (temp_hdd[id].esdi_channel << 3)); break; - case HDD_BUS_XTIDE: - xtide_tracking &= ~(1 << (temp_hdd[id].xtide_channel << 3)); + case HDD_BUS_XTA: + xta_tracking &= ~(1 << (temp_hdd[id].xta_channel << 3)); break; - case HDD_BUS_IDE_PIO_ONLY: - case HDD_BUS_IDE_PIO_AND_DMA: + case HDD_BUS_IDE: ide_tracking &= ~(1 << (temp_hdd[id].ide_channel << 3)); break; case HDD_BUS_SCSI: - case HDD_BUS_SCSI_REMOVABLE: scsi_tracking[temp_hdd[id].scsi_id] &= ~(1 << (temp_hdd[id].scsi_lun << 3)); break; } @@ -3650,10 +3509,6 @@ win_settings_hard_disks_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lPar } hard_disk_untrack(hdlv_current_sel); assign = (temp_hdd[hdlv_current_sel].bus == b) ? 0 : 1; - if ((b == HDD_BUS_IDE_PIO_ONLY) && (temp_hdd[hdlv_current_sel].bus == HDD_BUS_IDE_PIO_AND_DMA)) - assign = 0; - else if ((b == HDD_BUS_IDE_PIO_AND_DMA) && (temp_hdd[hdlv_current_sel].bus == HDD_BUS_IDE_PIO_ONLY)) - assign = 0; temp_hdd[hdlv_current_sel].bus = b; recalc_location_controls(hdlg, 0, assign); hard_disk_track(hdlv_current_sel); @@ -3680,9 +3535,9 @@ hd_bus_skip: { temp_hdd[hdlv_current_sel].esdi_channel = SendMessage(h, CB_GETCURSEL, 0, 0); } - else if (temp_hdd[hdlv_current_sel].bus == HDD_BUS_XTIDE) + else if (temp_hdd[hdlv_current_sel].bus == HDD_BUS_XTA) { - temp_hdd[hdlv_current_sel].xtide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_hdd[hdlv_current_sel].xta_channel = SendMessage(h, CB_GETCURSEL, 0, 0); } hard_disk_track(hdlv_current_sel); h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); @@ -3817,6 +3672,7 @@ static BOOL win_settings_floppy_drives_image_list_init(HWND hwndList) HIMAGELIST hSmall; int i = 0; + intptr_t icon; hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), @@ -3824,7 +3680,8 @@ static BOOL win_settings_floppy_drives_image_list_init(HWND hwndList) for (i = 0; i < 14; i++) { - hiconItem = LoadIcon(hinstance, (LPCWSTR) fdd_type_to_icon(i)); + icon = fdd_type_to_icon(i); + hiconItem = LoadIcon(hinstance, (LPCWSTR) icon); ImageList_AddIcon(hSmall, hiconItem); DestroyIcon(hiconItem); } @@ -3953,12 +3810,7 @@ static BOOL win_settings_cdrom_drives_recalc_list(HWND hwndList) lvI.pszText = plat_get_string(fsid); lvI.iImage = 0; break; - case CDROM_BUS_ATAPI_PIO_ONLY: - wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); - lvI.pszText = szText; - lvI.iImage = 1; - break; - case CDROM_BUS_ATAPI_PIO_AND_DMA: + case CDROM_BUS_ATAPI: wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); lvI.pszText = szText; lvI.iImage = 1; @@ -4016,12 +3868,7 @@ static BOOL win_settings_zip_drives_recalc_list(HWND hwndList) lvI.pszText = plat_get_string(fsid); lvI.iImage = 0; break; - case ZIP_BUS_ATAPI_PIO_ONLY: - wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].ide_channel >> 1, temp_zip_drives[i].ide_channel & 1); - lvI.pszText = szText; - lvI.iImage = 1; - break; - case ZIP_BUS_ATAPI_PIO_AND_DMA: + case ZIP_BUS_ATAPI: wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].ide_channel >> 1, temp_zip_drives[i].ide_channel & 1); lvI.pszText = szText; lvI.iImage = 1; @@ -4283,12 +4130,7 @@ static void win_settings_cdrom_drives_update_item(HWND hwndList, int i) lvI.pszText = plat_get_string(fsid); lvI.iImage = 0; break; - case CDROM_BUS_ATAPI_PIO_ONLY: - wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); - lvI.pszText = szText; - lvI.iImage = 1; - break; - case CDROM_BUS_ATAPI_PIO_AND_DMA: + case CDROM_BUS_ATAPI: wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); lvI.pszText = szText; lvI.iImage = 1; @@ -4342,12 +4184,7 @@ static void win_settings_zip_drives_update_item(HWND hwndList, int i) lvI.pszText = plat_get_string(fsid); lvI.iImage = 0; break; - case ZIP_BUS_ATAPI_PIO_ONLY: - wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].ide_channel >> 1, temp_zip_drives[i].ide_channel & 1); - lvI.pszText = szText; - lvI.iImage = 1; - break; - case ZIP_BUS_ATAPI_PIO_AND_DMA: + case ZIP_BUS_ATAPI: wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].ide_channel >> 1, temp_zip_drives[i].ide_channel & 1); lvI.pszText = szText; lvI.iImage = 1; @@ -4386,9 +4223,9 @@ static void cdrom_add_locations(HWND hdlg) h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); for (i = CDROM_BUS_DISABLED; i <= CDROM_BUS_SCSI; i++) { - if ((i == CDROM_BUS_DISABLED) || (i >= CDROM_BUS_ATAPI_PIO_ONLY)) + if ((i == CDROM_BUS_DISABLED) || (i >= CDROM_BUS_ATAPI)) { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(combo_id_to_string_id(i))); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(combo_id_to_string_id(i))); } } @@ -4461,8 +4298,7 @@ static void cdrom_recalc_location_controls(HWND hdlg, int assign_id) switch(bus) { - case CDROM_BUS_ATAPI_PIO_ONLY: /* ATAPI (PIO-only) */ - case CDROM_BUS_ATAPI_PIO_AND_DMA: /* ATAPI (PIO and DMA) */ + case CDROM_BUS_ATAPI: /* ATAPI */ h = GetDlgItem(hdlg, IDT_1743); ShowWindow(h, SW_SHOW); EnableWindow(h, TRUE); @@ -4510,9 +4346,9 @@ static void zip_add_locations(HWND hdlg) h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); for (i = ZIP_BUS_DISABLED; i <= ZIP_BUS_SCSI; i++) { - if ((i == ZIP_BUS_DISABLED) || (i >= ZIP_BUS_ATAPI_PIO_ONLY)) + if ((i == ZIP_BUS_DISABLED) || (i >= ZIP_BUS_ATAPI)) { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(combo_id_to_string_id(i))); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(combo_id_to_string_id(i))); } } @@ -4568,8 +4404,7 @@ static void zip_recalc_location_controls(HWND hdlg, int assign_id) switch(bus) { - case ZIP_BUS_ATAPI_PIO_ONLY: /* ATAPI (PIO-only) */ - case ZIP_BUS_ATAPI_PIO_AND_DMA: /* ATAPI (PIO and DMA) */ + case ZIP_BUS_ATAPI: /* ATAPI */ h = GetDlgItem(hdlg, IDT_1756); ShowWindow(h, SW_SHOW); EnableWindow(h, TRUE); @@ -4609,7 +4444,7 @@ static void zip_recalc_location_controls(HWND hdlg, int assign_id) static void cdrom_track(uint8_t id) { - if ((temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI_PIO_ONLY) || (temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI_PIO_ONLY)) + if (temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI) ide_tracking |= (2 << (temp_cdrom_drives[id].ide_channel << 3)); else if (temp_cdrom_drives[id].bus_type == CDROM_BUS_SCSI) scsi_tracking[temp_cdrom_drives[id].scsi_device_id] |= (1 << temp_cdrom_drives[id].scsi_device_lun); @@ -4617,7 +4452,7 @@ static void cdrom_track(uint8_t id) static void cdrom_untrack(uint8_t id) { - if ((temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI_PIO_ONLY) || (temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI_PIO_ONLY)) + if (temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI) ide_tracking &= ~(2 << (temp_cdrom_drives[id].ide_channel << 3)); else if (temp_cdrom_drives[id].bus_type == CDROM_BUS_SCSI) scsi_tracking[temp_cdrom_drives[id].scsi_device_id] &= ~(1 << temp_cdrom_drives[id].scsi_device_lun); @@ -4636,7 +4471,7 @@ static void cdrom_track_all(void) static void zip_track(uint8_t id) { - if ((temp_zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_ONLY) || (temp_zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_ONLY)) + if (temp_zip_drives[id].bus_type == ZIP_BUS_ATAPI) ide_tracking |= (1 << temp_zip_drives[id].ide_channel); else if (temp_zip_drives[id].bus_type == ZIP_BUS_SCSI) scsi_tracking[temp_zip_drives[id].scsi_device_id] |= (1 << temp_zip_drives[id].scsi_device_lun); @@ -4644,7 +4479,7 @@ static void zip_track(uint8_t id) static void zip_untrack(uint8_t id) { - if ((temp_zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_ONLY) || (temp_zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_ONLY)) + if (temp_zip_drives[id].bus_type == ZIP_BUS_ATAPI) ide_tracking &= ~(1 << temp_zip_drives[id].ide_channel); else if (temp_zip_drives[id].bus_type == ZIP_BUS_SCSI) scsi_tracking[temp_zip_drives[id].scsi_device_id] &= ~(1 << temp_zip_drives[id].scsi_device_lun); @@ -4691,7 +4526,7 @@ win_settings_floppy_drives_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM l { if (i == 0) { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)plat_get_string(IDS_5376)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5376)); } else { @@ -4808,7 +4643,7 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam HWND h; int old_sel = 0; int b = 0; - int b2 = 0; + uint32_t b2 = 0; int assign = 0; switch (message) @@ -4832,14 +4667,11 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam default: b = 0; break; - case CDROM_BUS_ATAPI_PIO_ONLY: + case CDROM_BUS_ATAPI: b = 1; break; - case CDROM_BUS_ATAPI_PIO_AND_DMA: - b = 2; - break; case CDROM_BUS_SCSI: - b = 3; + b = 2; break; } @@ -4863,14 +4695,11 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam default: b = 0; break; - case ZIP_BUS_ATAPI_PIO_ONLY: + case ZIP_BUS_ATAPI: b = 1; break; - case ZIP_BUS_ATAPI_PIO_AND_DMA: - b = 2; - break; case ZIP_BUS_SCSI: - b = 3; + b = 2; break; } @@ -4916,14 +4745,11 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam default: b = 0; break; - case CDROM_BUS_ATAPI_PIO_ONLY: + case CDROM_BUS_ATAPI: b = 1; break; - case CDROM_BUS_ATAPI_PIO_AND_DMA: - b = 2; - break; case CDROM_BUS_SCSI: - b = 3; + b = 2; break; } @@ -4958,14 +4784,11 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam default: b = 0; break; - case ZIP_BUS_ATAPI_PIO_ONLY: + case ZIP_BUS_ATAPI: b = 1; break; - case ZIP_BUS_ATAPI_PIO_AND_DMA: - b = 2; - break; case ZIP_BUS_SCSI: - b = 3; + b = 2; break; } @@ -4998,12 +4821,9 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam b2 = CDROM_BUS_DISABLED; break; case 1: - b2 = CDROM_BUS_ATAPI_PIO_ONLY; + b2 = CDROM_BUS_ATAPI; break; case 2: - b2 = CDROM_BUS_ATAPI_PIO_AND_DMA; - break; - case 3: b2 = CDROM_BUS_SCSI; break; } @@ -5015,10 +4835,6 @@ win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam assign = (temp_cdrom_drives[cdlv_current_sel].bus_type == b2) ? 0 : 1; if (temp_cdrom_drives[cdlv_current_sel].bus_type == CDROM_BUS_DISABLED) temp_cdrom_drives[cdlv_current_sel].speed = 8; - if ((b2 == CDROM_BUS_ATAPI_PIO_ONLY) && (temp_cdrom_drives[cdlv_current_sel].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) - assign = 0; - else if ((b2 == CDROM_BUS_ATAPI_PIO_AND_DMA) && (temp_cdrom_drives[cdlv_current_sel].bus_type == CDROM_BUS_ATAPI_PIO_ONLY)) - assign = 0; temp_cdrom_drives[cdlv_current_sel].bus_type = b2; cdrom_recalc_location_controls(hdlg, assign); cdrom_track(cdlv_current_sel); @@ -5105,12 +4921,9 @@ cdrom_bus_skip: b2 = ZIP_BUS_DISABLED; break; case 1: - b2 = ZIP_BUS_ATAPI_PIO_ONLY; + b2 = ZIP_BUS_ATAPI; break; case 2: - b2 = ZIP_BUS_ATAPI_PIO_AND_DMA; - break; - case 3: b2 = ZIP_BUS_SCSI; break; } @@ -5120,10 +4933,6 @@ cdrom_bus_skip: } zip_untrack(zdlv_current_sel); assign = (temp_zip_drives[zdlv_current_sel].bus_type == b2) ? 0 : 1; - if ((b2 == ZIP_BUS_ATAPI_PIO_ONLY) && (temp_zip_drives[zdlv_current_sel].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) - assign = 0; - else if ((b2 == ZIP_BUS_ATAPI_PIO_AND_DMA) && (temp_zip_drives[cdlv_current_sel].bus_type == ZIP_BUS_ATAPI_PIO_ONLY)) - assign = 0; temp_zip_drives[zdlv_current_sel].bus_type = b2; zip_recalc_location_controls(hdlg, assign); zip_track(zdlv_current_sel); diff --git a/src/win/win_stbar.c b/src/win/win_stbar.c index 9c2ac2593..bfca21c5d 100644 --- a/src/win/win_stbar.c +++ b/src/win/win_stbar.c @@ -8,7 +8,7 @@ * * Implement the application's Status Bar. * - * Version: @(#)win_stbar.c 1.0.17 2018/03/18 + * Version: @(#)win_stbar.c 1.0.17 2018/03/26 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -33,14 +33,14 @@ #include "../cpu/cpu.h" #include "../device.h" #include "../machine/machine.h" -#include "../cdrom/cdrom.h" -#include "../cdrom/cdrom_image.h" -#include "../cdrom/cdrom_null.h" #include "../disk/hdd.h" #include "../disk/hdc.h" #include "../disk/zip.h" #include "../floppy/fdd.h" #include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../cdrom/cdrom_image.h" +#include "../cdrom/cdrom_null.h" #include "../scsi/scsi_disk.h" #include "../network/network.h" #include "../video/video.h" @@ -63,11 +63,11 @@ static HMENU *sb_menu_handles; static HMENU menuSBAR; static WCHAR **sbTips; static int *iStatusWidths; -static int *sb_icon_flags; static int *sb_part_meanings; static int *sb_part_icons; static int sb_parts = 0; static int sb_ready = 0; +static uint8_t sb_map[256]; /* Also used by win_settings.c */ @@ -80,22 +80,13 @@ fdd_type_to_icon(int type) case 0: break; - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: + case 1: case 2: case 3: case 4: + case 5: case 6: ret = 128; break; - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: + case 7: case 8: case 9: case 10: + case 11: case 12: case 13: ret = 144; break; @@ -150,9 +141,6 @@ StatusBarCreateFloppySubmenu(HMENU m, int id) static void StatusBarCreateCdromSubmenu(HMENU m, int id) { - WCHAR s[64]; - int i; - AppendMenu(m, MF_STRING, IDM_CDROM_MUTE | id, plat_get_string(IDS_2165)); AppendMenu(m, MF_SEPARATOR, 0, 0); @@ -164,41 +152,12 @@ StatusBarCreateCdromSubmenu(HMENU m, int id) AppendMenu(m, MF_STRING, IDM_CDROM_IMAGE | id, plat_get_string(IDS_2168)); - if (host_cdrom_drive_available_num == 0) { - if ((cdrom_drives[id].host_drive >= 'A') && - (cdrom_drives[id].host_drive <= 'Z')) { - cdrom_drives[id].host_drive = 0; - } - - goto check_menu_items; - } else { - if ((cdrom_drives[id].host_drive >= 'A') && - (cdrom_drives[id].host_drive <= 'Z')) { - if (!host_cdrom_drive_available[cdrom_drives[id].host_drive - 'A']) { - cdrom_drives[id].host_drive = 0; - } - } - } - - AppendMenu(m, MF_SEPARATOR, 0, 0); - - for (i=0; i<26; i++) { - _swprintf(s, L"Host CD/DVD Drive (%c:)", i+'A'); - if (host_cdrom_drive_available[i]) - AppendMenu(m, MF_STRING, IDM_CDROM_HOST_DRIVE | (i<<3)|id, s); - } - -check_menu_items: if (! cdrom_drives[id].sound_on) CheckMenuItem(m, IDM_CDROM_MUTE | id, MF_CHECKED); if (cdrom_drives[id].host_drive == 200) CheckMenuItem(m, IDM_CDROM_IMAGE | id, MF_CHECKED); - else - if ((cdrom_drives[id].host_drive >= 'A') && (cdrom_drives[id].host_drive <= 'Z')) { - CheckMenuItem(m, IDM_CDROM_HOST_DRIVE | id | - ((cdrom_drives[id].host_drive - 'A') << 3), MF_CHECKED); - } else { + else { cdrom_drives[id].host_drive = 0; CheckMenuItem(m, IDM_CDROM_EMPTY | id, MF_CHECKED); } @@ -231,74 +190,26 @@ StatusBarCreateZIPSubmenu(HMENU m, int id) } -static void -StatusBarCreateRemovableDiskSubmenu(HMENU m, int id) -{ - AppendMenu(m, MF_STRING, IDM_RDISK_EJECT | id, - plat_get_string(IDS_2164)); - AppendMenu(m, MF_STRING, IDM_RDISK_RELOAD | id, - plat_get_string(IDS_2167)); - AppendMenu(m, MF_SEPARATOR, 0, 0); - AppendMenu(m, MF_STRING, IDM_RDISK_SEND_CHANGE | id, - plat_get_string(IDS_2142)); - AppendMenu(m, MF_SEPARATOR, 0, 0); - AppendMenu(m, MF_STRING, IDM_RDISK_IMAGE | id, - plat_get_string(IDS_2168)); - AppendMenu(m, MF_STRING, IDM_RDISK_IMAGE_WP | id, - plat_get_string(IDS_2169)); -} - - /* API */ -int -ui_sb_find_part(int tag) -{ - int found = -1; - int i; - - if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) { - return -1; - } - - for (i=0; i= SB_TEXT) || !sb_ready || (sb_parts == 0) || (sb_icon_flags == NULL) || (sb_part_icons == NULL)) { + if (((tag & 0xf0) >= SB_TEXT) || !sb_ready) return; - } - temp_flags |= active; + found = sb_map[tag]; + if (found != 0xff) { + sb_part_icons[found] &= ~1; + sb_part_icons[found] |= active; - found = ui_sb_find_part(tag); - if (found != -1) { - if (temp_flags != (sb_icon_flags[found] & 1)) { - sb_icon_flags[found] &= ~1; - sb_icon_flags[found] |= active; - - sb_part_icons[found] &= ~257; - sb_part_icons[found] |= sb_icon_flags[found]; - - SendMessage(hwndSBAR, SB_SETICON, found, - (LPARAM)hIcon[sb_part_icons[found]]); - } + SendMessage(hwndSBAR, SB_SETICON, found, + (LPARAM)hIcon[sb_part_icons[found]]); } } @@ -307,19 +218,15 @@ ui_sb_update_icon(int tag, int active) void ui_sb_update_icon_state(int tag, int state) { - int found = -1; + uint8_t found = 0xff; - if (((tag & 0xf0) >= SB_HDD) || !sb_ready || (sb_parts == 0) || (sb_icon_flags == NULL) || (sb_part_icons == NULL)) { + if (((tag & 0xf0) >= SB_HDD) || !sb_ready) return; - } - found = ui_sb_find_part(tag); - if (found != -1) { - sb_icon_flags[found] &= ~256; - sb_icon_flags[found] |= state ? 256 : 0; - - sb_part_icons[found] &= ~257; - sb_part_icons[found] |= sb_icon_flags[found]; + found = sb_map[tag]; + if (found != 0xff) { + sb_part_icons[found] &= ~256; + sb_part_icons[found] |= (state ? 256 : 0); SendMessage(hwndSBAR, SB_SETICON, found, (LPARAM)hIcon[sb_part_icons[found]]); @@ -357,28 +264,22 @@ StatusBarCreateFloppyTip(int part) static void StatusBarCreateCdromTip(int part) { - WCHAR wtext[512]; WCHAR tempTip[512]; WCHAR *szText; int id; int drive = sb_part_meanings[part] & 0xf; int bus = cdrom_drives[drive].bus_type; - id = IDS_4352 + (bus - 1); + id = IDS_5377 + (bus - 1); szText = plat_get_string(id); if (cdrom_drives[drive].host_drive == 200) { - if (wcslen(cdrom_image[drive].image_path) == 0) { + if (wcslen(cdrom_image[drive].image_path) == 0) _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, plat_get_string(IDS_2057)); - } else { + else _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, cdrom_image[drive].image_path); - } - } else if ((cdrom_drives[drive].host_drive >= 'A') && (cdrom_drives[drive].host_drive <= 'Z')) { - _swprintf(wtext, plat_get_string(IDS_2058), cdrom_drives[drive].host_drive & ~0x20); - _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, wtext); - } else { + } else _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, plat_get_string(IDS_2057)); - } if (sbTips[part] != NULL) { free(sbTips[part]); @@ -393,38 +294,22 @@ static void StatusBarCreateZIPTip(int part) { WCHAR tempTip[512]; - + WCHAR *szText; + int id; int drive = sb_part_meanings[part] & 0xf; + int bus = zip_drives[drive].bus_type; + + id = IDS_5377 + (bus - 1); + szText = plat_get_string(id); int type = zip_drives[drive].is_250 ? 250 : 100; if (wcslen(zip_drives[drive].image_path) == 0) { _swprintf(tempTip, plat_get_string(IDS_2177), - drive+1, type, plat_get_string(IDS_2057)); + type, drive+1, szText, plat_get_string(IDS_2057)); } else { _swprintf(tempTip, plat_get_string(IDS_2177), - drive+1, type, zip_drives[drive].image_path); - } - - if (sbTips[part] != NULL) { - free(sbTips[part]); - sbTips[part] = NULL; - } - sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); - wcscpy(sbTips[part], tempTip); -} - - -static void -StatusBarCreateRemovableDiskTip(int part) -{ - WCHAR tempTip[512]; - int drive = sb_part_meanings[part] & 0x1f; - - if (wcslen(hdd[drive].fn) == 0) { - _swprintf(tempTip, plat_get_string(IDS_4115), drive, plat_get_string(IDS_2057)); - } else { - _swprintf(tempTip, plat_get_string(IDS_4115), drive, hdd[drive].fn); + type, drive+1, szText, zip_drives[drive].image_path); } if (sbTips[part] != NULL) { @@ -487,18 +372,13 @@ StatusBarCreateSoundTip(int part) void ui_sb_update_tip(int meaning) { - int part = -1; - int i; + uint8_t part = 0xff; if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) return; - for (i=0; i= 'A') && (cdrom_drives[id].host_drive <= 'Z')) { - sb_icon_flags[i] = 0; - } else { - sb_icon_flags[i] = 256; - } - sb_part_icons[i] = 160 | sb_icon_flags[i]; + if (cdrom_drives[id].host_drive == 200) + sb_part_icons[i] = (wcslen(cdrom_image[id].image_path) == 0) ? 256 : 0; + else + sb_part_icons[i] = 256; + sb_part_icons[i] |= 160; sb_menu_handles[i] = StatusBarCreatePopupMenu(i); StatusBarCreateCdromSubmenu(sb_menu_handles[i], sb_part_meanings[i] & 0xf); EnableMenuItem(sb_menu_handles[i], IDM_CDROM_RELOAD | (sb_part_meanings[i] & 0xf), MF_BYCOMMAND | MF_GRAYED); @@ -872,32 +692,21 @@ ui_sb_update_panes(void) break; case SB_ZIP: /* Iomega ZIP */ - sb_icon_flags[i] = (wcslen(zip_drives[sb_part_meanings[i] & 0xf].image_path) == 0) ? 256 : 0; - sb_part_icons[i] = 176 + sb_icon_flags[i]; + sb_part_icons[i] = (wcslen(zip_drives[sb_part_meanings[i] & 0xf].image_path) == 0) ? 256 : 0; + sb_part_icons[i] |= 176; sb_menu_handles[i] = StatusBarCreatePopupMenu(i); StatusBarCreateZIPSubmenu(sb_menu_handles[i], sb_part_meanings[i] & 0xf); - EnableMenuItem(sb_menu_handles[i], IDM_ZIP_EJECT | (sb_part_meanings[i] & 0xf), MF_BYCOMMAND | ((sb_icon_flags[i] & 256) ? MF_GRAYED : MF_ENABLED)); + EnableMenuItem(sb_menu_handles[i], IDM_ZIP_EJECT | (sb_part_meanings[i] & 0xf), MF_BYCOMMAND | ((sb_part_icons[i] & 256) ? MF_GRAYED : MF_ENABLED)); StatusBarCreateZIPTip(i); break; - case SB_RDISK: /* Removable hard disk */ - sb_icon_flags[i] = (wcslen(hdd[sb_part_meanings[i] & 0x1f].fn) == 0) ? 256 : 0; - sb_part_icons[i] = 192 + sb_icon_flags[i]; - sb_menu_handles[i] = StatusBarCreatePopupMenu(i); - StatusBarCreateRemovableDiskSubmenu(sb_menu_handles[i], sb_part_meanings[i] & 0x1f); - EnableMenuItem(sb_menu_handles[i], IDM_RDISK_EJECT | (sb_part_meanings[i] & 0x1f), MF_BYCOMMAND | ((sb_icon_flags[i] & 256) ? MF_GRAYED : MF_ENABLED)); - EnableMenuItem(sb_menu_handles[i], IDM_RDISK_RELOAD | (sb_part_meanings[i] & 0x1f), MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(sb_menu_handles[i], IDM_RDISK_SEND_CHANGE | (sb_part_meanings[i] & 0x1f), MF_BYCOMMAND | ((sb_icon_flags[i] & 256) ? MF_GRAYED : MF_ENABLED)); - StatusBarCreateRemovableDiskTip(i); - break; - case SB_HDD: /* Hard disk */ - sb_part_icons[i] = 208; + sb_part_icons[i] = 192; StatusBarCreateDiskTip(i); break; case SB_NETWORK: /* Network */ - sb_part_icons[i] = 224; + sb_part_icons[i] = 208; StatusBarCreateNetworkTip(i); break; @@ -916,9 +725,8 @@ ui_sb_update_panes(void) SendMessage(hwndSBAR, SB_SETTEXT, i | SBT_NOBORDERS, (LPARAM)L""); SendMessage(hwndSBAR, SB_SETICON, i, (LPARAM)hIcon[sb_part_icons[i]]); SendMessage(hwndSBAR, SB_SETTIPTEXT, i, (LPARAM)sbTips[i]); - } else { + } else SendMessage(hwndSBAR, SB_SETICON, i, (LPARAM)NULL); - } } sb_ready = 1; @@ -979,13 +787,11 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) WCHAR temp_path[1024]; RECT rc; POINT pt; - int new_cdrom_drive; int ret = 0; int item_id = 0; int item_params = 0; int id = 0; - int part = 0; - int letter = 0; + uint8_t part = 0; switch (message) { case WM_COMMAND: @@ -995,15 +801,15 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) switch (item_id) { case IDM_FLOPPY_IMAGE_NEW: id = item_params & 0x0003; - part = ui_sb_find_part(SB_FLOPPY | id); + part = sb_map[SB_FLOPPY | id]; NewFloppyDialogCreate(hwnd, id, part); break; case IDM_FLOPPY_IMAGE_EXISTING: case IDM_FLOPPY_IMAGE_EXISTING_WP: id = item_params & 0x0003; - part = ui_sb_find_part(SB_FLOPPY | id); - if ((part == -1) || (sb_menu_handles == NULL)) + part = sb_map[SB_FLOPPY | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) break; ret = file_dlg_w_st(hwnd, IDS_2159, floppyfns[id], 0); @@ -1013,8 +819,8 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_FLOPPY_EJECT: id = item_params & 0x0003; - part = ui_sb_find_part(SB_FLOPPY | id); - if ((part == -1) || (sb_menu_handles == NULL)) + part = sb_map[SB_FLOPPY | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) break; fdd_close(id); @@ -1027,8 +833,8 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_FLOPPY_EXPORT_TO_86F: id = item_params & 0x0003; - part = ui_sb_find_part(SB_FLOPPY | id); - if ((part == -1) || (sb_menu_handles == NULL)) + part = sb_map[SB_FLOPPY | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) break; ret = file_dlg_w_st(hwnd, IDS_2173, floppyfns[id], 1); @@ -1043,8 +849,8 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_CDROM_MUTE: id = item_params & 0x0007; - part = ui_sb_find_part(SB_CDROM | id); - if ((part == -1) || (sb_menu_handles == NULL)) + part = sb_map[SB_CDROM | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) break; cdrom_drives[id].sound_on ^= 1; @@ -1065,8 +871,8 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_CDROM_IMAGE: id = item_params & 0x0007; - part = ui_sb_find_part(SB_CDROM | id); - if ((part == -1) || (sb_menu_handles == NULL)) + part = sb_map[SB_CDROM | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) break; if (!file_dlg_w_st(hwnd, IDS_2075, cdrom_image[id].image_path, 0)) { @@ -1075,15 +881,13 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (!cdrom_image[id].prev_image_path) cdrom_image[id].prev_image_path = (wchar_t *) malloc(1024); wcscpy(cdrom_image[id].prev_image_path, cdrom_image[id].image_path); - cdrom_drives[id].handler->exit(id); - cdrom_close(id); + cdrom[id]->handler->exit(id); + cdrom_close_handler(id); + memset(cdrom_image[id].image_path, 0, 2048); image_open(id, temp_path); /* Signal media change to the emulated machine. */ - cdrom_insert(id); + cdrom_insert(cdrom[id]); CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); - if ((cdrom_drives[id].host_drive >= 'A') && (cdrom_drives[id].host_drive <= 'Z')) { - CheckMenuItem(sb_menu_handles[part], IDM_CDROM_HOST_DRIVE | id | ((cdrom_drives[id].host_drive - 'A') << 3), MF_UNCHECKED); - } cdrom_drives[id].host_drive = (wcslen(cdrom_image[id].image_path) == 0) ? 0 : 200; if (cdrom_drives[id].host_drive == 200) { CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_CHECKED); @@ -1099,52 +903,17 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } break; - case IDM_CDROM_HOST_DRIVE: - id = item_params & 0x0007; - letter = ((item_params >> 3) & 0x001f) + 'A'; - part = ui_sb_find_part(SB_CDROM | id); - if ((part == -1) || (sb_menu_handles == NULL)) - { - break; - } - - new_cdrom_drive = letter; - if (cdrom_drives[id].host_drive == new_cdrom_drive) - { - /* Switching to the same drive. Do nothing. */ - break; - } - cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; - cdrom_drives[id].handler->exit(id); - cdrom_close(id); - ioctl_open(id, new_cdrom_drive); - /* Signal media change to the emulated machine. */ - cdrom_insert(id); - CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); - if ((cdrom_drives[id].host_drive >= 'A') && (cdrom_drives[id].host_drive <= 'Z')) - { - CheckMenuItem(sb_menu_handles[part], IDM_CDROM_HOST_DRIVE | id | ((cdrom_drives[id].host_drive - 'A') << 3), MF_UNCHECKED); - } - CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_UNCHECKED); - cdrom_drives[id].host_drive = new_cdrom_drive; - CheckMenuItem(sb_menu_handles[part], IDM_CDROM_HOST_DRIVE | id | ((cdrom_drives[id].host_drive - 'A') << 3), MF_CHECKED); - EnableMenuItem(sb_menu_handles[part], IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); - ui_sb_update_icon_state(SB_CDROM | id, 0); - ui_sb_update_tip(SB_CDROM | id); - config_save(); - break; - case IDM_ZIP_IMAGE_NEW: id = item_params & 0x0003; - part = ui_sb_find_part(SB_ZIP | id); + part = sb_map[SB_ZIP | id]; NewFloppyDialogCreate(hwnd, id | 0x80, part); /* NewZIPDialogCreate */ break; case IDM_ZIP_IMAGE_EXISTING: case IDM_ZIP_IMAGE_EXISTING_WP: id = item_params & 0x0003; - part = ui_sb_find_part(SB_ZIP | id); - if ((part == -1) || (sb_menu_handles == NULL)) + part = sb_map[SB_ZIP | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) break; ret = file_dlg_w_st(hwnd, IDS_2175, zip_drives[id].image_path, 0); @@ -1162,49 +931,6 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) zip_reload(id); break; - case IDM_RDISK_EJECT: - id = item_params & 0x001f; - removable_disk_eject(id); - break; - - case IDM_RDISK_RELOAD: - id = item_params & 0x001f; - removable_disk_reload(id); - break; - - case IDM_RDISK_SEND_CHANGE: - id = item_params & 0x001f; - scsi_disk_insert(id); - break; - - case IDM_RDISK_IMAGE: - case IDM_RDISK_IMAGE_WP: - id = item_params & 0x001f; - ret = file_dlg_w_st(hwnd, IDS_4106, hdd[id].fn, id); - if (!ret) { - removable_disk_unload(id); - memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); - wcscpy(hdd[id].fn, wopenfilestring); - hdd[id].wp = (item_id == IDM_RDISK_IMAGE_WP) ? 1 : 0; - scsi_loadhd(hdd[id].scsi_id, hdd[id].scsi_lun, id); - scsi_disk_insert(id); - if (wcslen(hdd[id].fn) > 0) { - ui_sb_update_icon_state(SB_RDISK | id, 0); - EnableMenuItem(sb_menu_handles[part], IDM_RDISK_EJECT | id, MF_BYCOMMAND | MF_ENABLED); - EnableMenuItem(sb_menu_handles[part], IDM_RDISK_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(sb_menu_handles[part], IDM_RDISK_SEND_CHANGE | id, MF_BYCOMMAND | MF_ENABLED); - } - else { - ui_sb_update_icon_state(SB_RDISK | id, 1); - EnableMenuItem(sb_menu_handles[part], IDM_RDISK_EJECT | id, MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(sb_menu_handles[part], IDM_RDISK_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); - EnableMenuItem(sb_menu_handles[part], IDM_RDISK_SEND_CHANGE | id, MF_BYCOMMAND | MF_GRAYED); - } - ui_sb_update_tip(SB_RDISK | id); - config_save(); - } - break; - default: break; } @@ -1260,8 +986,6 @@ StatusBarCreate(HWND hwndParent, uintptr_t idStatus, HINSTANCE hInst) hIcon[i] = LoadIconEx((PCTSTR) i); for (i = 208; i < 210; i++) hIcon[i] = LoadIconEx((PCTSTR) i); - for (i = 224; i < 226; i++) - hIcon[i] = LoadIconEx((PCTSTR) i); for (i = 259; i < 260; i++) hIcon[i] = LoadIconEx((PCTSTR) i); for (i = 384; i < 386; i++) @@ -1272,8 +996,6 @@ StatusBarCreate(HWND hwndParent, uintptr_t idStatus, HINSTANCE hInst) hIcon[i] = LoadIconEx((PCTSTR) i); for (i = 432; i < 434; i++) hIcon[i] = LoadIconEx((PCTSTR) i); - for (i = 448; i < 450; i++) - hIcon[i] = LoadIconEx((PCTSTR) i); GetWindowRect(hwndParent, &rectDialog); dw = rectDialog.right - rectDialog.left; @@ -1317,8 +1039,6 @@ StatusBarCreate(HWND hwndParent, uintptr_t idStatus, HINSTANCE hInst) memset(sb_part_meanings, 0, sb_parts * sizeof(int)); sb_part_icons = (int *)malloc(sb_parts * sizeof(int)); memset(sb_part_icons, 0, sb_parts * sizeof(int)); - sb_icon_flags = (int *)malloc(sb_parts * sizeof(int)); - memset(sb_icon_flags, 0, sb_parts * sizeof(int)); sb_menu_handles = (HMENU *)malloc(sb_parts * sizeof(HMENU)); memset(sb_menu_handles, 0, sb_parts * sizeof(HMENU)); sbTips = (WCHAR **)malloc(sb_parts * sizeof(WCHAR *)); @@ -1339,10 +1059,10 @@ StatusBarCreate(HWND hwndParent, uintptr_t idStatus, HINSTANCE hInst) void ui_sb_check_menu_item(int tag, int id, int chk) { - int part; + uint8_t part; - part = ui_sb_find_part(tag); - if ((part == -1) || (sb_menu_handles == NULL)) + part = sb_map[tag]; + if ((part == 0xff) || (sb_menu_handles == NULL)) return; CheckMenuItem(sb_menu_handles[part], id, chk); @@ -1353,10 +1073,10 @@ ui_sb_check_menu_item(int tag, int id, int chk) void ui_sb_enable_menu_item(int tag, int id, int flg) { - int part; + uint8_t part; - part = ui_sb_find_part(tag); - if ((part == -1) || (sb_menu_handles == NULL)) + part = sb_map[tag]; + if ((part == 0xff) || (sb_menu_handles == NULL)) return; EnableMenuItem(sb_menu_handles[part], id, flg); @@ -1367,18 +1087,14 @@ ui_sb_enable_menu_item(int tag, int id, int flg) void ui_sb_set_text_w(wchar_t *wstr) { - int part = -1; - int i; + uint8_t part = 0xff; - if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) return; + if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) + return; - for (i=0; i * Fred N. van Kempen, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2017 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2017,2018 Fred N. van Kempen. */ #define UNICODE #define BITMAP WINDOWS_BITMAP @@ -39,7 +39,8 @@ typedef struct { thread_t * thread_create(void (*func)(void *param), void *param) { - return((thread_t *)_beginthread(func, 0, param)); + uintptr_t bt = _beginthread(func, 0, param); + return((thread_t *)bt); } diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 75c933fb3..e6ddcf234 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -8,7 +8,7 @@ * * user Interface module for WinAPI on Windows. * - * Version: @(#)win_ui.c 1.0.23 2018/03/19 + * Version: @(#)win_ui.c 1.0.24 2018/04/21 * * Authors: Sarah Walker, * Miran Grca, @@ -75,12 +75,10 @@ show_cursor(int val) return; if (val == 0) { - while (1) { + while (1) if (ShowCursor(FALSE) < 0) break; - } - } else { + } else ShowCursor(TRUE); - } vis = val; } @@ -94,23 +92,6 @@ LoadIconEx(PCTSTR pszIconName) } -#if 0 -static void -win_menu_update(void) -{ - menuMain = LoadMenu(hinstance, L"MainMenu")); - - menuSBAR = LoadMenu(hinstance, L"StatusBarMenu"); - - initmenu(); - - SetMenu(hwndMain, menu); - - win_title_update = 1; -} -#endif - - static void video_toggle_option(HMENU h, int *val, int id) { @@ -554,6 +535,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) break; #endif +#if 0 case IDM_CONFIG_LOAD: plat_pause(1); if (!file_dlg_st(hwnd, IDS_2160, "", 0) && @@ -571,6 +553,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) } plat_pause(0); break; +#endif } return(0); @@ -749,11 +732,6 @@ ui_init(int nCmdShow) HACCEL haccel; /* handle to accelerator table */ int bRet; -#if 0 - /* We should have an application-wide at_exit catcher. */ - atexit(plat_mouse_capture); -#endif - if (settings_only) { if (! pc_init_modules()) { /* Dang, no ROMs found at all! */ @@ -1021,9 +999,6 @@ plat_resize(int x, int y) int sb_borders[3]; RECT r; -#if 0 -pclog("PLAT: VID[%d,%d] resizing to %dx%d\n", video_fullscreen, vid_api, x, y); -#endif /* First, see if we should resize the UI window. */ if (!vid_resize) { video_wait_for_blit();