From 2792da5432100e7a5676234689cb504529b92051 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 14 Oct 2017 07:03:19 +0200 Subject: [PATCH] Refactored AHA-154x and BusLogic emulation and made them use a common core; Fixed AHA-154x scatter/gather transfers; Two-phased SCSI read-direction commands; Made scsi_bus.c use a dynamically malloc'd buffer instead of a giant fixed-size buffer; The AHA-154x/BusLogic thread now uses mutexes; The BusLogic BT-545C is now the BT-545S; Added the BusLogic BT-542BH; The AHA-1542CF now again uses the v2.11 BIOS as the CD booting now works; Applied PCem commit that adds NMI support to the recompiler; Applied PCem commit that adds the IBM XT 286; Applied PCem commits that have to do with sound, including the ES1371; Fixed the NCR5380 output data register; Moved the SLiRP mutex stuff from win.c to the appropriate network files; Added sanity checks to everything in win_thread.c. --- src/Makefile.mingw | 11 +- src/cdrom/cdrom.c | 98 +- src/cpu/386_dynarec.c | 23 + src/cpu/386_dynarec_ops.c | 1 + src/cpu/cpu.c | 7 + src/cpu/cpu.h | 1 + src/cpu/x86_ops_io.h | 24 + src/machine/machine.c | 1 + src/network/net_slirp.c | 23 + src/network/network.c | 2 + src/network/network.h | 1 + src/pc.c | 2 + src/plat.h | 3 - src/rom.c | 7 + src/rom.h | 1 + src/scsi/scsi.c | 37 +- src/scsi/scsi.h | 9 +- src/scsi/scsi_aha154x.c | 2186 +++++------------------- src/scsi/scsi_bios_command.c | 457 ----- src/scsi/scsi_bios_command.h | 47 - src/scsi/scsi_bus.c | 57 +- src/scsi/scsi_buslogic.c | 3134 +++++++++------------------------- src/scsi/scsi_buslogic.h | 3 +- src/scsi/scsi_device.c | 11 +- src/scsi/scsi_device.h | 3 +- src/scsi/scsi_disk.c | 515 +++--- src/scsi/scsi_disk.h | 4 +- src/scsi/scsi_ncr5380.c | 9 +- src/scsi/scsi_x54x.c | 1917 +++++++++++++++++++++ src/scsi/scsi_x54x.h | 513 ++++++ src/sound/midi_fluidsynth.c | 16 +- src/sound/snd_audiopci.c | 1086 ++++++++++++ src/sound/snd_audiopci.h | 1 + src/sound/snd_emu8k.c | 158 +- src/sound/snd_emu8k.h | 460 ++++- src/sound/snd_sb.c | 1086 ++++++++---- src/sound/snd_sb_dsp.c | 364 +++- src/sound/snd_sb_dsp.h | 16 +- src/sound/sound.c | 7 +- src/win/win.c | 18 - src/win/win_thread.c | 32 + 41 files changed, 6919 insertions(+), 5432 deletions(-) delete mode 100644 src/scsi/scsi_bios_command.c delete mode 100644 src/scsi/scsi_bios_command.h create mode 100644 src/scsi/scsi_x54x.c create mode 100644 src/scsi/scsi_x54x.h create mode 100644 src/sound/snd_audiopci.c create mode 100644 src/sound/snd_audiopci.h diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 2ca7cf2cb..e315ad862 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -8,7 +8,7 @@ # # Modified Makefile for Win32 (MinGW32) environment. # -# Version: @(#)Makefile.mingw 1.0.58 2017/10/13 +# Version: @(#)Makefile.mingw 1.0.59 2017/10/14 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -316,8 +316,11 @@ USBOBJ := usb.o endif SCSIOBJ := scsi.o \ - scsi_bus.o scsi_bios_command.o scsi_device.o scsi_disk.o \ - scsi_buslogic.o scsi_aha154x.o scsi_ncr5380.o + scsi_bus.o scsi_device.o \ + scsi_disk.o \ + scsi_x54x.o \ + scsi_buslogic.o scsi_aha154x.o \ + scsi_ncr5380.o NETOBJ := network.o \ net_pcap.o \ @@ -341,7 +344,7 @@ SNDOBJ := sound.o \ snd_speaker.o \ snd_ps1.o snd_pssj.o \ snd_lpt_dac.o snd_lpt_dss.o \ - snd_adlib.o snd_adlibgold.o snd_ad1848.o \ + snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ snd_sb.o snd_sb_dsp.o snd_cms.o snd_dbopl.o \ snd_emu8k.o snd_gus.o snd_opl.o \ snd_mpu401.o \ diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 084b1b14a..9c0279cd9 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.16 2017/10/12 + * Version: @(#)cdrom.c 1.0.17 2017/10/14 * * Author: Miran Grca, * @@ -2279,16 +2279,20 @@ void cdrom_command(uint8_t id, uint8_t *cdb) 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; #if 1 int CdbLength; #endif if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { + BufLen = &SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].BufferLength; cdrom[id].status &= ~ERR_STAT; } else { + BufLen = &blen; cdrom[id].error = 0; } @@ -2355,13 +2359,13 @@ void cdrom_command(uint8_t id, uint8_t *cdb) SCSIPhase = SCSI_PHASE_DATA_IN; if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - if ((SCSI_BufferLength == -1) || (cdb[4] < SCSI_BufferLength)) + if ((*BufLen == -1) || (cdb[4] < *BufLen)) { - SCSI_BufferLength = cdb[4]; + *BufLen = cdb[4]; } - if (SCSI_BufferLength < cdb[4]) + if (*BufLen < cdb[4]) { - cdb[4] = SCSI_BufferLength; + cdb[4] = *BufLen; } } cdrom_request_sense(id, cdbufferb, cdb[4]); @@ -2370,7 +2374,7 @@ void cdrom_command(uint8_t id, uint8_t *cdb) case GPCMD_SET_SPEED: case GPCMD_SET_SPEED_ALT: - SCSIPhase = SCSI_PHASE_DATA_IN; + SCSIPhase = SCSI_PHASE_STATUS; cdrom_command_complete(id); break; @@ -2379,9 +2383,9 @@ void cdrom_command(uint8_t id, uint8_t *cdb) len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } memset(cdbufferb, 0, 8); @@ -2410,9 +2414,9 @@ void cdrom_command(uint8_t id, uint8_t *cdb) } else { - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } } alloc_length = cdbufferb[0]; @@ -2460,9 +2464,9 @@ cdrom_readtoc_fallback: cdbufferb[1] = (len - 2) & 0xff; } - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } cdrom_data_command_finish(id, len, len, len, 0); @@ -2543,9 +2547,9 @@ cdrom_readtoc_fallback: cdrom[id].packet_len = max_len * alloc_length; - if ((SCSI_BufferLength == -1) || (cdrom[id].packet_len < SCSI_BufferLength)) + if ((*BufLen == -1) || (cdrom[id].packet_len < *BufLen)) { - SCSI_BufferLength = cdrom[id].packet_len; + *BufLen = cdrom[id].packet_len; } if (cdrom[id].requested_blocks > 1) @@ -2579,9 +2583,9 @@ cdrom_readtoc_fallback: } else { - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } } } @@ -2607,9 +2611,9 @@ cdrom_readtoc_fallback: len = 8; } - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } cdrom_data_command_finish(id, len, len, len, 0); @@ -2688,9 +2692,9 @@ cdrom_readtoc_fallback: alloc_length = len; } - if ((SCSI_BufferLength == -1) || (alloc_length < SCSI_BufferLength)) + if ((*BufLen == -1) || (alloc_length < *BufLen)) { - SCSI_BufferLength = alloc_length; + *BufLen = alloc_length; } cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", id, cdb[2]); @@ -2711,9 +2715,9 @@ cdrom_readtoc_fallback: len = (cdb[7] << 8) | cdb[8]; } - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } ret = cdrom_mode_select_init(id, cdb[0], len, cdb[1] & 1); @@ -2773,9 +2777,9 @@ cdrom_readtoc_fallback: cdbufferb[2] = ((alloc_length - 4) >> 8) & 0xff; cdbufferb[3] = (alloc_length - 4) & 0xff; - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } cdrom_data_command_finish(id, len, len, alloc_length, 0); @@ -2839,9 +2843,9 @@ cdrom_readtoc_fallback: memcpy(cdbufferb, gesn_event_header, 4); - if ((SCSI_BufferLength == -1) || (used_len < SCSI_BufferLength)) + if ((*BufLen == -1) || (used_len < *BufLen)) { - SCSI_BufferLength = used_len; + *BufLen = used_len; } cdrom_data_command_finish(id, used_len, used_len, used_len, 0); @@ -2883,9 +2887,9 @@ cdrom_readtoc_fallback: len=34; } - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } cdrom_data_command_finish(id, len, len, max_len, 0); @@ -2951,9 +2955,9 @@ cdrom_readtoc_fallback: } } - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } cdrom_data_command_finish(id, len, len, max_len, 0); @@ -3120,9 +3124,9 @@ cdrom_readtoc_fallback: } } - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } cdrom_data_command_finish(id, len, len, max_len, 0); @@ -3140,9 +3144,9 @@ cdrom_readtoc_fallback: } else { - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } } } @@ -3190,9 +3194,9 @@ cdrom_readtoc_fallback: { ret = cdrom_read_dvd_structure(id, format, cdb, cdbufferb); - if ((SCSI_BufferLength == -1) || (alloc_length < SCSI_BufferLength)) + if ((*BufLen == -1) || (alloc_length < *BufLen)) { - SCSI_BufferLength = alloc_length; + *BufLen = alloc_length; } if (ret) @@ -3327,9 +3331,9 @@ atapi_out: cdbufferb[size_idx] = idx - preamble_len; len=idx; - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } cdrom_data_command_finish(id, len, len, max_len, 0); @@ -3396,9 +3400,9 @@ atapi_out: return; } - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } cdrom_data_command_finish(id, len, len, len, 0); @@ -3591,6 +3595,7 @@ int cdrom_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) uint8_t *cdbufferb; uint8_t id = scsi_cdrom_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; cdbufferb = (uint8_t *) cdrom[id].buffer; @@ -3599,14 +3604,15 @@ int cdrom_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) return 0; } - cdrom_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, SCSI_BufferLength); - memcpy(cdbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, SCSI_BufferLength); + 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; } int cdrom_read_from_dma(uint8_t id) { uint8_t *cdbufferb = (uint8_t *) cdrom[id].buffer; + int32_t *BufLen = &SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].BufferLength; int i = 0; int ret = 0; @@ -3629,7 +3635,7 @@ int cdrom_read_from_dma(uint8_t id) if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { - in_data_length = SCSI_BufferLength; + in_data_length = *BufLen; cdrom_log("CD-ROM %i: SCSI Input data length: %i\n", id, in_data_length); } else @@ -3714,6 +3720,7 @@ int cdrom_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) uint8_t *cdbufferb; uint8_t id = scsi_cdrom_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; if (id > CDROM_NUM) { @@ -3722,8 +3729,8 @@ int cdrom_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) cdbufferb = (uint8_t *) cdrom[id].buffer; - cdrom_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, SCSI_BufferLength); - memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, cdbufferb, SCSI_BufferLength); + 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; @@ -3735,6 +3742,7 @@ int cdrom_write_to_dma(uint8_t id) 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); } else diff --git a/src/cpu/386_dynarec.c b/src/cpu/386_dynarec.c index 38feafdda..81781b57f 100644 --- a/src/cpu/386_dynarec.c +++ b/src/cpu/386_dynarec.c @@ -13,6 +13,7 @@ #include "x86_ops.h" #include "x87.h" #include "../mem.h" +#include "../nmi.h" #include "../pic.h" #include "../timer.h" #include "../floppy/floppy.h" @@ -602,6 +603,9 @@ void exec386_dynarec(int cycs) if (trap) CPU_BLOCK_END(); + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + ins++; insc++; @@ -750,6 +754,9 @@ inrecomp=0; if (trap) CPU_BLOCK_END(); + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + if (cpu_state.abrt) { @@ -818,6 +825,9 @@ inrecomp=0; if (trap) CPU_BLOCK_END(); + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + if (cpu_state.abrt) { @@ -884,6 +894,19 @@ inrecomp=0; loadcs(readmemw(0,addr+2)); } } + else if (nmi && nmi_enable && nmi_mask) + { + cpu_state.oldpc = cpu_state.pc; + oldcs = CS; + pclog("NMI\n"); + x86_int(2); + nmi_enable = 0; + if (nmi_auto_clear) + { + nmi_auto_clear = 0; + nmi = 0; + } + } else if ((flags&I_FLAG) && pic_intpending) { temp=picinterrupt(); diff --git a/src/cpu/386_dynarec_ops.c b/src/cpu/386_dynarec_ops.c index e6526bf47..5e7a6692c 100644 --- a/src/cpu/386_dynarec_ops.c +++ b/src/cpu/386_dynarec_ops.c @@ -13,6 +13,7 @@ #include "x87.h" #include "x86_flags.h" #include "../mem.h" +#include "../nmi.h" #include "codegen.h" #include "../pic.h" diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index ae09c637f..5cbdfd642 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -260,6 +260,13 @@ CPU cpus_ibmat[] = {"", -1, 0, 0, 0, 0} }; +CPU cpus_ibmxt286[] = +{ + /*286*/ + {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2}, + {"", -1, 0, 0, 0, 0} +}; + CPU cpus_ps1_m2011[] = { /*286*/ diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 95b3064ba..732edb894 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -130,6 +130,7 @@ extern CPU cpus_pcjr[]; extern CPU cpus_europc[]; extern CPU cpus_pc1512[]; extern CPU cpus_ibmat[]; +extern CPU cpus_ibmxt286[]; extern CPU cpus_ps1_m2011[]; extern CPU cpus_ps2_m30_286[]; extern CPU cpus_acer[]; diff --git a/src/cpu/x86_ops_io.h b/src/cpu/x86_ops_io.h index 7d42299cc..9fa91a215 100644 --- a/src/cpu/x86_ops_io.h +++ b/src/cpu/x86_ops_io.h @@ -5,6 +5,8 @@ static int opIN_AL_imm(uint32_t fetchdat) AL = inb(port); CLOCK_CYCLES(12); PREFETCH_RUN(12, 2, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opIN_AX_imm(uint32_t fetchdat) @@ -15,6 +17,8 @@ static int opIN_AX_imm(uint32_t fetchdat) AX = inw(port); CLOCK_CYCLES(12); PREFETCH_RUN(12, 2, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opIN_EAX_imm(uint32_t fetchdat) @@ -27,6 +31,8 @@ static int opIN_EAX_imm(uint32_t fetchdat) EAX = inl(port); CLOCK_CYCLES(12); PREFETCH_RUN(12, 2, -1, 0,1,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } @@ -39,6 +45,8 @@ static int opOUT_AL_imm(uint32_t fetchdat) PREFETCH_RUN(10, 2, -1, 0,0,1,0, 0); if (port == 0x64) return x86_was_reset; + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opOUT_AX_imm(uint32_t fetchdat) @@ -49,6 +57,8 @@ static int opOUT_AX_imm(uint32_t fetchdat) outw(port, AX); CLOCK_CYCLES(10); PREFETCH_RUN(10, 2, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opOUT_EAX_imm(uint32_t fetchdat) @@ -61,6 +71,8 @@ static int opOUT_EAX_imm(uint32_t fetchdat) outl(port, EAX); CLOCK_CYCLES(10); PREFETCH_RUN(10, 2, -1, 0,0,0,1, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } @@ -70,6 +82,8 @@ static int opIN_AL_DX(uint32_t fetchdat) AL = inb(DX); CLOCK_CYCLES(12); PREFETCH_RUN(12, 1, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opIN_AX_DX(uint32_t fetchdat) @@ -79,6 +93,8 @@ static int opIN_AX_DX(uint32_t fetchdat) AX = inw(DX); CLOCK_CYCLES(12); PREFETCH_RUN(12, 1, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opIN_EAX_DX(uint32_t fetchdat) @@ -90,6 +106,8 @@ static int opIN_EAX_DX(uint32_t fetchdat) EAX = inl(DX); CLOCK_CYCLES(12); PREFETCH_RUN(12, 1, -1, 0,1,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } @@ -99,6 +117,8 @@ static int opOUT_AL_DX(uint32_t fetchdat) outb(DX, AL); CLOCK_CYCLES(11); PREFETCH_RUN(11, 1, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; return x86_was_reset; } static int opOUT_AX_DX(uint32_t fetchdat) @@ -108,6 +128,8 @@ static int opOUT_AX_DX(uint32_t fetchdat) outw(DX, AX); CLOCK_CYCLES(11); PREFETCH_RUN(11, 1, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opOUT_EAX_DX(uint32_t fetchdat) @@ -118,5 +140,7 @@ static int opOUT_EAX_DX(uint32_t fetchdat) check_io_perm(DX + 3); outl(DX, EAX); PREFETCH_RUN(11, 1, -1, 0,0,0,1, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } diff --git a/src/machine/machine.c b/src/machine/machine.c index 2b69c25ee..477cd50ba 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -76,6 +76,7 @@ machine_t machines[] = {"[286 ISA] IBM AT", ROM_IBMAT, "ibmat", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_top_remap_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_PS2 | MACHINE_PS2_HDD, 512,16384, 512, 127, 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_PS2_HDD, 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, 256,15872, 128, 0, machine_at_top_remap_init, NULL }, {"[286 ISA] Samsung SPC-4200P", ROM_SPC4200P, "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512,16384, 128, 127, machine_at_scat_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_PS2_HDD, 1, 16, 1, 63, machine_ps2_model_50_init, NULL }, diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 639772a86..d22071b24 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -32,6 +32,29 @@ static queueADT slirpq; /* SLiRP library handle */ static thread_t *poll_tid; static NETRXCB poll_rx; /* network RX function to call */ static void *poll_arg; /* network RX function arg */ +static void *slirpMutex; + + + +void +network_slirp_mutex_init(void) +{ + slirpMutex = thread_create_mutex(L"86Box.SLiRPMutex"); +} + + +static void +startslirp(void) +{ + thread_wait_mutex(slirpMutex); +} + + +static void +endslirp(void) +{ + thread_release_mutex(slirpMutex); +} /* Instead of calling this and crashing some times diff --git a/src/network/network.c b/src/network/network.c index f6866def0..5b09ebda8 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -89,6 +89,8 @@ network_init(void) if (network_type != NET_TYPE_PCAP) network_pcap_close(); + + network_slirp_mutex_init(); } diff --git a/src/network/network.h b/src/network/network.h index 6ec70e6c5..4c6103468 100644 --- a/src/network/network.h +++ b/src/network/network.h @@ -70,6 +70,7 @@ extern void network_pcap_close(void); extern int network_pcap_test(void); extern void network_pcap_in(uint8_t *, int); +extern void network_slirp_mutex_init(void); extern int network_slirp_setup(uint8_t *, NETRXCB, void *); extern void network_slirp_close(void); extern int network_slirp_test(void); diff --git a/src/pc.c b/src/pc.c index c4247b855..8461b4694 100644 --- a/src/pc.c +++ b/src/pc.c @@ -294,6 +294,7 @@ usage: hdd_init(); network_init(); cdrom_global_init(); + scsi_mutex_init(); /* Load the configuration file. */ config_load(cfg); @@ -491,6 +492,7 @@ pc_reset_hard_close(void) nvr_save(); device_close_all(); + midi_close(); mouse_emu_close(); closeal(); } diff --git a/src/plat.h b/src/plat.h index 83b865a8e..0ab9b6c4c 100644 --- a/src/plat.h +++ b/src/plat.h @@ -106,8 +106,5 @@ extern void delay_ms(uint32_t count); } #endif -extern void startslirp(void); -extern void endslirp(void); - #endif /*EMU_PLAT_H*/ diff --git a/src/rom.c b/src/rom.c index 8851c2f5c..7d48e4820 100644 --- a/src/rom.c +++ b/src/rom.c @@ -311,6 +311,13 @@ rom_load_bios(int rom_id) 0x008000, 32768, 0, rom)) return(1); break; + case ROM_IBMXT286: /* IBM PX-XT 286 */ + if (rom_load_interleaved( + L"roms/machines/ibmxt286/BIOS_5162_21APR86_U34_78X7460_27256.BIN", + L"roms/machines/ibmxt286/BIOS_5162_21APR86_U35_78X7461_27256.BIN", + 0x000000, 65536, 0, rom)) return(1); + break; + case ROM_IBMPCJR: /* IBM PCjr */ if (rom_load_linear( L"roms/machines/ibmpcjr/bios.rom", diff --git a/src/rom.h b/src/rom.h index 46f3ad72d..aa6c33764 100644 --- a/src/rom.h +++ b/src/rom.h @@ -71,6 +71,7 @@ enum { ROM_ENDEAVOR, ROM_REVENGE, ROM_IBMPS1_2011, + ROM_IBMXT286, ROM_DESKPRO_386, ROM_PORTABLE, #if 0 diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index cde338459..fc2b49584 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -23,14 +23,18 @@ #include #include "../86box.h" #include "../ibm.h" +#include "../mem.h" +#include "../rom.h" #include "../timer.h" #include "../device.h" #include "../cdrom/cdrom.h" #include "../disk/hdc.h" +#include "../plat.h" #include "scsi.h" #include "scsi_aha154x.h" #include "scsi_buslogic.h" #include "scsi_ncr5380.h" +#include "scsi_x54x.h" scsi_device_t SCSIDevices[SCSI_ID_MAX][SCSI_LUN_MAX]; @@ -44,6 +48,7 @@ int scsi_card_current = 0; int scsi_card_last = 0; uint32_t SCSI_BufferLength; +void *scsiMutex; typedef struct { @@ -56,14 +61,15 @@ typedef struct { static SCSI_CARD scsi_cards[] = { { "None", "none", NULL, NULL }, - { "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, aha_device_reset }, - { "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, aha_device_reset }, - { "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, aha_device_reset }, - { "[ISA] BusLogic BT-545C", "bt545c", &buslogic_device, BuslogicDeviceReset }, + { "[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 }, - { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, aha_device_reset }, + { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, x54x_device_reset }, { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, BuslogicDeviceReset }, { "", "", NULL, NULL }, }; @@ -118,6 +124,12 @@ int scsi_card_get_from_internal_name(char *s) } +void scsi_mutex_init(void) +{ + scsiMutex = thread_create_mutex(L"86Box.SCSIMutex"); +} + + void scsi_card_init(void) { int i, j; @@ -136,6 +148,7 @@ void scsi_card_init(void) } else { SCSIDevices[i][j].LunType = SCSI_NONE; } + SCSIDevices[i][j].CmdBuffer = NULL; } } @@ -184,3 +197,17 @@ void SCSIReset(uint8_t id, uint8_t lun) SCSIDevices[id][lun].CmdBuffer = NULL; } } + + +void +startscsi(void) +{ + thread_wait_mutex(scsiMutex); +} + + +void +endscsi(void) +{ + thread_release_mutex(scsiMutex); +} diff --git a/src/scsi/scsi.h b/src/scsi/scsi.h index d48ec206c..9abcdf34b 100644 --- a/src/scsi/scsi.h +++ b/src/scsi/scsi.h @@ -259,11 +259,10 @@ extern int prev_status; #define SCSI_PHASE_MESSAGE_OUT (BUS_MSG | BUS_CD) #define SCSI_PHASE_MESSAGE_IN (BUS_MSG | BUS_CD | BUS_IO) -extern uint32_t SCSI_BufferLength; - typedef struct { uint8_t *CmdBuffer; int LunType; + int32_t BufferLength; } scsi_device_t; @@ -294,7 +293,8 @@ extern device_t *scsi_card_getdevice(int card); extern int scsi_card_has_config(int card); extern char *scsi_card_get_internal_name(int card); extern int scsi_card_get_from_internal_name(char *s); -extern void scsi_card_init(); +extern void scsi_mutex_init(void); +extern void scsi_card_init(void); extern void scsi_card_reset(void); extern uint8_t scsi_hard_disks[16][8]; @@ -351,3 +351,6 @@ typedef struct { #define MODE_SELECT_PHASE_PAGE 4 #endif /*EMU_SCSI_H*/ + +extern void startscsi(void); +extern void endscsi(void); diff --git a/src/scsi/scsi_aha154x.c b/src/scsi/scsi_aha154x.c index 663e88718..5e9d7722a 100644 --- a/src/scsi/scsi_aha154x.c +++ b/src/scsi/scsi_aha154x.c @@ -10,9 +10,7 @@ * made by Adaptec, Inc. These controllers were designed for * the ISA bus. * - * NOTE: THIS IS CURRENTLY A MESS, but will be cleaned up as I go. - * - * Version: @(#)scsi_aha154x.c 1.0.28 2017/10/12 + * Version: @(#)scsi_aha154x.c 1.0.29 2017/10/14 * * Authors: Fred N. van Kempen, * Original Buslogic version by SA1988 and Miran Grca. @@ -38,113 +36,8 @@ #include "../device.h" #include "../plat.h" #include "scsi.h" -#include "scsi_bios_command.h" -#include "scsi_device.h" #include "scsi_aha154x.h" - - -#define SCSI_DELAY_TM 1 /* was 50 */ -#define AHA_RESET_DURATION_US UINT64_C(50000) - - -#define ROM_SIZE 16384 /* one ROM is 16K */ -#define NVR_SIZE 32 /* size of NVR */ - - -/* EEPROM map and bit definitions. */ -#define EE0_HOSTID 0x07 /* EE(0) [2:0] */ -#define EE0_ALTFLOP 0x80 /* EE(0) [7] FDC at 370h */ -#define EE1_IRQCH 0x07 /* EE(1) [3:0] */ -#define EE1_DMACH 0x70 /* EE(1) [7:4] */ -#define EE2_RMVOK 0x01 /* EE(2) [0] Support removable disks */ -#define EE2_HABIOS 0x02 /* EE(2) [1] HA Bios Space Reserved */ -#define EE2_INT19 0x04 /* EE(2) [2] HA Bios Controls INT19 */ -#define EE2_DYNSCAN 0x08 /* EE(2) [3] Dynamically scan bus */ -#define EE2_TWODRV 0x10 /* EE(2) [4] Allow more than 2 drives */ -#define EE2_SEEKRET 0x20 /* EE(2) [5] Immediate return on seek */ -#define EE2_EXT1G 0x80 /* EE(2) [7] Extended Translation >1GB */ -#define EE3_SPEED 0x00 /* EE(3) [7:0] DMA Speed */ -#define SPEED_33 0xFF -#define SPEED_50 0x00 -#define SPEED_56 0x04 -#define SPEED_67 0x01 -#define SPEED_80 0x02 -#define SPEED_10 0x03 -#define EE4_FLOPTOK 0x80 /* EE(4) [7] Support Flopticals */ -#define EE6_PARITY 0x01 /* EE(6) [0] parity check enable */ -#define EE6_TERM 0x02 /* EE(6) [1] host term enable */ -#define EE6_RSTBUS 0x04 /* EE(6) [2] reset SCSI bus on boot */ -#define EEE_SYNC 0x01 /* EE(E) [0] Enable Sync Negotiation */ -#define EEE_DISCON 0x02 /* EE(E) [1] Enable Disconnection */ -#define EEE_FAST 0x04 /* EE(E) [2] Enable FAST SCSI */ -#define EEE_START 0x08 /* EE(E) [3] Enable Start Unit */ - - -/* - * Host Adapter I/O ports. - * - * READ Port x+0: STATUS - * WRITE Port x+0: CONTROL - * - * READ Port x+1: DATA - * WRITE Port x+1: COMMAND - * - * READ Port x+2: INTERRUPT STATUS - * WRITE Port x+2: (undefined?) - * - * R/W Port x+3: (undefined) - */ - -/* WRITE CONTROL commands. */ -#define CTRL_HRST 0x80 /* Hard reset */ -#define CTRL_SRST 0x40 /* Soft reset */ -#define CTRL_IRST 0x20 /* interrupt reset */ -#define CTRL_SCRST 0x10 /* SCSI bus reset */ - -/* READ STATUS. */ -#define STAT_STST 0x80 /* self-test in progress */ -#define STAT_DFAIL 0x40 /* internal diagnostic failure */ -#define STAT_INIT 0x20 /* mailbox initialization required */ -#define STAT_IDLE 0x10 /* HBA is idle */ -#define STAT_CDFULL 0x08 /* Command/Data output port is full */ -#define STAT_DFULL 0x04 /* Data input port is full */ -#define STAT_INVCMD 0x01 /* Invalid command */ - -/* READ/WRITE DATA. */ -#define CMD_NOP 0x00 /* No operation */ -#define CMD_MBINIT 0x01 /* mailbox initialization */ -#define CMD_START_SCSI 0x02 /* Start SCSI command */ -#define CMD_BIOSCMD 0x03 /* Execute ROM BIOS command */ -#define CMD_INQUIRY 0x04 /* Adapter inquiry */ -#define CMD_EMBOI 0x05 /* enable Mailbox Out Interrupt */ -#define CMD_SELTIMEOUT 0x06 /* Set SEL timeout */ -#define CMD_BUSON_TIME 0x07 /* set bus-On time */ -#define CMD_BUSOFF_TIME 0x08 /* set bus-off time */ -#define CMD_DMASPEED 0x09 /* set ISA DMA speed */ -#define CMD_RETDEVS 0x0A /* return installed devices */ -#define CMD_RETCONF 0x0B /* return configuration data */ -#define CMD_TARGET 0x0C /* set HBA to target mode */ -#define CMD_RETSETUP 0x0D /* return setup data */ -#define CMD_WRITE_CH2 0x1A /* write channel 2 buffer */ -#define CMD_READ_CH2 0x1B /* read channel 2 buffer */ -#define CMD_ECHO 0x1F /* ECHO command data */ -#define CMD_OPTIONS 0x21 /* set adapter options */ -#define CMD_WRITE_EEPROM 0x22 /* UNDOC: Write EEPROM */ -#define CMD_READ_EEPROM 0x23 /* UNDOC: Read EEPROM */ -#define CMD_SHADOW_RAM 0x24 /* UNDOC: BIOS shadow ram */ -#define CMD_BIOS_MBINIT 0x25 /* UNDOC: BIOS mailbox initialization */ -#define CMD_MEMORY_MAP_1 0x26 /* UNDOC: Memory Mapper */ -#define CMD_MEMORY_MAP_2 0x27 /* UNDOC: Memory Mapper */ -#define CMD_EXTBIOS 0x28 /* UNDOC: return extended BIOS info */ -#define CMD_MBENABLE 0x29 /* set mailbox interface enable */ -#define CMD_BIOS_SCSI 0x82 /* start ROM BIOS SCSI command */ - -/* READ INTERRUPT STATUS. */ -#define INTR_ANY 0x80 /* any interrupt */ -#define INTR_SRCD 0x08 /* SCSI reset detected */ -#define INTR_HACC 0x04 /* HA command complete */ -#define INTR_MBOA 0x02 /* MBO empty */ -#define INTR_MBIF 0x01 /* MBI full */ +#include "scsi_x54x.h" enum { @@ -156,297 +49,34 @@ enum { }; -/* Structure for the INQUIRE_SETUP_INFORMATION reply. */ -#pragma pack(push,1) -typedef struct { - uint8_t uOffset :4, - uTransferPeriod :3, - fSynchronous :1; -} ReplyInquireSetupInformationSynchronousValue; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint8_t fSynchronousInitiationEnabled :1, - fParityCheckingEnabled :1, - uReserved1 :6; - uint8_t uBusTransferRate; - uint8_t uPreemptTimeOnBus; - uint8_t uTimeOffBus; - uint8_t cMailbox; - addr24 MailboxAddress; - ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; - uint8_t uDisconnectPermittedId0To7; - uint8_t uSignature; - uint8_t uCharacterD; - uint8_t uHostBusType; - uint8_t uWideTransferPermittedId0To7; - uint8_t uWideTransfersActiveId0To7; - ReplyInquireSetupInformationSynchronousValue SynchronousValuesId8To15[8]; - uint8_t uDisconnectPermittedId8To15; - uint8_t uReserved2; - uint8_t uWideTransferPermittedId8To15; - uint8_t uWideTransfersActiveId8To15; -} ReplyInquireSetupInformation; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint8_t Count; - addr24 Address; -} MailboxInit_t; -#pragma pack(pop) - -/* - * Mailbox Definitions. - * - * Mailbox Out (MBO) command values. - */ -#define MBO_FREE 0x00 -#define MBO_START 0x01 -#define MBO_ABORT 0x02 - -/* Mailbox In (MBI) status values. */ -#define MBI_FREE 0x00 -#define MBI_SUCCESS 0x01 -#define MBI_ABORT 0x02 -#define MBI_NOT_FOUND 0x03 -#define MBI_ERROR 0x04 - -#pragma pack(push,1) -typedef struct { - uint8_t CmdStatus; - addr24 CCBPointer; -} Mailbox_t; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint32_t CCBPointer; - union { - struct { - uint8_t Reserved[3]; - uint8_t ActionCode; - } out; - struct { - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Reserved; - uint8_t CompletionCode; - } in; - } u; -} Mailbox32_t; -#pragma pack(pop) - -/* - * - * CCB - SCSI Command Control Block - * - * The CCB is a superset of the CDB (Command Descriptor Block) - * and specifies detailed information about a SCSI command. - * - */ -/* Byte 0 Command Control Block Operation Code */ -#define SCSI_INITIATOR_COMMAND 0x00 -#define TARGET_MODE_COMMAND 0x01 -#define SCATTER_GATHER_COMMAND 0x02 -#define SCSI_INITIATOR_COMMAND_RES 0x03 -#define SCATTER_GATHER_COMMAND_RES 0x04 -#define BUS_RESET 0x81 - -/* Byte 1 Address and Direction Control */ -#define CCB_TARGET_ID_SHIFT 0x06 /* CCB Op Code = 00, 02 */ -#define CCB_INITIATOR_ID_SHIFT 0x06 /* CCB Op Code = 01 */ -#define CCB_DATA_XFER_IN 0x01 -#define CCB_DATA_XFER_OUT 0x02 -#define CCB_LUN_MASK 0x07 /* Logical Unit Number */ - -/* Byte 2 SCSI_Command_Length - Length of SCSI CDB - Byte 3 Request Sense Allocation Length */ -#define FOURTEEN_BYTES 0x00 /* Request Sense Buffer size */ -#define NO_AUTO_REQUEST_SENSE 0x01 /* No Request Sense Buffer */ - -/* Bytes 4, 5 and 6 Data Length - Data transfer byte count */ -/* Bytes 7, 8 and 9 Data Pointer - SGD List or Data Buffer */ -/* Bytes 10, 11 and 12 Link Pointer - Next CCB in Linked List */ -/* Byte 13 Command Link ID - TBD (I don't know yet) */ -/* Byte 14 Host Status - Host Adapter status */ -#define CCB_COMPLETE 0x00 /* CCB completed without error */ -#define CCB_LINKED_COMPLETE 0x0A /* Linked command completed */ -#define CCB_LINKED_COMPLETE_INT 0x0B /* Linked complete with intr */ -#define CCB_SELECTION_TIMEOUT 0x11 /* Set SCSI selection timed out */ -#define CCB_DATA_OVER_UNDER_RUN 0x12 -#define CCB_UNEXPECTED_BUS_FREE 0x13 /* Trg dropped SCSI BSY */ -#define CCB_PHASE_SEQUENCE_FAIL 0x14 /* Trg bus phase sequence fail */ -#define CCB_BAD_MBO_COMMAND 0x15 /* MBO command not 0, 1 or 2 */ -#define CCB_INVALID_OP_CODE 0x16 /* CCB invalid operation code */ -#define CCB_BAD_LINKED_LUN 0x17 /* Linked CCB LUN diff from 1st */ -#define CCB_INVALID_DIRECTION 0x18 /* Invalid target direction */ -#define CCB_DUPLICATE_CCB 0x19 /* Duplicate CCB */ -#define CCB_INVALID_CCB 0x1A /* Invalid CCB - bad parameter */ - -/* Byte 15 Target Status - - See scsi.h files for these statuses. - Bytes 16 and 17 Reserved (must be 0) - Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block */ - -#pragma pack(push,1) -typedef struct { - uint8_t Opcode; - uint8_t Reserved1 :3, - ControlByte :2, - TagQueued :1, - QueueTag :2; - uint8_t CdbLength; - uint8_t RequestSenseLength; - uint32_t DataLength; - uint32_t DataPointer; - uint8_t Reserved2[2]; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Id; - uint8_t Lun :5, - LegacyTagEnable :1, - LegacyQueueTag :2; - uint8_t Cdb[12]; - uint8_t Reserved3[6]; - uint32_t SensePointer; -} CCB32; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint8_t Opcode; - uint8_t Lun :3, - ControlByte :2, - Id :3; - uint8_t CdbLength; - uint8_t RequestSenseLength; - addr24 DataLength; - addr24 DataPointer; - addr24 LinkPointer; - uint8_t LinkId; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Reserved[2]; - uint8_t Cdb[12]; -} CCB; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint8_t Opcode; - uint8_t Pad1 :3, - ControlByte :2, - Pad2 :3; - uint8_t CdbLength; - uint8_t RequestSenseLength; - uint8_t Pad3[10]; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Pad4[2]; - uint8_t Cdb[12]; -} CCBC; -#pragma pack(pop) - -#pragma pack(push,1) -typedef union { - CCB32 new; - CCB old; - CCBC common; -} CCBU; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - CCBU CmdBlock; - uint8_t *RequestSenseBuffer; - uint32_t CCBPointer; - int Is24bit; - uint8_t TargetID; - uint8_t LUN; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t MailboxCompletionCode; -} Req_t; -#pragma pack(pop) - -typedef struct { - int8_t type; /* type of device */ - char name[16]; /* name of device */ - - int8_t Irq; - int8_t DmaChannel; - int8_t HostID; - uint32_t Base; - uint8_t pos_regs[8]; /* MCA */ - - uint8_t bid; /* board ID */ - char fwl, fwh; /* firmware info */ - - wchar_t *bios_path; /* path to BIOS image file */ - uint32_t rom_addr; /* address of BIOS ROM */ - uint16_t rom_ioaddr; /* offset in BIOS of I/O addr */ - uint16_t rom_shram; /* index to shared RAM */ - uint16_t rom_shramsz; /* size of shared RAM */ - uint16_t rom_fwhigh; /* offset in BIOS of ver ID */ - rom_t bios; /* BIOS memory descriptor */ - rom_t uppersck; /* BIOS memory descriptor */ - uint8_t *rom1; /* main BIOS image */ - uint8_t *rom2; /* SCSI-Select image */ - - wchar_t *nvr_path; /* path to NVR image file */ - uint8_t *nvr; /* EEPROM buffer */ - - int64_t ResetCB; - - volatile uint8_t /* for multi-threading, keep */ - Status, /* these volatile */ - Interrupt; - - int ExtendedLUNCCBFormat; - Req_t Req; - uint8_t Geometry; - uint8_t Control; - uint8_t Command; - uint8_t CmdBuf[53]; - uint8_t CmdParam; - uint8_t CmdParamLeft; - uint8_t DataBuf[64]; - uint16_t DataReply; - uint16_t DataReplyLeft; - uint32_t MailboxCount; - uint32_t MailboxOutAddr; - uint32_t MailboxOutPosCur; - uint32_t MailboxInAddr; - uint32_t MailboxInPosCur; - int Mbx24bit; - int MailboxOutInterrupts; - int MbiActive[256]; - int PendingInterrupt; - int Lock; - uint8_t shadow_ram[128]; - event_t *evt; - uint8_t MailboxIsBIOS; - uint8_t shram_mode; - uint8_t last_mb; - uint8_t ToRaise; - uint8_t dma_buffer[64]; - uint32_t BIOSMailboxCount; - uint32_t BIOSMailboxOutAddr; - uint32_t BIOSMailboxOutPosCur; -} aha_t; +#define AHA_RESET_DURATION_US UINT64_C(50000) -static uint16_t aha_ports[] = { +#define CMD_WRITE_EEPROM 0x22 /* UNDOC: Write EEPROM */ +#define CMD_READ_EEPROM 0x23 /* UNDOC: Read EEPROM */ +#define CMD_SHADOW_RAM 0x24 /* UNDOC: BIOS shadow ram */ +#define CMD_BIOS_MBINIT 0x25 /* UNDOC: BIOS mailbox initialization */ +#define CMD_MEMORY_MAP_1 0x26 /* UNDOC: Memory Mapper */ +#define CMD_MEMORY_MAP_2 0x27 /* UNDOC: Memory Mapper */ +#define CMD_EXTBIOS 0x28 /* UNDOC: return extended BIOS info */ +#define CMD_MBENABLE 0x29 /* set mailbox interface enable */ +#define CMD_BIOS_SCSI 0x82 /* start ROM BIOS SCSI command */ + + +uint16_t aha_ports[] = { 0x0330, 0x0334, 0x0230, 0x0234, 0x0130, 0x0134, 0x0000, 0x0000 }; -static void aha_cmd_thread(void *priv); -static thread_t *poll_tid; +typedef struct { + uint8_t CustomerSignature[20]; + uint8_t uAutoRetry; + uint8_t uBoardSwitches; + uint8_t uChecksum; + uint8_t uUnknown; + addr24 BIOSMailboxAddress; +} aha_setup_t; #ifdef ENABLE_AHA154X_LOG @@ -483,7 +113,7 @@ aha_log(const char *fmt, ...) static void aha_mem_write(uint32_t addr, uint8_t val, void *priv) { - aha_t *dev = (aha_t *)priv; + x54x_t *dev = (x54x_t *)priv; addr &= 0x3fff; @@ -495,7 +125,7 @@ aha_mem_write(uint32_t addr, uint8_t val, void *priv) static uint8_t aha_mem_read(uint32_t addr, void *priv) { - aha_t *dev = (aha_t *)priv; + x54x_t *dev = (x54x_t *)priv; rom_t *rom = &dev->bios; addr &= 0x3fff; @@ -508,7 +138,7 @@ aha_mem_read(uint32_t addr, void *priv) static uint8_t -aha154x_shram(aha_t *dev, uint8_t cmd) +aha154x_shram(x54x_t *dev, uint8_t cmd) { /* If not supported, give up. */ if (dev->rom_shram == 0x0000) return(0x04); @@ -522,10 +152,24 @@ aha154x_shram(aha_t *dev, uint8_t cmd) } -static uint8_t -aha154x_eeprom(aha_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint8_t *bufp) +static void +aha_eeprom_save(x54x_t *dev) { FILE *f; + + f = nvr_fopen(dev->nvr_path, L"wb"); + if (f) + { + fwrite(dev->nvr, 1, NVR_SIZE, f); + fclose(f); + f = NULL; + } +} + + +static uint8_t +aha154x_eeprom(x54x_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint8_t *bufp) +{ uint8_t r = 0xff; aha_log("%s: EEPROM cmd=%02x, arg=%02x len=%d, off=%02x\n", @@ -541,13 +185,7 @@ aha154x_eeprom(aha_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint8 memcpy(&dev->nvr[off], bufp, len); r = 0; - f = nvr_fopen(dev->nvr_path, L"wb"); - if (f) - { - fwrite(dev->nvr, 1, NVR_SIZE, f); - fclose(f); - f = NULL; - } + aha_eeprom_save(dev); } if (cmd == 0x23) { @@ -562,7 +200,7 @@ aha154x_eeprom(aha_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint8 /* Map either the main or utility (Select) ROM into the memory space. */ static uint8_t -aha154x_mmap(aha_t *dev, uint8_t cmd) +aha154x_mmap(x54x_t *dev, uint8_t cmd) { aha_log("%s: MEMORY cmd=%02x\n", dev->name, cmd); @@ -582,1317 +220,279 @@ aha154x_mmap(aha_t *dev, uint8_t cmd) } -static void -raise_irq(aha_t *dev, int suppress, uint8_t Interrupt) +static uint8_t +aha_get_host_id(void *p) { - if (Interrupt & (INTR_MBIF | INTR_MBOA)) { - if (! (dev->Interrupt & INTR_HACC)) { - dev->Interrupt |= Interrupt; /* Report now. */ - } else { - dev->PendingInterrupt |= Interrupt; /* Report later. */ - } - } else if (Interrupt & INTR_HACC) { - if (dev->Interrupt == 0 || dev->Interrupt == (INTR_ANY | INTR_HACC)) { - aha_log("%s: RaiseInterrupt(): Interrupt=%02X\n", - dev->name, dev->Interrupt); - } - dev->Interrupt |= Interrupt; - } else { - aha_log("%s: RaiseInterrupt(): Invalid interrupt state!\n", dev->name); - } + x54x_t *dev = (x54x_t *)p; - dev->Interrupt |= INTR_ANY; - - if (! suppress) - picint(1 << dev->Irq); -} - - -static void -clear_irq(aha_t *dev) -{ - dev->Interrupt = 0; - aha_log("%s: lowering IRQ %i (stat 0x%02x)\n", - dev->name, dev->Irq, dev->Interrupt); - picintc(1 << dev->Irq); - if (dev->PendingInterrupt) { - aha_log("%s: Raising Interrupt 0x%02X (Pending)\n", - dev->name, dev->Interrupt); - if (dev->MailboxOutInterrupts || !(dev->Interrupt & INTR_MBOA)) { - raise_irq(dev, 0, dev->PendingInterrupt); - } - dev->PendingInterrupt = 0; - } -} - - -static void -aha_reset(aha_t *dev) -{ - if (dev->evt) { - thread_destroy_event(dev->evt); - dev->evt = NULL; - if (poll_tid) { - thread_kill(poll_tid); - poll_tid = NULL; - } - } - - dev->ResetCB = 0LL; - - dev->Status = STAT_IDLE | STAT_INIT; - dev->Geometry = 0x80; - dev->Command = 0xFF; - dev->CmdParam = 0; - dev->CmdParamLeft = 0; - dev->ExtendedLUNCCBFormat = 0; - dev->MailboxCount = 0; - dev->MailboxOutPosCur = 0; - dev->MailboxInPosCur = 0; - dev->MailboxOutInterrupts = 0; - dev->PendingInterrupt = 0; - dev->Lock = 0; - dev->shram_mode = 0; - dev->last_mb = 0; - dev->MailboxIsBIOS = 0; - dev->BIOSMailboxCount = 0; - dev->BIOSMailboxOutPosCur = 0; - - clear_irq(dev); -} - - -static void -aha_reset_ctrl(aha_t *dev, uint8_t Reset) -{ - /* Only if configured.. */ - if (dev->Base == 0x0000) return; - - /* Say hello! */ - pclog("Adaptec %s (IO=0x%04X, IRQ=%d, DMA=%d, BIOS @%05lX) ID=%d\n", - dev->name, dev->Base, dev->Irq, dev->DmaChannel, - dev->rom_addr, dev->HostID); - - aha_reset(dev); - if (Reset) { - dev->Status |= STAT_STST; - dev->Status &= ~STAT_IDLE; - } - dev->ResetCB = AHA_RESET_DURATION_US * TIMER_USEC; -} - - -static void -aha_reset_poll(void *priv) -{ - aha_t *dev = (aha_t *)priv; - - dev->Status &= ~STAT_STST; - dev->Status |= STAT_IDLE; - - dev->ResetCB = 0LL; -} - - -static void -aha_cmd_done(aha_t *dev, int suppress) -{ - dev->DataReply = 0; - dev->Status |= STAT_IDLE; - - if ((dev->Command != CMD_START_SCSI) && (dev->Command != CMD_BIOS_SCSI)) { - dev->Status &= ~STAT_DFULL; - aha_log("%s: Raising IRQ %i\n", dev->name, dev->Irq); - raise_irq(dev, suppress, INTR_HACC); - } - - dev->Command = 0xff; - dev->CmdParam = 0; -} - - -static void -aha_mbi_setup(aha_t *dev, uint32_t CCBPointer, CCBU *CmdBlock, - uint8_t HostStatus, uint8_t TargetStatus, uint8_t mbcc) -{ - Req_t *req = &dev->Req; - - req->CCBPointer = CCBPointer; - memcpy(&(req->CmdBlock), CmdBlock, sizeof(CCB32)); - req->Is24bit = dev->Mbx24bit; - req->HostStatus = HostStatus; - req->TargetStatus = TargetStatus; - req->MailboxCompletionCode = mbcc; - - aha_log("Mailbox in setup\n"); -} - - -static void -aha_ccb(aha_t *dev) -{ - Req_t *req = &dev->Req; - uint32_t CCBPointer = req->CCBPointer; - CCBU *CmdBlock = &(req->CmdBlock); - uint8_t HostStatus = req->HostStatus; - uint8_t TargetStatus = req->TargetStatus; - uint8_t MailboxCompletionCode = req->MailboxCompletionCode; - - aha_log("%02X%02X%02X %02X\n", CmdBlock->common.Pad3[6], CmdBlock->common.Pad3[7], CmdBlock->common.Pad3[8], CmdBlock->common.Pad3[9]); - CmdBlock->common.Pad3[9] = MailboxCompletionCode; - CmdBlock->common.HostStatus = HostStatus; - CmdBlock->common.TargetStatus = TargetStatus; - - /* Rewrite the CCB up to the CDB. */ - aha_log("CCB rewritten to the CDB (pointer %08X)\n", CCBPointer); - aha_log("%02X%02X%02X %02X\n", CmdBlock->common.Pad3[6], CmdBlock->common.Pad3[7], CmdBlock->common.Pad3[8], CmdBlock->common.Pad3[9]); - DMAPageWrite(CCBPointer, (char *)CmdBlock, 18); - - if (dev->MailboxOutInterrupts) - { - dev->ToRaise = INTR_MBOA | INTR_ANY; - } - else - { - dev->ToRaise = 0; - } -} - - -static void -aha_mbi(aha_t *dev) -{ - Req_t *req = &dev->Req; - uint32_t CCBPointer = req->CCBPointer; - CCBU *CmdBlock = &(req->CmdBlock); - uint8_t HostStatus = req->HostStatus; - uint8_t TargetStatus = req->TargetStatus; - uint8_t MailboxCompletionCode = req->MailboxCompletionCode; - Mailbox32_t Mailbox32; - Mailbox_t MailboxIn; - uint32_t Incoming; - - Mailbox32.CCBPointer = CCBPointer; - Mailbox32.u.in.HostStatus = HostStatus; - Mailbox32.u.in.TargetStatus = TargetStatus; - Mailbox32.u.in.CompletionCode = MailboxCompletionCode; - - Incoming = dev->MailboxInAddr + (dev->MailboxInPosCur * (dev->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); - - if (MailboxCompletionCode != MBI_NOT_FOUND) { - CmdBlock->common.HostStatus = HostStatus; - CmdBlock->common.TargetStatus = TargetStatus; - - /* Rewrite the CCB up to the CDB. */ - aha_log("CCB rewritten to the CDB (pointer %08X)\n", CCBPointer); - DMAPageWrite(CCBPointer, (char *)CmdBlock, 18); - } else { - aha_log("Mailbox not found!\n"); - } - - aha_log("Host Status 0x%02X, Target Status 0x%02X\n",HostStatus,TargetStatus); - - if (dev->Mbx24bit) { - MailboxIn.CmdStatus = Mailbox32.u.in.CompletionCode; - U32_TO_ADDR(MailboxIn.CCBPointer, Mailbox32.CCBPointer); - aha_log("Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", MailboxIn.CmdStatus, ADDR_TO_U32(MailboxIn.CCBPointer)); - - DMAPageWrite(Incoming, (char *)&MailboxIn, sizeof(Mailbox_t)); - aha_log("%i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); - } else { - aha_log("Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", Mailbox32.u.in.CompletionCode, Mailbox32.CCBPointer); - - DMAPageWrite(Incoming, (char *)&Mailbox32, sizeof(Mailbox32_t)); - aha_log("%i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); - } - - dev->MailboxInPosCur++; - if (dev->MailboxInPosCur >= dev->MailboxCount) - dev->MailboxInPosCur = 0; - - dev->ToRaise = INTR_MBIF | INTR_ANY; - if (dev->MailboxOutInterrupts) - { - dev->ToRaise |= INTR_MBOA; - } -} - - -static void -aha_rd_sge(int Is24bit, uint32_t SGList, uint32_t Entries, SGE32 *SG) -{ - SGE SGE24[MAX_SG_DESCRIPTORS]; - uint32_t i; - - if (Is24bit) { - DMAPageRead(SGList, (char *)&SGE24, Entries * sizeof(SGE)); - - for (i=0; iCmdBlock.old.DataPointer); - DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); - aha_log("Data length: %08X\n", req->CmdBlock.old.DataLength); - } else { - DataPointer = req->CmdBlock.new.DataPointer; - DataLength = req->CmdBlock.new.DataLength; - } - aha_log("Data Buffer write: length %d, pointer 0x%04X\n", - DataLength, DataPointer); - - if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) { - free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; - } - - if ((req->CmdBlock.common.ControlByte != 0x03) && DataLength) { - if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || - req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { - uint32_t SGRead; - uint32_t ScatterEntry; - SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; - uint32_t SGLeft = DataLength / SGEntryLength; - uint32_t SGAddrCurrent = DataPointer; - uint32_t DataToTransfer = 0; - - do { - SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); - SGLeft -= SGRead; - - aha_rd_sge(Is24bit, SGAddrCurrent, SGRead, SGBuffer); - - for (ScatterEntry=0; ScatterEntry 0); - - aha_log("Data to transfer (S/G) %d\n", DataToTransfer); - - return DataToTransfer; - } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || - req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { - return DataLength; - } else { - return 0; - } - } else { - return 0; - } -} - - -static void -aha_residual_on_error(Req_t *req, int length) -{ - if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || - (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { - /* Should be 0 when scatter/gather? */ - - if (req->Is24bit) { - U32_TO_ADDR(req->CmdBlock.old.DataLength, length); - aha_log("24-bit Residual data length for reading: %d\n", - ADDR_TO_U32(req->CmdBlock.old.DataLength)); - } else { - req->CmdBlock.new.DataLength = length; - aha_log("32-bit Residual data length for reading: %d\n", - req->CmdBlock.new.DataLength); - } - } -} - - -static void -aha_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) -{ - uint32_t sg_buffer_pos = 0; - uint32_t DataPointer, DataLength; - uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - uint32_t Address; - uint32_t Residual; - /* uint32_t CCBPointer = req->CCBPointer; */ - - if (Is24bit) { - DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); - DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); - } else { - DataPointer = req->CmdBlock.new.DataPointer; - DataLength = req->CmdBlock.new.DataLength; - } - aha_log("Data Buffer %s: length %d, pointer 0x%04X\n", - dir ? "write" : "read", SCSI_BufferLength, DataPointer); - - if ((req->CmdBlock.common.ControlByte != 0x03) && DataLength) { - if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || - req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { - uint32_t SGRead; - uint32_t ScatterEntry; - SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; - uint32_t SGLeft = DataLength / SGEntryLength; - uint32_t SGAddrCurrent = DataPointer; - uint32_t DataToTransfer = 0; - - TransferLength -= SCSI_BufferLength; - - /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without - checking its length, so do this procedure for both no read/write commands. */ - if ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || - (req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || - (req->CmdBlock.common.ControlByte == 0x00)) { - SGLeft = DataLength / SGEntryLength; - SGAddrCurrent = DataPointer; - - do { - SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); - SGLeft -= SGRead; - - aha_rd_sge(Is24bit, SGAddrCurrent, - SGRead, SGBuffer); - - for (ScatterEntry=0; ScatterEntryCmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))) - { - DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); - } - else - if (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))) - { - DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); - } - sg_buffer_pos += DataToTransfer; - SCSI_BufferLength -= DataToTransfer; - } - - SGAddrCurrent += SGRead * (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - } while (SGLeft > 0); - } - } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || - req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { - Address = DataPointer; - - SCSI_BufferLength = DataLength; - - if ((DataLength > 0) && (SCSI_BufferLength > 0)) { - if (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))) - { - DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); - } - else - if (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))) - { - DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); - } - } - } - } - - if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || - (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { - /* Should be 0 when scatter/gather? */ - if (TransferLength > 0) { - Residual = TransferLength; - } else { - Residual = 0; - } - - if (req->Is24bit) { - U32_TO_ADDR(req->CmdBlock.old.DataLength, Residual); - aha_log("24-bit Residual data length for reading: %d\n", - ADDR_TO_U32(req->CmdBlock.old.DataLength)); - } else { - req->CmdBlock.new.DataLength = Residual; - aha_log("32-bit Residual data length for reading: %d\n", - req->CmdBlock.new.DataLength); - } - } -} - - -static void -aha_buf_alloc(Req_t *req, int length) -{ - if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) { - free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; - } - - aha_log("Allocating data buffer (%i bytes)\n", length); - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = (uint8_t *) malloc(length); - memset(SCSIDevices[req->TargetID][req->LUN].CmdBuffer, 0, length); -} - - -static void -aha_buf_free(Req_t *req) -{ - if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) { - free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; - } + return dev->nvr[0] & 3; } static uint8_t -ConvertSenseLength(uint8_t RequestSenseLength) +aha_get_irq(void *p) { - aha_log("Unconverted Request Sense length %i\n", RequestSenseLength); + x54x_t *dev = (x54x_t *)p; - if (RequestSenseLength == 0) - RequestSenseLength = 14; - else if (RequestSenseLength == 1) - RequestSenseLength = 0; - - aha_log("Request Sense length %i\n", RequestSenseLength); - - return(RequestSenseLength); -} - - -static void -SenseBufferFree(Req_t *req, int Copy) -{ - uint8_t SenseLength = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); - uint32_t SenseBufferAddress; - uint8_t temp_sense[256]; - - if (SenseLength/* && Copy*/) { - scsi_device_request_sense(req->TargetID, req->LUN, temp_sense, SenseLength); - - /* - * The sense address, in 32-bit mode, is located in the - * Sense Pointer of the CCB, but in 24-bit mode, it is - * located at the end of the Command Descriptor Block. - */ - if (req->Is24bit) { - SenseBufferAddress = req->CCBPointer; - SenseBufferAddress += req->CmdBlock.common.CdbLength + 18; - } else { - SenseBufferAddress = req->CmdBlock.new.SensePointer; - } - - aha_log("Request Sense address: %02X\n", SenseBufferAddress); - - aha_log("SenseBufferFree(): Writing %i bytes at %08X\n", - SenseLength, SenseBufferAddress); - DMAPageWrite(SenseBufferAddress, (char *)temp_sense, SenseLength); - aha_log("Sense data written to buffer: %02X %02X %02X\n", - temp_sense[2], temp_sense[12], temp_sense[13]); - } -} - - -static void -aha_scsi_cmd(aha_t *dev) -{ - Req_t *req = &dev->Req; - uint8_t id, lun; - uint8_t temp_cdb[12]; - uint32_t i; - int target_cdb_len = 12; - int target_data_len; - uint8_t bit24 = !!req->Is24bit; - - id = req->TargetID; - lun = req->LUN; - - target_cdb_len = scsi_device_cdb_length(id, lun); - target_data_len = aha_get_length(req, bit24); - - if (!scsi_device_valid(id, lun)) - fatal("SCSI target on %02i:%02i has disappeared\n", id, lun); - - aha_buf_alloc(req, target_data_len); - - aha_log("SCSI command being executed on ID %i, LUN %i\n", id, lun); - - aha_log("SCSI CDB[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); - for (i=1; iCmdBlock.common.CdbLength; i++) - aha_log("SCSI CDB[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); - - memset(temp_cdb, 0x00, target_cdb_len); - if (req->CmdBlock.common.CdbLength <= target_cdb_len) { - memcpy(temp_cdb, req->CmdBlock.common.Cdb, - req->CmdBlock.common.CdbLength); - } else { - memcpy(temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); - } - - SCSI_BufferLength = target_data_len; - scsi_device_command_phase0(id, lun, req->CmdBlock.common.CdbLength, temp_cdb); - - if (SCSIPhase == SCSI_PHASE_DATA_OUT) - { - aha_buf_dma_transfer(req, bit24, target_data_len, 1); - scsi_device_command_phase1(id, lun); - } - else if (SCSIPhase == SCSI_PHASE_DATA_IN) - { - aha_buf_dma_transfer(req, bit24, target_data_len, 0); - } - else - { - if (target_data_len) { - aha_residual_on_error(req, target_data_len); - } - } - - aha_buf_free(req); - - SenseBufferFree(req, (SCSIStatus != SCSI_STATUS_OK)); - - aha_log("Request complete\n"); - - if (SCSIStatus == SCSI_STATUS_OK) { - aha_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, - CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); - } else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) { - aha_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, - CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); - } - - aha_log("SCSIStatus = %02X\n", SCSIStatus); - - if (temp_cdb[0] == 0x42) { - thread_wait_event(dev->evt, 10); - } -} - - -static void -aha_notify(aha_t *dev) -{ - if (dev->MailboxIsBIOS) - { - aha_ccb(dev); - } - else - { - aha_mbi(dev); - } -} - - -static void -aha_req_setup(aha_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; - int len; - - /* Fetch data from the Command Control Block. */ - DMAPageRead(CCBPointer, (char *)&req->CmdBlock, sizeof(CCB32)); - - req->Is24bit = dev->Mbx24bit; - req->CCBPointer = CCBPointer; - req->TargetID = dev->Mbx24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; - req->LUN = dev->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; - - id = req->TargetID; - lun = req->LUN; - if ((id > max_id) || (lun > 7)) { - aha_mbi_setup(dev, CCBPointer, &req->CmdBlock, - CCB_INVALID_CCB, SCSI_STATUS_OK, MBI_ERROR); - aha_log("%s: Callback: Send incoming mailbox\n", dev->name); - aha_notify(dev); - return; - } - - aha_log("Scanning SCSI Target ID %i\n", id); - - SCSIStatus = SCSI_STATUS_OK; - SCSI_BufferLength = 0; - - if (! scsi_device_present(id, lun)) { - aha_log("SCSI Target ID %i and LUN %i have no device attached\n",id,lun); - len = aha_get_length(req, req->Is24bit); - if (len) { - aha_residual_on_error(req, len); - } - SenseBufferFree(req, 0); - aha_mbi_setup(dev, CCBPointer, &req->CmdBlock, - CCB_SELECTION_TIMEOUT,SCSI_STATUS_OK,MBI_ERROR); - aha_log("%s: Callback: Send incoming mailbox\n", dev->name); - aha_notify(dev); - } else { - aha_log("SCSI Target ID %i and LUN %i detected and working\n", id, lun); - - aha_log("Transfer Control %02X\n", req->CmdBlock.common.ControlByte); - aha_log("CDB Length %i\n", req->CmdBlock.common.CdbLength); - aha_log("CCB Opcode %x\n", req->CmdBlock.common.Opcode); - if (req->CmdBlock.common.ControlByte > 0x03) { - aha_log("Invalid control byte: %02X\n", - req->CmdBlock.common.ControlByte); - } - - aha_log("%s: Callback: Process SCSI request\n", dev->name); - aha_scsi_cmd(dev); - - aha_log("%s: Callback: Send incoming mailbox\n", dev->name); - aha_notify(dev); - } -} - - -static void -aha_req_abort(aha_t *dev, uint32_t CCBPointer) -{ - CCBU CmdBlock; - - /* Fetch data from the Command Control Block. */ - DMAPageRead(CCBPointer, (char *)&CmdBlock, sizeof(CCB32)); - - aha_mbi_setup(dev, CCBPointer, &CmdBlock, - 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); - aha_log("%s: Callback: Send incoming mailbox\n", dev->name); - aha_notify(dev); -} - - -static uint32_t -aha_mbo(aha_t *dev, Mailbox32_t *Mailbox32) -{ - Mailbox_t MailboxOut; - uint32_t Outgoing; - uint32_t ccbp; - uint32_t Addr; - uint32_t Cur; - - if (dev->MailboxIsBIOS) { - Addr = dev->BIOSMailboxOutAddr; - Cur = dev->BIOSMailboxOutPosCur; - } else { - Addr = dev->MailboxOutAddr; - Cur = dev->MailboxOutPosCur; - } - - if (dev->Mbx24bit) { - Outgoing = Addr + (Cur * sizeof(Mailbox_t)); - DMAPageRead(Outgoing, (char *)&MailboxOut, sizeof(Mailbox_t)); - - ccbp = *(uint32_t *) &MailboxOut; - Mailbox32->CCBPointer = (ccbp >> 24) | ((ccbp >> 8) & 0xff00) | ((ccbp << 8) & 0xff0000); - Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; - } else { - Outgoing = Addr + (Cur * sizeof(Mailbox32_t)); - - DMAPageRead(Outgoing, (char *)Mailbox32, sizeof(Mailbox32_t)); - } - - return(Outgoing); -} - - -static void -aha_mbo_adv(aha_t *dev) -{ - if (dev->MailboxIsBIOS) { - if (dev->BIOSMailboxCount > 0) - dev->BIOSMailboxOutPosCur = (dev->BIOSMailboxOutPosCur + 1) % dev->BIOSMailboxCount; - } else { - if (dev->MailboxCount > 0) - dev->MailboxOutPosCur = (dev->MailboxOutPosCur + 1) % dev->MailboxCount; - } + return (dev->nvr[1] & 0x0F) + 9; } static uint8_t -aha_do_mail(aha_t *dev) +aha_get_dma(void *p) { - Mailbox32_t mb32; - uint32_t Outgoing; - uint8_t CmdStatus = MBO_FREE; - uint32_t CodeOffset = 0; - uint32_t Cur = 0; + x54x_t *dev = (x54x_t *)p; - CodeOffset = dev->Mbx24bit ? 0 : 7; + return (dev->nvr[1] & 0xF0) >> 4; +} - if (!dev->MailboxCount && !dev->BIOSMailboxCount) { - aha_log("aha_do_mail(): No Mailboxes of any kind\n"); + +static uint8_t +aha_cmd_is_fast(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + if (dev->Command == CMD_BIOS_SCSI) + return 1; + else return 0; - } +} - if (!dev->MailboxCount) { - aha_log("aha_do_mail(): No Mailboxes\n"); - goto aha_mbo_skip_to_bios; - } - /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ - dev->MailboxIsBIOS = 0; - Cur = dev->MailboxOutPosCur; +static uint8_t +aha_fast_cmds(void *p, uint8_t cmd) +{ + x54x_t *dev = (x54x_t *)p; - do { - /* Fetch mailbox from guest memory. */ - Outgoing = aha_mbo(dev, &mb32); + if (cmd == CMD_BIOS_SCSI) { + x54x_busy_set(); + dev->BIOSMailboxReq++; - /* Check the next mailbox. */ - aha_mbo_adv(dev); - } while ((mb32.u.out.ActionCode != MBO_START) && (mb32.u.out.ActionCode != MBO_ABORT) && (dev->MailboxOutPosCur != Cur)); - - if (mb32.u.out.ActionCode == MBO_START) { - aha_log("Start Mailbox Command\n"); - aha_req_setup(dev, mb32.CCBPointer, &mb32); - } else if (mb32.u.out.ActionCode == MBO_ABORT) { - aha_log("Abort Mailbox Command\n"); - aha_req_abort(dev, mb32.CCBPointer); - } /* else { - aha_log("Invalid action code: %02X\n", mb32.u.out.ActionCode); - } */ - - if ((mb32.u.out.ActionCode == MBO_START) || (mb32.u.out.ActionCode == MBO_ABORT)) { - /* We got the mailbox, mark it as free in the guest. */ - aha_log("aha_do_mail(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); - DMAPageWrite(Outgoing + CodeOffset, (char *)&CmdStatus, 1); - - if (dev->ToRaise) - { - raise_irq(dev, 0, dev->ToRaise); - - while (dev->Interrupt) { - } - } - } - -aha_mbo_skip_to_bios: - if (!dev->BIOSMailboxCount) { - aha_log("aha_do_mail(): No BIOS Mailboxes\n"); + x54x_thread_start(dev); + x54x_busy_clear(); return 1; } - /* Search for a filled BIOS mailbox - stop if we have scanned all mailboxes. */ - dev->MailboxIsBIOS = 1; - Cur = dev->BIOSMailboxOutPosCur; - - do { - /* Fetch mailbox from guest memory. */ - Outgoing = aha_mbo(dev, &mb32); - - /* Check the next mailbox. */ - aha_mbo_adv(dev); - } while ((mb32.u.out.ActionCode != MBO_START) && (dev->BIOSMailboxOutPosCur != Cur)); - - if (mb32.u.out.ActionCode == MBO_START) { - aha_log("Start Mailbox Command\n"); - aha_req_setup(dev, mb32.CCBPointer, &mb32); - } /* else { - aha_log("Invalid action code: %02X\n", mb32.u.out.ActionCode); - } */ - - if (mb32.u.out.ActionCode == MBO_START) { - /* We got the mailbox, mark it as free in the guest. */ - aha_log("aha_do_mail(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); - DMAPageWrite(Outgoing + CodeOffset, (char *)&CmdStatus, 1); - - if (dev->ToRaise) - { - raise_irq(dev, 0, dev->ToRaise); - - while (dev->Interrupt) { - } - } - } - - return 1; -} - - -static void -aha_cmd_done(aha_t *dev, int suppress); - - -static void -aha_cmd_thread(void *priv) -{ - aha_t *dev = (aha_t *)priv; - - /* Create a waitable event. */ - dev->evt = thread_create_event(); - - while (1) - { - if (!aha_do_mail(dev)) { - break; - } - } - - thread_destroy_event(dev->evt); - dev->evt = poll_tid = NULL; - - aha_log("%s: Callback: polling stopped.\n", dev->name); + return 0; } static uint8_t -aha_read(uint16_t port, void *priv) +aha_param_len(void *p) { - aha_t *dev = (aha_t *)priv; - uint8_t ret; + x54x_t *dev = (x54x_t *)p; + + switch (dev->Command) { + case CMD_BIOS_MBINIT: + /* Same as 0x01 for AHA. */ + return sizeof(MailboxInit_t); + break; + + case CMD_SHADOW_RAM: + return 1; + break; + + case CMD_WRITE_EEPROM: + return 3+32; + break; + + case CMD_READ_EEPROM: + return 3; + + case CMD_MBENABLE: + return 2; - switch (port & 3) { - case 0: default: - ret = dev->Status; - break; - - case 1: - ret = dev->DataBuf[dev->DataReply]; - if (dev->DataReplyLeft) { - dev->DataReply++; - dev->DataReplyLeft--; - if (! dev->DataReplyLeft) - aha_cmd_done(dev, 0); - } - break; - - case 2: - ret = dev->Interrupt; - break; - - case 3: - ret = dev->Geometry; - break; + return 0; } - -// #if 0 -#ifndef WALTJE - aha_log("%s: Read Port 0x%02X, Returned Value %02X\n", - dev->name, port, ret); -#endif -// #endif - - return(ret); } -static uint16_t -aha_readw(uint16_t port, void *priv) +static uint8_t +aha_cmds(void *p) { - return(aha_read(port, priv)); -} - - -static void -aha_write(uint16_t port, uint8_t val, void *priv) -{ - ReplyInquireSetupInformation *ReplyISI; - aha_t *dev = (aha_t *)priv; + x54x_t *dev = (x54x_t *)p; MailboxInit_t *mbi; - int i = 0; - uint8_t j = 0; - BIOSCMD *cmd; - uint16_t cyl = 0; - int suppress = 0; - uint32_t addr = 0; - aha_log("%s: Write Port 0x%02X, Value %02X\n", dev->name, port, val); - - switch (port & 3) { - case 0: - if ((val & CTRL_HRST) || (val & CTRL_SRST)) { - uint8_t Reset = (val & CTRL_HRST); - aha_log("Reset completed = %x\n", Reset); - aha_reset_ctrl(dev, Reset); + if (! dev->CmdParamLeft) { + aha_log("Running Operation Code 0x%02X\n", dev->Command); + switch (dev->Command) { + case CMD_WRITE_EEPROM: /* write EEPROM */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = + aha154x_eeprom(dev, + dev->Command, + dev->CmdBuf[0], + dev->CmdBuf[1], + dev->CmdBuf[2], + dev->DataBuf); + if (dev->DataReplyLeft == 0xff) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } break; - } - - if (val & CTRL_IRST) { - clear_irq(dev); - } - break; - case 1: - /* Fast path for the mailbox execution command. */ - if (((val == CMD_START_SCSI) || (val == CMD_BIOS_SCSI)) && - (dev->Command == 0xff)) { - /* If there are no mailboxes configured, don't even try to do anything. */ - if (((val == CMD_START_SCSI) && dev->MailboxCount) || ((val == CMD_BIOS_SCSI) && dev->BIOSMailboxCount)) { - if (! poll_tid) { - aha_log("%s: starting thread.. [%04X:%04X] [%04X]\n", dev->name, CS, cpu_state.pc, DS); - poll_tid = thread_create(aha_cmd_thread, dev); - } - else { - aha_log("%s: continuing thread.. [%04X:%04X] [%04X]\n", dev->name, CS, cpu_state.pc, DS); - } + case CMD_READ_EEPROM: /* read EEPROM */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = + aha154x_eeprom(dev, + dev->Command, + dev->CmdBuf[0], + dev->CmdBuf[1], + dev->CmdBuf[2], + dev->DataBuf); + if (dev->DataReplyLeft == 0xff) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; } - return; - } + break; - if (dev->Command == 0xff) { - dev->Command = val; - dev->CmdParam = 0; - dev->CmdParamLeft = 0; - - dev->Status &= ~(STAT_INVCMD | STAT_IDLE); - aha_log("%s: Operation Code 0x%02X\n", dev->name, val); - switch (dev->Command) { - case CMD_MBINIT: - dev->CmdParamLeft = sizeof(MailboxInit_t); - break; - - case CMD_BIOSCMD: - dev->CmdParamLeft = 10; - break; + case CMD_SHADOW_RAM: /* Shadow RAM */ + /* + * For AHA1542CF, this is the command + * to play with the Shadow RAM. BIOS + * gives us one argument (00,02,03) + * and expects a 0x04 back in the INTR + * register. --FvK + */ + /* dev->Interrupt = aha154x_shram(dev,val); */ + dev->Interrupt = aha154x_shram(dev, dev->CmdBuf[0]); + break; - case CMD_BIOS_MBINIT: - /* Same as 0x01 for AHA. */ - dev->CmdParamLeft = sizeof(MailboxInit_t); - break; + case CMD_BIOS_MBINIT: /* BIOS Mailbox Initialization */ + /* Sent by CF BIOS. */ + x54x_busy_set(); + dev->Mbx24bit = 1; - case CMD_EMBOI: - case CMD_BUSON_TIME: - case CMD_BUSOFF_TIME: - case CMD_DMASPEED: - case CMD_RETSETUP: - case CMD_ECHO: - case CMD_OPTIONS: - case CMD_SHADOW_RAM: - dev->CmdParamLeft = 1; - break; + mbi = (MailboxInit_t *)dev->CmdBuf; - case CMD_SELTIMEOUT: - dev->CmdParamLeft = 4; - break; + dev->BIOSMailboxInit = 1; + dev->BIOSMailboxCount = mbi->Count; + dev->BIOSMailboxOutAddr = ADDR_TO_U32(mbi->Address); - case CMD_WRITE_EEPROM: - dev->CmdParamLeft = 3+32; - break; + aha_log("Initialize BIOS Mailbox: MBO=0x%08lx, %d entries at 0x%08lx\n", + dev->BIOSMailboxOutAddr, + mbi->Count, + ADDR_TO_U32(mbi->Address)); - case CMD_READ_EEPROM: - case CMD_WRITE_CH2: - case CMD_READ_CH2: - dev->CmdParamLeft = 3; - break; + dev->Status &= ~STAT_INIT; + dev->DataReplyLeft = 0; + x54x_busy_clear(); + break; - case CMD_MBENABLE: - dev->CmdParamLeft = 2; - break; - } - } else { - dev->CmdBuf[dev->CmdParam] = val; - dev->CmdParam++; - dev->CmdParamLeft--; - } - - if (! dev->CmdParamLeft) { - aha_log("Running Operation Code 0x%02X\n", dev->Command); - switch (dev->Command) { - case CMD_NOP: /* No Operation */ - dev->DataReplyLeft = 0; - break; + case CMD_MEMORY_MAP_1: /* AHA memory mapper */ + case CMD_MEMORY_MAP_2: /* AHA memory mapper */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = + aha154x_mmap(dev, dev->Command); + break; - case CMD_MBINIT: /* mailbox initialization */ - dev->Mbx24bit = 1; - - mbi = (MailboxInit_t *)dev->CmdBuf; - - dev->MailboxCount = mbi->Count; - dev->MailboxOutAddr = ADDR_TO_U32(mbi->Address); - dev->MailboxInAddr = dev->MailboxOutAddr + (dev->MailboxCount * sizeof(Mailbox_t)); - - aha_log("Initialize Mailbox: MBO=0x%08lx, MBI=0x%08lx, %d entries at 0x%08lx\n", - dev->MailboxOutAddr, - dev->MailboxInAddr, - mbi->Count, - ADDR_TO_U32(mbi->Address)); - - dev->Status &= ~STAT_INIT; - dev->DataReplyLeft = 0; - break; - - case CMD_BIOSCMD: /* execute BIOS */ - cmd = (BIOSCMD *)dev->CmdBuf; - if (dev->type != AHA_1640) { - /* 1640 uses LBA. */ - cyl = ((cmd->u.chs.cyl & 0xff) << 8) | ((cmd->u.chs.cyl >> 8) & 0xff); - cmd->u.chs.cyl = cyl; - } - if (dev->type == AHA_1640) { - /* 1640 uses LBA. */ - aha_log("BIOS LBA=%06lx (%lu)\n", - lba32_blk(cmd), - lba32_blk(cmd)); - } else { - cmd->u.chs.head &= 0xf; - cmd->u.chs.sec &= 0x1f; - aha_log("BIOS CHS=%04X/%02X%02X\n", - cmd->u.chs.cyl, - cmd->u.chs.head, - cmd->u.chs.sec); - } - dev->DataBuf[0] = scsi_bios_command(7, cmd, (dev->type==AHA_1640)?1:0); - aha_log("BIOS Completion/Status Code %x\n", dev->DataBuf[0]); - dev->DataReplyLeft = 1; - break; - - case CMD_INQUIRY: /* Inquiry */ - dev->DataBuf[0] = dev->bid; - dev->DataBuf[1] = (dev->type != AHA_1640) ? 0x30 : 0x42; - dev->DataBuf[2] = dev->fwh; - dev->DataBuf[3] = dev->fwl; - dev->DataReplyLeft = 4; - break; - - case CMD_EMBOI: /* enable MBO Interrupt */ - if (dev->CmdBuf[0] <= 1) { - dev->MailboxOutInterrupts = dev->CmdBuf[0]; - aha_log("Mailbox out interrupts: %s\n", dev->MailboxOutInterrupts ? "ON" : "OFF"); - suppress = 1; - } else { - dev->Status |= STAT_INVCMD; - } - dev->DataReplyLeft = 0; - break; - - case CMD_SELTIMEOUT: /* Selection Time-out */ - dev->DataReplyLeft = 0; - break; - - case CMD_BUSON_TIME: /* bus-on time */ - dev->DataReplyLeft = 0; - aha_log("Bus-on time: %d\n", dev->CmdBuf[0]); - break; - - case CMD_BUSOFF_TIME: /* bus-off time */ - dev->DataReplyLeft = 0; - aha_log("Bus-off time: %d\n", dev->CmdBuf[0]); - break; - - case CMD_DMASPEED: /* DMA Transfer Rate */ - dev->DataReplyLeft = 0; - aha_log("DMA transfer rate: %02X\n", dev->CmdBuf[0]); - break; - - case CMD_RETDEVS: /* return Installed Devices */ - memset(dev->DataBuf, 0x00, 8); - for (i=0; iDataBuf[i] = 0x00; - - /* Skip the HA .. */ - if (i == dev->HostID) continue; - - for (j=0; jDataBuf[i] |= (1<DataReplyLeft = i; - break; - - case CMD_RETCONF: /* return Configuration */ - dev->DataBuf[0] = (1<DmaChannel); - if (dev->Irq >= 8) - dev->DataBuf[1]=(1<<(dev->Irq-9)); - else - dev->DataBuf[1]=(1<Irq); - dev->DataBuf[2] = dev->HostID; - dev->DataReplyLeft = 3; - break; - - case CMD_RETSETUP: /* return Setup */ - { - dev->DataReplyLeft = dev->CmdBuf[0]; - - ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; - memset(ReplyISI, 0x00, sizeof(ReplyInquireSetupInformation)); + case CMD_EXTBIOS: /* Return extended BIOS information */ + dev->DataBuf[0] = 0x08; + dev->DataBuf[1] = dev->Lock; + dev->DataReplyLeft = 2; + break; - ReplyISI->fSynchronousInitiationEnabled = 1; - ReplyISI->fParityCheckingEnabled = 1; - ReplyISI->cMailbox = dev->MailboxCount; - U32_TO_ADDR(ReplyISI->MailboxAddress, dev->MailboxOutAddr); - aha_log("Return Setup Information: %d\n", dev->CmdBuf[0]); + case CMD_MBENABLE: /* Mailbox interface enable Command */ + dev->DataReplyLeft = 0; + if (dev->CmdBuf[1] == dev->Lock) { + if (dev->CmdBuf[0] & 1) { + dev->Lock = 1; + } else { + dev->Lock = 0; } - break; - - case CMD_ECHO: /* ECHO data */ - dev->DataBuf[0] = dev->CmdBuf[0]; - dev->DataReplyLeft = 1; - break; - - case CMD_WRITE_CH2: /* write channel 2 buffer */ - addr = dev->CmdBuf[2] | (dev->CmdBuf[1] << 8) | (dev->CmdBuf[0] << 16); - aha_log("Write channel 2 buffer: %06X\n", addr); - DMAPageRead(addr, (char *)dev->dma_buffer, 64); - dev->DataReplyLeft = 0; - break; - - case CMD_READ_CH2: /* write channel 2 buffer */ - addr = dev->CmdBuf[2] | (dev->CmdBuf[1] << 8) | (dev->CmdBuf[0] << 16); - aha_log("Write channel 2 buffer: %06X\n", addr); - DMAPageWrite(addr, (char *)dev->dma_buffer, 64); - dev->DataReplyLeft = 0; - break; - - case CMD_OPTIONS: /* Set adapter options */ - if (dev->CmdParam == 1) - dev->CmdParamLeft = dev->CmdBuf[0]; - dev->DataReplyLeft = 0; - break; - - case CMD_WRITE_EEPROM: /* write EEPROM */ - /* Sent by CF BIOS. */ - dev->DataReplyLeft = - aha154x_eeprom(dev, - dev->Command, - dev->CmdBuf[0], - dev->CmdBuf[1], - dev->CmdBuf[2], - dev->DataBuf); - if (dev->DataReplyLeft == 0xff) { - dev->DataReplyLeft = 0; - dev->Status |= STAT_INVCMD; - } - break; - - case CMD_READ_EEPROM: /* read EEPROM */ - /* Sent by CF BIOS. */ - dev->DataReplyLeft = - aha154x_eeprom(dev, - dev->Command, - dev->CmdBuf[0], - dev->CmdBuf[1], - dev->CmdBuf[2], - dev->DataBuf); - if (dev->DataReplyLeft == 0xff) { - dev->DataReplyLeft = 0; - dev->Status |= STAT_INVCMD; - } - break; - - case CMD_SHADOW_RAM: /* Shadow RAM */ - /* - * For AHA1542CF, this is the command - * to play with the Shadow RAM. BIOS - * gives us one argument (00,02,03) - * and expects a 0x04 back in the INTR - * register. --FvK - */ - /* dev->Interrupt = aha154x_shram(dev,val); */ - dev->Interrupt = aha154x_shram(dev, dev->CmdBuf[0]); - break; - - case CMD_BIOS_MBINIT: /* BIOS Mailbox Initialization */ - /* Sent by CF BIOS. */ - dev->Mbx24bit = 1; - - mbi = (MailboxInit_t *)dev->CmdBuf; - - dev->BIOSMailboxCount = mbi->Count; - dev->BIOSMailboxOutAddr = ADDR_TO_U32(mbi->Address); - - aha_log("Initialize BIOS Mailbox: MBO=0x%08lx, %d entries at 0x%08lx\n", - dev->BIOSMailboxOutAddr, - mbi->Count, - ADDR_TO_U32(mbi->Address)); - - dev->Status &= ~STAT_INIT; - dev->DataReplyLeft = 0; - break; - - case CMD_MEMORY_MAP_1: /* AHA memory mapper */ - case CMD_MEMORY_MAP_2: /* AHA memory mapper */ - /* Sent by CF BIOS. */ - dev->DataReplyLeft = - aha154x_mmap(dev, dev->Command); - break; - - case CMD_EXTBIOS: /* Return extended BIOS information */ - dev->DataBuf[0] = 0x08; - dev->DataBuf[1] = dev->Lock; - dev->DataReplyLeft = 2; - break; - - case CMD_MBENABLE: /* Mailbox interface enable Command */ - dev->DataReplyLeft = 0; - if (dev->CmdBuf[1] == dev->Lock) { - if (dev->CmdBuf[0] & 1) { - dev->Lock = 1; - } else { - dev->Lock = 0; - } - } - break; - - case 0x2C: /* AHA-1542CP sends this */ - dev->DataBuf[0] = 0x00; - dev->DataReplyLeft = 1; - break; - - case 0x33: /* AHA-1542CP sends this */ - dev->DataBuf[0] = 0x00; - dev->DataBuf[1] = 0x00; - dev->DataBuf[2] = 0x00; - dev->DataBuf[3] = 0x00; - dev->DataReplyLeft = 256; - break; - - default: - dev->DataReplyLeft = 0; - dev->Status |= STAT_INVCMD; - break; } - } - - if (dev->DataReplyLeft) - dev->Status |= STAT_DFULL; - else if (!dev->CmdParamLeft) - aha_cmd_done(dev, suppress); - break; - - case 2: - break; - - case 3: + break; + + case 0x2C: /* AHA-1542CP sends this */ + dev->DataBuf[0] = 0x00; + dev->DataReplyLeft = 1; + break; + + case 0x33: /* AHA-1542CP sends this */ + dev->DataBuf[0] = 0x00; + dev->DataBuf[1] = 0x00; + dev->DataBuf[2] = 0x00; + dev->DataBuf[3] = 0x00; + dev->DataReplyLeft = 256; + break; + + default: + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + } + + return 0; +} + + +static void +aha_setup_data(void *p) +{ + x54x_t *dev = (x54x_t *)p; + ReplyInquireSetupInformation *ReplyISI; + aha_setup_t *aha_setup; + + ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; + aha_setup = (aha_setup_t *)ReplyISI->VendorSpecificData; + + U32_TO_ADDR(aha_setup->BIOSMailboxAddress, dev->BIOSMailboxOutAddr); + aha_setup->uChecksum = 0xA3; + aha_setup->uUnknown = 0xC2; +} + + +static void +aha_reset(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + dev->Lock = 0; + dev->shram_mode = 0; + dev->MailboxIsBIOS = 0; + dev->BIOSMailboxCount = 0; + dev->BIOSMailboxOutPosCur = 0; +} + + +static void +aha_do_bios_mail(x54x_t *dev) +{ + dev->MailboxIsBIOS = 1; + + if (!dev->BIOSMailboxCount) { + aha_log("aha_do_bios_mail(): No BIOS Mailboxes\n"); + return; + } + + /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ + for (dev->BIOSMailboxOutPosCur = 0; dev->BIOSMailboxOutPosCur < dev->BIOSMailboxCount; dev->BIOSMailboxOutPosCur++) { + if (x54x_mbo_process(dev)) break; } } static void -aha_writew(uint16_t Port, uint16_t Val, void *p) +aha_thread(void *p) { - aha_write(Port, Val & 0xFF, p); + x54x_t *dev = (x54x_t *)p; + + if (dev->BIOSMailboxInit && dev->BIOSMailboxReq) + { + x54x_wait_for_poll(); + + aha_do_bios_mail(dev); + } } static uint8_t aha_mca_read(int port, void *priv) { - aha_t *dev = (aha_t *)priv; + x54x_t *dev = (x54x_t *)priv; return(dev->pos_regs[port & 7]); } @@ -1901,7 +501,7 @@ aha_mca_read(int port, void *priv) static void aha_mca_write(int port, uint8_t val, void *priv) { - aha_t *dev = (aha_t *)priv; + x54x_t *dev = (x54x_t *)priv; /* MCA does not write registers below 0x0100. */ if (port < 0x0102) return; @@ -1936,6 +536,9 @@ aha_mca_write(int port, uint8_t val, void *priv) break; } + /* This is always necessary so that the old handler doesn't remain. */ + x54x_io_remove(dev, dev->Base); + /* Save the new IRQ and DMA channel values. */ dev->Irq = (dev->pos_regs[4] & 0x07) + 8; dev->DmaChannel = dev->pos_regs[5] & 0x0f; @@ -1992,20 +595,15 @@ aha_mca_write(int port, uint8_t val, void *priv) * * So, remove current address, if any. */ - io_removehandler(dev->Base, 4, - aha_read, aha_readw, NULL, - aha_write, aha_writew, NULL, dev); mem_mapping_disable(&dev->bios.mapping); /* Initialize the device if fully configured. */ if (dev->pos_regs[2] & 0x01) { /* Card enabled; register (new) I/O handler. */ - io_sethandler(dev->Base, 4, - aha_read, aha_readw, NULL, - aha_write, aha_writew, NULL, dev); + x54x_io_set(dev, dev->Base); /* Reset the device. */ - aha_reset_ctrl(dev, CTRL_HRST); + x54x_reset_ctrl(dev, CTRL_HRST); /* Enable or disable the BIOS ROM. */ if (dev->rom_addr != 0x000000) { @@ -2018,7 +616,7 @@ aha_mca_write(int port, uint8_t val, void *priv) /* Initialize the board's ROM BIOS. */ static void -aha_setbios(aha_t *dev) +aha_setbios(x54x_t *dev) { uint32_t size; uint32_t mask; @@ -2030,7 +628,7 @@ aha_setbios(aha_t *dev) if (dev->bios_path == NULL) return; /* Open the BIOS image file and make sure it exists. */ - pclog("%s: loading BIOS from '%S'\n", dev->name, dev->bios_path); + pclog("%s: loading BIOS from '%ls'\n", dev->name, dev->bios_path); if ((f = rom_fopen(dev->bios_path, L"rb")) == NULL) { pclog("%s: BIOS ROM not found!\n", dev->name); return; @@ -2121,28 +719,11 @@ aha_setbios(aha_t *dev) /* Negation of the DIP switches to satify the checksum. */ dev->bios.rom[dev->rom_ioaddr + 1] = (uint8_t)((i ^ 0xff) + 1); } - - /* - * The more recent BIOS images have their version ID - * encoded in the image, and we can use that info to - * report it back. - * - * Start out with a fake BIOS firmware version. - */ - dev->fwh = '3'; - dev->fwl = '4'; -#if 0 - if (dev->rom_fwhigh != 0x0000) { - /* Read firmware version from the BIOS. */ - dev->fwh = dev->bios.rom[dev->rom_fwhigh] + 0x30; - dev->fwl = dev->bios.rom[dev->rom_fwhigh+1] + 0x30; - } -#endif } static void -aha_initnvr(aha_t *dev) +aha_initnvr(x54x_t *dev) { /* Initialize the on-board EEPROM. */ dev->nvr[0] = dev->HostID; /* SCSI ID 7 */ @@ -2160,7 +741,7 @@ aha_initnvr(aha_t *dev) /* Initialize the board's EEPROM (NVR.) */ static void -aha_setnvr(aha_t *dev) +aha_setnvr(x54x_t *dev) { FILE *f; @@ -2189,13 +770,10 @@ aha_setnvr(aha_t *dev) static void * aha_init(device_t *info) { - aha_t *dev; + x54x_t *dev; - /* Allocate control block and set up basic stuff. */ - dev = malloc(sizeof(aha_t)); - if (dev == NULL) return(dev); - memset(dev, 0x00, sizeof(aha_t)); - dev->type = info->local; + /* Call common initializer. */ + dev = x54x_init(info); /* * Set up the (initial) I/O address, IRQ and DMA info. @@ -2208,11 +786,21 @@ aha_init(device_t *info) dev->Irq = device_get_config_int("irq"); dev->DmaChannel = device_get_config_int("dma"); dev->rom_addr = device_get_config_hex20("bios_addr"); -#if NOT_YET_USED - dev->HostID = device_get_config_int("hostid"); -#else dev->HostID = 7; /* default HA ID */ -#endif + dev->setup_info_len = sizeof(aha_setup_t); + dev->reset_duration = AHA_RESET_DURATION_US; + dev->max_id = 7; + dev->int_geom_writable = 0; + + dev->ven_thread = aha_thread; + dev->ven_cmd_is_fast = aha_cmd_is_fast; + dev->ven_fast_cmds = aha_fast_cmds; + dev->get_ven_param_len = aha_param_len; + dev->ven_cmds = aha_cmds; + dev->get_ven_data = aha_setup_data; + dev->ven_reset = aha_reset; + + strcpy(dev->vendor, "Adaptec"); /* Perform per-board initialization. */ switch(dev->type) { @@ -2229,46 +817,57 @@ aha_init(device_t *info) L"roms/scsi/adaptec/aha1540b320_334.bin"; break; } - dev->bid = 'A'; + dev->fw_rev = "A001"; + /* This is configurable from the configuration for the 154xB, the rest of the controllers read it from the EEPROM. */ + dev->HostID = device_get_config_int("hostid"); break; case AHA_154xC: strcpy(dev->name, "AHA-154xC"); dev->bios_path = L"roms/scsi/adaptec/aha1542c102.bin"; dev->nvr_path = L"aha1542c.nvr"; - dev->bid = 'D'; + dev->fw_rev = "D001"; dev->rom_shram = 0x3F80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ + dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ break; case AHA_154xCF: strcpy(dev->name, "AHA-154xCF"); - dev->bios_path = L"roms/scsi/adaptec/aha1542cf201.bin"; + dev->bios_path = L"roms/scsi/adaptec/aha1542cf211.bin"; dev->nvr_path = L"aha1542cf.nvr"; - dev->bid = 'E'; + dev->fw_rev = "E001"; dev->rom_shram = 0x3F80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ + dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ break; case AHA_154xCP: strcpy(dev->name, "AHA-154xCP"); dev->bios_path = L"roms/scsi/adaptec/aha1542cp102.bin"; dev->nvr_path = L"aha1540cp.nvr"; - dev->bid = 'F'; + dev->fw_rev = "F001"; dev->rom_shram = 0x3F80; /* shadow RAM address base */ dev->rom_shramsz = 128; /* size of shadow RAM */ dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ dev->rom_fwhigh = 0x0055; /* firmware version (hi/lo) */ + dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ break; case AHA_1640: strcpy(dev->name, "AHA-1640"); dev->bios_path = L"roms/scsi/adaptec/aha1640.bin"; - dev->bid = 'B'; + dev->fw_rev = "BB01"; /* Enable MCA. */ dev->pos_regs[0] = 0x1F; /* MCA board ID */ @@ -2283,21 +882,19 @@ aha_init(device_t *info) /* Initialize EEPROM (NVR) if needed. */ aha_setnvr(dev); - timer_add(aha_reset_poll, &dev->ResetCB, &dev->ResetCB, dev); - if (dev->Base != 0) { - /* Register our address space. */ - io_sethandler(dev->Base, 4, - aha_read, aha_readw, NULL, - aha_write, aha_writew, NULL, dev); - /* Initialize the device. */ - aha_reset_ctrl(dev, CTRL_HRST); + x54x_reset_ctrl(dev, CTRL_HRST); - /* Enable the memory. */ - if (dev->rom_addr != 0x000000) { - mem_mapping_enable(&dev->bios.mapping); - mem_mapping_set_addr(&dev->bios.mapping, dev->rom_addr, ROM_SIZE); + if (!(dev->bus & DEVICE_MCA)) { + /* Register our address space. */ + x54x_io_set(dev, dev->Base); + + /* Enable the memory. */ + if (dev->rom_addr != 0x000000) { + mem_mapping_enable(&dev->bios.mapping); + mem_mapping_set_addr(&dev->bios.mapping, dev->rom_addr, ROM_SIZE); + } } } @@ -2305,38 +902,135 @@ aha_init(device_t *info) } -static void -aha_close(void *priv) -{ - aha_t *dev = (aha_t *)priv; - - if (dev) - { - if (dev->evt) { - thread_destroy_event(dev->evt); - dev->evt = NULL; - if (poll_tid) { - thread_kill(poll_tid); - poll_tid = NULL; - } +static device_config_t aha_154xb_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x334, + { + { + "None", 0 + }, + { + "0x330", 0x330 + }, + { + "0x334", 0x334 + }, + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x130", 0x130 + }, + { + "0x134", 0x134 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + "dma", "DMA channel", CONFIG_SELECTION, "", 6, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "" + } + }, + }, + { + "hostid", "Host ID", CONFIG_SELECTION, "", 7, + { + { + "0", 0 + }, + { + "1", 1 + }, + { + "2", 2 + }, + { + "3", 3 + }, + { + "4", 4 + }, + { + "5", 5 + }, + { + "6", 6 + }, + { + "7", 7 + }, + { + "" + } + }, + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "D000H", 0xd0000 + }, + { + "D800H", 0xd8000 + }, + { + "" + } + }, + }, + { + "", "", -1 } - - if (dev->nvr != NULL) - free(dev->nvr); - - free(dev); - dev = NULL; - } -} - - -void -aha_device_reset(void *priv) -{ - aha_t *dev = (aha_t *)priv; - - aha_reset_ctrl(dev, 1); -} +}; static device_config_t aha_154x_config[] = { @@ -2442,16 +1136,16 @@ device_t aha1540b_device = { "Adaptec AHA-1540B", DEVICE_ISA | DEVICE_AT, AHA_154xB, - aha_init, aha_close, NULL, + aha_init, x54x_close, NULL, NULL, NULL, NULL, NULL, - aha_154x_config + aha_154xb_config }; device_t aha1542c_device = { "Adaptec AHA-1542C", DEVICE_ISA | DEVICE_AT, AHA_154xC, - aha_init, aha_close, NULL, + aha_init, x54x_close, NULL, NULL, NULL, NULL, NULL, aha_154x_config }; @@ -2460,7 +1154,7 @@ device_t aha1542cf_device = { "Adaptec AHA-1542CF", DEVICE_ISA | DEVICE_AT, AHA_154xCF, - aha_init, aha_close, NULL, + aha_init, x54x_close, NULL, NULL, NULL, NULL, NULL, aha_154x_config }; @@ -2469,7 +1163,7 @@ device_t aha1640_device = { "Adaptec AHA-1640", DEVICE_MCA, AHA_1640, - aha_init, aha_close, NULL, + aha_init, x54x_close, NULL, NULL, NULL, NULL, NULL, NULL }; diff --git a/src/scsi/scsi_bios_command.c b/src/scsi/scsi_bios_command.c deleted file mode 100644 index 694662389..000000000 --- a/src/scsi/scsi_bios_command.c +++ /dev/null @@ -1,457 +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. - * - * The shared AHA and Buslogic SCSI BIOS command handler. - * - * Version: @(#)scsi_bios_command.c 1.0.4 2017/10/07 - * - * Authors: TheCollector1995, - * Miran Grca, - * Fred N. van Kempen, - * Copyright 2017 Miran Grca. - * Copyright 2017 Fred N. van Kempen. - */ -#include -#include -#include -#include -#include -#include -#include "../ibm.h" -#include "../dma.h" -#include "../device.h" -#include "scsi.h" -#include "scsi_bios_command.h" -#include "scsi_device.h" - - -#if ENABLE_SCSI_BIOS_COMMAND_LOG -int scsi_bios_command_do_log = ENABLE_SCSI_BIOS_COMMAND_LOG; -#endif - - -static void -cmd_log(const char *fmt, ...) -{ -#if ENABLE_SCSI_BIOS_COMMAND_LOG - va_list ap; - - if (scsi_bios_command_do_log) { - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - fflush(stdout); - } -#endif -} - - -static void -target_check(uint8_t id, uint8_t lun) -{ - if (! scsi_device_valid(id, lun)) { - fatal("BIOS INT13 device on %02i:%02i has disappeared\n", id, lun); - } -} - - -static uint8_t -completion_code(uint8_t *sense) -{ - switch (sense[12]) { - case 0x00: - return(0x00); - - case 0x20: - return(0x01); - - case 0x12: - case 0x21: - return(0x02); - - case 0x27: - return(0x03); - - case 0x14: - case 0x16: - return(0x04); - - case 0x10: - case 0x11: - return(0x10); - - case 0x17: - case 0x18: - return(0x11); - - case 0x01: - case 0x03: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - return(0x20); - - case 0x15: - case 0x02: - return(0x40); - - case 0x04: - case 0x28: - case 0x29: - case 0x2a: - return(0xaa); - - default: - break; - }; - - return(0xff); -} - - -uint8_t -scsi_bios_command_08(uint8_t id, uint8_t lun, uint8_t *buffer) -{ - uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0,0,0,0,0,0,0,0,0,0,0 }; - uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; - uint32_t len = 0; - int i, ret, sc; - - ret = scsi_device_read_capacity(id, lun, cdb, rcbuf, &len); - sc = completion_code(scsi_device_sense(id, lun)); - if (ret == 0) return(sc); - - memset(buffer, 0x00, 6); - for (i=0; i<4; i++) - buffer[i] = rcbuf[i]; - for (i=4; i<6; i++) - buffer[i] = rcbuf[(i + 2) ^ 1]; - cmd_log("BIOS Command 0x08: %02X %02X %02X %02X %02X %02X\n", - buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); - - return(0); -} - - -int -scsi_bios_command_15(uint8_t id, uint8_t lun, uint8_t *buffer) -{ - uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0,0,0,0,0,0,0,0,0,0,0 }; - uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; - uint32_t len = 0; - int i, ret, sc; - - ret = scsi_device_read_capacity(id, lun, cdb, rcbuf, &len); - sc = completion_code(scsi_device_sense(id, lun)); - - memset(buffer, 0x00, 6); - for (i=0; i<4; i++) - buffer[i] = (ret == 0) ? 0 : rcbuf[i]; - - scsi_device_type_data(id, lun, &(buffer[4]), &(buffer[5])); - - cmd_log("BIOS Command 0x15: %02X %02X %02X %02X %02X %02X\n", - buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); - - return(sc); -} - - -/* This returns the completion code. */ -uint8_t -scsi_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) -{ - uint8_t cdb[12] = { 0,0,0,0,0,0,0,0,0,0,0,0 }; - scsi_device_t *dev; - uint32_t dma_address; - uint32_t lba; - int sector_len = cmd->secount; - int block_shift; - uint8_t ret; - - if (islba) - lba = lba32_blk(cmd); - else - lba = (cmd->u.chs.cyl << 9) + (cmd->u.chs.head << 5) + cmd->u.chs.sec; - - cmd_log("BIOS Command = 0x%02X\n", cmd->command); - - if ((cmd->id > max_id) || (cmd->lun > 7)) return(0x80); - - /* Get pointer to selected device. */ - dev = &SCSIDevices[cmd->id][cmd->lun]; - SCSI_BufferLength = 0; - - if (! scsi_device_present(cmd->id, cmd->lun)) { - cmd_log("BIOS Target ID %i and LUN %i have no device attached\n", - cmd->id, cmd->lun); - return(0x80); - } - - dma_address = ADDR_TO_U32(cmd->dma_address); - - cmd_log("BIOS Data Buffer write: length %d, pointer 0x%04X\n", - sector_len, dma_address); - - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - block_shift = scsi_device_block_shift(cmd->id, cmd->lun); - - switch(cmd->command) { - case 0x00: /* Reset Disk System, in practice it's a nop */ - return(0); - - case 0x01: /* Read Status of Last Operation */ - target_check(cmd->id, cmd->lun); - - /* - * Assuming 14 bytes because that is the default - * length for SCSI sense, and no command-specific - * indication is given. - */ - SCSI_BufferLength = 14; - dev->CmdBuffer = (uint8_t *)malloc(14); - memset(dev->CmdBuffer, 0x00, 14); - -#if 0 - SCSIStatus = scsi_bios_command_08(cmd->id, cmd->lun, dev->CmdBuffer) ? SCSI_STATUS_OK : SCSI_STATUS_CHECK_CONDITION; -#endif - - if (sector_len > 0) { - cmd_log("BIOS DMA: Reading 14 bytes at %08X\n", - dma_address); - DMAPageWrite(dma_address, - (char *)scsi_device_sense(cmd->id, cmd->lun), 14); - } - - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - return(0); - - case 0x02: /* Read Desired Sectors to Memory */ - target_check(cmd->id, cmd->lun); - - SCSI_BufferLength = sector_len << block_shift; - dev->CmdBuffer = (uint8_t *)malloc(SCSI_BufferLength); - memset(dev->CmdBuffer, 0x00, SCSI_BufferLength); - - cdb[0] = GPCMD_READ_10; - cdb[1] = (cmd->lun & 7) << 5; - cdb[2] = (lba >> 24) & 0xff; - cdb[3] = (lba >> 16) & 0xff; - cdb[4] = (lba >> 8) & 0xff; - cdb[5] = lba & 0xff; - cdb[7] = (sector_len >> 8) & 0xff; - cdb[8] = sector_len & 0xff; -#if 0 - cmd_log("BIOS CMD(READ, %08lx, %d)\n", lba, cmd->secount); -#endif - - scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); - if (sector_len > 0) { - cmd_log("BIOS DMA: Reading %i bytes at %08X\n", - SCSI_BufferLength, dma_address); - DMAPageWrite(dma_address, - (char *)dev->CmdBuffer, SCSI_BufferLength); - } - - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); - - case 0x03: /* Write Desired Sectors from Memory */ - target_check(cmd->id, cmd->lun); - - SCSI_BufferLength = sector_len << block_shift; - dev->CmdBuffer = (uint8_t *)malloc(SCSI_BufferLength); - memset(dev->CmdBuffer, 0x00, SCSI_BufferLength); - - cdb[0] = GPCMD_WRITE_10; - cdb[1] = (cmd->lun & 7) << 5; - cdb[2] = (lba >> 24) & 0xff; - cdb[3] = (lba >> 16) & 0xff; - cdb[4] = (lba >> 8) & 0xff; - cdb[5] = lba & 0xff; - cdb[7] = (sector_len >> 8) & 0xff; - cdb[8] = sector_len & 0xff; -#if 0 - cmd_log("BIOS CMD(WRITE, %08lx, %d)\n", lba, cmd->secount); -#endif - - scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); - - if (sector_len > 0) { - cmd_log("BIOS DMA: Reading %i bytes at %08X\n", - SCSI_BufferLength, dma_address); - DMAPageRead(dma_address, - (char *)dev->CmdBuffer, SCSI_BufferLength); - } - - scsi_device_command_phase1(cmd->id, cmd->lun); - - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); - - case 0x04: /* Verify Desired Sectors */ - target_check(cmd->id, cmd->lun); - - cdb[0] = GPCMD_VERIFY_10; - cdb[1] = (cmd->lun & 7) << 5; - cdb[2] = (lba >> 24) & 0xff; - cdb[3] = (lba >> 16) & 0xff; - cdb[4] = (lba >> 8) & 0xff; - cdb[5] = lba & 0xff; - cdb[7] = (sector_len >> 8) & 0xff; - cdb[8] = sector_len & 0xff; - - scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); - - return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); - - case 0x05: /* Format Track, invalid since SCSI has no tracks */ -//FIXME: add a longer delay here --FvK - return(1); - - case 0x06: /* Identify SCSI Devices, in practice it's a nop */ -//FIXME: add a longer delay here --FvK - return(0); - - case 0x07: /* Format Unit */ - target_check(cmd->id, cmd->lun); - - cdb[0] = GPCMD_FORMAT_UNIT; - cdb[1] = (cmd->lun & 7) << 5; - - scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); - - return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); - - case 0x08: /* Read Drive Parameters */ - target_check(cmd->id, cmd->lun); - - SCSI_BufferLength = 6; - dev->CmdBuffer = (uint8_t *)malloc(SCSI_BufferLength); - memset(dev->CmdBuffer, 0x00, SCSI_BufferLength); - - ret = scsi_bios_command_08(cmd->id, cmd->lun, dev->CmdBuffer); - - cmd_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); - DMAPageWrite(dma_address, - (char *)dev->CmdBuffer, SCSI_BufferLength); - - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - return(ret); - - case 0x09: /* Initialize Drive Pair Characteristics, in practice it's a nop */ -//FIXME: add a longer delay here --FvK - return(0); - - case 0x0c: /* Seek */ - target_check(cmd->id, cmd->lun); - -//FIXME: is this needed? Looks like a copy-paste leftover.. --FvK - SCSI_BufferLength = sector_len << block_shift; - - cdb[0] = GPCMD_SEEK_10; - cdb[1] = (cmd->lun & 7) << 5; - cdb[2] = (lba >> 24) & 0xff; - cdb[3] = (lba >> 16) & 0xff; - cdb[4] = (lba >> 8) & 0xff; - cdb[5] = lba & 0xff; - - scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); - - return((SCSIStatus == SCSI_STATUS_OK) ? 1 : 0); - - case 0x0d: /* Alternate Disk Reset, in practice it's a nop */ -//FIXME: add a longer delay here --FvK - return(0); - - case 0x10: /* Test Drive Ready */ - target_check(cmd->id, cmd->lun); - - cdb[0] = GPCMD_TEST_UNIT_READY; - cdb[1] = (cmd->lun & 7) << 5; - - scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); - - return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); - - case 0x11: /* Recalibrate */ - target_check(cmd->id, cmd->lun); - - cdb[0] = GPCMD_REZERO_UNIT; - cdb[1] = (cmd->lun & 7) << 5; - - scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); - - return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); - - case 0x14: /* Controller Diagnostic */ -//FIXME: add a longer delay here --FvK - return(0); - - case 0x15: /* Read DASD Type */ - target_check(cmd->id, cmd->lun); - - SCSI_BufferLength = 6; - dev->CmdBuffer = (uint8_t *)malloc(SCSI_BufferLength); - memset(dev->CmdBuffer, 0x00, SCSI_BufferLength); - - ret = scsi_bios_command_15(cmd->id, cmd->lun, dev->CmdBuffer); - - cmd_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); - DMAPageWrite(dma_address, - (char *)dev->CmdBuffer, SCSI_BufferLength); - - if (dev->CmdBuffer != NULL) { - free(dev->CmdBuffer); - dev->CmdBuffer = NULL; - } - - return(ret); - - default: - cmd_log("BIOS: Unimplemented command: %02X\n", cmd->command); - return(1); - } - - cmd_log("BIOS Request complete\n"); -} diff --git a/src/scsi/scsi_bios_command.h b/src/scsi/scsi_bios_command.h deleted file mode 100644 index 5e66f035f..000000000 --- a/src/scsi/scsi_bios_command.h +++ /dev/null @@ -1,47 +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. - * - * The shared AHA and Buslogic SCSI BIOS command handler's - * headler. - * - * Version: @(#)scsi_bios_command.h 1.0.0 2017/08/26 - * - * Authors: TheCollector1995, - * Miran Grca, - * Fred N. van Kempen, - * Copyright 2016,2017 Miran Grca. - * Copyright 2017 Fred N. van Kempen. - */ -#pragma pack(push,1) -typedef struct -{ - uint8_t command; - uint8_t lun:3, - reserved:2, - id:3; - union { - struct { - uint16_t cyl; - uint8_t head; - uint8_t sec; - } chs; - struct { - uint8_t lba0; /* MSB */ - uint8_t lba1; - uint8_t lba2; - uint8_t lba3; /* LSB */ - } lba; - } u; - uint8_t secount; - addr24 dma_address; -} BIOSCMD; -#pragma pack(pop) -#define lba32_blk(p) ((uint32_t)(p->u.lba.lba0<<24) | (p->u.lba.lba1<<16) | \ - (p->u.lba.lba2<<8) | p->u.lba.lba3) - -extern uint8_t scsi_bios_command(uint8_t last_id, BIOSCMD *BiosCmd, int8_t islba); diff --git a/src/scsi/scsi_bus.c b/src/scsi/scsi_bus.c index 05145e7fd..4ff706a41 100644 --- a/src/scsi/scsi_bus.c +++ b/src/scsi/scsi_bus.c @@ -38,7 +38,6 @@ uint32_t SCSI_BufferLength; -#define ENABLE_SCSI_BUS_LOG 0 int scsi_bus_do_log = 0; @@ -94,12 +93,8 @@ int scsi_bus_update(scsi_bus_t *bus, int bus_assert) scsi_device_t *dev; uint8_t lun = 0; - dev = &SCSIDevices[bus->dev_id][0]; - if (bus_assert & BUS_ARB) bus->state = STATE_IDLE; - - dev->CmdBuffer = (uint8_t *)bus->buffer; switch (bus->state) { @@ -159,12 +154,26 @@ int scsi_bus_update(scsi_bus_t *bus, int bus_assert) { lun = (bus->command[1] >> 5) & 7; bus->data_pos = 0; - + + dev = &SCSIDevices[bus->dev_id][lun]; + scsi_bus_log("Command 0x%02X\n", bus->command[0]); - SCSI_BufferLength = -1; + dev->BufferLength = -1; + + pclog("(%02X:%02X): Command %02X: Buffer length %i\n", bus->dev_id, lun, bus->command[0], dev->BufferLength); + scsi_device_command_phase0(bus->dev_id, lun, get_cmd_len(bus->command[0]), bus->command); + pclog("SCSI Phase: %02X\n", SCSIPhase); + + if ((SCSIPhase == SCSI_PHASE_DATA_IN) || (SCSIPhase == SCSI_PHASE_DATA_OUT)) + { + pclog("dev->CmdBuffer = %08X\n", dev->CmdBuffer); + dev->CmdBuffer = (uint8_t *) malloc(dev->BufferLength); + pclog("dev->CmdBuffer = %08X\n", dev->CmdBuffer); + } + if (SCSIPhase == SCSI_PHASE_DATA_OUT) { /* Write direction commands have delayed execution - only execute them after the bus has gotten all the data from the host. */ @@ -176,8 +185,11 @@ int scsi_bus_update(scsi_bus_t *bus, int bus_assert) else { /* Other command - execute immediately. */ - scsi_bus_log("Next state is defined by command\n"); bus->new_state = SCSIPhase; + if (SCSIPhase == SCSI_PHASE_DATA_IN) + { + scsi_device_command_phase1(bus->dev_id, lun); + } bus->change_state_delay = 4; } @@ -197,9 +209,15 @@ int scsi_bus_update(scsi_bus_t *bus, int bus_assert) scsi_bus_log("State Data In\n"); /* This seems to be read, so we first execute the command, then we return the bytes to the host. */ - - if (bus->data_pos >= SCSI_BufferLength) + + lun = (bus->command[1] >> 5) & 7; + + dev = &SCSIDevices[bus->dev_id][lun]; + + if (bus->data_pos >= SCSIDevices[bus->dev_id][lun].BufferLength) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; bus->bus_out &= ~BUS_REQ; bus->new_state = SCSI_PHASE_STATUS; bus->change_state_delay = 4; @@ -221,17 +239,22 @@ int scsi_bus_update(scsi_bus_t *bus, int bus_assert) if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) { scsi_bus_log("State Data Out\n"); + + lun = (bus->command[1] >> 5) & 7; + + dev = &SCSIDevices[bus->dev_id][lun]; /* This is write, so first get the data from the host, then execute the last phase of the command. */ dev->CmdBuffer[bus->data_pos++] = BUS_GETDATA(bus_assert); - if (bus->data_pos >= SCSI_BufferLength) + if (bus->data_pos >= SCSIDevices[bus->dev_id][lun].BufferLength) { /* pclog("%04X bytes written (%02X %02X)\n", bus->data_pos, bus->command[0], bus->command[1]); */ scsi_bus_log("Actually executing write command\n"); - lun = (bus->command[1] >> 5) & 7; - bus->bus_out &= ~BUS_REQ; scsi_device_command_phase1(bus->dev_id, lun); + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + bus->bus_out &= ~BUS_REQ; bus->new_state = SCSI_PHASE_STATUS; bus->change_state_delay = 4; bus->new_req_delay = 8; @@ -275,10 +298,7 @@ int scsi_bus_update(scsi_bus_t *bus, int bus_assert) int scsi_bus_read(scsi_bus_t *bus) { scsi_device_t *dev; - - dev = &SCSIDevices[bus->dev_id][0]; - - dev->CmdBuffer = (uint8_t *)bus->buffer; + uint8_t lun = 0; if (bus->clear_req) { @@ -306,6 +326,9 @@ int scsi_bus_read(scsi_bus_t *bus) switch (bus->bus_out & SCSI_PHASE_MESSAGE_IN) { case SCSI_PHASE_DATA_IN: + lun = (bus->command[1] >> 5) & 7; + dev = &SCSIDevices[bus->dev_id][lun]; + scsi_bus_log("Phase data in\n"); bus->state = STATE_DATAIN; val = dev->CmdBuffer[bus->data_pos++]; diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index 027c86f87..bf3b72573 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -7,10 +7,11 @@ * Emulation of BusLogic ISA and PCI SCSI controllers. Boards * supported: * - * 0 - BT-545C ISA; - * 1 - BT-958D PCI (but BT-545C ISA on non-PCI machines) + * 0 - BT-542BH ISA; + * 1 - BT-545S ISA; + * 2 - BT-958D PCI * - * Version: @(#)scsi_buslogic.c 1.0.22 2017/10/11 + * Version: @(#)scsi_buslogic.c 1.0.23 2017/10/14 * * Authors: TheCollector1995, * Miran Grca, @@ -27,7 +28,9 @@ #include #include "../ibm.h" #include "../io.h" +#include "../mca.h" #include "../mem.h" +#include "../mca.h" #include "../rom.h" #include "../nvr.h" #include "../dma.h" @@ -37,69 +40,14 @@ #include "../device.h" #include "../plat.h" #include "scsi.h" -#include "scsi_bios_command.h" -#include "scsi_device.h" #include "scsi_buslogic.h" +#include "scsi_device.h" +#include "scsi_x54x.h" #define BUSLOGIC_RESET_DURATION_US UINT64_C(5000) -/* - * Host Adapter I/O ports. - * - * READ Port x+0: STATUS - * WRITE Port x+0: CONTROL - * - * READ Port x+1: DATA - * WRITE Port x+1: COMMAND - * - * READ Port x+2: INTERRUPT STATUS - * WRITE Port x+2: (undefined?) - * - * R/W Port x+3: (undefined) - */ - -/* WRITE CONTROL commands. */ -#define CTRL_HRST 0x80 /* Hard reset */ -#define CTRL_SRST 0x40 /* Soft reset */ -#define CTRL_IRST 0x20 /* interrupt reset */ -#define CTRL_SCRST 0x10 /* SCSI bus reset */ - -/* READ STATUS. */ -#define STAT_STST 0x80 /* self-test in progress */ -#define STAT_DFAIL 0x40 /* internal diagnostic failure */ -#define STAT_INIT 0x20 /* mailbox initialization required */ -#define STAT_IDLE 0x10 /* HBA is idle */ -#define STAT_CDFULL 0x08 /* Command/Data output port is full */ -#define STAT_DFULL 0x04 /* Data input port is full */ -#define STAT_INVCMD 0x01 /* Invalid command */ - -/* READ/WRITE DATA. */ -#define CMD_NOP 0x00 /* No operation */ -#define CMD_MBINIT 0x01 /* mailbox initialization */ -#define CMD_START_SCSI 0x02 /* Start SCSI command */ -#define CMD_BIOS 0x03 /* Execute ROM BIOS command */ -#define CMD_INQUIRY 0x04 /* Adapter inquiry */ -#define CMD_EMBOI 0x05 /* enable Mailbox Out Interrupt */ -#define CMD_SELTIMEOUT 0x06 /* Set SEL timeout */ -#define CMD_BUSON_TIME 0x07 /* set bus-On time */ -#define CMD_BUSOFF_TIME 0x08 /* set bus-off time */ -#define CMD_DMASPEED 0x09 /* set ISA DMA speed */ -#define CMD_RETDEVS 0x0A /* return installed devices */ -#define CMD_RETCONF 0x0B /* return configuration data */ -#define CMD_TARGET 0x0C /* set HBA to target mode */ -#define CMD_RETSETUP 0x0D /* return setup data */ -#define CMD_ECHO 0x1F /* ECHO command data */ - -/* READ INTERRUPT STATUS. */ -#define INTR_ANY 0x80 /* any interrupt */ -#define INTR_SRCD 0x08 /* SCSI reset detected */ -#define INTR_HACC 0x04 /* HA command complete */ -#define INTR_MBOA 0x02 /* MBO empty */ -#define INTR_MBIF 0x01 /* MBI full */ - - /* * Auto SCSI structure which is located * in host adapter RAM and contains several @@ -180,24 +128,6 @@ typedef union { /** Structure for the INQUIRE_SETUP_INFORMATION reply. */ #pragma pack(push,1) typedef struct { - uint8_t uOffset :4, - uTransferPeriod :3, - fSynchronous :1; -} ReplyInquireSetupInformationSynchronousValue; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint8_t fSynchronousInitiationEnabled :1, - fParityCheckingEnabled :1, - uReserved1 :6; - uint8_t uBusTransferRate; - uint8_t uPreemptTimeOnBus; - uint8_t uTimeOffBus; - uint8_t cMailbox; - addr24 MailboxAddress; - ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; - uint8_t uDisconnectPermittedId0To7; uint8_t uSignature; uint8_t uCharacterD; uint8_t uHostBusType; @@ -208,7 +138,7 @@ typedef struct { uint8_t uReserved2; uint8_t uWideTransferPermittedId8To15; uint8_t uWideTransfersActiveId8To15; -} ReplyInquireSetupInformation; +} buslogic_setup_t; #pragma pack(pop) /* Structure for the INQUIRE_EXTENDED_SETUP_INFORMATION. */ @@ -250,184 +180,6 @@ typedef struct { } BuslogicPCIInformation_t; #pragma pack(pop) -#pragma pack(push,1) -typedef struct { - uint8_t Count; - addr24 Address; -} MailboxInit_t; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint8_t Count; - uint32_t Address; -} MailboxInitExtended_t; -#pragma pack(pop) - - -/* - * Mailbox Definitions. - * - * Mailbox Out (MBO) command values. - */ -#define MBO_FREE 0x00 -#define MBO_START 0x01 -#define MBO_ABORT 0x02 - -/* Mailbox In (MBI) status values. */ -#define MBI_FREE 0x00 -#define MBI_SUCCESS 0x01 -#define MBI_ABORT 0x02 -#define MBI_NOT_FOUND 0x03 -#define MBI_ERROR 0x04 - - -#pragma pack(push,1) -typedef struct { - uint8_t CmdStatus; - addr24 CCBPointer; -} Mailbox_t; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint32_t CCBPointer; - union { - struct { - uint8_t Reserved[3]; - uint8_t ActionCode; - } out; - struct { - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Reserved; - uint8_t CompletionCode; - } in; - } u; -} Mailbox32_t; -#pragma pack(pop) - - -/* - * - * CCB - SCSI Command Control Block - * - * The CCB is a superset of the CDB (Command Descriptor Block) - * and specifies detailed information about a SCSI command. - * - */ -/* Byte 0 Command Control Block Operation Code */ -#define SCSI_INITIATOR_COMMAND 0x00 -#define TARGET_MODE_COMMAND 0x01 -#define SCATTER_GATHER_COMMAND 0x02 -#define SCSI_INITIATOR_COMMAND_RES 0x03 -#define SCATTER_GATHER_COMMAND_RES 0x04 -#define BUS_RESET 0x81 - -/* Byte 1 Address and Direction Control */ -#define CCB_TARGET_ID_SHIFT 0x06 /* CCB Op Code = 00, 02 */ -#define CCB_INITIATOR_ID_SHIFT 0x06 /* CCB Op Code = 01 */ -#define CCB_DATA_XFER_IN 0x01 -#define CCB_DATA_XFER_OUT 0x02 -#define CCB_LUN_MASK 0x07 /* Logical Unit Number */ - -/* Byte 2 SCSI_Command_Length - Length of SCSI CDB - Byte 3 Request Sense Allocation Length */ -#define FOURTEEN_BYTES 0x00 /* Request Sense Buffer size */ -#define NO_AUTO_REQUEST_SENSE 0x01 /* No Request Sense Buffer */ - -/* Bytes 4, 5 and 6 Data Length - Data transfer byte count */ -/* Bytes 7, 8 and 9 Data Pointer - SGD List or Data Buffer */ -/* Bytes 10, 11 and 12 Link Pointer - Next CCB in Linked List */ -/* Byte 13 Command Link ID - TBD (I don't know yet) */ -/* Byte 14 Host Status - Host Adapter status */ -#define CCB_COMPLETE 0x00 /* CCB completed without error */ -#define CCB_LINKED_COMPLETE 0x0A /* Linked command completed */ -#define CCB_LINKED_COMPLETE_INT 0x0B /* Linked complete with intr */ -#define CCB_SELECTION_TIMEOUT 0x11 /* Set SCSI selection timed out */ -#define CCB_DATA_OVER_UNDER_RUN 0x12 -#define CCB_UNEXPECTED_BUS_FREE 0x13 /* Trg dropped SCSI BSY */ -#define CCB_PHASE_SEQUENCE_FAIL 0x14 /* Trg bus phase sequence fail */ -#define CCB_BAD_MBO_COMMAND 0x15 /* MBO command not 0, 1 or 2 */ -#define CCB_INVALID_OP_CODE 0x16 /* CCB invalid operation code */ -#define CCB_BAD_LINKED_LUN 0x17 /* Linked CCB LUN diff from 1st */ -#define CCB_INVALID_DIRECTION 0x18 /* Invalid target direction */ -#define CCB_DUPLICATE_CCB 0x19 /* Duplicate CCB */ -#define CCB_INVALID_CCB 0x1A /* Invalid CCB - bad parameter */ - -/* Byte 15 Target Status - - See scsi.h files for these statuses. - Bytes 16 and 17 Reserved (must be 0) - Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block */ - -#pragma pack(push,1) -typedef struct { - uint8_t Opcode; - uint8_t Reserved1 :3, - ControlByte :2, - TagQueued :1, - QueueTag :2; - uint8_t CdbLength; - uint8_t RequestSenseLength; - uint32_t DataLength; - uint32_t DataPointer; - uint8_t Reserved2[2]; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Id; - uint8_t Lun :5, - LegacyTagEnable :1, - LegacyQueueTag :2; - uint8_t Cdb[12]; - uint8_t Reserved3[6]; - uint32_t SensePointer; -} CCB32; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint8_t Opcode; - uint8_t Lun :3, - ControlByte :2, - Id :3; - uint8_t CdbLength; - uint8_t RequestSenseLength; - addr24 DataLength; - addr24 DataPointer; - addr24 LinkPointer; - uint8_t LinkId; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Reserved[2]; - uint8_t Cdb[12]; -} CCB; -#pragma pack(pop) - -#pragma pack(push,1) -typedef struct { - uint8_t Opcode; - uint8_t Pad1 :3, - ControlByte :2, - Pad2 :3; - uint8_t CdbLength; - uint8_t RequestSenseLength; - uint8_t Pad3[10]; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t Pad4[2]; - uint8_t Cdb[12]; -} CCBC; -#pragma pack(pop) - -#pragma pack(push,1) -typedef union { - CCB32 new; - CCB old; - CCBC common; -} CCBU; -#pragma pack(pop) - #pragma pack(push,1) typedef struct { @@ -454,79 +206,33 @@ typedef struct #pragma pack(push,1) typedef struct { - CCBU CmdBlock; - uint8_t *RequestSenseBuffer; - uint32_t CCBPointer; - int Is24bit; - uint8_t TargetID; - uint8_t LUN; - uint8_t HostStatus; - uint8_t TargetStatus; - uint8_t MailboxCompletionCode; -} Req_t; + uint8_t Count; + uint32_t Address; +} MailboxInitExtended_t; #pragma pack(pop) -#pragma pack(push,1) typedef struct { rom_t bios; - int UseLocalRAM; int ExtendedLUNCCBFormat; + int fAggressiveRoundRobinMode; HALocalRAM LocalRAM; - Req_t Req; - volatile uint8_t /* for multi-threading, keep */ - Status, /* these volatile */ - Interrupt; - uint8_t Geometry; - uint8_t Control; - uint8_t Command; - uint8_t CmdBuf[128]; - uint8_t CmdParam; - uint8_t CmdParamLeft; - uint8_t DataBuf[65536]; - uint16_t DataReply; - uint16_t DataReplyLeft; - uint32_t MailboxCount; - uint32_t MailboxOutAddr; - uint32_t MailboxOutPosCur; - uint32_t MailboxInAddr; - uint32_t MailboxInPosCur; - int Base; int PCIBase; int MMIOBase; - int Irq; - int DmaChannel; - int IrqEnabled; - int Mbx24bit; - int MailboxOutInterrupts; - int MbiActive[256]; - int PendingInterrupt; - int Lock; - mem_mapping_t mmio_mapping; int chip; - int Card; int has_bios; uint32_t bios_addr, bios_size, bios_mask; uint8_t AutoSCSIROM[32768]; uint8_t SCAMData[65536]; - event_t *evt; - int scan_restart; - uint8_t ToRaise; -} Buslogic_t; -#pragma pack(pop) - - -static int64_t BuslogicResetCallback = 0LL; - - -static void BuslogicCommandThread(void *p); -static thread_t *poll_tid; +} buslogic_data_t; enum { + CHIP_BUSLOGIC_ISA_542, CHIP_BUSLOGIC_ISA, CHIP_BUSLOGIC_MCA, + CHIP_BUSLOGIC_EISA, CHIP_BUSLOGIC_VLB, CHIP_BUSLOGIC_PCI }; @@ -536,7 +242,7 @@ int buslogic_do_log = ENABLE_BUSLOGIC_LOG; #endif static void -BuslogicLog(const char *format, ...) +buslogic_log(const char *format, ...) { #ifdef ENABLE_BUSLOGIC_LOG va_list ap; @@ -549,56 +255,23 @@ BuslogicLog(const char *format, ...) } #endif } -#define pclog BuslogicLog - -static void -BuslogicInterrupt(Buslogic_t *bl, int set) -{ - if (bl->chip == CHIP_BUSLOGIC_PCI) - { - if (set) - { - pci_set_irq(bl->Card, PCI_INTA); - } - else - { - pci_clear_irq(bl->Card, PCI_INTA); - } - } - else - { - if (set) - { - if (bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt) - { - picintlevel(1 << bl->Irq); - } - else - { - picint(1 << bl->Irq); - } - /* pclog("Interrupt Set\n"); */ - } - else - { - picintc(1 << bl->Irq); - /* pclog("Interrupt Cleared\n"); */ - } - } -} static wchar_t * -BuslogicGetNVRFileName(Buslogic_t *bl) +BuslogicGetNVRFileName(buslogic_data_t *bl) { switch(bl->chip) { + case CHIP_BUSLOGIC_ISA_542: + return L"bt542bh.nvr"; case CHIP_BUSLOGIC_ISA: - return L"bt545c.nvr"; + return L"bt545s.nvr"; +#ifdef BUSLOGIC_NOT_WORKING case CHIP_BUSLOGIC_MCA: return L"bt640a.nvr"; case CHIP_BUSLOGIC_VLB: return L"bt445s.nvr"; +#endif case CHIP_BUSLOGIC_PCI: return L"bt958d.nvr"; default: @@ -609,131 +282,120 @@ BuslogicGetNVRFileName(Buslogic_t *bl) static void -BuslogicAutoSCSIRamSetDefaults(Buslogic_t *bl, uint8_t safe) +BuslogicAutoSCSIRamSetDefaults(x54x_t *dev, uint8_t safe) { - HALocalRAM *HALR = &bl->LocalRAM; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + HALocalRAM *HALR = &bl->LocalRAM; - memset(&(HALR->structured.autoSCSIData), 0, sizeof(AutoSCSIRam)); + memset(&(HALR->structured.autoSCSIData), 0, sizeof(AutoSCSIRam)); - HALR->structured.autoSCSIData.aInternalSignature[0] = 'F'; - HALR->structured.autoSCSIData.aInternalSignature[1] = 'A'; + HALR->structured.autoSCSIData.aInternalSignature[0] = 'F'; + HALR->structured.autoSCSIData.aInternalSignature[1] = 'A'; - HALR->structured.autoSCSIData.cbInformation = 64; + HALR->structured.autoSCSIData.cbInformation = 64; - HALR->structured.autoSCSIData.aHostAdaptertype[0] = ' '; - switch (bl->chip) - { - case CHIP_BUSLOGIC_ISA: - HALR->structured.autoSCSIData.aHostAdaptertype[1] = '5'; - HALR->structured.autoSCSIData.aHostAdaptertype[2] = '4'; - HALR->structured.autoSCSIData.aHostAdaptertype[3] = '5'; - HALR->structured.autoSCSIData.aHostAdaptertype[4] = 'C'; + HALR->structured.autoSCSIData.aHostAdaptertype[0] = ' '; + HALR->structured.autoSCSIData.aHostAdaptertype[5] = ' '; + switch (bl->chip) { + case CHIP_BUSLOGIC_ISA_542: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "542BH", 5); + break; + case CHIP_BUSLOGIC_ISA: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "545S", 4); + break; +#ifdef BUSLOGIC_NOT_WORKING + case CHIP_BUSLOGIC_VLB: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "445S", 4); + break; + case CHIP_BUSLOGIC_MCA: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "640A", 4); + break; +#endif + case CHIP_BUSLOGIC_PCI: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "958D", 4); + break; + } + + HALR->structured.autoSCSIData.fLevelSensitiveInterrupt = (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; + HALR->structured.autoSCSIData.uSystemRAMAreForBIOS = 6; + + if (bl->chip != CHIP_BUSLOGIC_PCI) { + switch(dev->DmaChannel) { + case 5: + HALR->structured.autoSCSIData.uDMAChannel = 1; break; - case CHIP_BUSLOGIC_VLB: - HALR->structured.autoSCSIData.aHostAdaptertype[1] = '4'; - HALR->structured.autoSCSIData.aHostAdaptertype[2] = '4'; - HALR->structured.autoSCSIData.aHostAdaptertype[3] = '5'; - HALR->structured.autoSCSIData.aHostAdaptertype[4] = 'S'; + case 6: + HALR->structured.autoSCSIData.uDMAChannel = 2; break; - case CHIP_BUSLOGIC_MCA: - HALR->structured.autoSCSIData.aHostAdaptertype[1] = '6'; - HALR->structured.autoSCSIData.aHostAdaptertype[2] = '4'; - HALR->structured.autoSCSIData.aHostAdaptertype[3] = '0'; - HALR->structured.autoSCSIData.aHostAdaptertype[4] = 'A'; + case 7: + HALR->structured.autoSCSIData.uDMAChannel = 3; break; - case CHIP_BUSLOGIC_PCI: - HALR->structured.autoSCSIData.aHostAdaptertype[1] = '9'; - HALR->structured.autoSCSIData.aHostAdaptertype[2] = '5'; - HALR->structured.autoSCSIData.aHostAdaptertype[3] = '8'; - HALR->structured.autoSCSIData.aHostAdaptertype[4] = 'D'; + default: + HALR->structured.autoSCSIData.uDMAChannel = 0; break; } - HALR->structured.autoSCSIData.aHostAdaptertype[5] = ' '; + } + HALR->structured.autoSCSIData.fDMAAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; - HALR->structured.autoSCSIData.fLevelSensitiveInterrupt = (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; - HALR->structured.autoSCSIData.uSystemRAMAreForBIOS = 6; - - if (bl->chip != CHIP_BUSLOGIC_PCI) - { - switch(bl->DmaChannel) - { - case 5: - HALR->structured.autoSCSIData.uDMAChannel = 1; - break; - case 6: - HALR->structured.autoSCSIData.uDMAChannel = 2; - break; - case 7: - HALR->structured.autoSCSIData.uDMAChannel = 3; - break; - default: - HALR->structured.autoSCSIData.uDMAChannel = 0; - break; - } + if (bl->chip != CHIP_BUSLOGIC_PCI) { + switch(dev->Irq) { + case 9: + HALR->structured.autoSCSIData.uIrqChannel = 1; + break; + case 10: + HALR->structured.autoSCSIData.uIrqChannel = 2; + break; + case 11: + HALR->structured.autoSCSIData.uIrqChannel = 3; + break; + case 12: + HALR->structured.autoSCSIData.uIrqChannel = 4; + break; + case 14: + HALR->structured.autoSCSIData.uIrqChannel = 5; + break; + case 15: + HALR->structured.autoSCSIData.uIrqChannel = 6; + break; + default: + HALR->structured.autoSCSIData.uIrqChannel = 0; + break; } - HALR->structured.autoSCSIData.fDMAAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + } + HALR->structured.autoSCSIData.fIrqAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; - if (bl->chip != CHIP_BUSLOGIC_PCI) - { - switch(bl->Irq) - { - case 9: - HALR->structured.autoSCSIData.uIrqChannel = 1; - break; - case 10: - HALR->structured.autoSCSIData.uIrqChannel = 2; - break; - case 11: - HALR->structured.autoSCSIData.uIrqChannel = 3; - break; - case 12: - HALR->structured.autoSCSIData.uIrqChannel = 4; - break; - case 14: - HALR->structured.autoSCSIData.uIrqChannel = 5; - break; - case 15: - HALR->structured.autoSCSIData.uIrqChannel = 6; - break; - default: - HALR->structured.autoSCSIData.uIrqChannel = 0; - break; - } - } - HALR->structured.autoSCSIData.fIrqAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + HALR->structured.autoSCSIData.uDMATransferRate = ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_ISA)) ? 1 : 0; - HALR->structured.autoSCSIData.uDMATransferRate = (bl->chip == CHIP_BUSLOGIC_ISA) ? 1 : 0; + HALR->structured.autoSCSIData.uSCSIId = 7; + HALR->structured.autoSCSIData.uSCSIConfiguration = 0x3F; + HALR->structured.autoSCSIData.uBusOnDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 7; + HALR->structured.autoSCSIData.uBusOffDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 4; + HALR->structured.autoSCSIData.uBIOSConfiguration = (bl->has_bios) ? 0x33 : 0x32; + if (!safe) + HALR->structured.autoSCSIData.uBIOSConfiguration |= 0x04; - HALR->structured.autoSCSIData.uSCSIId = 7; - HALR->structured.autoSCSIData.uSCSIConfiguration = 0x3F; - HALR->structured.autoSCSIData.uBusOnDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 7; - HALR->structured.autoSCSIData.uBusOffDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 4; - HALR->structured.autoSCSIData.uBIOSConfiguration = (bl->has_bios) ? 0x33 : 0x32; - if (!safe) - { - HALR->structured.autoSCSIData.uBIOSConfiguration |= 0x04; - } + HALR->structured.autoSCSIData.u16DeviceEnabledMask = 0xffff; + HALR->structured.autoSCSIData.u16WidePermittedMask = 0xffff; + HALR->structured.autoSCSIData.u16FastPermittedMask = 0xffff; + HALR->structured.autoSCSIData.u16DisconnectPermittedMask = 0xffff; - HALR->structured.autoSCSIData.u16DeviceEnabledMask = 0xffff; - HALR->structured.autoSCSIData.u16WidePermittedMask = 0xffff; - HALR->structured.autoSCSIData.u16FastPermittedMask = 0xffff; - HALR->structured.autoSCSIData.u16DisconnectPermittedMask = 0xffff; + HALR->structured.autoSCSIData.uPCIInterruptPin = PCI_INTA; + HALR->structured.autoSCSIData.fVesaBusSpeedGreaterThan33MHz = 1; - HALR->structured.autoSCSIData.uPCIInterruptPin = PCI_INTA; - HALR->structured.autoSCSIData.fVesaBusSpeedGreaterThan33MHz = 1; + HALR->structured.autoSCSIData.uAutoSCSIMaximumLUN = 7; - HALR->structured.autoSCSIData.uAutoSCSIMaximumLUN = 7; - - HALR->structured.autoSCSIData.fForceBusDeviceScanningOrder = 1; - HALR->structured.autoSCSIData.fInt13Extension = safe ? 0 : 1; - HALR->structured.autoSCSIData.fCDROMBoot = safe ? 0 : 1; - HALR->structured.autoSCSIData.fMultiBoot = safe ? 0 : 1; - HALR->structured.autoSCSIData.fAggressiveRoundRobinMode = safe ? 0 : 1; /* 1 = aggressive, 0 = strict */ + HALR->structured.autoSCSIData.fForceBusDeviceScanningOrder = 1; + HALR->structured.autoSCSIData.fInt13Extension = safe ? 0 : 1; + HALR->structured.autoSCSIData.fCDROMBoot = safe ? 0 : 1; + HALR->structured.autoSCSIData.fMultiBoot = safe ? 0 : 1; + HALR->structured.autoSCSIData.fAggressiveRoundRobinMode = safe ? 0 : 1; /* 1 = aggressive, 0 = strict */ } -static void BuslogicInitializeAutoSCSIRam(Buslogic_t *bl) +static void +BuslogicInitializeAutoSCSIRam(x54x_t *dev) { + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; FILE *f; f = nvr_fopen(BuslogicGetNVRFileName(bl), L"rb"); @@ -745,756 +407,122 @@ static void BuslogicInitializeAutoSCSIRam(Buslogic_t *bl) } else { - BuslogicAutoSCSIRamSetDefaults(bl, 0); + BuslogicAutoSCSIRamSetDefaults(dev, 0); } } static void -BuslogicRaiseInterrupt(Buslogic_t *bl, int suppress, uint8_t Interrupt) +buslogic_cmd_phase1(void *p) { - if (Interrupt & (INTR_MBIF | INTR_MBOA)) - { - if (!(bl->Interrupt & INTR_HACC)) - { - bl->Interrupt |= Interrupt; /* Report now. */ - } - else - { - bl->PendingInterrupt |= Interrupt; /* Report later. */ - } - } - else if (Interrupt & INTR_HACC) - { - if (bl->Interrupt == 0 || bl->Interrupt == (INTR_ANY | INTR_HACC)) - { - pclog("BuslogicRaiseInterrupt(): Interrupt=%02X\n", bl->Interrupt); - } - bl->Interrupt |= Interrupt; - } - else - { - pclog("BuslogicRaiseInterrupt(): Invalid interrupt state!\n"); - } + x54x_t *dev = (x54x_t *)p; - bl->Interrupt |= INTR_ANY; - - if (bl->IrqEnabled && !suppress) - { - BuslogicInterrupt(bl, 1); - } -} - - -static void -BuslogicClearInterrupt(Buslogic_t *bl) -{ - /* pclog("Buslogic: Lowering Interrupt 0x%02X\n", bl->Interrupt); */ - bl->Interrupt = 0; - /* pclog("Lowering IRQ %i\n", bl->Irq); */ - BuslogicInterrupt(bl, 0); - if (bl->PendingInterrupt) { - /* pclog("Buslogic: Raising Interrupt 0x%02X (Pending)\n", bl->PendingInterrupt); */ - if (bl->MailboxOutInterrupts || !(bl->Interrupt & INTR_MBOA)) { - BuslogicRaiseInterrupt(bl, 0, bl->PendingInterrupt); - } - bl->PendingInterrupt = 0; - } -} - -static void -BuslogicReset(Buslogic_t *bl) -{ - /* pclog("BuslogicReset()\n"); */ - if (bl->evt) - { - thread_destroy_event(bl->evt); - bl->evt = NULL; - if (poll_tid) - { - thread_kill(poll_tid); - poll_tid = NULL; - } + if ((dev->CmdParam == 2) && (dev->Command == 0x90)) { + dev->CmdParamLeft = dev->CmdBuf[1]; } - BuslogicResetCallback = 0LL; - bl->scan_restart = 0; - - bl->Geometry = 0x80; - bl->Status = STAT_IDLE | STAT_INIT; - bl->Command = 0xFF; - bl->CmdParam = 0; - bl->CmdParamLeft = 0; - bl->IrqEnabled = 1; - bl->ExtendedLUNCCBFormat = 0; - bl->MailboxCount = 0; - bl->MailboxOutPosCur = 0; - bl->MailboxInPosCur = 0; - bl->MailboxOutInterrupts = 0; - bl->PendingInterrupt = 0; - bl->Lock = 0; - - BuslogicClearInterrupt(bl); -} - - -static void -BuslogicResetControl(Buslogic_t *bl, uint8_t Reset) -{ - /* pclog("BuslogicResetControl()\n"); */ - BuslogicReset(bl); - if (Reset) { - bl->Status |= STAT_STST; - bl->Status &= ~STAT_IDLE; - } - BuslogicResetCallback = BUSLOGIC_RESET_DURATION_US * TIMER_USEC; -} - - -static void -BuslogicCommandComplete(Buslogic_t *bl, int suppress) -{ - pclog("BuslogicCommandComplete()\n"); - bl->DataReply = 0; - bl->Status |= STAT_IDLE; - - if (bl->Command != 0x02) - { - bl->Status &= ~STAT_DFULL; - - pclog("BuslogicCommandComplete(): Raising IRQ %i\n", bl->Irq); - BuslogicRaiseInterrupt(bl, suppress, INTR_HACC); - } - - bl->Command = 0xFF; - bl->CmdParam = 0; -} - - -static void -BuslogicMailboxInSetup(Buslogic_t *bl, uint32_t CCBPointer, CCBU *CmdBlock, - uint8_t HostStatus, uint8_t TargetStatus, - uint8_t MailboxCompletionCode) -{ - Req_t *req = &bl->Req; - - req->CCBPointer = CCBPointer; - memcpy(&(req->CmdBlock), CmdBlock, sizeof(CCB32)); - req->Is24bit = bl->Mbx24bit; - req->HostStatus = HostStatus; - req->TargetStatus = TargetStatus; - req->MailboxCompletionCode = MailboxCompletionCode; - - BuslogicLog("BuslogicMailboxInSetup(): Request set up\n"); -} - - -static void -BuslogicMailboxIn(Buslogic_t *bl) -{ - Req_t *req = &bl->Req; - uint32_t CCBPointer = req->CCBPointer; - CCBU *CmdBlock = &(req->CmdBlock); - uint8_t HostStatus = req->HostStatus; - uint8_t TargetStatus = req->TargetStatus; - uint8_t MailboxCompletionCode = req->MailboxCompletionCode; - Mailbox32_t Mailbox32; - Mailbox_t MailboxIn; - uint32_t Incoming; - - Mailbox32.CCBPointer = CCBPointer; - Mailbox32.u.in.HostStatus = HostStatus; - Mailbox32.u.in.TargetStatus = TargetStatus; - Mailbox32.u.in.CompletionCode = MailboxCompletionCode; - - Incoming = bl->MailboxInAddr + (bl->MailboxInPosCur * (bl->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); - - if (MailboxCompletionCode != MBI_NOT_FOUND) { - CmdBlock->common.HostStatus = HostStatus; - CmdBlock->common.TargetStatus = TargetStatus; - - /* Rewrite the CCB up to the CDB. */ - BuslogicLog("BuslogicMailboxIn(): CCB rewritten to the CDB (pointer %08X)\n", CCBPointer); - DMAPageWrite(CCBPointer, (char *)CmdBlock, 18); - } else { - BuslogicLog("BuslogicMailboxIn(): Mailbox not found!\n"); + if ((dev->CmdParam == 10) && ((dev->Command == 0x97) || (dev->Command == 0xA7))) { + dev->CmdParamLeft = dev->CmdBuf[6]; + dev->CmdParamLeft <<= 8; + dev->CmdParamLeft |= dev->CmdBuf[7]; + dev->CmdParamLeft <<= 8; + dev->CmdParamLeft |= dev->CmdBuf[8]; } - BuslogicLog("BuslogicMailboxIn(): Host Status 0x%02X, Target Status 0x%02X\n",HostStatus,TargetStatus); - - if (bl->Mbx24bit) { - MailboxIn.CmdStatus = Mailbox32.u.in.CompletionCode; - U32_TO_ADDR(MailboxIn.CCBPointer, Mailbox32.CCBPointer); - BuslogicLog("BuslogicMailboxIn(): Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", MailboxIn.CmdStatus, ADDR_TO_U32(MailboxIn.CCBPointer)); - - DMAPageWrite(Incoming, (char *)&MailboxIn, sizeof(Mailbox_t)); - BuslogicLog("BuslogicMailboxIn(): %i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); - } else { - BuslogicLog("BuslogicMailboxIn(): Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", Mailbox32.u.in.CompletionCode, Mailbox32.CCBPointer); - - DMAPageWrite(Incoming, (char *)&Mailbox32, sizeof(Mailbox32_t)); - BuslogicLog("BuslogicMailboxIn(): %i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); - } - - bl->MailboxInPosCur++; - if (bl->MailboxInPosCur >= bl->MailboxCount) - bl->MailboxInPosCur = 0; - - bl->ToRaise = INTR_MBIF | INTR_ANY; - if (bl->MailboxOutInterrupts) - { - bl->ToRaise |= INTR_MBOA; - } -} - - -static void -BuslogicReadSGEntries(int Is24bit, uint32_t SGList, uint32_t Entries, SGE32 *SG) -{ - uint32_t i; - SGE SGE24[MAX_SG_DESCRIPTORS]; - - if (Is24bit) { - DMAPageRead(SGList, (char *)&SGE24, Entries * sizeof(SGE)); - - for (i=0;iCmdBlock.old.DataPointer); - DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); - pclog("Data length: %08X\n", req->CmdBlock.old.DataLength); - } else { - DataPointer = req->CmdBlock.new.DataPointer; - DataLength = req->CmdBlock.new.DataLength; - } - BuslogicLog("BuslogicDataBufferLength(): Data Buffer write: length %d, pointer 0x%04X\n", - DataLength, DataPointer); - - if (SCSIDevices[req->TargetID][req->LUN].CmdBuffer != NULL) { - free(SCSIDevices[req->TargetID][req->LUN].CmdBuffer); - SCSIDevices[req->TargetID][req->LUN].CmdBuffer = NULL; - } - - if ((req->CmdBlock.common.ControlByte != 0x03) && DataLength) { - if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || - req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { - uint32_t SGRead; - uint32_t ScatterEntry; - SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; - uint32_t SGLeft = DataLength / SGEntryLength; - uint32_t SGAddrCurrent = DataPointer; - uint32_t DataToTransfer = 0; - - do { - SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); - SGLeft -= SGRead; - - BuslogicReadSGEntries(Is24bit, SGAddrCurrent, SGRead, SGBuffer); - - for (ScatterEntry=0; ScatterEntry 0); - - BuslogicLog("BuslogicDataBufferLength(): Data to transfer (S/G) %d\n", DataToTransfer); - - return DataToTransfer; - } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || - req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { - return DataLength; - } else { - return 0; - } - } else { - return 0; - } -} - - -static void -BuslogicResidualOnError(Req_t *req, int length) -{ - if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || - (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { - /* Should be 0 when scatter/gather? */ - - if (req->Is24bit) { - U32_TO_ADDR(req->CmdBlock.old.DataLength, length); - BuslogicLog("BuslogicResidualOnError(): 24-bit Residual data length for reading: %d\n", - ADDR_TO_U32(req->CmdBlock.old.DataLength)); - } else { - req->CmdBlock.new.DataLength = length; - BuslogicLog("BuslogicResidualOnError(): 32-bit Residual data length for reading: %d\n", - req->CmdBlock.new.DataLength); - } - } -} - - -static void -BuslogicDMATransfer(Req_t *req, int Is24bit, int TransferLength, int dir) -{ - uint32_t sg_buffer_pos = 0; - uint32_t DataPointer, DataLength; - uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - uint32_t Address; - uint32_t Residual; - /* uint32_t CCBPointer = req->CCBPointer; */ - - if (Is24bit) { - DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); - DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); - } else { - DataPointer = req->CmdBlock.new.DataPointer; - DataLength = req->CmdBlock.new.DataLength; - } - BuslogicLog("BuslogicDMATransfer(): Data Buffer %s: length %d, pointer 0x%04X\n", - dir ? "write" : "read", SCSI_BufferLength, DataPointer); - - if ((req->CmdBlock.common.ControlByte != 0x03) && DataLength) { - if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || - req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { - uint32_t SGRead; - uint32_t ScatterEntry; - SGE32 SGBuffer[MAX_SG_DESCRIPTORS]; - uint32_t SGLeft = DataLength / SGEntryLength; - uint32_t SGAddrCurrent = DataPointer; - uint32_t DataToTransfer = 0; - - TransferLength -= SCSI_BufferLength; - - /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without - checking its length, so do this procedure for both no read/write commands. */ - if ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || - (req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || - (req->CmdBlock.common.ControlByte == 0x00)) { - SGLeft = DataLength / SGEntryLength; - SGAddrCurrent = DataPointer; - - do { - SGRead = (SGLeft < ELEMENTS(SGBuffer)) ? SGLeft : ELEMENTS(SGBuffer); - SGLeft -= SGRead; - - BuslogicReadSGEntries(Is24bit, SGAddrCurrent, - SGRead, SGBuffer); - - for (ScatterEntry=0; ScatterEntryCmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))) - { - BuslogicLog("BuslogicDMATransfer(): S/G Read: Address=%08X DatatoTransfer=%u\n", Address, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); - DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); - } - else - if (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))) - { - BuslogicLog("BuslogicDMATransfer(): S/G Write: Address=%08X DatatoTransfer=%u\n", Address, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); - DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer + sg_buffer_pos, (SCSI_BufferLength < DataToTransfer) ? SCSI_BufferLength : DataToTransfer); - } - sg_buffer_pos += DataToTransfer; - SCSI_BufferLength -= DataToTransfer; - } - - SGAddrCurrent += SGRead * (Is24bit ? sizeof(SGE) : sizeof(SGE32)); - } while (SGLeft > 0); - } - } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || - req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { - Address = DataPointer; - - SCSI_BufferLength = DataLength; - - if ((DataLength > 0) && (SCSI_BufferLength > 0)) { - if (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))) - { - BuslogicLog("BuslogicDMATransfer(): Read: Address=%08X DatatoTransfer=%u\n", Address, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); - DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); - } - else - if (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))) - { - BuslogicLog("BuslogicDMATransfer(): Write: Address=%08X DatatoTransfer=%u\n", Address, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); - DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); - } - } - } - } - - if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || - (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { - /* Should be 0 when scatter/gather? */ - if (TransferLength > 0) { - Residual = TransferLength; - } else { - Residual = 0; - } - - if (req->Is24bit) { - U32_TO_ADDR(req->CmdBlock.old.DataLength, Residual); - BuslogicLog("BuslogicDMATransfer(): 24-bit Residual data length for reading: %d\n", - ADDR_TO_U32(req->CmdBlock.old.DataLength)); - } else { - req->CmdBlock.new.DataLength = Residual; - BuslogicLog("BuslogicDMATransfer(): 32-bit Residual data length for reading: %d\n", - req->CmdBlock.new.DataLength); - } - } -} - - -static void -BuslogicDataBufferAllocate(uint8_t ID, uint8_t LUN, int length) -{ - if (SCSIDevices[ID][LUN].CmdBuffer != NULL) { - free(SCSIDevices[ID][LUN].CmdBuffer); - SCSIDevices[ID][LUN].CmdBuffer = NULL; - } - - BuslogicLog("BuslogicDataBufferAllocate(): Allocating data buffer (%i bytes)\n", length); - SCSIDevices[ID][LUN].CmdBuffer = (uint8_t *) malloc(length); - memset(SCSIDevices[ID][LUN].CmdBuffer, 0, length); -} - - -static void -BuslogicDataBufferFree(uint8_t ID, uint8_t LUN) -{ - if (SCSIDevices[ID][LUN].CmdBuffer != NULL) { - free(SCSIDevices[ID][LUN].CmdBuffer); - SCSIDevices[ID][LUN].CmdBuffer = NULL; + if ((dev->CmdParam == 4) && (dev->Command == 0xA9)) { + dev->CmdParamLeft = dev->CmdBuf[3]; + dev->CmdParamLeft <<= 8; + dev->CmdParamLeft |= dev->CmdBuf[2]; } } static uint8_t -BuslogicConvertSenseLength(uint8_t RequestSenseLength) +buslogic_get_host_id(void *p) { - BuslogicLog("BuslogicConvertSenseLength(): Unconverted Request Sense length %i\n", RequestSenseLength); + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - if (RequestSenseLength == 0) - RequestSenseLength = 14; - else if (RequestSenseLength == 1) - RequestSenseLength = 0; + HALocalRAM *HALR = &bl->LocalRAM; - BuslogicLog("BuslogicConvertSenseLength(): Request Sense length %i\n", RequestSenseLength); - - return(RequestSenseLength); -} - - -static void -SenseBufferFree(Req_t *req, int Copy) -{ - uint8_t SenseLength = BuslogicConvertSenseLength(req->CmdBlock.common.RequestSenseLength); - uint32_t SenseBufferAddress; - uint8_t temp_sense[256]; - - if (SenseLength/* && Copy*/) { - scsi_device_request_sense(req->TargetID, req->LUN, temp_sense, SenseLength); - - /* - * The sense address, in 32-bit mode, is located in the - * Sense Pointer of the CCB, but in 24-bit mode, it is - * located at the end of the Command Descriptor Block. - */ - if (req->Is24bit) { - SenseBufferAddress = req->CCBPointer; - SenseBufferAddress += req->CmdBlock.common.CdbLength + 18; - } else { - SenseBufferAddress = req->CmdBlock.new.SensePointer; - } - - BuslogicLog("SenseBufferFree(): Request Sense address: %02X\n", SenseBufferAddress); - - BuslogicLog("SenseBufferFree(): Writing %i bytes at %08X\n", - SenseLength, SenseBufferAddress); - DMAPageWrite(SenseBufferAddress, (char *)temp_sense, SenseLength); - BuslogicLog("SenseBufferFree(): Sense data written to buffer: %02X %02X %02X\n", - temp_sense[2], temp_sense[12], temp_sense[13]); - } -} - - -static void -BuslogicSCSICommand(Buslogic_t *bl) -{ - Req_t *req = &bl->Req; - uint8_t id, lun; - uint8_t temp_cdb[12]; - uint32_t i; - int target_cdb_len = 12; - int target_data_len; - uint8_t bit24 = !!req->Is24bit; - - id = req->TargetID; - lun = req->LUN; - - target_cdb_len = scsi_device_cdb_length(id, lun); - target_data_len = BuslogicDataBufferLength(req, bit24); - - if (!scsi_device_valid(id, lun)) - fatal("SCSI target on %02i:%02i has disappeared\n", id, lun); - - BuslogicDataBufferAllocate(id, lun, target_data_len); - - BuslogicLog("BuslogicSCSICommand(): SCSI command being executed on ID %i, LUN %i\n", id, lun); - - BuslogicLog("BuslogicSCSICommand(): SCSI CDB[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); - for (i=1; iCmdBlock.common.CdbLength; i++) - BuslogicLog("BuslogicSCSICommand(): SCSI CDB[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); - - memset(temp_cdb, 0x00, target_cdb_len); - if (req->CmdBlock.common.CdbLength <= target_cdb_len) { - memcpy(temp_cdb, req->CmdBlock.common.Cdb, - req->CmdBlock.common.CdbLength); - } else { - memcpy(temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); - } - - SCSI_BufferLength = target_data_len; - scsi_device_command_phase0(id, lun, req->CmdBlock.common.CdbLength, temp_cdb); - - if (SCSIPhase == SCSI_PHASE_DATA_OUT) - { - BuslogicDMATransfer(req, bit24, target_data_len, 1); - scsi_device_command_phase1(id, lun); - } - else if (SCSIPhase == SCSI_PHASE_DATA_IN) - { - BuslogicDMATransfer(req, bit24, target_data_len, 0); - } + if (bl->chip == CHIP_BUSLOGIC_ISA_542) + return dev->HostID; else - { - if (target_data_len) { - BuslogicResidualOnError(req, target_data_len); - } - } - - BuslogicDataBufferFree(id, lun); - - SenseBufferFree(req, (SCSIStatus != SCSI_STATUS_OK)); - - BuslogicLog("BuslogicSCSICommand(): Request complete\n"); - - if (SCSIStatus == SCSI_STATUS_OK) { - BuslogicMailboxInSetup(bl, req->CCBPointer, &req->CmdBlock, - CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); - } else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) { - BuslogicMailboxInSetup(bl, req->CCBPointer, &req->CmdBlock, - CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); - } - - BuslogicLog("BuslogicSCSICommand(): SCSIStatus = %02X\n", SCSIStatus); - - if (temp_cdb[0] == 0x42) { - thread_wait_event(bl->evt, 10); - } -} - - -static void -BuslogicSCSIRequestSetup(Buslogic_t *bl, uint32_t CCBPointer, Mailbox32_t *Mailbox32) -{ - Req_t *req = &bl->Req; - uint8_t id, lun; - uint8_t max_id = SCSI_ID_MAX-1; - int len; - - /* Fetch data from the Command Control Block. */ - DMAPageRead(CCBPointer, (char *)&req->CmdBlock, sizeof(CCB32)); - - req->Is24bit = bl->Mbx24bit; - req->CCBPointer = CCBPointer; - req->TargetID = bl->Mbx24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; - req->LUN = bl->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; - - id = req->TargetID; - lun = req->LUN; - if ((id > max_id) || (lun > 7)) { - BuslogicMailboxInSetup(bl, CCBPointer, &req->CmdBlock, - CCB_INVALID_CCB, SCSI_STATUS_OK, MBI_ERROR); - BuslogicLog("BuslogicSCSIRequestSetup(): Invalid ID or LUN, send incoming mailbox\n"); - BuslogicMailboxIn(bl); - return; - } - - BuslogicLog("BuslogicSCSIRequestSetup(): Scanning SCSI Target ID %i\n", id); - - SCSIStatus = SCSI_STATUS_OK; - SCSI_BufferLength = 0; - - if (! scsi_device_present(id, lun)) { - BuslogicLog("BuslogicSCSIRequestSetup(): SCSI Target ID %i and LUN %i have no device attached\n",id,lun); - len = BuslogicDataBufferLength(req, req->Is24bit); - if (len) { - BuslogicResidualOnError(req, len); - } - SenseBufferFree(req, 0); - BuslogicMailboxInSetup(bl, CCBPointer, &req->CmdBlock, - CCB_SELECTION_TIMEOUT,SCSI_STATUS_OK,MBI_ERROR); - BuslogicLog("BuslogicSCSIRequestSetup(): Callback: Send incoming mailbox\n"); - BuslogicMailboxIn(bl); - } else { - BuslogicLog("BuslogicSCSIRequestSetup(): SCSI Target ID %i and LUN %i detected and working\n", id, lun); - - BuslogicLog("BuslogicSCSIRequestSetup(): Transfer Control %02X\n", req->CmdBlock.common.ControlByte); - BuslogicLog("BuslogicSCSIRequestSetup(): CDB Length %i\n", req->CmdBlock.common.CdbLength); - BuslogicLog("BuslogicSCSIRequestSetup(): CCB Opcode %x\n", req->CmdBlock.common.Opcode); - if (req->CmdBlock.common.ControlByte > 0x03) { - BuslogicLog("BuslogicSCSIRequestSetup(): Invalid control byte: %02X\n", - req->CmdBlock.common.ControlByte); - } - - BuslogicLog("BuslogicSCSIRequestSetup(): Callback: Process SCSI request\n"); - BuslogicSCSICommand(bl); - - BuslogicLog("BuslogicSCSIRequestSetup(): Callback: Send incoming mailbox\n"); - BuslogicMailboxIn(bl); - } -} - - -static void -BuslogicSCSIRequestAbort(Buslogic_t *bl, uint32_t CCBPointer) -{ - CCBU CmdBlock; - - /* Fetch data from the Command Control Block. */ - DMAPageRead(CCBPointer, (char *)&CmdBlock, sizeof(CCB32)); - - /* Only SCSI CD-ROMs are supported at the moment, SCSI hard disk support will come soon. */ - BuslogicMailboxInSetup(bl, CCBPointer, &CmdBlock, - 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); - - pclog("BusLogicSCSIRequestAbort(): Send incoming mailbox\n"); - BuslogicMailboxIn(bl); -} - - -static uint32_t -BuslogicMailboxOut(Buslogic_t *bl, Mailbox32_t *Mailbox32) -{ - Mailbox_t MailboxOut; - uint32_t Outgoing; - - if (bl->Mbx24bit) { - Outgoing = bl->MailboxOutAddr + (bl->MailboxOutPosCur * sizeof(Mailbox_t)); - DMAPageRead(Outgoing, (char *)&MailboxOut, sizeof(Mailbox_t)); - - Mailbox32->CCBPointer = ADDR_TO_U32(MailboxOut.CCBPointer); - Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; - } else { - Outgoing = bl->MailboxOutAddr + (bl->MailboxOutPosCur * sizeof(Mailbox32_t)); - - DMAPageRead(Outgoing, (char *)Mailbox32, sizeof(Mailbox32_t)); - } - - return Outgoing; -} - - -static void -BuslogicMailboxOutAdvance(Buslogic_t *bl) -{ - bl->MailboxOutPosCur = (bl->MailboxOutPosCur + 1) % bl->MailboxCount; + return HALR->structured.autoSCSIData.uSCSIId; } static uint8_t -BuslogicProcessMailbox(Buslogic_t *bl) +buslogic_get_irq(void *p) { - Mailbox32_t mb32; - uint32_t Outgoing; - uint8_t CmdStatus = MBO_FREE; - uint32_t CodeOffset = 0; + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - CodeOffset = bl->Mbx24bit ? 0 : 7; + uint8_t bl_irq[7] = { 0, 9, 10, 11, 12, 14, 15 }; -#if 0 - pclog("BuslogicProcessMailbox(): Operating in %s mode\n", bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode ? "aggressive" : "strict"); -#endif + HALocalRAM *HALR = &bl->LocalRAM; - /* 0 = strict, 1 = aggressive */ - if (bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode) { - /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ - do { - /* Fetch mailbox from guest memory. */ - Outgoing = BuslogicMailboxOut(bl, &mb32); + if (bl->chip == CHIP_BUSLOGIC_PCI) + return dev->Irq; + else + return bl_irq[HALR->structured.autoSCSIData.uIrqChannel]; +} - /* Check the next mailbox. */ - BuslogicMailboxOutAdvance(bl); - } while ((mb32.u.out.ActionCode != MBO_START) && (mb32.u.out.ActionCode != MBO_ABORT)); - } else { - Outgoing = BuslogicMailboxOut(bl, &mb32); - if (mb32.u.out.ActionCode == MBO_FREE) { +static uint8_t +buslogic_get_dma(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + uint8_t bl_dma[4] = { 0, 5, 6, 7 }; + + HALocalRAM *HALR = &bl->LocalRAM; + + if (bl->chip == CHIP_BUSLOGIC_PCI) + return dev->DmaChannel; + else + return bl_dma[HALR->structured.autoSCSIData.uDMAChannel]; +} + + +static uint8_t +buslogic_param_len(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + switch (dev->Command) { + case 0x21: + return 5; + case 0x25: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8F: + case 0x92: + case 0x96: + return 1; + case 0x81: + return sizeof(MailboxInitExtended_t); + case 0x83: + return 12; + case 0x90: + case 0x91: + return 2; + case 0x94: + return 3; + case 0x95: /* Valid only for PCI */ + return (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; + case 0x97: /* Valid only for PCI */ + case 0xA7: /* Valid only for PCI */ + return (bl->chip == CHIP_BUSLOGIC_PCI) ? 10 : 0; + case 0xA8: /* Valid only for PCI */ + case 0xA9: /* Valid only for PCI */ + return (bl->chip == CHIP_BUSLOGIC_PCI) ? 4 : 0; + default: return 0; - } } - -#if 0 - pclog("BuslogicProcessMailbox(): Outgoing mailbox action code: %i\n", mb32.u.out.ActionCode); -#endif - - if (mb32.u.out.ActionCode == MBO_START) { - pclog("Start Mailbox Command\n"); - BuslogicSCSIRequestSetup(bl, mb32.CCBPointer, &mb32); - } else if (mb32.u.out.ActionCode == MBO_ABORT) { - pclog("Abort Mailbox Command\n"); - BuslogicSCSIRequestAbort(bl, mb32.CCBPointer); - } else { - BuslogicLog("BuslogicProcessMailbox(): Invalid action code: %02X\n", mb32.u.out.ActionCode); - } - - if ((mb32.u.out.ActionCode == MBO_START) || (mb32.u.out.ActionCode == MBO_ABORT)) { - /* We got the mailbox, mark it as free in the guest. */ - BuslogicLog("BuslogicProcessMailbox(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); - DMAPageWrite(Outgoing + CodeOffset, (char *)&CmdStatus, sizeof(CmdStatus)); - - BuslogicRaiseInterrupt(bl, 0, bl->ToRaise); - - while (bl->Interrupt) { - } - } - - /* Advance to the next mailbox. */ - if (! bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode) - BuslogicMailboxOutAdvance(bl); - - return 1; } @@ -1504,57 +532,44 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN, int uint32_t DataPointer = ESCSICmd->DataPointer; uint32_t DataLength = ESCSICmd->DataLength; uint32_t Address; - -#if 0 - if ((DataLength != 0) && (ESCSICmd->CDB[0] == GPCMD_TEST_UNIT_READY)) { - pclog("Data length not 0 with TEST UNIT READY: %i (%i)\n", - DataLength, SCSI_BufferLength); - } - - if (ESCSICmd->CDB[0] == GPCMD_TEST_UNIT_READY) { - DataLength = 0; - } -#endif + uint32_t TransferLength; if (ESCSICmd->DataDirection == 0x03) { /* Non-data command. */ - BuslogicLog("BuslogicSCSIBIOSDMATransfer(): Non-data control byte\n"); + buslogic_log("BuslogicSCSIBIOSDMATransfer(): Non-data control byte\n"); return; } - BuslogicLog("BuslogicSCSIBIOSDMATransfer(): BIOS Data Buffer read: length %d, pointer 0x%04X\n", DataLength, DataPointer); + buslogic_log("BuslogicSCSIBIOSDMATransfer(): BIOS Data Buffer read: length %d, pointer 0x%04X\n", DataLength, DataPointer); /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without checking its length, so do this procedure for both read/write commands. */ - if ((DataLength > 0) && (SCSI_BufferLength > 0)) { + if ((DataLength > 0) && (SCSIDevices[TargetID][LUN].BufferLength > 0)) { Address = DataPointer; + TransferLength = MIN(DataLength, SCSIDevices[TargetID][LUN].BufferLength); - if (dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_OUT) || (ESCSICmd->DataDirection == 0x00))) - { - pclog("BusLogic BIOS DMA: Reading %i bytes from %08X\n", DataLength, Address); - DMAPageRead(Address, (char *)SCSIDevices[TargetID][LUN].CmdBuffer, DataLength); - } - else if (!dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || (ESCSICmd->DataDirection == 0x00))) - { - Address = DataPointer; - - pclog("BusLogic BIOS DMA: Writing %i bytes at %08X\n", (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength, Address); - DMAPageWrite(Address, (char *)SCSIDevices[TargetID][LUN].CmdBuffer, (SCSI_BufferLength < DataLength) ? SCSI_BufferLength : DataLength); + if (dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_OUT) || (ESCSICmd->DataDirection == 0x00))) { + buslogic_log("BusLogic BIOS DMA: Reading %i bytes from %08X\n", TransferLength, Address); + DMAPageRead(Address, (char *)SCSIDevices[TargetID][LUN].CmdBuffer, TransferLength); + } else if (!dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || (ESCSICmd->DataDirection == 0x00))) { + buslogic_log("BusLogic BIOS DMA: Writing %i bytes at %08X\n", TransferLength, Address); + DMAPageWrite(Address, (char *)SCSIDevices[TargetID][LUN].CmdBuffer, TransferLength); } } } static void -BuslogicSCSIBIOSRequestSetup(Buslogic_t *bl, uint8_t *CmdBuf, uint8_t *DataInBuf, uint8_t DataReply) +BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, uint8_t DataReply) { - ESCMD *ESCSICmd = (ESCMD *)CmdBuf; - uint32_t i; - uint8_t temp_cdb[12]; - int target_cdb_len = 12; - uint8_t target_id = 0; + ESCMD *ESCSICmd = (ESCMD *)CmdBuf; + uint32_t i; + uint8_t temp_cdb[12]; + int target_cdb_len = 12; + uint8_t target_id = 0; + int phase; - DataInBuf[0] = DataInBuf[1] = 0; + DataInBuf[0] = DataInBuf[1] = 0; if ((ESCSICmd->TargetId > 15) || (ESCSICmd->LogicalUnit > 7)) { DataInBuf[2] = CCB_INVALID_CCB; @@ -1562,37 +577,36 @@ BuslogicSCSIBIOSRequestSetup(Buslogic_t *bl, uint8_t *CmdBuf, uint8_t *DataInBuf return; } - pclog("Scanning SCSI Target ID %i\n", ESCSICmd->TargetId); + buslogic_log("Scanning SCSI Target ID %i\n", ESCSICmd->TargetId); SCSIStatus = SCSI_STATUS_OK; - SCSI_BufferLength = 0; if (!scsi_device_present(ESCSICmd->TargetId, ESCSICmd->LogicalUnit)) { - pclog("SCSI Target ID %i and LUN %i have no device attached\n",ESCSICmd->TargetId,ESCSICmd->LogicalUnit); + buslogic_log("SCSI Target ID %i and LUN %i have no device attached\n",ESCSICmd->TargetId,ESCSICmd->LogicalUnit); DataInBuf[2] = CCB_SELECTION_TIMEOUT; DataInBuf[3] = SCSI_STATUS_OK; } else { - pclog("SCSI Target ID %i and LUN %i detected and working\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + buslogic_log("SCSI Target ID %i and LUN %i detected and working\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit); - pclog("Transfer Control %02X\n", ESCSICmd->DataDirection); - pclog("CDB Length %i\n", ESCSICmd->CDBLength); + buslogic_log("Transfer Control %02X\n", ESCSICmd->DataDirection); + buslogic_log("CDB Length %i\n", ESCSICmd->CDBLength); if (ESCSICmd->DataDirection > 0x03) { - pclog("Invalid control byte: %02X\n", + buslogic_log("Invalid control byte: %02X\n", ESCSICmd->DataDirection); } } - BuslogicDataBufferAllocate(ESCSICmd->TargetId, ESCSICmd->LogicalUnit, ESCSICmd->DataLength); + x54x_buf_alloc(ESCSICmd->TargetId, ESCSICmd->LogicalUnit, ESCSICmd->DataLength); target_cdb_len = scsi_device_cdb_length(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); if (!scsi_device_valid(ESCSICmd->TargetId, ESCSICmd->LogicalUnit)) fatal("SCSI target on %02i:%02i has disappeared\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit); - pclog("SCSI target command being executed on: SCSI ID %i, SCSI LUN %i, Target %i\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit, target_id); + buslogic_log("SCSI target command being executed on: SCSI ID %i, SCSI LUN %i, Target %i\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit, target_id); - pclog("SCSI Cdb[0]=0x%02X\n", ESCSICmd->CDB[0]); + buslogic_log("SCSI Cdb[0]=0x%02X\n", ESCSICmd->CDB[0]); for (i = 1; i < ESCSICmd->CDBLength; i++) { - pclog("SCSI Cdb[%i]=%i\n", i, ESCSICmd->CDB[i]); + buslogic_log("SCSI Cdb[%i]=%i\n", i, ESCSICmd->CDB[i]); } memset(temp_cdb, 0, target_cdb_len); @@ -1602,19 +616,21 @@ BuslogicSCSIBIOSRequestSetup(Buslogic_t *bl, uint8_t *CmdBuf, uint8_t *DataInBuf memcpy(temp_cdb, ESCSICmd->CDB, target_cdb_len); } - SCSI_BufferLength = ESCSICmd->DataLength; + SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].BufferLength = ESCSICmd->DataLength; scsi_device_command_phase0(ESCSICmd->TargetId, ESCSICmd->LogicalUnit, ESCSICmd->CDBLength, temp_cdb); - if (SCSIPhase == SCSI_PHASE_DATA_OUT) { - BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit, 1); - scsi_device_command_phase1(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); - } else if (SCSIPhase == SCSI_PHASE_DATA_IN) { - BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit, 0); + phase = SCSIPhase; + if (phase != SCSI_PHASE_STATUS) { + if (phase == SCSI_PHASE_DATA_IN) + scsi_device_command_phase1(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit, (phase == SCSI_PHASE_DATA_OUT)); + if (phase == SCSI_PHASE_DATA_OUT) + scsi_device_command_phase1(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); } - BuslogicDataBufferFree(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + x54x_buf_free(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); - pclog("BIOS Request complete\n"); + buslogic_log("BIOS Request complete\n"); if (SCSIStatus == SCSI_STATUS_OK) { DataInBuf[2] = CCB_COMPLETE; @@ -1624,988 +640,400 @@ BuslogicSCSIBIOSRequestSetup(Buslogic_t *bl, uint8_t *CmdBuf, uint8_t *DataInBuf DataInBuf[3] = SCSI_STATUS_CHECK_CONDITION; } - bl->DataReplyLeft = DataReply; + dev->DataReplyLeft = DataReply; } static uint8_t -BuslogicRead(uint16_t Port, void *p) +buslogic_cmds(void *p) { - Buslogic_t *bl = (Buslogic_t *)p; - uint8_t Temp; + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - switch (Port & 3) { - case 0: - default: - Temp = bl->Status; - break; - - case 1: - Temp = bl->DataBuf[bl->DataReply]; - if (bl->DataReplyLeft) - { - bl->DataReply++; - bl->DataReplyLeft--; - if (!bl->DataReplyLeft) { - BuslogicCommandComplete(bl, 0); - } - } - break; - - case 2: - Temp = bl->Interrupt; - break; - - case 3: - Temp = bl->Geometry; - break; - } - - /* if (Port < 0x1000) { */ - if (Port & 3) { - pclog("Buslogic: Read Port 0x%02X, Returned Value %02X\n", - Port, Temp); - } - - return(Temp); -} - - -static uint16_t -BuslogicReadW(uint16_t Port, void *p) -{ - return BuslogicRead(Port, p); -} - - -static uint32_t -BuslogicReadL(uint16_t Port, void *p) -{ - return BuslogicRead(Port, p); -} - - -static uint8_t -BuslogicMemRead(uint32_t addr, void *p) -{ - pclog("BuslogicMemRead(%08X, %08X)\n", addr, p); - return BuslogicRead(addr & 3, p); -} - - -static uint16_t -BuslogicMemReadW(uint32_t addr, void *p) -{ - pclog("BuslogicMemReadW(%08X, %08X)\n", addr, p); - return BuslogicReadW(addr & 3, p); -} - -static uint32_t -BuslogicMemReadL(uint32_t addr, void *p) -{ - pclog("BuslogicMemReadL(%08X, %08X)\n", addr, p); - return BuslogicReadL(addr & 3, p); -} - - -static void BuslogicWriteW(uint16_t Port, uint16_t Val, void *p); -static void BuslogicWriteL(uint16_t Port, uint32_t Val, void *p); -static void -BuslogicWrite(uint16_t Port, uint8_t Val, void *p) -{ - int i = 0; - uint8_t j = 0; - Buslogic_t *bl = (Buslogic_t *)p; + FILE *f; + uint16_t TargetsPresentMask = 0; uint8_t Offset; - MailboxInit_t *MailboxInit; - BIOSCMD *BiosCmd; - ReplyInquireSetupInformation *ReplyISI; + int i = 0; + int j = 0; MailboxInitExtended_t *MailboxInitE; ReplyInquireExtendedSetupInformation *ReplyIESI; BuslogicPCIInformation_t *ReplyPI; - char aModelName[] = "542B "; /* Trailing \0 is fine, that's the filler anyway. */ int cCharsToTransfer; - int suppress = 0; - uint16_t cyl = 0; - FILE *f; - pclog("Buslogic: Write Port 0x%02X, Value %02X\n", Port, Val); - - switch (Port & 3) - { - case 0: - if ((Val & CTRL_HRST) || (Val & CTRL_SRST)) - { - uint8_t Reset = (Val & CTRL_HRST); - BuslogicResetControl(bl, Reset); - break; - } - - if (Val & CTRL_IRST) { - BuslogicClearInterrupt(bl); - } + switch (dev->Command) { + case 0x20: + dev->DataReplyLeft = 0; + x54x_reset_ctrl(dev, 1); break; - - case 1: - /* Fast path for the mailbox execution command. */ - if ((Val == 0x02) && (bl->Command == 0xFF)) { - /* If there are no mailboxes configured, don't even try to do anything. */ - if (bl->MailboxCount) { - if (!poll_tid) { - pclog("Buslogic: starting thread..\n"); - poll_tid = thread_create(BuslogicCommandThread, bl); - bl->scan_restart = 0; - } - else { - bl->scan_restart = bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode ? 0 : 1; - } - } - return; + case 0x21: + if (dev->CmdParam == 1) + dev->CmdParamLeft = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + break; + case 0x23: + memset(dev->DataBuf, 0, 8); + for (i = 8; i < 15; i++) { + dev->DataBuf[i-8] = 0; + for (j=0; j<8; j++) { + if (scsi_device_present(i, j) && (i != buslogic_get_host_id(dev))) + dev->DataBuf[i-8] |= (1<DataReplyLeft = 8; + break; + case 0x24: + for (i=0; i<15; i++) { + if (scsi_device_present(i, 0) && (i != buslogic_get_host_id(dev))) + TargetsPresentMask |= (1 << i); + } + dev->DataBuf[0] = TargetsPresentMask & 0xFF; + dev->DataBuf[1] = TargetsPresentMask >> 8; + dev->DataReplyLeft = 2; + break; + case 0x25: + if (dev->CmdBuf[0] == 0) + dev->IrqEnabled = 0; + else + dev->IrqEnabled = 1; + return 1; + case 0x81: + x54x_busy_set(); + dev->Mbx24bit = 0; - if (bl->Command == 0xFF) { - bl->Command = Val; - bl->CmdParam = 0; - bl->CmdParamLeft = 0; - - bl->Status &= ~(STAT_INVCMD | STAT_IDLE); - pclog("Buslogic: Operation Code 0x%02X\n", Val); - switch (bl->Command) { - case 0x01: - bl->CmdParamLeft = sizeof(MailboxInit_t); - break; + MailboxInitE = (MailboxInitExtended_t *)dev->CmdBuf; - case 0x03: - bl->CmdParamLeft = 10; - break; - - case 0x25: - bl->CmdParamLeft = 1; - break; + dev->MailboxInit = 1; + dev->MailboxCount = MailboxInitE->Count; + dev->MailboxOutAddr = MailboxInitE->Address; + dev->MailboxInAddr = MailboxInitE->Address + (dev->MailboxCount * sizeof(Mailbox32_t)); - case 0x05: - case 0x07: - case 0x08: - case 0x09: - case 0x0D: - case 0x1F: - bl->CmdParamLeft = 1; - break; - - case 0x21: - bl->CmdParamLeft = 5; - break; + buslogic_log("Buslogic Extended Initialize Mailbox Command\n"); + buslogic_log("Mailbox Out Address=0x%08X\n", dev->MailboxOutAddr); + buslogic_log("Mailbox In Address=0x%08X\n", dev->MailboxInAddr); + buslogic_log("Initialized Extended Mailbox, %d entries at 0x%08X\n", MailboxInitE->Count, MailboxInitE->Address); - case 0x1A: - case 0x1B: - bl->CmdParamLeft = 3; - break; - - case 0x06: - bl->CmdParamLeft = 4; - break; - - case 0x8B: - case 0x8D: - case 0x8F: - case 0x96: - bl->CmdParamLeft = 1; - break; - - case 0x81: - bl->CmdParamLeft = sizeof(MailboxInitExtended_t); - break; - - case 0x83: - bl->CmdParamLeft = 12; - break; - - case 0x8C: - bl->CmdParamLeft = 1; - break; - - case 0x90: - bl->CmdParamLeft = 2; - break; - - case 0x91: - bl->CmdParamLeft = 2; - break; - - case 0x92: - bl->CmdParamLeft = 1; - break; - - case 0x94: - bl->CmdParamLeft = 3; - break; - - case 0x95: /* Valid only for PCI */ - bl->CmdParamLeft = (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; - break; - - case 0x97: /* Valid only for PCI */ - case 0xA7: /* Valid only for PCI */ - bl->CmdParamLeft = (bl->chip == CHIP_BUSLOGIC_PCI) ? 10 : 0; - - case 0xA8: /* Valid only for PCI */ - case 0xA9: /* Valid only for PCI */ - bl->CmdParamLeft = (bl->chip == CHIP_BUSLOGIC_PCI) ? 4 : 0; - break; - } + dev->Status &= ~STAT_INIT; + dev->DataReplyLeft = 0; + x54x_busy_clear(); + break; + case 0x83: + if (dev->CmdParam == 12) { + dev->CmdParamLeft = dev->CmdBuf[11]; + buslogic_log("Execute SCSI BIOS Command: %u more bytes follow\n", dev->CmdParamLeft); } else { - bl->CmdBuf[bl->CmdParam] = Val; - bl->CmdParam++; - bl->CmdParamLeft--; - - if ((bl->CmdParam == 2) && (bl->Command == 0x90)) - { - bl->CmdParamLeft = bl->CmdBuf[1]; - } - - if ((bl->CmdParam == 10) && ((bl->Command == 0x97) || (bl->Command == 0xA7))) - { - bl->CmdParamLeft = bl->CmdBuf[6]; - bl->CmdParamLeft <<= 8; - bl->CmdParamLeft |= bl->CmdBuf[7]; - bl->CmdParamLeft <<= 8; - bl->CmdParamLeft |= bl->CmdBuf[8]; - } - - if ((bl->CmdParam == 4) && (bl->Command == 0xA9)) - { - bl->CmdParamLeft = bl->CmdBuf[3]; - bl->CmdParamLeft <<= 8; - bl->CmdParamLeft |= bl->CmdBuf[2]; - } - } - - if (!bl->CmdParamLeft) - { - pclog("Running Operation Code 0x%02X\n", bl->Command); - bl->DataReply = 0; - switch (bl->Command) { - case 0x00: - bl->DataReplyLeft = 0; - break; - - case 0x01: - bl->Mbx24bit = 1; - - MailboxInit = (MailboxInit_t *)bl->CmdBuf; - - bl->MailboxCount = MailboxInit->Count; - bl->MailboxOutAddr = ADDR_TO_U32(MailboxInit->Address); - bl->MailboxInAddr = bl->MailboxOutAddr + (bl->MailboxCount * sizeof(Mailbox_t)); - - pclog("Buslogic Initialize Mailbox Command\n"); - pclog("Mailbox Out Address=0x%08X\n", bl->MailboxOutAddr); - pclog("Mailbox In Address=0x%08X\n", bl->MailboxInAddr); - pclog("Initialized Mailbox, %d entries at 0x%08X\n", MailboxInit->Count, ADDR_TO_U32(MailboxInit->Address)); - - bl->Status &= ~STAT_INIT; - bl->DataReplyLeft = 0; - break; - - case 0x03: - BiosCmd = (BIOSCMD *)bl->CmdBuf; - - if (bl->chip != CHIP_BUSLOGIC_MCA) { - cyl = ((BiosCmd->u.chs.cyl & 0xff) << 8) | ((BiosCmd->u.chs.cyl >> 8) & 0xff); - BiosCmd->u.chs.cyl = cyl; - } - - if (bl->chip == CHIP_BUSLOGIC_MCA) { - pclog("BIOS LBA=%06lx (%lu)\n", - lba32_blk(BiosCmd), - lba32_blk(BiosCmd)); - } else { - BiosCmd->u.chs.head &= 0xf; - BiosCmd->u.chs.sec &= 0x1f; - pclog("BIOS CHS=%04X/%02X%02X\n", - BiosCmd->u.chs.cyl, - BiosCmd->u.chs.head, - BiosCmd->u.chs.sec); - } - - BiosCmd->u.chs.cyl = cyl; - BiosCmd->u.chs.head &= 0x0f; - BiosCmd->u.chs.sec &= 0x1f; - pclog("C: %04X, H: %02X, S: %02X\n", BiosCmd->u.chs.cyl, BiosCmd->u.chs.head, BiosCmd->u.chs.sec); - bl->DataBuf[0] = scsi_bios_command(15, BiosCmd, (bl->chip == CHIP_BUSLOGIC_MCA) ? 1 : 0); - pclog("BIOS Completion/Status Code %x\n", bl->DataBuf[0]); - bl->DataReplyLeft = 1; - break; - - case 0x04: - pclog("Inquire Board\n"); - bl->DataBuf[0] = (bl->chip == CHIP_BUSLOGIC_MCA) ? 0x42 : 0x41; - bl->DataBuf[1] = 0x41; - bl->DataBuf[2] = (bl->chip == CHIP_BUSLOGIC_PCI) ? '5' : '4'; - bl->DataBuf[3] = (bl->chip == CHIP_BUSLOGIC_PCI) ? '0' : '2'; - bl->DataReplyLeft = 4; - break; - - case 0x05: - if (bl->CmdBuf[0] <= 1) { - bl->MailboxOutInterrupts = bl->CmdBuf[0]; - pclog("Mailbox out interrupts: %s\n", bl->MailboxOutInterrupts ? "ON" : "OFF"); - suppress = 1; - } else { - bl->Status |= STAT_INVCMD; - } - bl->DataReplyLeft = 0; - break; - - case 0x06: - pclog("Selection Time-Out\n"); - bl->DataReplyLeft = 0; - break; - - case 0x07: - bl->DataReplyLeft = 0; - bl->LocalRAM.structured.autoSCSIData.uBusOnDelay = bl->CmdBuf[0]; - pclog("Bus-on time: %d\n", bl->CmdBuf[0]); - break; - - case 0x08: - bl->DataReplyLeft = 0; - bl->LocalRAM.structured.autoSCSIData.uBusOffDelay = bl->CmdBuf[0]; - pclog("Bus-off time: %d\n", bl->CmdBuf[0]); - break; - - case 0x09: - bl->DataReplyLeft = 0; - bl->LocalRAM.structured.autoSCSIData.uDMATransferRate = bl->CmdBuf[0]; - pclog("DMA transfer rate: %02X\n", bl->CmdBuf[0]); - break; - - case 0x0A: - memset(bl->DataBuf, 0, 8); - for (i=0; i<8; i++) { - bl->DataBuf[i] = 0; - for (j=0; j<8; j++) { - if (scsi_device_present(i, j) && (i != bl->LocalRAM.structured.autoSCSIData.uSCSIId)) - bl->DataBuf[i] |= (1 << j); - } - } - bl->DataReplyLeft = 8; - break; - - case 0x0B: - pclog("Inquire Configuration\n"); - bl->DataBuf[0] = (1 << bl->DmaChannel); - if ((bl->Irq >= 9) && (bl->Irq <= 15)) - { - bl->DataBuf[1] = (1<<(bl->Irq-9)); - } - else - bl->DataBuf[1] = 0; - { - } - bl->DataBuf[2] = bl->LocalRAM.structured.autoSCSIData.uSCSIId; /* HOST ID */ - bl->DataReplyLeft = 3; - break; - - case 0x0D: - { - bl->DataReplyLeft = bl->CmdBuf[0]; - - ReplyISI = (ReplyInquireSetupInformation *)bl->DataBuf; - memset(ReplyISI, 0, sizeof(ReplyInquireSetupInformation)); - - ReplyISI->fSynchronousInitiationEnabled = 1; - ReplyISI->fParityCheckingEnabled = 1; - ReplyISI->cMailbox = bl->MailboxCount; - U32_TO_ADDR(ReplyISI->MailboxAddress, bl->MailboxOutAddr); - - ReplyISI->uSignature = 'B'; - /* The 'D' signature prevents Buslogic's OS/2 drivers from getting too - * friendly with Adaptec hardware and upsetting the HBA state. - */ - ReplyISI->uCharacterD = 'D'; /* BusLogic model. */ - switch(bl->chip) - { - case CHIP_BUSLOGIC_ISA: - ReplyISI->uHostBusType = 'A'; - break; - case CHIP_BUSLOGIC_MCA: - ReplyISI->uHostBusType = 'B'; - break; - case CHIP_BUSLOGIC_VLB: - ReplyISI->uHostBusType = 'E'; - break; - case CHIP_BUSLOGIC_PCI: - ReplyISI->uHostBusType = 'F'; - break; - } - - pclog("Return Setup Information: %d\n", bl->CmdBuf[0]); - } - break; - - case 0x1A: - { - uint32_t FIFOBuf; - addr24 Address; - - bl->DataReplyLeft = 0; - Address.hi = bl->CmdBuf[0]; - Address.mid = bl->CmdBuf[1]; - Address.lo = bl->CmdBuf[2]; - FIFOBuf = ADDR_TO_U32(Address); - pclog("Buslogic LocalRAM: Reading 64 bytes at %08X\n", FIFOBuf); - DMAPageRead(FIFOBuf, (char *)bl->LocalRAM.u8View, 64); - } - break; - - case 0x1B: - { - uint32_t FIFOBuf; - addr24 Address; - - bl->DataReplyLeft = 0; - Address.hi = bl->CmdBuf[0]; - Address.mid = bl->CmdBuf[1]; - Address.lo = bl->CmdBuf[2]; - FIFOBuf = ADDR_TO_U32(Address); - pclog("Buslogic LocalRAM: Writing 64 bytes at %08X\n", FIFOBuf); - DMAPageWrite(FIFOBuf, (char *)bl->LocalRAM.u8View, 64); - } - break; - - case 0x1F: - bl->DataBuf[0] = bl->CmdBuf[0]; - bl->DataReplyLeft = 1; - break; - - case 0x20: - bl->DataReplyLeft = 0; - BuslogicResetControl(bl, 1); - break; - - case 0x21: - if (bl->CmdParam == 1) - bl->CmdParamLeft = bl->CmdBuf[0]; - bl->DataReplyLeft = 0; - break; - - case 0x23: - memset(bl->DataBuf, 0, 8); - for (i = 8; i < 15; i++) { - bl->DataBuf[i-8] = 0; - for (j=0; j<8; j++) { - if (scsi_device_present(i, j) && (i != bl->LocalRAM.structured.autoSCSIData.uSCSIId)) - bl->DataBuf[i-8] |= (1<DataReplyLeft = 8; - break; - - case 0x24: - { - uint16_t TargetsPresentMask = 0; - - for (i=0; i<15; i++) { - if (scsi_device_present(i, 0) && (i != bl->LocalRAM.structured.autoSCSIData.uSCSIId)) - TargetsPresentMask |= (1 << i); - } - bl->DataBuf[0] = TargetsPresentMask & 0xFF; - bl->DataBuf[1] = TargetsPresentMask >> 8; - bl->DataReplyLeft = 2; - } - break; - - case 0x25: - if (bl->CmdBuf[0] == 0) - bl->IrqEnabled = 0; - else - bl->IrqEnabled = 1; - /* pclog("Lowering IRQ %i\n", bl->Irq); - BuslogicInterrupt(bl, 0); */ - suppress = 1; - break; - - case 0x81: - { - bl->Mbx24bit = 0; - - MailboxInitE = (MailboxInitExtended_t *)bl->CmdBuf; - - bl->MailboxCount = MailboxInitE->Count; - bl->MailboxOutAddr = MailboxInitE->Address; - bl->MailboxInAddr = MailboxInitE->Address + (bl->MailboxCount * sizeof(Mailbox32_t)); - - pclog("Buslogic Extended Initialize Mailbox Command\n"); - pclog("Mailbox Out Address=0x%08X\n", bl->MailboxOutAddr); - pclog("Mailbox In Address=0x%08X\n", bl->MailboxInAddr); - pclog("Initialized Extended Mailbox, %d entries at 0x%08X\n", MailboxInitE->Count, MailboxInitE->Address); - - bl->Status &= ~STAT_INIT; - bl->DataReplyLeft = 0; - } - break; - - case 0x83: - if (bl->CmdParam == 12) - { - bl->CmdParamLeft = bl->CmdBuf[11]; - pclog("Execute SCSI BIOS Command: %u more bytes follow\n", bl->CmdParamLeft); - } - else - { - pclog("Execute SCSI BIOS Command: received %u bytes\n", bl->CmdBuf[0]); - BuslogicSCSIBIOSRequestSetup(bl, bl->CmdBuf, bl->DataBuf, 4); - } - break; - - case 0x84: - bl->DataBuf[0] = (bl->chip == CHIP_BUSLOGIC_PCI) ? '7' : '1'; - bl->DataReplyLeft = 1; - break; - - case 0x85: - bl->DataBuf[0] = (bl->chip == CHIP_BUSLOGIC_PCI) ? 'B' : 'E'; - bl->DataReplyLeft = 1; - break; - - case 0x86: - if (bl->chip == CHIP_BUSLOGIC_PCI) - { - ReplyPI = (BuslogicPCIInformation_t *) bl->DataBuf; - memset(ReplyPI, 0, sizeof(BuslogicPCIInformation_t)); - ReplyPI->InformationIsValid = 0; - switch(bl->Base) - { - case 0x330: - ReplyPI->IsaIOPort = 0; - break; - case 0x334: - ReplyPI->IsaIOPort = 1; - break; - case 0x230: - ReplyPI->IsaIOPort = 2; - break; - case 0x234: - ReplyPI->IsaIOPort = 3; - break; - case 0x130: - ReplyPI->IsaIOPort = 4; - break; - case 0x134: - ReplyPI->IsaIOPort = 5; - break; - default: - ReplyPI->IsaIOPort = 0xFF; - break; - } - ReplyPI->IRQ = bl->Irq; - bl->DataReplyLeft = sizeof(BuslogicPCIInformation_t); - } else { - bl->DataReplyLeft = 0; - bl->Status |= STAT_INVCMD; - } - break; - - case 0x8B: - { - /* The reply length is set by the guest and is found in the first byte of the command buffer. */ - bl->DataReplyLeft = bl->CmdBuf[0]; - memset(bl->DataBuf, 0, bl->DataReplyLeft); - switch(bl->chip) - { - case CHIP_BUSLOGIC_ISA: - aModelName[0] = '5'; - aModelName[1] = '4'; - aModelName[2] = '5'; - aModelName[3] = 'C'; - break; - case CHIP_BUSLOGIC_MCA: - aModelName[0] = '6'; - aModelName[1] = '4'; - aModelName[2] = '0'; - aModelName[3] = 'A'; - break; - case CHIP_BUSLOGIC_VLB: - aModelName[0] = '4'; - aModelName[1] = '4'; - aModelName[2] = '5'; - aModelName[3] = 'S'; - break; - case CHIP_BUSLOGIC_PCI: - aModelName[0] = '9'; - aModelName[1] = '5'; - aModelName[2] = '8'; - aModelName[3] = 'D'; - break; - } - cCharsToTransfer = bl->DataReplyLeft <= sizeof(aModelName) - ? bl->DataReplyLeft - : sizeof(aModelName); - - for (i = 0; i < cCharsToTransfer; i++) - bl->DataBuf[i] = aModelName[i]; - - pclog("Model Name\n"); - pclog("Buffer 0: %x\n", bl->DataBuf[0]); - pclog("Buffer 1: %x\n", bl->DataBuf[1]); - pclog("Buffer 2: %x\n", bl->DataBuf[2]); - pclog("Buffer 3: %x\n", bl->DataBuf[3]); - pclog("Buffer 4: %x\n", bl->DataBuf[4]); - } - break; - - case 0x8C: - bl->DataReplyLeft = bl->CmdBuf[0]; - memset(bl->DataBuf, 0, bl->DataReplyLeft); - break; - - case 0x8D: - bl->DataReplyLeft = bl->CmdBuf[0]; - ReplyIESI = (ReplyInquireExtendedSetupInformation *)bl->DataBuf; - memset(ReplyIESI, 0, sizeof(ReplyInquireExtendedSetupInformation)); - - switch (bl->chip) - { - case CHIP_BUSLOGIC_ISA: - case CHIP_BUSLOGIC_VLB: - ReplyIESI->uBusType = 'A'; /* ISA style */ - break; - case CHIP_BUSLOGIC_MCA: - ReplyIESI->uBusType = 'M'; /* MCA style */ - break; - case CHIP_BUSLOGIC_PCI: - ReplyIESI->uBusType = 'E'; /* PCI style */ - break; - } - ReplyIESI->uBiosAddress = 0xd8; - ReplyIESI->u16ScatterGatherLimit = 8192; - ReplyIESI->cMailbox = bl->MailboxCount; - ReplyIESI->uMailboxAddressBase = bl->MailboxOutAddr; - ReplyIESI->fHostWideSCSI = 1; /* This should be set for the BT-542B as well. */ - ReplyIESI->fLevelSensitiveInterrupt = bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; - if (bl->chip == CHIP_BUSLOGIC_PCI) { - ReplyIESI->fHostUltraSCSI = 1; - } - memcpy(ReplyIESI->aFirmwareRevision, (bl->chip == CHIP_BUSLOGIC_PCI) ? "07B" : "21E", sizeof(ReplyIESI->aFirmwareRevision)); - pclog("Return Extended Setup Information: %d\n", bl->CmdBuf[0]); - break; - - /* VirtualBox has these two modes implemented in reverse. - According to the BusLogic datasheet: - 0 is the strict round robin mode, which is also the one used by the AHA-154x according to the - Adaptec specification; - 1 is the aggressive round robin mode, which "hunts" for an active outgoing mailbox and then - processes it. */ - case 0x8F: - bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode = bl->CmdBuf[0] & 1; - - bl->DataReplyLeft = 0; - break; - - case 0x90: - pclog("Store Local RAM\n"); - Offset = bl->CmdBuf[0]; - bl->DataReplyLeft = 0; - memcpy(&(bl->LocalRAM.u8View[Offset]), &(bl->CmdBuf[2]), bl->CmdBuf[1]); - - bl->DataReply = 0; - break; - - case 0x91: - pclog("Fetch Local RAM\n"); - Offset = bl->CmdBuf[0]; - bl->DataReplyLeft = bl->CmdBuf[1]; - memcpy(bl->DataBuf, &(bl->LocalRAM.u8View[Offset]), bl->CmdBuf[1]); - - bl->DataReply = 0; - break; - - case 0x92: - bl->DataReplyLeft = 0; - - switch (bl->CmdBuf[0]) - { - case 0: - case 2: - BuslogicAutoSCSIRamSetDefaults(bl, 0); - break; - case 3: - BuslogicAutoSCSIRamSetDefaults(bl, 3); - break; - case 1: - f = nvr_fopen(BuslogicGetNVRFileName(bl), L"wb"); - if (f) - { - fwrite(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); - fclose(f); - f = NULL; - } - break; - default: - bl->Status |= STAT_INVCMD; - break; - } - break; - - case 0x94: - if (bl->CmdBuf[0]) - { - pclog("Invalid AutoSCSI command mode %x\n", bl->CmdBuf[0]); - bl->DataReplyLeft = 0; - bl->Status |= STAT_INVCMD; - } - else - { - bl->DataReplyLeft = bl->CmdBuf[2]; - bl->DataReplyLeft <<= 8; - bl->DataReplyLeft |= bl->CmdBuf[1]; - memcpy(bl->DataBuf, bl->AutoSCSIROM, bl->DataReplyLeft); - } - break; - - case 0x95: - if (bl->chip == CHIP_BUSLOGIC_PCI) { - if (bl->Base != 0) { - io_removehandler(bl->Base, 4, - BuslogicRead, - BuslogicReadW, - BuslogicReadL, - BuslogicWrite, - BuslogicWriteW, - BuslogicWriteL, - bl); - } - switch(bl->CmdBuf[0]) { - case 0: - bl->Base = 0x330; - break; - case 1: - bl->Base = 0x334; - break; - case 2: - bl->Base = 0x230; - break; - case 3: - bl->Base = 0x234; - break; - case 4: - bl->Base = 0x130; - break; - case 5: - bl->Base = 0x134; - break; - default: - bl->Base = 0; - break; - } - if (bl->Base != 0) { - io_sethandler(bl->Base, 4, - BuslogicRead, - BuslogicReadW, - BuslogicReadL, - BuslogicWrite, - BuslogicWriteW, - BuslogicWriteL, - bl); - } - bl->DataReplyLeft = 0; - suppress = 1; - } else { - bl->DataReplyLeft = 0; - bl->Status |= STAT_INVCMD; - } - break; - - case 0x96: - if (bl->CmdBuf[0] == 0) - bl->ExtendedLUNCCBFormat = 0; - else if (bl->CmdBuf[0] == 1) - bl->ExtendedLUNCCBFormat = 1; - - bl->DataReplyLeft = 0; - break; - - case 0x97: - case 0xA7: - /* TODO: Actually correctly implement this whole SCSI BIOS Flash stuff. */ - bl->DataReplyLeft = 0; - break; - - case 0xA8: - if (bl->chip != CHIP_BUSLOGIC_PCI) - { - bl->DataReplyLeft = 0; - bl->Status |= STAT_INVCMD; - break; - } - - Offset = bl->CmdBuf[1]; - Offset <<= 8; - Offset |= bl->CmdBuf[0]; - - bl->DataReplyLeft = bl->CmdBuf[3]; - bl->DataReplyLeft <<= 8; - bl->DataReplyLeft |= bl->CmdBuf[2]; - - memcpy(bl->DataBuf, &(bl->SCAMData[Offset]), bl->DataReplyLeft); - - bl->DataReply = 0; - break; - - case 0xA9: - if (bl->chip != CHIP_BUSLOGIC_PCI) - { - bl->DataReplyLeft = 0; - bl->Status |= STAT_INVCMD; - break; - } - - Offset = bl->CmdBuf[1]; - Offset <<= 8; - Offset |= bl->CmdBuf[0]; - - bl->DataReplyLeft = bl->CmdBuf[3]; - bl->DataReplyLeft <<= 8; - bl->DataReplyLeft |= bl->CmdBuf[2]; - - memcpy(&(bl->SCAMData[Offset]), &(bl->CmdBuf[4]), bl->DataReplyLeft); - bl->DataReplyLeft = 0; - - bl->DataReply = 0; - break; - - default: - pclog("Invalid command %x\n", bl->Command); - bl->DataReplyLeft = 0; - bl->Status |= STAT_INVCMD; - break; - } - } - - if (bl->DataReplyLeft) - { - bl->Status |= STAT_DFULL; - pclog("Data Full\n"); - } - else if (!bl->CmdParamLeft) - { - BuslogicCommandComplete(bl, suppress); - pclog("No Command Parameters Left, completing command\n"); + buslogic_log("Execute SCSI BIOS Command: received %u bytes\n", dev->CmdBuf[0]); + BuslogicSCSIBIOSRequestSetup(dev, dev->CmdBuf, dev->DataBuf, 4); } break; - - case 2: - bl->Interrupt = Val; + case 0x84: + dev->DataBuf[0] = dev->fw_rev[4]; + dev->DataReplyLeft = 1; + break; + case 0x85: + if (strlen(dev->fw_rev) == 6) + dev->DataBuf[0] = dev->fw_rev[5]; + else + dev->DataBuf[0] = ' '; + dev->DataReplyLeft = 1; + break; + case 0x86: + if (bl->chip == CHIP_BUSLOGIC_PCI) { + ReplyPI = (BuslogicPCIInformation_t *) dev->DataBuf; + memset(ReplyPI, 0, sizeof(BuslogicPCIInformation_t)); + ReplyPI->InformationIsValid = 0; + switch(dev->Base) { + case 0x330: + ReplyPI->IsaIOPort = 0; + break; + case 0x334: + ReplyPI->IsaIOPort = 1; + break; + case 0x230: + ReplyPI->IsaIOPort = 2; + break; + case 0x234: + ReplyPI->IsaIOPort = 3; + break; + case 0x130: + ReplyPI->IsaIOPort = 4; + break; + case 0x134: + ReplyPI->IsaIOPort = 5; + break; + default: + ReplyPI->IsaIOPort = 0xFF; + break; + } + ReplyPI->IRQ = dev->Irq; + dev->DataReplyLeft = sizeof(BuslogicPCIInformation_t); + } else { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + case 0x8B: + /* The reply length is set by the guest and is found in the first byte of the command buffer. */ + dev->DataReplyLeft = dev->CmdBuf[0]; + memset(dev->DataBuf, 0, dev->DataReplyLeft); + if (bl->chip == CHIP_BUSLOGIC_ISA_542) + i = 5; + else + i = 4; + cCharsToTransfer = MIN(dev->DataReplyLeft, i); + + memcpy(dev->DataBuf, &(bl->LocalRAM.structured.autoSCSIData.aHostAdaptertype[1]), cCharsToTransfer); + break; + case 0x8C: + dev->DataReplyLeft = dev->CmdBuf[0]; + memset(dev->DataBuf, 0, dev->DataReplyLeft); + break; + case 0x8D: + dev->DataReplyLeft = dev->CmdBuf[0]; + ReplyIESI = (ReplyInquireExtendedSetupInformation *)dev->DataBuf; + memset(ReplyIESI, 0, sizeof(ReplyInquireExtendedSetupInformation)); + + switch (bl->chip) { + case CHIP_BUSLOGIC_ISA_542: + case CHIP_BUSLOGIC_ISA: + case CHIP_BUSLOGIC_VLB: + ReplyIESI->uBusType = 'A'; /* ISA style */ + break; + case CHIP_BUSLOGIC_MCA: + ReplyIESI->uBusType = 'M'; /* MCA style */ + break; + case CHIP_BUSLOGIC_PCI: + ReplyIESI->uBusType = 'E'; /* PCI style */ + break; + } + ReplyIESI->uBiosAddress = 0xd8; + ReplyIESI->u16ScatterGatherLimit = 8192; + ReplyIESI->cMailbox = dev->MailboxCount; + ReplyIESI->uMailboxAddressBase = dev->MailboxOutAddr; + ReplyIESI->fHostWideSCSI = 1; /* This should be set for the BT-542B as well. */ + if (bl->chip != CHIP_BUSLOGIC_ISA_542) + ReplyIESI->fLevelSensitiveInterrupt = bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; + if (bl->chip == CHIP_BUSLOGIC_PCI) + ReplyIESI->fHostUltraSCSI = 1; + memcpy(ReplyIESI->aFirmwareRevision, &(dev->fw_rev[strlen(dev->fw_rev) - 3]), sizeof(ReplyIESI->aFirmwareRevision)); + buslogic_log("Return Extended Setup Information: %d\n", dev->CmdBuf[0]); + break; + case 0x8F: + if (bl->chip == CHIP_BUSLOGIC_ISA_542) + bl->fAggressiveRoundRobinMode = dev->CmdBuf[0] & 1; + else + bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode = dev->CmdBuf[0] & 1; + + dev->DataReplyLeft = 0; + break; + case 0x90: + buslogic_log("Store Local RAM\n"); + Offset = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + memcpy(&(bl->LocalRAM.u8View[Offset]), &(dev->CmdBuf[2]), dev->CmdBuf[1]); + + dev->DataReply = 0; + break; + case 0x91: + buslogic_log("Fetch Local RAM\n"); + Offset = dev->CmdBuf[0]; + dev->DataReplyLeft = dev->CmdBuf[1]; + memcpy(dev->DataBuf, &(bl->LocalRAM.u8View[Offset]), dev->CmdBuf[1]); + + dev->DataReply = 0; + break; + case 0x92: + if (bl->chip == CHIP_BUSLOGIC_ISA_542) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; break; - - case 3: - bl->Geometry = Val; + } + + dev->DataReplyLeft = 0; + + switch (dev->CmdBuf[0]) { + case 0: + case 2: + BuslogicAutoSCSIRamSetDefaults(dev, 0); + break; + case 3: + BuslogicAutoSCSIRamSetDefaults(dev, 3); + break; + case 1: + f = nvr_fopen(BuslogicGetNVRFileName(bl), L"wb"); + if (f) { + fwrite(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); + fclose(f); + f = NULL; + } + break; + default: + dev->Status |= STAT_INVCMD; + break; + } + break; + case 0x94: + if (bl->chip == CHIP_BUSLOGIC_ISA_542) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; break; - } -} + } + if (dev->CmdBuf[0]) { + buslogic_log("Invalid AutoSCSI command mode %x\n", dev->CmdBuf[0]); + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } else { + dev->DataReplyLeft = dev->CmdBuf[2]; + dev->DataReplyLeft <<= 8; + dev->DataReplyLeft |= dev->CmdBuf[1]; + memcpy(dev->DataBuf, bl->AutoSCSIROM, dev->DataReplyLeft); + buslogic_log("Returning AutoSCSI ROM (%04X %04X %04X %04X)\n", dev->DataBuf[0], dev->DataBuf[1], dev->DataBuf[2], dev->DataBuf[3]); + } + break; + case 0x95: + if (bl->chip == CHIP_BUSLOGIC_PCI) { + if (dev->Base != 0) + x54x_io_remove(dev, dev->Base); + if (dev->CmdBuf[0] < 6) { + dev->Base = ((3 - (dev->CmdBuf[0] >> 1)) << 8) | ((dev->CmdBuf[0] & 1) ? 0x34 : 0x30); + x54x_io_set(dev, dev->Base); + } else + dev->Base = 0; + dev->DataReplyLeft = 0; + return 1; + } else { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + case 0x96: + if (dev->CmdBuf[0] == 0) + bl->ExtendedLUNCCBFormat = 0; + else if (dev->CmdBuf[0] == 1) + bl->ExtendedLUNCCBFormat = 1; + + dev->DataReplyLeft = 0; + break; + case 0x97: + case 0xA7: + /* TODO: Actually correctly implement this whole SCSI BIOS Flash stuff. */ + dev->DataReplyLeft = 0; + break; + case 0xA8: + if (bl->chip != CHIP_BUSLOGIC_PCI) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } -static void -BuslogicWriteW(uint16_t Port, uint16_t Val, void *p) -{ - BuslogicWrite(Port, Val & 0xFF, p); -} + Offset = dev->CmdBuf[1]; + Offset <<= 8; + Offset |= dev->CmdBuf[0]; + dev->DataReplyLeft = dev->CmdBuf[3]; + dev->DataReplyLeft <<= 8; + dev->DataReplyLeft |= dev->CmdBuf[2]; -static void -BuslogicWriteL(uint16_t Port, uint32_t Val, void *p) -{ - BuslogicWrite(Port, Val & 0xFF, p); -} + memcpy(dev->DataBuf, &(bl->SCAMData[Offset]), dev->DataReplyLeft); + dev->DataReply = 0; + break; + case 0xA9: + if (bl->chip != CHIP_BUSLOGIC_PCI) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } -static void -BuslogicMemWrite(uint32_t addr, uint8_t Val, void *p) -{ - pclog("BuslogicMemWrite(%08X, %02X, %08X)\n", addr, Val, p); - BuslogicWrite(addr & 3, Val, p); -} + Offset = dev->CmdBuf[1]; + Offset <<= 8; + Offset |= dev->CmdBuf[0]; + dev->DataReplyLeft = dev->CmdBuf[3]; + dev->DataReplyLeft <<= 8; + dev->DataReplyLeft |= dev->CmdBuf[2]; -static void -BuslogicMemWriteW(uint32_t addr, uint16_t Val, void *p) -{ - pclog("BuslogicMemWriteW(%08X, %04X, %08X)\n", addr, Val, p); - BuslogicWriteW(addr & 3, Val, p); -} + memcpy(&(bl->SCAMData[Offset]), &(dev->CmdBuf[4]), dev->DataReplyLeft); + dev->DataReplyLeft = 0; - -static void -BuslogicMemWriteL(uint32_t addr, uint32_t Val, void *p) -{ - pclog("BuslogicMemWriteL(%08X, %08X, %08X)\n", addr, Val, p); - BuslogicWriteL(addr & 3, Val, p); -} - - -static void -BuslogicResetPoll(void *p) -{ - Buslogic_t *bl = (Buslogic_t *)p; - - bl->Status &= ~STAT_STST; - bl->Status |= STAT_IDLE; - - BuslogicResetCallback = 0LL; -} - - -static void -BuslogicCommandThread(void *p) -{ - Buslogic_t *bl = (Buslogic_t *)p; - -BuslogicEventRestart: - /* Create a waitable event. */ - bl->evt = thread_create_event(); - -BuslogicScanRestart: - if (bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode) - { - while (bl->MailboxCount) - { - BuslogicProcessMailbox(bl); - } + dev->DataReply = 0; + break; } + return 0; +} + + +static void +buslogic_setup_data(void *p) +{ + x54x_t *dev = (x54x_t *)p; + ReplyInquireSetupInformation *ReplyISI; + buslogic_setup_t *bl_setup; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; + bl_setup = (buslogic_setup_t *)ReplyISI->VendorSpecificData; + + bl_setup->uSignature = 'B'; + /* The 'D' signature prevents Buslogic's OS/2 drivers from getting too + * friendly with Adaptec hardware and upsetting the HBA state. + */ + bl_setup->uCharacterD = 'D'; /* BusLogic model. */ + switch(bl->chip) + { + case CHIP_BUSLOGIC_ISA_542: + case CHIP_BUSLOGIC_ISA: + bl_setup->uHostBusType = 'A'; + break; +#ifdef BUSLOGIC_NOT_WORKING + case CHIP_BUSLOGIC_MCA: + bl_setup->uHostBusType = 'B'; + break; + case CHIP_BUSLOGIC_VLB: + bl_setup->uHostBusType = 'E'; + break; +#endif + case CHIP_BUSLOGIC_PCI: + bl_setup->uHostBusType = 'F'; + break; + } +} + + +static uint8_t +buslogic_is_aggressive_mode(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + HALocalRAM *HALR = &bl->LocalRAM; + if (bl->chip == CHIP_BUSLOGIC_ISA_542) + return bl->fAggressiveRoundRobinMode; else - { - while (BuslogicProcessMailbox(bl) && bl->MailboxCount) - { - } - } + return HALR->structured.autoSCSIData.fAggressiveRoundRobinMode; +} - if (!bl->MailboxCount) - { - thread_destroy_event(bl->evt); - bl->evt = NULL; - poll_tid = NULL; - return; - } - if (bl->scan_restart) - { - bl->scan_restart = 0; - goto BuslogicScanRestart; - } +static uint8_t +buslogic_interrupt_type(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - thread_destroy_event(bl->evt); - bl->evt = NULL; + if (bl->chip == CHIP_BUSLOGIC_ISA_542) + return 0; + else + return !!bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; +} - if (bl->scan_restart) - { - bl->scan_restart = 0; - goto BuslogicEventRestart; - } - poll_tid = NULL; +static void +buslogic_reset(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - pclog("Buslogic: polling stopped.\n"); + bl->ExtendedLUNCCBFormat = 0; } @@ -2614,7 +1042,7 @@ bar_t buslogic_pci_bar[3]; static void -BuslogicBIOSUpdate(Buslogic_t *bl) +BuslogicBIOSUpdate(buslogic_data_t *bl) { int bios_enabled = buslogic_pci_bar[2].addr_regs[0] & 0x01; @@ -2627,9 +1055,9 @@ BuslogicBIOSUpdate(Buslogic_t *bl) mem_mapping_enable(&bl->bios.mapping); mem_mapping_set_addr(&bl->bios.mapping, bl->bios_addr, bl->bios_size); - pclog("BT-958D: BIOS now at: %06X\n", bl->bios_addr); + buslogic_log("BT-958D: BIOS now at: %06X\n", bl->bios_addr); } else { - pclog("BT-958D: BIOS disabled\n"); + buslogic_log("BT-958D: BIOS disabled\n"); mem_mapping_disable(&bl->bios.mapping); } } @@ -2637,9 +1065,10 @@ BuslogicBIOSUpdate(Buslogic_t *bl) static uint8_t BuslogicPCIRead(int func, int addr, void *p) { - Buslogic_t *bl = (Buslogic_t *)p; + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - pclog("BT-958D: Reading register %02X\n", addr & 0xff); + buslogic_log("BT-958D: Reading register %02X\n", addr & 0xff); switch (addr) { case 0x00: @@ -2691,22 +1120,22 @@ BuslogicPCIRead(int func, int addr, void *p) case 0x2F: return 0x10; case 0x30: /* PCI_ROMBAR */ - pclog("BT-958D: BIOS BAR 00 = %02X\n", buslogic_pci_bar[2].addr_regs[0] & 0x01); + buslogic_log("BT-958D: BIOS BAR 00 = %02X\n", buslogic_pci_bar[2].addr_regs[0] & 0x01); return buslogic_pci_bar[2].addr_regs[0] & 0x01; case 0x31: /* PCI_ROMBAR 15:11 */ - pclog("BT-958D: BIOS BAR 01 = %02X\n", (buslogic_pci_bar[2].addr_regs[1] & bl->bios_mask)); + buslogic_log("BT-958D: BIOS BAR 01 = %02X\n", (buslogic_pci_bar[2].addr_regs[1] & bl->bios_mask)); return buslogic_pci_bar[2].addr_regs[1]; break; case 0x32: /* PCI_ROMBAR 23:16 */ - pclog("BT-958D: BIOS BAR 02 = %02X\n", buslogic_pci_bar[2].addr_regs[2]); + buslogic_log("BT-958D: BIOS BAR 02 = %02X\n", buslogic_pci_bar[2].addr_regs[2]); return buslogic_pci_bar[2].addr_regs[2]; break; case 0x33: /* PCI_ROMBAR 31:24 */ - pclog("BT-958D: BIOS BAR 03 = %02X\n", buslogic_pci_bar[2].addr_regs[3]); + buslogic_log("BT-958D: BIOS BAR 03 = %02X\n", buslogic_pci_bar[2].addr_regs[3]); return buslogic_pci_bar[2].addr_regs[3]; break; case 0x3C: - return bl->Irq; + return dev->Irq; case 0x3D: return PCI_INTA; } @@ -2718,32 +1147,26 @@ BuslogicPCIRead(int func, int addr, void *p) static void BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) { - Buslogic_t *bl = (Buslogic_t *)p; + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + uint8_t valxor; - pclog("BT-958D: Write value %02X to register %02X\n", val, addr & 0xff); + buslogic_log("BT-958D: Write value %02X to register %02X\n", val, addr & 0xff); switch (addr) { case 0x04: valxor = (val & 0x27) ^ buslogic_pci_regs[addr]; if (valxor & PCI_COMMAND_IO) { - io_removehandler(bl->PCIBase, 0x20, - BuslogicRead, BuslogicReadW, BuslogicReadL, - BuslogicWrite, BuslogicWriteW, BuslogicWriteL, - bl); + x54x_io_remove(dev, bl->PCIBase); if ((bl->PCIBase != 0) && (val & PCI_COMMAND_IO)) { - io_sethandler(bl->PCIBase, 0x0020, - BuslogicRead, BuslogicReadW, - BuslogicReadL, BuslogicWrite, - BuslogicWriteW, BuslogicWriteL, - bl); + x54x_io_set(dev, bl->PCIBase); } } if (valxor & PCI_COMMAND_MEM) { - mem_mapping_disable(&bl->mmio_mapping); + x54x_mem_disable(dev); if ((bl->MMIOBase != 0) & (val & PCI_COMMAND_MEM)) { - mem_mapping_set_addr(&bl->mmio_mapping, - bl->MMIOBase, 0x20); + x54x_mem_set_addr(dev, bl->MMIOBase); } } buslogic_pci_regs[addr] = val & 0x27; @@ -2756,24 +1179,17 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) case 0x11: case 0x12: case 0x13: /* I/O Base set. */ /* First, remove the old I/O. */ - io_removehandler(bl->PCIBase, 0x0020, - BuslogicRead, BuslogicReadW, BuslogicReadL, - BuslogicWrite, BuslogicWriteW, BuslogicWriteL, - bl); + x54x_io_remove(dev, bl->PCIBase); /* Then let's set the PCI regs. */ buslogic_pci_bar[0].addr_regs[addr & 3] = val; /* Then let's calculate the new I/O base. */ bl->PCIBase = buslogic_pci_bar[0].addr & 0xffe0; /* Log the new base. */ - pclog("BusLogic PCI: New I/O base is %04X\n" , bl->PCIBase); + buslogic_log("BusLogic PCI: New I/O base is %04X\n" , bl->PCIBase); /* We're done, so get out of the here. */ if (buslogic_pci_regs[4] & PCI_COMMAND_IO) { if (bl->PCIBase != 0) { - io_sethandler(bl->PCIBase, 0x0020, - BuslogicRead, BuslogicReadW, - BuslogicReadL, BuslogicWrite, - BuslogicWriteW, BuslogicWriteL, - bl); + x54x_io_set(dev, bl->PCIBase); } } return; @@ -2782,20 +1198,19 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) val &= 0xe0; case 0x15: case 0x16: case 0x17: - /* I/O Base set. */ + /* MMIO Base set. */ /* First, remove the old I/O. */ - mem_mapping_disable(&bl->mmio_mapping); + x54x_mem_disable(dev); /* Then let's set the PCI regs. */ buslogic_pci_bar[1].addr_regs[addr & 3] = val; /* Then let's calculate the new I/O base. */ bl->MMIOBase = buslogic_pci_bar[1].addr & 0xffffffe0; /* Log the new base. */ - pclog("BusLogic PCI: New MMIO base is %04X\n" , bl->MMIOBase); + buslogic_log("BusLogic PCI: New MMIO base is %04X\n" , bl->MMIOBase); /* We're done, so get out of the here. */ if (buslogic_pci_regs[4] & PCI_COMMAND_MEM) { if (bl->MMIOBase != 0) { - mem_mapping_set_addr(&bl->mmio_mapping, - bl->MMIOBase, 0x20); + x54x_mem_set_addr(dev, bl->MMIOBase); } } return; @@ -2807,15 +1222,15 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) buslogic_pci_bar[2].addr_regs[addr & 3] = val; buslogic_pci_bar[2].addr &= 0xffffc001; bl->bios_addr = buslogic_pci_bar[2].addr & 0xffffc000; - pclog("BT-958D: BIOS BAR %02X = NOW %02X (%02X)\n", addr & 3, buslogic_pci_bar[2].addr_regs[addr & 3], val); + buslogic_log("BT-958D: BIOS BAR %02X = NOW %02X (%02X)\n", addr & 3, buslogic_pci_bar[2].addr_regs[addr & 3], val); BuslogicBIOSUpdate(bl); return; case 0x3C: buslogic_pci_regs[addr] = val; if (val != 0xFF) { - BuslogicLog("BusLogic IRQ now: %i\n", val); - bl->Irq = val; + buslogic_log("BusLogic IRQ now: %i\n", val); + dev->Irq = val; } return; } @@ -2823,42 +1238,42 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) static void -BuslogicInitializeLocalRAM(Buslogic_t *bl) +BuslogicInitializeLocalRAM(buslogic_data_t *bl) { - memset(bl->LocalRAM.u8View, 0, sizeof(HALocalRAM)); - if (PCI && (bl->chip == CHIP_BUSLOGIC_PCI)) - { - bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 1; - } - else - { - bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 0; - } - bl->LocalRAM.structured.autoSCSIData.u16DeviceEnabledMask = ~0; - bl->LocalRAM.structured.autoSCSIData.u16WidePermittedMask = ~0; - bl->LocalRAM.structured.autoSCSIData.u16FastPermittedMask = ~0; - bl->LocalRAM.structured.autoSCSIData.u16SynchronousPermittedMask = ~0; - bl->LocalRAM.structured.autoSCSIData.u16DisconnectPermittedMask = ~0; - bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode = 0; - bl->LocalRAM.structured.autoSCSIData.u16UltraPermittedMask = ~0; + memset(bl->LocalRAM.u8View, 0, sizeof(HALocalRAM)); + if (bl->chip == CHIP_BUSLOGIC_PCI) { + bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 1; + } else { + bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 0; + } + + bl->LocalRAM.structured.autoSCSIData.u16DeviceEnabledMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16WidePermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16FastPermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16SynchronousPermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16DisconnectPermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.fAggressiveRoundRobinMode = 0; + bl->LocalRAM.structured.autoSCSIData.u16UltraPermittedMask = ~0; } void BuslogicDeviceReset(void *p) { - Buslogic_t *dev = (Buslogic_t *) p; - BuslogicResetControl(dev, 1); + x54x_t *dev = (x54x_t *) p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; - BuslogicInitializeLocalRAM(dev); - BuslogicInitializeAutoSCSIRam(dev); + x54x_reset_ctrl(dev, 1); + + BuslogicInitializeLocalRAM(bl); + BuslogicInitializeAutoSCSIRam(dev); } static void * -Buslogic_Init(device_t *info) +buslogic_init(device_t *info) { - Buslogic_t *bl; + x54x_t *dev; wchar_t *bios_rom_name; uint16_t bios_rom_size; uint16_t bios_rom_mask; @@ -2869,168 +1284,170 @@ Buslogic_Init(device_t *info) wchar_t *scam_rom_name; uint16_t scam_rom_size; FILE *f; + buslogic_data_t *bl; - bl = malloc(sizeof(Buslogic_t)); - memset(bl, 0x00, sizeof(Buslogic_t)); + /* Call common initializer. */ + dev = x54x_init(info); + + dev->ven_data = malloc(sizeof(buslogic_data_t)); + memset(dev->ven_data, 0x00, sizeof(buslogic_data_t)); + + bl = (buslogic_data_t *) dev->ven_data; + + dev->bus = info->flags; + dev->Base = device_get_config_hex16("base"); + dev->Irq = device_get_config_int("irq"); + dev->DmaChannel = device_get_config_int("dma"); + dev->HostID = 7; /* default HA ID */ + dev->setup_info_len = sizeof(buslogic_setup_t); + dev->reset_duration = BUSLOGIC_RESET_DURATION_US; + dev->max_id = 7; + dev->int_geom_writable = 1; bl->chip = info->local; - bl->Base = device_get_config_hex16("base"); bl->PCIBase = 0; bl->MMIOBase = 0; - bl->Irq = device_get_config_int("irq"); - bl->DmaChannel = device_get_config_int("dma"); bl->has_bios = device_get_config_int("bios"); - if (bl->Base != 0) { - if (bl->chip == CHIP_BUSLOGIC_PCI) { - io_sethandler(bl->Base, 4, - BuslogicRead, BuslogicReadW, BuslogicReadL, - BuslogicWrite, BuslogicWriteW, BuslogicWriteL, - bl); - } else { - io_sethandler(bl->Base, 4, - BuslogicRead, BuslogicReadW, NULL, - BuslogicWrite, BuslogicWriteW, NULL, bl); - } + dev->ven_cmd_phase1 = buslogic_cmd_phase1; + dev->ven_get_host_id = buslogic_get_host_id; + dev->ven_get_irq = buslogic_get_irq; + dev->ven_get_dma = buslogic_get_dma; + dev->get_ven_param_len = buslogic_param_len; + dev->ven_cmds = buslogic_cmds; + dev->interrupt_type = buslogic_interrupt_type; + dev->is_aggressive_mode = buslogic_is_aggressive_mode; + dev->get_ven_data = buslogic_setup_data; + dev->ven_reset = buslogic_reset; + + strcpy(dev->vendor, "BusLogic"); + + if ((dev->Base != 0) && !(dev->bus & DEVICE_MCA)) { + x54x_io_set(dev, dev->Base); } + switch(bl->chip) + { + case CHIP_BUSLOGIC_ISA_542: + strcpy(dev->name, "BT-542BH"); + bios_rom_name = L"roms/scsi/buslogic/BT-542BH_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "AA335"; + bl->fAggressiveRoundRobinMode = 1; + break; + case CHIP_BUSLOGIC_ISA: + default: + strcpy(dev->name, "BT-545S"); + bios_rom_name = L"roms/scsi/buslogic/BT-545S_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = L"roms/scsi/buslogic/BT-545S_AutoSCSI.rom"; + autoscsi_rom_size = 0x4000; + has_scam_rom = 0; + dev->fw_rev = "AA421E"; + break; +#ifdef BUSLOGIC_NOT_WORKING + case CHIP_BUSLOGIC_MCA: + strcpy(dev->name, "BT-640A"); + bios_rom_name = L"roms/scsi/buslogic/BT-640_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = L"roms/scsi/buslogic/BT-640_AutoSCSI.rom"; + autoscsi_rom_size = 0x4000; + has_scam_rom = 0; + dev->fw_rev = "BA421E"; + break; +#endif + case CHIP_BUSLOGIC_PCI: + strcpy(dev->name, "BT-958D"); + bios_rom_name = L"roms/scsi/buslogic/BT-958D_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = L"roms/scsi/buslogic/BT-958D_AutoSCSI.rom"; + autoscsi_rom_size = 0x8000; + has_scam_rom = 1; + scam_rom_name = L"roms/scsi/buslogic/BT-958D_SCAM.rom"; + scam_rom_size = 0x0200; + dev->fw_rev = "AA507B"; + break; + } - switch(bl->chip) - { - case CHIP_BUSLOGIC_ISA: - default: - bios_rom_name = L"roms/scsi/buslogic/BT-545C_BIOS.rom"; - bios_rom_size = 0x4000; - bios_rom_mask = 0x3fff; - has_autoscsi_rom = 1; - autoscsi_rom_name = L"roms/scsi/buslogic/BT-545C_AutoSCSI.rom"; - autoscsi_rom_size = 0x4000; - has_scam_rom = 0; - break; - case CHIP_BUSLOGIC_PCI: - bios_rom_name = L"roms/scsi/buslogic/BT-958D_BIOS.rom"; - bios_rom_size = 0x4000; - bios_rom_mask = 0x3fff; - has_autoscsi_rom = 1; - autoscsi_rom_name = L"roms/scsi/buslogic/BT-958D_AutoSCSI.rom"; - autoscsi_rom_size = 0x8000; - has_scam_rom = 1; - scam_rom_name = L"roms/scsi/buslogic/BT-958D_SCAM.rom"; - scam_rom_size = 0x0200; - break; - } + memset(bl->AutoSCSIROM, 0xff, 32768); + memset(bl->SCAMData, 0x00, 65536); - memset(bl->AutoSCSIROM, 0xff, 32768); + if (bl->has_bios) + { + bl->bios_size = bios_rom_size; - memset(bl->SCAMData, 0x00, 65536); + bl->bios_mask = 0xffffc000; + rom_init(&bl->bios, bios_rom_name, 0xd8000, bios_rom_size, bios_rom_mask, 0, MEM_MAPPING_EXTERNAL); - if (bl->has_bios) - { - bl->bios_size = bios_rom_size; - - bl->bios_mask = 0xffffc000; - - rom_init(&bl->bios, bios_rom_name, 0xd8000, bios_rom_size, bios_rom_mask, 0, MEM_MAPPING_EXTERNAL); - - if (has_autoscsi_rom) - { - f = rom_fopen(autoscsi_rom_name, L"rb"); - if (f) - { - fread(bl->AutoSCSIROM, 1, autoscsi_rom_size, f); - fclose(f); - f = NULL; - } - } - - if (has_scam_rom) - { - f = rom_fopen(scam_rom_name, L"rb"); - if (f) - { - fread(bl->SCAMData, 1, scam_rom_size, f); - fclose(f); - f = NULL; - } + if (has_autoscsi_rom) { + f = rom_fopen(autoscsi_rom_name, L"rb"); + if (f) { + fread(bl->AutoSCSIROM, 1, autoscsi_rom_size, f); + fclose(f); + f = NULL; } } - else - { - bl->bios_size = 0; - bl->bios_mask = 0; + if (has_scam_rom) { + f = rom_fopen(scam_rom_name, L"rb"); + if (f) { + fread(bl->SCAMData, 1, scam_rom_size, f); + fclose(f); + f = NULL; + } } + } + else { + bl->bios_size = 0; - timer_add(BuslogicResetPoll, - &BuslogicResetCallback, &BuslogicResetCallback, bl); + bl->bios_mask = 0; + } if (bl->chip == CHIP_BUSLOGIC_PCI) { - bl->Card = pci_add_card(PCI_ADD_NORMAL, BuslogicPCIRead, BuslogicPCIWrite, bl); + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, BuslogicPCIRead, BuslogicPCIWrite, dev); buslogic_pci_bar[0].addr_regs[0] = 1; buslogic_pci_bar[1].addr_regs[0] = 0; buslogic_pci_regs[0x04] = 3; -#if 0 - buslogic_pci_regs[0x05] = 0; - buslogic_pci_regs[0x07] = 2; -#endif /* Enable our BIOS space in PCI, if needed. */ - if (bl->has_bios) - { + if (bl->has_bios) { buslogic_pci_bar[2].addr = 0xFFFFC000; - } - else - { + } else { buslogic_pci_bar[2].addr = 0; } - mem_mapping_add(&bl->mmio_mapping, 0xfffd0000, 0x20, - BuslogicMemRead, BuslogicMemReadW, BuslogicMemReadL, - BuslogicMemWrite, BuslogicMemWriteW, BuslogicMemWriteL, - NULL, MEM_MAPPING_EXTERNAL, bl); - mem_mapping_disable(&bl->mmio_mapping); + x54x_mem_init(dev, 0xfffd0000); + x54x_mem_disable(dev); + mem_mapping_disable(&bl->bios.mapping); } - pclog("Buslogic on port 0x%04X\n", bl->Base); + buslogic_log("Buslogic on port 0x%04X\n", dev->Base); - BuslogicResetControl(bl, CTRL_HRST); + x54x_reset_ctrl(dev, CTRL_HRST); - BuslogicInitializeLocalRAM(bl); - BuslogicInitializeAutoSCSIRam(bl); - - return(bl); -} - - -static void -BuslogicClose(void *p) -{ - Buslogic_t *bl = (Buslogic_t *)p; - if (bl) - { - if (bl->evt) - { - thread_destroy_event(bl->evt); - bl->evt = NULL; - - if (poll_tid) - { - thread_kill(poll_tid); - poll_tid = NULL; - } - } - - free(bl); - bl = NULL; + if (bl->chip != CHIP_BUSLOGIC_ISA_542) { + BuslogicInitializeLocalRAM(bl); + BuslogicInitializeAutoSCSIRam(dev); } + + return(dev); } -static device_config_t BT545C_Config[] = { +static device_config_t BT_ISA_Config[] = { { "base", "Address", CONFIG_HEX16, "", 0x334, { @@ -3149,19 +1566,28 @@ static device_config_t BT958D_Config[] = { device_t buslogic_device = { - "Buslogic BT-545C ISA", + "Buslogic BT-542BH ISA", + DEVICE_ISA | DEVICE_AT, + CHIP_BUSLOGIC_ISA_542, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, NULL, + BT_ISA_Config +}; + +device_t buslogic_545s_device = { + "Buslogic BT-545S ISA", DEVICE_ISA | DEVICE_AT, CHIP_BUSLOGIC_ISA, - Buslogic_Init, BuslogicClose, NULL, + buslogic_init, x54x_close, NULL, NULL, NULL, NULL, NULL, - BT545C_Config + BT_ISA_Config }; device_t buslogic_pci_device = { "Buslogic BT-958D PCI", DEVICE_PCI, CHIP_BUSLOGIC_PCI, - Buslogic_Init, BuslogicClose, NULL, + buslogic_init, x54x_close, NULL, NULL, NULL, NULL, NULL, BT958D_Config }; diff --git a/src/scsi/scsi_buslogic.h b/src/scsi/scsi_buslogic.h index f6d60f94d..398e3db25 100644 --- a/src/scsi/scsi_buslogic.h +++ b/src/scsi/scsi_buslogic.h @@ -7,7 +7,7 @@ * Emulation of BusLogic BT-542B ISA and BT-958D PCI SCSI * controllers. * - * Version: @(#)scsi_buslogic.h 1.0.1 2017/08/23 + * Version: @(#)scsi_buslogic.h 1.0.2 2017/10/14 * * Authors: TheCollector1995, * Miran Grca, @@ -21,6 +21,7 @@ extern device_t buslogic_device; +extern device_t buslogic_545s_device; extern device_t buslogic_pci_device; extern void BuslogicDeviceReset(void *p); diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index 036045d6f..87ca35848 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -295,7 +295,7 @@ void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, break; default: id = 0; - break; + return; } /* @@ -322,7 +322,7 @@ void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, scsi_device_target_phase_callback(lun_type, id); } else { /* Command first phase complete - call the callback to execute the second phase. */ - if (SCSIPhase != SCSI_PHASE_DATA_OUT) + if (SCSIPhase == SCSI_PHASE_STATUS) { scsi_device_target_phase_callback(lun_type, id); SCSIStatus = scsi_device_target_err_stat_to_scsi(lun_type, id); @@ -352,7 +352,7 @@ void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun) break; default: id = 0; - break; + return; } scsi_device_target_phase_callback(lun_type, id); @@ -360,3 +360,8 @@ void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun) /* Command second phase complete - call the callback to complete the command. */ scsi_device_target_phase_callback(lun_type, id); } + +int32_t *scsi_device_get_buf_len(uint8_t scsi_id, uint8_t scsi_lun) +{ + return &SCSIDevices[scsi_id][scsi_lun].BufferLength; +} diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index 561a5f339..fd5f21c14 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -27,7 +27,6 @@ typedef struct int command_pos; uint8_t command[20]; int data_pos; - uint8_t buffer[390144]; int change_state_delay; int new_req_delay; @@ -51,10 +50,10 @@ extern void scsi_device_command(uint8_t id, uint8_t lun, int cdb_len, extern void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb); extern void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun); +extern int32_t *scsi_device_get_buf_len(uint8_t scsi_id, uint8_t scsi_lun); extern int scsi_bus_update(scsi_bus_t *bus, int bus_assert); extern int scsi_bus_read(scsi_bus_t *bus); extern int scsi_bus_match(scsi_bus_t *bus, int bus_assert); - #endif /*SCSI_DEVICE_H*/ diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 2a1536f85..0a82e62e6 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -6,7 +6,7 @@ * * Emulation of SCSI fixed and removable disks. * - * Version: @(#)scsi_disk.c 1.0.14 2017/10/12 + * Version: @(#)scsi_disk.c 1.0.15 2017/10/14 * * Author: Miran Grca, * Copyright 2017 Miran Grca. @@ -125,36 +125,36 @@ uint8_t scsi_hd_command_flags[0x100] = { }; -uint64_t scsi_hd_mode_sense_page_flags[HDD_NUM] = { (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES), - (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << GPMODE_ALL_PAGES) }; +uint64_t scsi_hd_mode_sense_page_flags[HDD_NUM] = { (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F), + (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F) }; /* This should be done in a better way but for time being, it's been done this way so it's not as huge and more readable. */ const uint8_t scsi_hd_mode_sense_pages_default[HDD_NUM][0x40][0x40] = @@ -439,7 +439,6 @@ uint8_t scsi_hd_mode_sense_pages_saved[HDD_NUM][0x40][0x40] = [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } } }; -#define ENABLE_SCSI_HD_LOG 0 int scsi_hd_do_log = 0; @@ -1318,6 +1317,10 @@ void scsi_hd_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length) memset(buffer, 0, alloc_length); memcpy(buffer, shdc[id].sense, alloc_length); } + else + { + return; + } buffer[0] = 0x70; @@ -1392,9 +1395,9 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) 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 }; - uint8_t *tempbuffer; 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; @@ -1469,16 +1472,15 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) 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 ((SCSI_BufferLength == -1) || (cdb[4] < SCSI_BufferLength)) + if ((*BufLen == -1) || (cdb[4] < *BufLen)) { - SCSI_BufferLength = cdb[4]; + *BufLen = cdb[4]; } - if (SCSI_BufferLength < cdb[4]) + if (*BufLen < cdb[4]) { - cdb[4] = SCSI_BufferLength; + cdb[4] = *BufLen; } - scsi_hd_request_sense(id, hdbufferb, cdb[4]); SCSIPhase = SCSI_PHASE_DATA_IN; scsi_hd_data_command_finish(id, 18, 18, cdb[4], 0); @@ -1487,14 +1489,11 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) case GPCMD_MECHANISM_STATUS: len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } - memset(hdbufferb, 0, 8); - hdbufferb[5] = 1; - SCSIPhase = SCSI_PHASE_DATA_IN; scsi_hd_data_command_finish(id, 8, 8, len, 0); break; @@ -1524,9 +1523,10 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) return; } - if ((!shdc[id].sector_len) || (SCSI_BufferLength == 0)) + if ((!shdc[id].sector_len) || (*BufLen == 0)) { SCSIPhase = 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; @@ -1538,23 +1538,13 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) alloc_length = shdc[id].packet_len = max_len << 9; - if ((SCSI_BufferLength == -1) || (alloc_length < SCSI_BufferLength)) + if ((*BufLen == -1) || (alloc_length < *BufLen)) { - SCSI_BufferLength = alloc_length; + *BufLen = alloc_length; } - if ((shdc[id].requested_blocks > 0) && (SCSI_BufferLength > 0)) - { - if (alloc_length > SCSI_BufferLength) - { - hdd_image_read(id, shdc[id].sector_pos, SCSI_BufferLength >> 9, hdbufferb); - } - else - { - hdd_image_read(id, shdc[id].sector_pos, max_len, hdbufferb); - } - } SCSIPhase = 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); @@ -1564,113 +1554,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 0); } shdc[id].all_blocks_total = shdc[id].block_total; - if (shdc[id].packet_status != CDROM_PHASE_COMPLETE) - { - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); - } - else - { - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - } - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - SCSIPhase = 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; - - if (!(scsi_hd_mode_sense_page_flags[id] & (1LL << shdc[id].current_page_code))) - { - scsi_hd_invalid_field(id); - return; - } - - memset(hdbufferb, 0, len); - alloc_length = len; - - if (cdb[0] == GPCMD_MODE_SENSE_6) - { - len = scsi_hd_mode_sense(id, hdbufferb, 4, cdb[2], block_desc); - if (len > alloc_length) - { - len = alloc_length; - } - hdbufferb[0] = len - 1; - hdbufferb[1] = 0; - if (block_desc) - { - hdbufferb[3] = 8; - } - } - else - { - len = scsi_hd_mode_sense(id, hdbufferb, 8, cdb[2], block_desc); - if (len > alloc_length) - { - len = alloc_length; - } - hdbufferb[0]=(len - 2) >> 8; - hdbufferb[1]=(len - 2) & 255; - hdbufferb[2] = 0; - if (block_desc) - { - hdbufferb[6] = 0; - hdbufferb[7] = 8; - } - } - - if (len > alloc_length) - { - len = alloc_length; - } - else if (len < alloc_length) - { - alloc_length = len; - } - - if ((SCSI_BufferLength == -1) || (alloc_length < SCSI_BufferLength)) - { - SCSI_BufferLength = 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: - SCSIPhase = SCSI_PHASE_DATA_OUT; - - if (cdb[0] == GPCMD_MODE_SELECT_6) - { - len = cdb[4]; - } - else - { - len = (cdb[7] << 8) | cdb[8]; - } - - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) - { - SCSI_BufferLength = len; - } - - scsi_hd_mode_select_init(id, cdb[0], len, cdb[1] & 1); - - scsi_hd_data_command_finish(id, len, len, len, 1); + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 1); return; case GPCMD_WRITE_6: @@ -1706,9 +1590,10 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) return; } - if ((!shdc[id].sector_len) || (SCSI_BufferLength == 0)) + if ((!shdc[id].sector_len) || (*BufLen == 0)) { SCSIPhase = 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; @@ -1720,9 +1605,9 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) alloc_length = shdc[id].packet_len = max_len << 9; - if ((SCSI_BufferLength == -1) || (alloc_length < SCSI_BufferLength)) + if ((*BufLen == -1) || (alloc_length < *BufLen)) { - SCSI_BufferLength = alloc_length; + *BufLen = alloc_length; } SCSIPhase = SCSI_PHASE_DATA_OUT; @@ -1739,6 +1624,106 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) 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: + SCSIPhase = 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; + + if (!(scsi_hd_mode_sense_page_flags[id] & (1LL << shdc[id].current_page_code))) + { + scsi_hd_invalid_field(id); + return; + } + + memset(hdbufferb, 0, len); + alloc_length = len; + + shdc[id].temp_buffer = (uint8_t *) malloc(256); + 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) + { + hdbufferb[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; + } + } + + 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: + SCSIPhase = 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; + } + + scsi_hd_mode_select_init(id, cdb[0], len, cdb[1] & 1); + + scsi_hd_data_command_finish(id, len, len, len, 1); + return; + case GPCMD_START_STOP_UNIT: if (hdd[id].bus != HDD_BUS_SCSI_REMOVABLE) { @@ -1768,7 +1753,7 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) max_len <<= 8; max_len |= cdb[4]; - if ((!max_len) || (SCSI_BufferLength == 0)) + if ((!max_len) || (*BufLen == 0)) { SCSIPhase = SCSI_PHASE_STATUS; /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ @@ -1777,36 +1762,38 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) break; } - tempbuffer = malloc(1024); + shdc[id].temp_buffer = malloc(1024); if (cdb[1] & 1) { preamble_len = 4; size_idx = 3; - tempbuffer[idx++] = 05; - tempbuffer[idx++] = cdb[2]; - tempbuffer[idx++] = 0; + shdc[id].temp_buffer[idx++] = 05; + shdc[id].temp_buffer[idx++] = cdb[2]; + shdc[id].temp_buffer[idx++] = 0; idx++; switch (cdb[2]) { case 0x00: - tempbuffer[idx++] = 0x00; - tempbuffer[idx++] = 0x83; + 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; } - tempbuffer[idx++] = 0x02; - tempbuffer[idx++] = 0x00; - tempbuffer[idx++] = 0x00; - tempbuffer[idx++] = 20; + 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(hdbufferb + idx, 20, "53R141"); /* Serial */ idx += 20; @@ -1814,19 +1801,21 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) { goto atapi_out; } - tempbuffer[idx++] = 0x02; - tempbuffer[idx++] = 0x01; - tempbuffer[idx++] = 0x00; - tempbuffer[idx++] = 68; - ide_padstr8(tempbuffer + idx, 8, EMU_NAME); /* Vendor */ + 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(tempbuffer + idx, 40, device_identify_ex); /* Product */ + ide_padstr8(shdc[id].temp_buffer + idx, 40, device_identify_ex); /* Product */ idx += 40; - ide_padstr8(tempbuffer + idx, 20, "53R141"); /* Product */ + 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; } @@ -1836,48 +1825,46 @@ void scsi_hd_command(uint8_t id, uint8_t *cdb) preamble_len = 5; size_idx = 4; - memset(tempbuffer, 0, 8); - tempbuffer[0] = 0; /*SCSI HD*/ + memset(shdc[id].temp_buffer, 0, 8); + shdc[id].temp_buffer[0] = 0; /*SCSI HD*/ if (hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) { - tempbuffer[1] = 0x80; /*Removable*/ + shdc[id].temp_buffer[1] = 0x80; /*Removable*/ } else { - tempbuffer[1] = 0; /*Fixed*/ + shdc[id].temp_buffer[1] = 0; /*Fixed*/ } - tempbuffer[2] = 0x02; /*SCSI-2 compliant*/ - tempbuffer[3] = 0x02; - tempbuffer[4] = 31; + shdc[id].temp_buffer[2] = 0x02; /*SCSI-2 compliant*/ + shdc[id].temp_buffer[3] = 0x02; + shdc[id].temp_buffer[4] = 31; - ide_padstr8(tempbuffer + 8, 8, EMU_NAME); /* Vendor */ - ide_padstr8(tempbuffer + 16, 16, device_identify); /* Product */ - ide_padstr8(tempbuffer + 32, 4, EMU_VERSION); /* Revision */ + 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; } atapi_out: - tempbuffer[size_idx] = idx - preamble_len; + 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 ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } - if (len > SCSI_BufferLength) + if (len > *BufLen) { - len = SCSI_BufferLength; + len = *BufLen; } - - memcpy(hdbufferb, tempbuffer, len); - - free(tempbuffer); SCSIPhase = SCSI_PHASE_DATA_IN; scsi_hd_data_command_finish(id, len, len, max_len, 0); @@ -1906,14 +1893,17 @@ atapi_out: break; case GPCMD_READ_CDROM_CAPACITY: - if (scsi_hd_read_capacity(id, shdc[id].current_cdb, hdbufferb, &len) == 0) + shdc[id].temp_buffer = (uint8_t *) malloc(8); + + if (scsi_hd_read_capacity(id, shdc[id].current_cdb, shdc[id].temp_buffer, &len) == 0) { + SCSIPhase = SCSI_PHASE_STATUS; return; } - if ((SCSI_BufferLength == -1) || (len < SCSI_BufferLength)) + if ((*BufLen == -1) || (len < *BufLen)) { - SCSI_BufferLength = len; + *BufLen = len; } SCSIPhase = SCSI_PHASE_DATA_IN; @@ -1967,6 +1957,66 @@ int scsi_hd_mode_select_return(uint8_t id, int ret) } } +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"); + SCSIPhase = 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); + 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; + } + + SCSIPhase = SCSI_PHASE_STATUS; + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); +} + void scsi_hd_phase_data_out(uint8_t id) { int ret = 0; @@ -1975,11 +2025,36 @@ void scsi_hd_phase_data_out(uint8_t id) int in_data_length = 0; int i; + int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + + if (!*BufLen) + { + SCSIPhase = 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_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_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_MODE_SELECT_6: case GPCMD_MODE_SELECT_10: - in_data_length = SCSI_BufferLength; + in_data_length = *BufLen; for (i = 0; i < in_data_length; i++) { @@ -1996,30 +2071,13 @@ void scsi_hd_phase_data_out(uint8_t id) } } break; - case GPCMD_WRITE_6: - case GPCMD_WRITE_10: - case GPCMD_WRITE_12: - if ((shdc[id].requested_blocks > 0) && (SCSI_BufferLength > 0)) - { - if (shdc[id].packet_len > SCSI_BufferLength) - { - hdd_image_write(id, shdc[id].sector_pos, SCSI_BufferLength >> 9, hdbufferb); - } - else - { - hdd_image_write(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); - } - } - scsi_hd_log("HDD image written\n"); - - SCSIPhase = SCSI_PHASE_STATUS; - - ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); - break; default: fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); break; } + + SCSIPhase = SCSI_PHASE_STATUS; + ui_sb_update_icon((hdd[id].bus == HDD_BUS_SCSI_REMOVABLE) ? (SB_RDISK | id) : (SB_HDD | HDD_BUS_SCSI), 0); } /* If the result is 1, issue an IRQ, otherwise not. */ @@ -2060,6 +2118,7 @@ void scsi_hd_callback(uint8_t id) 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; diff --git a/src/scsi/scsi_disk.h b/src/scsi/scsi_disk.h index 199bd018c..5a1a48c4f 100644 --- a/src/scsi/scsi_disk.h +++ b/src/scsi/scsi_disk.h @@ -6,7 +6,7 @@ * * Emulation of SCSI fixed and removable disks. * - * Version: @(#)scsi_disk.h 1.0.2 2017/09/29 + * Version: @(#)scsi_disk.h 1.0.3 2017/10/14 * * Author: Miran Grca, * Copyright 2017 Miran Grca. @@ -54,6 +54,8 @@ typedef struct { int do_page_save; int block_descriptor_len; + + uint8_t *temp_buffer; } scsi_hard_disk_t; diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 27c5c442c..5f2f24ee2 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -100,6 +100,7 @@ typedef struct { uint8_t tcr; uint8_t ser; uint8_t isr; + uint8_t output_data; int target_bsy; int target_req; @@ -211,7 +212,7 @@ get_bus_host(ncr5380_t *ncr) if (ncr->mode & MODE_ARBITRATE) bus_host |= BUS_ARB; - return(bus_host | BUS_SETDATA(SCSI_BufferLength)); + return(bus_host | BUS_SETDATA(ncr->output_data)); } @@ -227,13 +228,13 @@ ncr_write(uint16_t port, uint8_t val, void *priv) #endif switch (port & 7) { case 0: /* Output data register */ - SCSI_BufferLength = val; + ncr->output_data = val; break; case 1: /* Initiator Command Register */ if ((val & (ICR_BSY | ICR_SEL)) == (ICR_BSY | ICR_SEL) && (ncr->icr & (ICR_BSY | ICR_SEL)) == ICR_SEL) { - uint8_t temp = SCSI_BufferLength & 0x7f; + uint8_t temp = ncr->output_data & 0x7f; ncr->target_id = -1; while (temp) { @@ -302,7 +303,7 @@ ncr_read(uint16_t port, void *priv) switch (port & 7) { case 0: /* current SCSI data */ if (ncr->icr & ICR_DBP) { - temp = SCSI_BufferLength; + temp = ncr->output_data; } else { bus = scsi_bus_read(&ncr->bus); temp = BUS_GETDATA(bus); diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c new file mode 100644 index 000000000..0785ed5b8 --- /dev/null +++ b/src/scsi/scsi_x54x.c @@ -0,0 +1,1917 @@ +/* + * 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 code common to the AHA-154x series of + * SCSI Host Adapters made by Adaptec, Inc. and the BusLogic + * series of SCSI Host Adapters made by Mylex. + * These controllers were designed for various buses. + * + * Version: @(#)scsi_x54x.c 1.0.0 2017/10/14 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016,2017 Miran Grca. + * Copyright 2017 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include "../ibm.h" +#include "../io.h" +#include "../mca.h" +#include "../mem.h" +#include "../mca.h" +#include "../rom.h" +#include "../nvr.h" +#include "../dma.h" +#include "../pci.h" +#include "../pic.h" +#include "../timer.h" +#include "../device.h" +#include "../plat.h" +#include "scsi.h" +#include "scsi_device.h" +#include "scsi_aha154x.h" +#include "scsi_x54x.h" + + +static void x54x_cmd_thread(void *priv); + +static thread_t *poll_tid; +static int busy; + +static event_t *evt; + +static event_t *poll_complete; + + +#ifdef ENABLE_X54X_LOG +int x54x_do_log = ENABLE_X54X_LOG; +#endif + + +static void +x54x_log(const char *fmt, ...) +{ +#if ENABLE_X54X_LOG + va_list ap; + + if (x54x_do_log) { + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + + +static void +x54x_irq(x54x_t *dev, int set) +{ + int int_type = 0; + int irq; + + if (dev->ven_get_irq) + irq = dev->ven_get_irq(dev); + else + irq = dev->Irq; + + if (dev->bus & DEVICE_PCI) + { + x54x_log("PCI IRQ: %02X, PCI_INTA\n", dev->pci_slot); + if (set) + { + pci_set_irq(dev->pci_slot, PCI_INTA); + } + else + { + pci_clear_irq(dev->pci_slot, PCI_INTA); + } + } + else + { + if (set) + { + if (dev->interrupt_type) + int_type = dev->interrupt_type(dev); + + if (int_type) + { + picintlevel(1 << irq); + } + else + { + picint(1 << irq); + } + } + else + { + picintc(1 << irq); + } + } +} + + +static void +raise_irq(x54x_t *dev, int suppress, uint8_t Interrupt) +{ + if (Interrupt & (INTR_MBIF | INTR_MBOA)) { + if (! (dev->Interrupt & INTR_HACC)) { + dev->Interrupt |= Interrupt; /* Report now. */ + } else { + dev->PendingInterrupt |= Interrupt; /* Report later. */ + } + } else if (Interrupt & INTR_HACC) { + if (dev->Interrupt == 0 || dev->Interrupt == (INTR_ANY | INTR_HACC)) { + x54x_log("%s: RaiseInterrupt(): Interrupt=%02X\n", + dev->name, dev->Interrupt); + } + dev->Interrupt |= Interrupt; + } else { + x54x_log("%s: RaiseInterrupt(): Invalid interrupt state!\n", dev->name); + } + + dev->Interrupt |= INTR_ANY; + + if (dev->IrqEnabled && !suppress) + x54x_irq(dev, 1); +} + + +static void +clear_irq(x54x_t *dev) +{ + dev->Interrupt = 0; + x54x_log("%s: lowering IRQ %i (stat 0x%02x)\n", + dev->name, dev->Irq, dev->Interrupt); + x54x_irq(dev, 0); + if (dev->PendingInterrupt) { + x54x_log("%s: Raising Interrupt 0x%02X (Pending)\n", + dev->name, dev->Interrupt); + if (dev->MailboxOutInterrupts || !(dev->Interrupt & INTR_MBOA)) { + raise_irq(dev, 0, dev->PendingInterrupt); + } + dev->PendingInterrupt = 0; + } +} + + +static void +x54x_reset(x54x_t *dev) +{ + dev->ResetCB = 0LL; + + dev->Status = STAT_IDLE | STAT_INIT; + dev->Geometry = 0x80; + dev->Command = 0xFF; + dev->CmdParam = 0; + dev->CmdParamLeft = 0; + dev->IrqEnabled = 1; + dev->MailboxCount = 0; + dev->MailboxOutPosCur = 0; + dev->MailboxInPosCur = 0; + dev->MailboxOutInterrupts = 0; + dev->PendingInterrupt = 0; + + if (dev->ven_reset) { + dev->ven_reset(dev); + } + + clear_irq(dev); +} + + +void +x54x_reset_ctrl(x54x_t *dev, uint8_t Reset) +{ + /* Only if configured.. */ + if (dev->Base == 0x0000) return; + + /* Say hello! */ + x54x_log("%s %s (IO=0x%04X, IRQ=%d, DMA=%d, BIOS @%05lX) ID=%d\n", + dev->vendor, dev->name, dev->Base, dev->Irq, dev->DmaChannel, + dev->rom_addr, dev->HostID); + + x54x_reset(dev); + if (Reset) { + dev->Status |= STAT_STST; + dev->Status &= ~STAT_IDLE; + } + dev->ResetCB = dev->reset_duration * TIMER_USEC; +} + + +static void +x54x_reset_poll(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + dev->Status &= ~STAT_STST; + dev->Status |= STAT_IDLE; + + dev->ResetCB = 0LL; +} + + +static void +target_check(uint8_t id, uint8_t lun) +{ + if (! scsi_device_valid(id, lun)) { + fatal("BIOS INT13 device on %02i:%02i has disappeared\n", id, lun); + } +} + + +static uint8_t +completion_code(uint8_t *sense) +{ + switch (sense[12]) { + case 0x00: + return(0x00); + + case 0x20: + return(0x01); + + case 0x12: + case 0x21: + return(0x02); + + case 0x27: + return(0x03); + + case 0x14: + case 0x16: + return(0x04); + + case 0x10: + case 0x11: + return(0x10); + + case 0x17: + case 0x18: + return(0x11); + + case 0x01: + case 0x03: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + return(0x20); + + case 0x15: + case 0x02: + return(0x40); + + case 0x04: + case 0x28: + case 0x29: + case 0x2a: + return(0xaa); + + default: + break; + }; + + return(0xff); +} + + +static uint8_t +x54x_bios_command_08(uint8_t id, uint8_t lun, uint8_t *buffer) +{ + uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0,0,0,0,0,0,0,0,0,0,0 }; + uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; + uint32_t len = 0; + int i, ret, sc; + + ret = scsi_device_read_capacity(id, lun, cdb, rcbuf, &len); + sc = completion_code(scsi_device_sense(id, lun)); + if (ret == 0) return(sc); + + memset(buffer, 0x00, 6); + for (i=0; i<4; i++) + buffer[i] = rcbuf[i]; + for (i=4; i<6; i++) + buffer[i] = rcbuf[(i + 2) ^ 1]; + x54x_log("BIOS Command 0x08: %02X %02X %02X %02X %02X %02X\n", + buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + + return(0); +} + + +static int +x54x_bios_command_15(uint8_t id, uint8_t lun, uint8_t *buffer) +{ + uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0,0,0,0,0,0,0,0,0,0,0 }; + uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; + uint32_t len = 0; + int i, ret, sc; + + ret = scsi_device_read_capacity(id, lun, cdb, rcbuf, &len); + sc = completion_code(scsi_device_sense(id, lun)); + + memset(buffer, 0x00, 6); + for (i=0; i<4; i++) + buffer[i] = (ret == 0) ? 0 : rcbuf[i]; + + scsi_device_type_data(id, lun, &(buffer[4]), &(buffer[5])); + + x54x_log("BIOS Command 0x15: %02X %02X %02X %02X %02X %02X\n", + buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + + return(sc); +} + + +/* This returns the completion code. */ +static uint8_t +x54x_bios_command(uint8_t max_id, BIOSCMD *cmd, int8_t islba) +{ + uint8_t cdb[12] = { 0,0,0,0,0,0,0,0,0,0,0,0 }; + scsi_device_t *dev; + uint32_t dma_address; + uint32_t lba; + int sector_len = cmd->secount; + int block_shift; + uint8_t ret; + + if (islba) + lba = lba32_blk(cmd); + else + lba = (cmd->u.chs.cyl << 9) + (cmd->u.chs.head << 5) + cmd->u.chs.sec; + + x54x_log("BIOS Command = 0x%02X\n", cmd->command); + + if ((cmd->id > max_id) || (cmd->lun > 7)) { + x54x_log("BIOS Target ID %i or LUN %i are above maximum\n", + cmd->id, cmd->lun); + return(0x80); + } + + /* Get pointer to selected device. */ + dev = &SCSIDevices[cmd->id][cmd->lun]; + dev->BufferLength = 0; + + if (! scsi_device_present(cmd->id, cmd->lun)) { + x54x_log("BIOS Target ID %i and LUN %i have no device attached\n", + cmd->id, cmd->lun); + return(0x80); + } + + dma_address = ADDR_TO_U32(cmd->dma_address); + + x54x_log("BIOS Data Buffer write: length %d, pointer 0x%04X\n", + sector_len, dma_address); + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + block_shift = scsi_device_block_shift(cmd->id, cmd->lun); + + switch(cmd->command) { + case 0x00: /* Reset Disk System, in practice it's a nop */ + return(0); + + case 0x01: /* Read Status of Last Operation */ + target_check(cmd->id, cmd->lun); + + /* + * Assuming 14 bytes because that is the default + * length for SCSI sense, and no command-specific + * indication is given. + */ + dev->BufferLength = 14; + dev->CmdBuffer = (uint8_t *)malloc(14); + memset(dev->CmdBuffer, 0x00, 14); + +#if 0 + SCSIStatus = x54x_bios_command_08(cmd->id, cmd->lun, dev->CmdBuffer) ? SCSI_STATUS_OK : SCSI_STATUS_CHECK_CONDITION; +#endif + + if (sector_len > 0) { + x54x_log("BIOS DMA: Reading 14 bytes at %08X\n", + dma_address); + DMAPageWrite(dma_address, + (char *)scsi_device_sense(cmd->id, cmd->lun), 14); + } + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(0); + + case 0x02: /* Read Desired Sectors to Memory */ + target_check(cmd->id, cmd->lun); + + dev->BufferLength = sector_len << block_shift; + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + memset(dev->CmdBuffer, 0x00, dev->BufferLength); + + cdb[0] = GPCMD_READ_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = (sector_len >> 8) & 0xff; + cdb[8] = sector_len & 0xff; +#if 0 + x54x_log("BIOS CMD(READ, %08lx, %d)\n", lba, cmd->secount); +#endif + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + scsi_device_command_phase1(cmd->id, cmd->lun); + if (sector_len > 0) { + x54x_log("BIOS DMA: Reading %i bytes at %08X\n", + dev->BufferLength, dma_address); + DMAPageWrite(dma_address, + (char *)dev->CmdBuffer, dev->BufferLength); + } + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x03: /* Write Desired Sectors from Memory */ + target_check(cmd->id, cmd->lun); + + dev->BufferLength = sector_len << block_shift; + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + memset(dev->CmdBuffer, 0x00, dev->BufferLength); + + cdb[0] = GPCMD_WRITE_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = (sector_len >> 8) & 0xff; + cdb[8] = sector_len & 0xff; +#if 0 + x54x_log("BIOS CMD(WRITE, %08lx, %d)\n", lba, cmd->secount); +#endif + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + if (sector_len > 0) { + x54x_log("BIOS DMA: Reading %i bytes at %08X\n", + dev->BufferLength, dma_address); + DMAPageRead(dma_address, + (char *)dev->CmdBuffer, dev->BufferLength); + } + + scsi_device_command_phase1(cmd->id, cmd->lun); + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x04: /* Verify Desired Sectors */ + target_check(cmd->id, cmd->lun); + + cdb[0] = GPCMD_VERIFY_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = (sector_len >> 8) & 0xff; + cdb[8] = sector_len & 0xff; + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x05: /* Format Track, invalid since SCSI has no tracks */ +//FIXME: add a longer delay here --FvK + return(1); + + case 0x06: /* Identify SCSI Devices, in practice it's a nop */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x07: /* Format Unit */ + target_check(cmd->id, cmd->lun); + + cdb[0] = GPCMD_FORMAT_UNIT; + cdb[1] = (cmd->lun & 7) << 5; + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x08: /* Read Drive Parameters */ + target_check(cmd->id, cmd->lun); + + dev->BufferLength = 6; + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + memset(dev->CmdBuffer, 0x00, dev->BufferLength); + + ret = x54x_bios_command_08(cmd->id, cmd->lun, dev->CmdBuffer); + + x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); + DMAPageWrite(dma_address, + (char *)dev->CmdBuffer, dev->BufferLength); + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(ret); + + case 0x09: /* Initialize Drive Pair Characteristics, in practice it's a nop */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x0c: /* Seek */ + target_check(cmd->id, cmd->lun); + + cdb[0] = GPCMD_SEEK_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + return((SCSIStatus == SCSI_STATUS_OK) ? 1 : 0); + + case 0x0d: /* Alternate Disk Reset, in practice it's a nop */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x10: /* Test Drive Ready */ + target_check(cmd->id, cmd->lun); + + cdb[0] = GPCMD_TEST_UNIT_READY; + cdb[1] = (cmd->lun & 7) << 5; + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x11: /* Recalibrate */ + target_check(cmd->id, cmd->lun); + + cdb[0] = GPCMD_REZERO_UNIT; + cdb[1] = (cmd->lun & 7) << 5; + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x14: /* Controller Diagnostic */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x15: /* Read DASD Type */ + target_check(cmd->id, cmd->lun); + + dev->BufferLength = 6; + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + memset(dev->CmdBuffer, 0x00, dev->BufferLength); + + ret = x54x_bios_command_15(cmd->id, cmd->lun, dev->CmdBuffer); + + x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); + DMAPageWrite(dma_address, + (char *)dev->CmdBuffer, dev->BufferLength); + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(ret); + + default: + x54x_log("BIOS: Unimplemented command: %02X\n", cmd->command); + return(1); + } + + x54x_log("BIOS Request complete\n"); +} + + +static void +x54x_cmd_done(x54x_t *dev, int suppress) +{ + int fast = 0; + + dev->DataReply = 0; + dev->Status |= STAT_IDLE; + + if (dev->ven_cmd_is_fast) { + fast = dev->ven_cmd_is_fast(dev); + } + + if ((dev->Command != CMD_START_SCSI) || fast) { + dev->Status &= ~STAT_DFULL; + x54x_log("%s: Raising IRQ %i\n", dev->name, dev->Irq); + raise_irq(dev, suppress, INTR_HACC); + } + + dev->Command = 0xff; + dev->CmdParam = 0; +} + + +static void +x54x_mbi_setup(x54x_t *dev, uint32_t CCBPointer, CCBU *CmdBlock, + uint8_t HostStatus, uint8_t TargetStatus, uint8_t mbcc) +{ + Req_t *req = &dev->Req; + + req->CCBPointer = CCBPointer; + memcpy(&(req->CmdBlock), CmdBlock, sizeof(CCB32)); + req->Is24bit = dev->Mbx24bit; + req->HostStatus = HostStatus; + req->TargetStatus = TargetStatus; + req->MailboxCompletionCode = mbcc; + + x54x_log("Mailbox in setup\n"); +} + + +static void +x54x_ccb(x54x_t *dev) +{ + Req_t *req = &dev->Req; + + /* Rewrite the CCB up to the CDB. */ + x54x_log("CCB completion code and statuses rewritten (pointer %08X)\n", req->CCBPointer); + DMAPageWrite(req->CCBPointer + 0x000D, (char *)&(req->MailboxCompletionCode), 1); + DMAPageWrite(req->CCBPointer + 0x000E, (char *)&(req->HostStatus), 1); + DMAPageWrite(req->CCBPointer + 0x000F, (char *)&(req->TargetStatus), 1); + + if (dev->MailboxOutInterrupts) + { + dev->ToRaise = INTR_MBOA | INTR_ANY; + } + else + { + dev->ToRaise = 0; + } +} + + +static void +x54x_mbi(x54x_t *dev) +{ + Req_t *req = &dev->Req; + // uint32_t CCBPointer = req->CCBPointer; + addr24 CCBPointer; + CCBU *CmdBlock = &(req->CmdBlock); + uint8_t HostStatus = req->HostStatus; + uint8_t TargetStatus = req->TargetStatus; + uint32_t MailboxCompletionCode = req->MailboxCompletionCode; + uint32_t Incoming; + + Incoming = dev->MailboxInAddr + (dev->MailboxInPosCur * (dev->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); + + if (MailboxCompletionCode != MBI_NOT_FOUND) { + CmdBlock->common.HostStatus = HostStatus; + CmdBlock->common.TargetStatus = TargetStatus; + + /* Rewrite the CCB up to the CDB. */ + x54x_log("CCB statuses rewritten (pointer %08X)\n", req->CCBPointer); + DMAPageWrite(req->CCBPointer + 0x000E, (char *)&(req->HostStatus), 1); + DMAPageWrite(req->CCBPointer + 0x000F, (char *)&(req->TargetStatus), 1); + } else { + x54x_log("Mailbox not found!\n"); + } + + x54x_log("Host Status 0x%02X, Target Status 0x%02X\n",HostStatus,TargetStatus); + + if (dev->Mbx24bit) { + U32_TO_ADDR(CCBPointer, req->CCBPointer); + x54x_log("Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", req->MailboxCompletionCode, CCBPointer); + DMAPageWrite(Incoming, (char *)&(req->MailboxCompletionCode), 1); + DMAPageWrite(Incoming + 1, (char *)&CCBPointer, 3); + x54x_log("%i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); + } else { + x54x_log("Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", req->MailboxCompletionCode, CCBPointer); + DMAPageWrite(Incoming, (char *)&(req->CCBPointer), 4); + DMAPageWrite(Incoming + 4, (char *)&(req->HostStatus), 1); + DMAPageWrite(Incoming + 5, (char *)&(req->TargetStatus), 1); + DMAPageWrite(Incoming + 7, (char *)&(req->MailboxCompletionCode), 1); + x54x_log("%i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); + } + + dev->MailboxInPosCur++; + if (dev->MailboxInPosCur >= dev->MailboxCount) + dev->MailboxInPosCur = 0; + + dev->ToRaise = INTR_MBIF | INTR_ANY; + if (dev->MailboxOutInterrupts) + { + dev->ToRaise |= INTR_MBOA; + } +} + + +static void +x54x_rd_sge(int Is24bit, uint32_t Address, SGE32 *SG) +{ + SGE SGE24; + + if (Is24bit) { + DMAPageRead(Address, (char *)&SGE24, sizeof(SGE)); + + /* Convert the 24-bit entries into 32-bit entries. */ + x54x_log("Read S/G block: %06X, %06X\n", SGE24.Segment, SGE24.SegmentPointer); + SG->Segment = ADDR_TO_U32(SGE24.Segment); + SG->SegmentPointer = ADDR_TO_U32(SGE24.SegmentPointer); + } else { + DMAPageRead(Address, (char *)SG, sizeof(SGE32)); + } +} + + +static int +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; + + if (Is24bit) { + DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + x54x_log("Data length: %08X\n", req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + x54x_log("Data Buffer write: length %d, pointer 0x%04X\n", + DataLength, DataPointer); + + if (!DataLength) + return 0; + + if (req->CmdBlock.common.ControlByte != 0x03) { + if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || + req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { + for (i = 0; i < DataLength; i += SGEntryLength) { + x54x_rd_sge(Is24bit, DataPointer + i, &SGBuffer); + + DataToTransfer += SGBuffer.Segment; + } + return DataToTransfer; + } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || + req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { + return DataLength; + } else { + return 0; + } + } else { + return 0; + } +} + + +static void +x54x_set_residue(Req_t *req, int32_t TransferLength) +{ + uint32_t Residue = 0; + addr24 Residue24; + int32_t BufLen = SCSIDevices[req->TargetID][req->LUN].BufferLength; + + if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + + if ((TransferLength > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { + TransferLength -= BufLen; + if (TransferLength > 0) + Residue = TransferLength; + } + + if (req->Is24bit) { + U32_TO_ADDR(Residue24, Residue); + DMAPageWrite(req->CCBPointer + 0x0004, (char *)&Residue24, 3); + x54x_log("24-bit Residual data length for reading: %d\n", Residue); + } else { + DMAPageWrite(req->CCBPointer + 0x0004, (char *)&Residue, 4); + x54x_log("32-bit Residual data length for reading: %d\n", Residue); + } + } +} + + +static void +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; + 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))); + int sg_pos = 0; + SGE32 SGBuffer; + uint32_t DataToTransfer = 0; + + if (Is24bit) { + DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + x54x_log("Data Buffer %s: length %d, pointer 0x%04X\n", + dir ? "write" : "read", BufLen, DataPointer); + + if ((req->CmdBlock.common.ControlByte != 0x03) && TransferLength && BufLen) { + if ((req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + + /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without + checking its length, so do this procedure for both no read/write commands. */ + if ((DataLength > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { + for (i = 0; i < DataLength; i += SGEntryLength) { + x54x_rd_sge(Is24bit, DataPointer + i, &SGBuffer); + + Address = SGBuffer.SegmentPointer; + DataToTransfer = MIN(SGBuffer.Segment, BufLen); + + if (read_from_host && DataToTransfer) { + x54x_log("Reading S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); + DMAPageRead(Address, (char *)&(SCSIDevices[req->TargetID][req->LUN].CmdBuffer[sg_pos]), DataToTransfer); + } + else if (write_to_host && DataToTransfer) { + x54x_log("Writing S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); + DMAPageWrite(Address, (char *)&(SCSIDevices[req->TargetID][req->LUN].CmdBuffer[sg_pos]), DataToTransfer); + } + else { + x54x_log("No action on S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); + } + + sg_pos += SGBuffer.Segment; + + BufLen -= SGBuffer.Segment; + if (BufLen < 0) + BufLen = 0; + + x54x_log("After S/G segment done: %i, %i\n", sg_pos, BufLen); + } + } + } else if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND) || + (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES)) { + Address = DataPointer; + + if ((DataLength > 0) && (BufLen > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { + if (read_from_host) + { + DMAPageRead(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, MIN(BufLen, DataLength)); + } + else + if (write_to_host) + { + DMAPageWrite(Address, (char *)SCSIDevices[req->TargetID][req->LUN].CmdBuffer, MIN(BufLen, DataLength)); + } + } + } + } +} + + +void +x54x_buf_alloc(uint8_t id, uint8_t lun, int length) +{ + if (SCSIDevices[id][lun].CmdBuffer != NULL) { + free(SCSIDevices[id][lun].CmdBuffer); + SCSIDevices[id][lun].CmdBuffer = NULL; + } + + x54x_log("Allocating data buffer (%i bytes)\n", length); + SCSIDevices[id][lun].CmdBuffer = (uint8_t *) malloc(length); + memset(SCSIDevices[id][lun].CmdBuffer, 0, length); +} + + +void +x54x_buf_free(uint8_t id, uint8_t lun) +{ + if (SCSIDevices[id][lun].CmdBuffer != NULL) { + free(SCSIDevices[id][lun].CmdBuffer); + SCSIDevices[id][lun].CmdBuffer = NULL; + } +} + + +static uint8_t +ConvertSenseLength(uint8_t RequestSenseLength) +{ + x54x_log("Unconverted Request Sense length %i\n", RequestSenseLength); + + if (RequestSenseLength == 0) + RequestSenseLength = 14; + else if (RequestSenseLength == 1) + RequestSenseLength = 0; + + x54x_log("Request Sense length %i\n", RequestSenseLength); + + return(RequestSenseLength); +} + + +static void +SenseBufferFree(Req_t *req, int Copy) +{ + uint8_t SenseLength = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); + uint32_t SenseBufferAddress; + uint8_t temp_sense[256]; + + if (SenseLength && Copy) { + scsi_device_request_sense(req->TargetID, req->LUN, temp_sense, SenseLength); + + /* + * The sense address, in 32-bit mode, is located in the + * Sense Pointer of the CCB, but in 24-bit mode, it is + * located at the end of the Command Descriptor Block. + */ + if (req->Is24bit) { + SenseBufferAddress = req->CCBPointer; + SenseBufferAddress += req->CmdBlock.common.CdbLength + 18; + } else { + SenseBufferAddress = req->CmdBlock.new.SensePointer; + } + + x54x_log("Request Sense address: %02X\n", SenseBufferAddress); + + x54x_log("SenseBufferFree(): Writing %i bytes at %08X\n", + SenseLength, SenseBufferAddress); + DMAPageWrite(SenseBufferAddress, (char *)temp_sense, SenseLength); + x54x_log("Sense data written to buffer: %02X %02X %02X\n", + temp_sense[2], temp_sense[12], temp_sense[13]); + } +} + + +static void +x54x_scsi_cmd(x54x_t *dev) +{ + Req_t *req = &dev->Req; + uint8_t id, lun; + uint8_t temp_cdb[12]; + uint32_t i; + int target_cdb_len = 12; + int target_data_len; + uint8_t bit24 = !!req->Is24bit; + int32_t *BufLen; + uint8_t phase; + + id = req->TargetID; + lun = req->LUN; + + target_cdb_len = scsi_device_cdb_length(id, lun); + target_data_len = x54x_get_length(req, bit24); + + if (!scsi_device_valid(id, lun)) + fatal("SCSI target on %02i:%02i has disappeared\n", id, lun); + + x54x_log("target_data_len = %i\n", target_data_len); + + x54x_log("SCSI command being executed on ID %i, LUN %i\n", id, lun); + + x54x_log("SCSI CDB[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); + for (i=1; iCmdBlock.common.CdbLength; i++) + x54x_log("SCSI CDB[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); + + memset(temp_cdb, 0x00, target_cdb_len); + if (req->CmdBlock.common.CdbLength <= target_cdb_len) { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, + req->CmdBlock.common.CdbLength); + } else { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); + } + + dev->Residue = 0; + + BufLen = scsi_device_get_buf_len(id, lun); + *BufLen = target_data_len; + + x54x_log("Command buffer: %08X\n", SCSIDevices[id][lun].CmdBuffer); + + scsi_device_command_phase0(id, lun, req->CmdBlock.common.CdbLength, temp_cdb); + + phase = SCSIPhase; + + if (phase != SCSI_PHASE_STATUS) { + x54x_buf_alloc(id, lun, MIN(target_data_len, *BufLen)); + if (phase == SCSI_PHASE_DATA_OUT) + x54x_buf_dma_transfer(req, bit24, target_data_len, 1); + scsi_device_command_phase1(id, lun); + if (phase == SCSI_PHASE_DATA_IN) + x54x_buf_dma_transfer(req, bit24, target_data_len, 0); + } + + x54x_set_residue(req, target_data_len); + + x54x_buf_free(id, lun); + + SenseBufferFree(req, (SCSIStatus != SCSI_STATUS_OK)); + + x54x_log("Request complete\n"); + + if (SCSIStatus == SCSI_STATUS_OK) { + x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); + } else if (SCSIStatus == SCSI_STATUS_CHECK_CONDITION) { + x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); + } + + x54x_log("SCSIStatus = %02X\n", SCSIStatus); + + if (temp_cdb[0] == 0x42) { + thread_wait_event(evt, 10); + } +} + + +static void +x54x_notify(x54x_t *dev) +{ + if (dev->MailboxIsBIOS) + { + x54x_ccb(dev); + } + else + { + x54x_mbi(dev); + } +} + + +static void +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, (char *)&req->CmdBlock, sizeof(CCB32)); + + req->Is24bit = dev->Mbx24bit; + req->CCBPointer = CCBPointer; + req->TargetID = dev->Mbx24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; + req->LUN = dev->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; + + id = req->TargetID; + lun = req->LUN; + if ((id > max_id) || (lun > 7)) { + x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, + CCB_INVALID_CCB, SCSI_STATUS_OK, MBI_ERROR); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + return; + } + + x54x_log("Scanning SCSI Target ID %i\n", id); + + SCSIStatus = SCSI_STATUS_OK; + + if (! scsi_device_present(id, lun)) { + x54x_log("SCSI Target ID %i and LUN %i have no device attached\n",id,lun); + x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, + CCB_SELECTION_TIMEOUT,SCSI_STATUS_OK,MBI_ERROR); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + } else { + x54x_log("SCSI Target ID %i and LUN %i detected and working\n", id, lun); + + x54x_log("Transfer Control %02X\n", req->CmdBlock.common.ControlByte); + x54x_log("CDB Length %i\n", req->CmdBlock.common.CdbLength); + x54x_log("CCB Opcode %x\n", req->CmdBlock.common.Opcode); + if (req->CmdBlock.common.ControlByte > 0x03) { + x54x_log("Invalid control byte: %02X\n", + req->CmdBlock.common.ControlByte); + } + + x54x_log("%s: Callback: Process SCSI request\n", dev->name); + x54x_scsi_cmd(dev); + + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + } +} + + +static void +x54x_req_abort(x54x_t *dev, uint32_t CCBPointer) +{ + CCBU CmdBlock; + + /* Fetch data from the Command Control Block. */ + DMAPageRead(CCBPointer, (char *)&CmdBlock, sizeof(CCB32)); + + x54x_mbi_setup(dev, CCBPointer, &CmdBlock, + 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); +} + + +static uint32_t +x54x_mbo(x54x_t *dev, Mailbox32_t *Mailbox32) +{ + Mailbox_t MailboxOut; + uint32_t Outgoing; + uint32_t ccbp; + uint32_t Addr; + uint32_t Cur; + + if (dev->MailboxIsBIOS) { + Addr = dev->BIOSMailboxOutAddr; + Cur = dev->BIOSMailboxOutPosCur; + } else { + Addr = dev->MailboxOutAddr; + Cur = dev->MailboxOutPosCur; + } + + if (dev->Mbx24bit) { + Outgoing = Addr + (Cur * sizeof(Mailbox_t)); + DMAPageRead(Outgoing, (char *)&MailboxOut, sizeof(Mailbox_t)); + + ccbp = *(uint32_t *) &MailboxOut; + Mailbox32->CCBPointer = (ccbp >> 24) | ((ccbp >> 8) & 0xff00) | ((ccbp << 8) & 0xff0000); + Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; + } else { + Outgoing = Addr + (Cur * sizeof(Mailbox32_t)); + + DMAPageRead(Outgoing, (char *)Mailbox32, sizeof(Mailbox32_t)); + } + + return(Outgoing); +} + + +uint8_t +x54x_mbo_process(x54x_t *dev) +{ + Mailbox32_t mb32; + uint32_t Outgoing; + uint8_t CmdStatus = MBO_FREE; + uint32_t CodeOffset = 0; + + CodeOffset = dev->Mbx24bit ? 0 : 7; + + Outgoing = x54x_mbo(dev, &mb32); + + if (mb32.u.out.ActionCode == MBO_START) { + x54x_log("Start Mailbox Command\n"); + x54x_req_setup(dev, mb32.CCBPointer, &mb32); + } else if (!dev->MailboxIsBIOS && (mb32.u.out.ActionCode == MBO_ABORT)) { + x54x_log("Abort Mailbox Command\n"); + x54x_req_abort(dev, mb32.CCBPointer); + } /* else { + x54x_log("Invalid action code: %02X\n", mb32.u.out.ActionCode); + } */ + + if ((mb32.u.out.ActionCode == MBO_START) || (!dev->MailboxIsBIOS && (mb32.u.out.ActionCode == MBO_ABORT))) { + /* We got the mailbox, mark it as free in the guest. */ + x54x_log("x54x_do_mail(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); + DMAPageWrite(Outgoing + CodeOffset, (char *)&CmdStatus, 1); + + if (dev->ToRaise) + { + raise_irq(dev, 0, dev->ToRaise); + + while (dev->Interrupt) { + } + } + + dev->MailboxReq--; + + return 1; + } + + return 0; +} + + +static void +x54x_do_mail(x54x_t *dev) +{ + int aggressive = 1; + + dev->MailboxIsBIOS = 0; + + if (dev->is_aggressive_mode) { + aggressive = dev->is_aggressive_mode(dev); + x54x_log("Processing mailboxes in %s mode...\n", aggressive ? "aggressive" : "strict"); + } else { + x54x_log("Defaulting to process mailboxes in %s mode...\n", aggressive ? "aggressive" : "strict"); + } + + if (!dev->MailboxCount) { + x54x_log("x54x_do_mail(): No Mailboxes\n"); + return; + } + + if (aggressive) { + /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ + for (dev->MailboxOutPosCur = 0; dev->MailboxOutPosCur < dev->MailboxCount; dev->MailboxOutPosCur++) { + if (x54x_mbo_process(dev)) + break; + } + } else { + /* Strict round robin mode - only process the current mailbox and advance the pointer if successful. */ + if (x54x_mbo_process(dev)) { + dev->MailboxOutPosCur++; + dev->MailboxOutPosCur %= dev->MailboxCount; + } + } +} + + +static void +x54x_cmd_done(x54x_t *dev, int suppress); + + +void +x54x_wait_for_poll(void) +{ + if (x54x_busy()) { + thread_wait_event(poll_complete, -1); + } + thread_reset_event(poll_complete); +} + + +static void +x54x_cmd_thread(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + x54x_log("Polling thread started\n"); + + while (1) + { + if ((dev->Status & STAT_INIT) || (!dev->MailboxInit && !dev->BIOSMailboxInit) || (!dev->MailboxReq && !dev->BIOSMailboxReq)) { + /* If we did not get anything, wait a while. */ + thread_wait_event(evt, 10); + continue; + } + + startscsi(); + + if (!(dev->Status & STAT_INIT) && dev->MailboxInit && dev->MailboxReq) + { + x54x_wait_for_poll(); + + x54x_do_mail(dev); + } + + if (dev->ven_thread) { + dev->ven_thread(dev); + } + + endscsi(); + } + + x54x_log("%s: Callback: polling stopped.\n", dev->name); +} + + +static uint8_t +x54x_in(uint16_t port, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + uint8_t ret; + + switch (port & 3) { + case 0: + default: + ret = dev->Status; + break; + + case 1: + ret = dev->DataBuf[dev->DataReply]; + if (dev->DataReplyLeft) { + dev->DataReply++; + dev->DataReplyLeft--; + if (! dev->DataReplyLeft) + x54x_cmd_done(dev, 0); + } + break; + + case 2: + ret = dev->Interrupt; + break; + + case 3: + ret = dev->Geometry; + break; + } + + return(ret); +} + + +static uint16_t +x54x_inw(uint16_t port, void *priv) +{ + return (uint16_t) x54x_in(port, priv); +} + + +static uint32_t +x54x_inl(uint16_t port, void *priv) +{ + return (uint32_t) x54x_in(port, priv); +} + + +static uint8_t +x54x_read(uint32_t port, void *priv) +{ + return x54x_in(port & 3, priv); +} + + +static uint16_t +x54x_readw(uint32_t port, void *priv) +{ + return x54x_inw(port & 3, priv); +} + + +static uint32_t +x54x_readl(uint32_t port, void *priv) +{ + return x54x_inl(port & 3, priv); +} + + +void +x54x_busy_set(void) +{ + busy = 1; +} + + +void +x54x_thread_start(x54x_t *dev) +{ + if (!poll_tid) { + x54x_log("Starting thread...\n"); + poll_tid = thread_create(x54x_cmd_thread, dev); + } +} + + +void +x54x_busy_clear(void) +{ + busy = 0; + x54x_log("Thread set event - poll complete\n"); + thread_set_event(poll_complete); +} + +uint8_t +x54x_busy(void) +{ + return !!busy; +} + + +static void +x54x_out(uint16_t port, uint8_t val, void *priv) +{ + ReplyInquireSetupInformation *ReplyISI; + x54x_t *dev = (x54x_t *)priv; + MailboxInit_t *mbi; + int i = 0; + uint8_t j = 0; + BIOSCMD *cmd; + uint16_t cyl = 0; + int suppress = 0; + uint32_t FIFOBuf; + uint8_t reset; + addr24 Address; + uint8_t host_id = dev->HostID; + uint8_t irq = 0; + + x54x_log("%s: Write Port 0x%02X, Value %02X\n", dev->name, port, val); + + switch (port & 3) { + case 0: + if ((val & CTRL_HRST) || (val & CTRL_SRST)) { + x54x_busy_set(); + reset = (val & CTRL_HRST); + x54x_log("Reset completed = %x\n", reset); + x54x_reset_ctrl(dev, reset); + x54x_busy_clear(); + break; + } + + if (val & CTRL_IRST) { + x54x_busy_set(); + clear_irq(dev); + x54x_busy_clear(); + } + break; + + case 1: + /* Fast path for the mailbox execution command. */ + if ((val == CMD_START_SCSI) && (dev->Command == 0xff)) { + x54x_busy_set(); + dev->MailboxReq++; + + x54x_thread_start(dev); + x54x_busy_clear(); + return; + } + if (dev->ven_fast_cmds) { + if (dev->Command == 0xff) { + if (dev->ven_fast_cmds(dev, val)) + return; + } + } + + if (dev->Command == 0xff) { + dev->Command = val; + dev->CmdParam = 0; + dev->CmdParamLeft = 0; + + dev->Status &= ~(STAT_INVCMD | STAT_IDLE); + x54x_log("%s: Operation Code 0x%02X\n", dev->name, val); + switch (dev->Command) { + case CMD_MBINIT: + dev->CmdParamLeft = sizeof(MailboxInit_t); + break; + + case CMD_BIOSCMD: + dev->CmdParamLeft = 10; + break; + + case CMD_EMBOI: + case CMD_BUSON_TIME: + case CMD_BUSOFF_TIME: + case CMD_DMASPEED: + case CMD_RETSETUP: + case CMD_ECHO: + case CMD_OPTIONS: + dev->CmdParamLeft = 1; + break; + + case CMD_SELTIMEOUT: + dev->CmdParamLeft = 4; + break; + + case CMD_WRITE_CH2: + case CMD_READ_CH2: + dev->CmdParamLeft = 3; + break; + + default: + if (dev->get_ven_param_len) + dev->CmdParamLeft = dev->get_ven_param_len(dev); + break; + } + } else { + dev->CmdBuf[dev->CmdParam] = val; + dev->CmdParam++; + dev->CmdParamLeft--; + + if (dev->ven_cmd_phase1) + dev->ven_cmd_phase1(dev); + } + + if (! dev->CmdParamLeft) { + x54x_log("Running Operation Code 0x%02X\n", dev->Command); + switch (dev->Command) { + case CMD_NOP: /* No Operation */ + dev->DataReplyLeft = 0; + break; + + case CMD_MBINIT: /* mailbox initialization */ + x54x_busy_set(); + dev->Mbx24bit = 1; + + mbi = (MailboxInit_t *)dev->CmdBuf; + + dev->MailboxInit = 1; + dev->MailboxCount = mbi->Count; + dev->MailboxOutAddr = ADDR_TO_U32(mbi->Address); + dev->MailboxInAddr = dev->MailboxOutAddr + (dev->MailboxCount * sizeof(Mailbox_t)); + + x54x_log("Initialize Mailbox: MBO=0x%08lx, MBI=0x%08lx, %d entries at 0x%08lx\n", + dev->MailboxOutAddr, + dev->MailboxInAddr, + mbi->Count, + ADDR_TO_U32(mbi->Address)); + + dev->Status &= ~STAT_INIT; + dev->DataReplyLeft = 0; + x54x_busy_clear(); + break; + + case CMD_BIOSCMD: /* execute BIOS */ + cmd = (BIOSCMD *)dev->CmdBuf; + if (!(dev->bus & DEVICE_MCA)) { + /* 1640 uses LBA. */ + cyl = ((cmd->u.chs.cyl & 0xff) << 8) | ((cmd->u.chs.cyl >> 8) & 0xff); + cmd->u.chs.cyl = cyl; + } + if (dev->bus & DEVICE_MCA) { + /* 1640 uses LBA. */ + x54x_log("BIOS LBA=%06lx (%lu)\n", + lba32_blk(cmd), + lba32_blk(cmd)); + } else { + cmd->u.chs.head &= 0xf; + cmd->u.chs.sec &= 0x1f; + x54x_log("BIOS CHS=%04X/%02X%02X\n", + cmd->u.chs.cyl, + cmd->u.chs.head, + cmd->u.chs.sec); + } + dev->DataBuf[0] = x54x_bios_command(dev->max_id, cmd, (dev->bus & DEVICE_MCA)?1:0); + x54x_log("BIOS Completion/Status Code %x\n", dev->DataBuf[0]); + dev->DataReplyLeft = 1; + break; + + case CMD_INQUIRY: /* Inquiry */ + memcpy(dev->DataBuf, dev->fw_rev, 4); + dev->DataReplyLeft = 4; + break; + + case CMD_EMBOI: /* enable MBO Interrupt */ + if (dev->CmdBuf[0] <= 1) { + dev->MailboxOutInterrupts = dev->CmdBuf[0]; + x54x_log("Mailbox out interrupts: %s\n", dev->MailboxOutInterrupts ? "ON" : "OFF"); + suppress = 1; + } else { + dev->Status |= STAT_INVCMD; + } + dev->DataReplyLeft = 0; + break; + + case CMD_SELTIMEOUT: /* Selection Time-out */ + dev->DataReplyLeft = 0; + break; + + case CMD_BUSON_TIME: /* bus-on time */ + dev->BusOnTime = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + x54x_log("Bus-on time: %d\n", dev->CmdBuf[0]); + break; + + case CMD_BUSOFF_TIME: /* bus-off time */ + dev->BusOffTime = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + x54x_log("Bus-off time: %d\n", dev->CmdBuf[0]); + break; + + case CMD_DMASPEED: /* DMA Transfer Rate */ + dev->ATBusSpeed = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + x54x_log("DMA transfer rate: %02X\n", dev->CmdBuf[0]); + break; + + case CMD_RETDEVS: /* return Installed Devices */ + memset(dev->DataBuf, 0x00, 8); + for (i=0; iDataBuf[i] = 0x00; + + /* Skip the HA .. */ + if (dev->ven_get_host_id) + host_id = dev->ven_get_host_id(dev); + + if (i == host_id) continue; + + for (j=0; jDataBuf[i] |= (1<DataReplyLeft = i; + break; + + case CMD_RETCONF: /* return Configuration */ + if (dev->ven_get_dma) + dev->DataBuf[0] = dev->ven_get_dma(dev); + else + dev->DataBuf[0] = (1<DmaChannel); + + if (dev->ven_get_irq) + irq = dev->ven_get_irq(dev); + else + irq = dev->Irq; + + if (irq >= 9) + dev->DataBuf[1]=(1<<(irq-9)); + else + dev->DataBuf[1]=0; + if (dev->ven_get_host_id) + dev->DataBuf[2] = dev->ven_get_host_id(dev); + else + dev->DataBuf[2] = dev->HostID; + dev->DataReplyLeft = 3; + break; + + case CMD_RETSETUP: /* return Setup */ + { + ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; + memset(ReplyISI, 0x00, sizeof(ReplyInquireSetupInformation)); + + ReplyISI->uBusTransferRate = dev->ATBusSpeed; + ReplyISI->uPreemptTimeOnBus = dev->BusOnTime; + ReplyISI->uTimeOffBus = dev->BusOffTime; + ReplyISI->cMailbox = dev->MailboxCount; + U32_TO_ADDR(ReplyISI->MailboxAddress, dev->MailboxOutAddr); + + if (dev->get_ven_data) { + dev->get_ven_data(dev); + } + + dev->DataReplyLeft = dev->CmdBuf[0]; + x54x_log("Return Setup Information: %d (length: %i)\n", dev->CmdBuf[0], sizeof(ReplyInquireSetupInformation)); + } + break; + + case CMD_ECHO: /* ECHO data */ + dev->DataBuf[0] = dev->CmdBuf[0]; + dev->DataReplyLeft = 1; + break; + + case CMD_WRITE_CH2: /* write channel 2 buffer */ + dev->DataReplyLeft = 0; + Address.hi = dev->CmdBuf[0]; + Address.mid = dev->CmdBuf[1]; + Address.lo = dev->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + x54x_log("Adaptec LocalRAM: Reading 64 bytes at %08X\n", FIFOBuf); + DMAPageRead(FIFOBuf, (char *)dev->dma_buffer, 64); + break; + + case CMD_READ_CH2: /* write channel 2 buffer */ + dev->DataReplyLeft = 0; + Address.hi = dev->CmdBuf[0]; + Address.mid = dev->CmdBuf[1]; + Address.lo = dev->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + x54x_log("Adaptec LocalRAM: Writing 64 bytes at %08X\n", FIFOBuf); + DMAPageWrite(FIFOBuf, (char *)dev->dma_buffer, 64); + break; + + case CMD_OPTIONS: /* Set adapter options */ + if (dev->CmdParam == 1) + dev->CmdParamLeft = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + break; + + default: + if (dev->ven_cmds) + suppress = dev->ven_cmds(dev); + else { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + } + } + + if (dev->DataReplyLeft) + dev->Status |= STAT_DFULL; + else if (!dev->CmdParamLeft) + x54x_cmd_done(dev, suppress); + break; + + case 2: + if (dev->int_geom_writable) + dev->Interrupt = val; + break; + + case 3: + if (dev->int_geom_writable) + dev->Geometry = val; + break; + } +} + + +static void +x54x_outw(uint16_t port, uint16_t val, void *priv) +{ + x54x_out(port, val & 0xFF, priv); +} + + +static void +x54x_outl(uint16_t port, uint32_t val, void *priv) +{ + x54x_out(port, val & 0xFF, priv); +} + + +static void +x54x_write(uint32_t port, uint8_t val, void *priv) +{ + x54x_out(port & 3, val, priv); +} + + +static void +x54x_writew(uint32_t port, uint16_t val, void *priv) +{ + x54x_outw(port & 3, val, priv); +} + + +static void +x54x_writel(uint32_t port, uint32_t val, void *priv) +{ + x54x_outl(port & 3, val, priv); +} + + +void +x54x_io_set(x54x_t *dev, uint32_t base) +{ + if (dev->bus & DEVICE_PCI) { + x54x_log("x54x: [PCI] Setting I/O handler at %04X\n", dev->Base); + io_sethandler(base, 4, + x54x_in, x54x_inw, x54x_inl, + x54x_out, x54x_outw, x54x_outl, dev); + } else { + x54x_log("x54x: [ISA] Setting I/O handler at %04X\n", dev->Base); + io_sethandler(base, 4, + x54x_in, x54x_inw, NULL, + x54x_out, x54x_outw, NULL, dev); + } +} + + +void +x54x_io_remove(x54x_t *dev, uint32_t base) +{ + x54x_log("x54x: Removing I/O handler at %04X\n", dev->Base); + + if (dev->bus & DEVICE_PCI) { + io_removehandler(base, 4, + x54x_in, x54x_inw, x54x_inl, + x54x_out, x54x_outw, x54x_outl, dev); + } else { + io_removehandler(base, 4, + x54x_in, x54x_inw, NULL, + x54x_out, x54x_outw, NULL, dev); + } +} + + +void +x54x_mem_init(x54x_t *dev, uint32_t addr) +{ + if (dev->bus & DEVICE_PCI) { + mem_mapping_add(&dev->mmio_mapping, addr, 0x20, + x54x_read, x54x_readw, x54x_readl, + x54x_write, x54x_writew, x54x_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); + } else { + mem_mapping_add(&dev->mmio_mapping, addr, 0x20, + x54x_read, x54x_readw, NULL, + x54x_write, x54x_writew, NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + } +} + + +void +x54x_mem_enable(x54x_t *dev) +{ + mem_mapping_enable(&dev->mmio_mapping); +} + + +void +x54x_mem_set_addr(x54x_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->mmio_mapping, + base, 0x20); +} + + +void +x54x_mem_disable(x54x_t *dev) +{ + mem_mapping_disable(&dev->mmio_mapping); +} + + +/* General initialization routine for all boards. */ +void * +x54x_init(device_t *info) +{ + x54x_t *dev; + + /* Allocate control block and set up basic stuff. */ + dev = malloc(sizeof(x54x_t)); + if (dev == NULL) return(dev); + memset(dev, 0x00, sizeof(x54x_t)); + dev->type = info->local; + + dev->bus = info->flags; + + timer_add(x54x_reset_poll, &dev->ResetCB, &dev->ResetCB, dev); + + poll_complete = thread_create_event(); + + /* Create a waitable event. */ + evt = thread_create_event(); + + return(dev); +} + + +void +x54x_close(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + if (dev) + { + dev->MailboxInit = dev->BIOSMailboxInit = 0; + dev->MailboxCount = dev->BIOSMailboxCount = 0; + dev->MailboxReq = dev->BIOSMailboxReq = 0; + + if (dev->ven_data) + free(dev->ven_data); + + if (poll_tid) { + thread_kill(poll_tid); + poll_tid = NULL; + } + + if (poll_complete) { + thread_destroy_event(poll_complete); + poll_complete = NULL; + } + + if (evt) { + thread_destroy_event(evt); + evt = NULL; + } + + if (dev->nvr != NULL) + free(dev->nvr); + + free(dev); + dev = NULL; + } +} + + +void +x54x_device_reset(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + x54x_reset_ctrl(dev, 1); +} diff --git a/src/scsi/scsi_x54x.h b/src/scsi/scsi_x54x.h new file mode 100644 index 000000000..9111344d2 --- /dev/null +++ b/src/scsi/scsi_x54x.h @@ -0,0 +1,513 @@ +/* + * 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. + * + * Header of the code common to the AHA-154x series of SCSI + * Host Adapters made by Adaptec, Inc. and the BusLogic series + * of SCSI Host Adapters made by Mylex. + * These controllers were designed for various buses. + * + * Version: @(#)scsi_x54x.h 1.0.0 2017/10/14 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016,2017 Miran Grca. + * Copyright 2017 Fred N. van Kempen. + */ +#ifndef SCSI_X54X_H + +#define SCSI_X54X_H + +#define SCSI_DELAY_TM 1 /* was 50 */ + + +#define ROM_SIZE 16384 /* one ROM is 16K */ +#define NVR_SIZE 32 /* size of NVR */ + + +/* EEPROM map and bit definitions. */ +#define EE0_HOSTID 0x07 /* EE(0) [2:0] */ +#define EE0_ALTFLOP 0x80 /* EE(0) [7] FDC at 370h */ +#define EE1_IRQCH 0x07 /* EE(1) [3:0] */ +#define EE1_DMACH 0x70 /* EE(1) [7:4] */ +#define EE2_RMVOK 0x01 /* EE(2) [0] Support removable disks */ +#define EE2_HABIOS 0x02 /* EE(2) [1] HA Bios Space Reserved */ +#define EE2_INT19 0x04 /* EE(2) [2] HA Bios Controls INT19 */ +#define EE2_DYNSCAN 0x08 /* EE(2) [3] Dynamically scan bus */ +#define EE2_TWODRV 0x10 /* EE(2) [4] Allow more than 2 drives */ +#define EE2_SEEKRET 0x20 /* EE(2) [5] Immediate return on seek */ +#define EE2_EXT1G 0x80 /* EE(2) [7] Extended Translation >1GB */ +#define EE3_SPEED 0x00 /* EE(3) [7:0] DMA Speed */ +#define SPEED_33 0xFF +#define SPEED_50 0x00 +#define SPEED_56 0x04 +#define SPEED_67 0x01 +#define SPEED_80 0x02 +#define SPEED_10 0x03 +#define EE4_FLOPTOK 0x80 /* EE(4) [7] Support Flopticals */ +#define EE6_PARITY 0x01 /* EE(6) [0] parity check enable */ +#define EE6_TERM 0x02 /* EE(6) [1] host term enable */ +#define EE6_RSTBUS 0x04 /* EE(6) [2] reset SCSI bus on boot */ +#define EEE_SYNC 0x01 /* EE(E) [0] Enable Sync Negotiation */ +#define EEE_DISCON 0x02 /* EE(E) [1] Enable Disconnection */ +#define EEE_FAST 0x04 /* EE(E) [2] Enable FAST SCSI */ +#define EEE_START 0x08 /* EE(E) [3] Enable Start Unit */ + + +/* + * Host Adapter I/O ports. + * + * READ Port x+0: STATUS + * WRITE Port x+0: CONTROL + * + * READ Port x+1: DATA + * WRITE Port x+1: COMMAND + * + * READ Port x+2: INTERRUPT STATUS + * WRITE Port x+2: (undefined?) + * + * R/W Port x+3: (undefined) + */ + +/* WRITE CONTROL commands. */ +#define CTRL_HRST 0x80 /* Hard reset */ +#define CTRL_SRST 0x40 /* Soft reset */ +#define CTRL_IRST 0x20 /* interrupt reset */ +#define CTRL_SCRST 0x10 /* SCSI bus reset */ + +/* READ STATUS. */ +#define STAT_STST 0x80 /* self-test in progress */ +#define STAT_DFAIL 0x40 /* internal diagnostic failure */ +#define STAT_INIT 0x20 /* mailbox initialization required */ +#define STAT_IDLE 0x10 /* HBA is idle */ +#define STAT_CDFULL 0x08 /* Command/Data output port is full */ +#define STAT_DFULL 0x04 /* Data input port is full */ +#define STAT_INVCMD 0x01 /* Invalid command */ + +/* READ/WRITE DATA. */ +#define CMD_NOP 0x00 /* No operation */ +#define CMD_MBINIT 0x01 /* mailbox initialization */ +#define CMD_START_SCSI 0x02 /* Start SCSI command */ +#define CMD_BIOSCMD 0x03 /* Execute ROM BIOS command */ +#define CMD_INQUIRY 0x04 /* Adapter inquiry */ +#define CMD_EMBOI 0x05 /* enable Mailbox Out Interrupt */ +#define CMD_SELTIMEOUT 0x06 /* Set SEL timeout */ +#define CMD_BUSON_TIME 0x07 /* set bus-On time */ +#define CMD_BUSOFF_TIME 0x08 /* set bus-off time */ +#define CMD_DMASPEED 0x09 /* set ISA DMA speed */ +#define CMD_RETDEVS 0x0A /* return installed devices */ +#define CMD_RETCONF 0x0B /* return configuration data */ +#define CMD_TARGET 0x0C /* set HBA to target mode */ +#define CMD_RETSETUP 0x0D /* return setup data */ +#define CMD_WRITE_CH2 0x1A /* write channel 2 buffer */ +#define CMD_READ_CH2 0x1B /* read channel 2 buffer */ +#define CMD_ECHO 0x1F /* ECHO command data */ +#define CMD_OPTIONS 0x21 /* set adapter options */ + +/* READ INTERRUPT STATUS. */ +#define INTR_ANY 0x80 /* any interrupt */ +#define INTR_SRCD 0x08 /* SCSI reset detected */ +#define INTR_HACC 0x04 /* HA command complete */ +#define INTR_MBOA 0x02 /* MBO empty */ +#define INTR_MBIF 0x01 /* MBI full */ + + +/* Structure for the INQUIRE_SETUP_INFORMATION reply. */ +#pragma pack(push,1) +typedef struct { + uint8_t uOffset :4, + uTransferPeriod :3, + fSynchronous :1; +} ReplyInquireSetupInformationSynchronousValue; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t fSynchronousInitiationEnabled :1, + fParityCheckingEnabled :1, + uReserved1 :6; + uint8_t uBusTransferRate; + uint8_t uPreemptTimeOnBus; + uint8_t uTimeOffBus; + uint8_t cMailbox; + addr24 MailboxAddress; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; + uint8_t uDisconnectPermittedId0To7; + uint8_t VendorSpecificData[28]; +} ReplyInquireSetupInformation; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Count; + addr24 Address; +} MailboxInit_t; +#pragma pack(pop) + +/* + * Mailbox Definitions. + * + * Mailbox Out (MBO) command values. + */ +#define MBO_FREE 0x00 +#define MBO_START 0x01 +#define MBO_ABORT 0x02 + +/* Mailbox In (MBI) status values. */ +#define MBI_FREE 0x00 +#define MBI_SUCCESS 0x01 +#define MBI_ABORT 0x02 +#define MBI_NOT_FOUND 0x03 +#define MBI_ERROR 0x04 + +#pragma pack(push,1) +typedef struct { + uint8_t CmdStatus; + addr24 CCBPointer; +} Mailbox_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint32_t CCBPointer; + union { + struct { + uint8_t Reserved[3]; + uint8_t ActionCode; + } out; + struct { + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved; + uint8_t CompletionCode; + } in; + } u; +} Mailbox32_t; +#pragma pack(pop) + +/* + * + * CCB - SCSI Command Control Block + * + * The CCB is a superset of the CDB (Command Descriptor Block) + * and specifies detailed information about a SCSI command. + * + */ +/* Byte 0 Command Control Block Operation Code */ +#define SCSI_INITIATOR_COMMAND 0x00 +#define TARGET_MODE_COMMAND 0x01 +#define SCATTER_GATHER_COMMAND 0x02 +#define SCSI_INITIATOR_COMMAND_RES 0x03 +#define SCATTER_GATHER_COMMAND_RES 0x04 +#define BUS_RESET 0x81 + +/* Byte 1 Address and Direction Control */ +#define CCB_TARGET_ID_SHIFT 0x06 /* CCB Op Code = 00, 02 */ +#define CCB_INITIATOR_ID_SHIFT 0x06 /* CCB Op Code = 01 */ +#define CCB_DATA_XFER_IN 0x01 +#define CCB_DATA_XFER_OUT 0x02 +#define CCB_LUN_MASK 0x07 /* Logical Unit Number */ + +/* Byte 2 SCSI_Command_Length - Length of SCSI CDB + Byte 3 Request Sense Allocation Length */ +#define FOURTEEN_BYTES 0x00 /* Request Sense Buffer size */ +#define NO_AUTO_REQUEST_SENSE 0x01 /* No Request Sense Buffer */ + +/* Bytes 4, 5 and 6 Data Length - Data transfer byte count */ +/* Bytes 7, 8 and 9 Data Pointer - SGD List or Data Buffer */ +/* Bytes 10, 11 and 12 Link Pointer - Next CCB in Linked List */ +/* Byte 13 Command Link ID - TBD (I don't know yet) */ +/* Byte 14 Host Status - Host Adapter status */ +#define CCB_COMPLETE 0x00 /* CCB completed without error */ +#define CCB_LINKED_COMPLETE 0x0A /* Linked command completed */ +#define CCB_LINKED_COMPLETE_INT 0x0B /* Linked complete with intr */ +#define CCB_SELECTION_TIMEOUT 0x11 /* Set SCSI selection timed out */ +#define CCB_DATA_OVER_UNDER_RUN 0x12 +#define CCB_UNEXPECTED_BUS_FREE 0x13 /* Trg dropped SCSI BSY */ +#define CCB_PHASE_SEQUENCE_FAIL 0x14 /* Trg bus phase sequence fail */ +#define CCB_BAD_MBO_COMMAND 0x15 /* MBO command not 0, 1 or 2 */ +#define CCB_INVALID_OP_CODE 0x16 /* CCB invalid operation code */ +#define CCB_BAD_LINKED_LUN 0x17 /* Linked CCB LUN diff from 1st */ +#define CCB_INVALID_DIRECTION 0x18 /* Invalid target direction */ +#define CCB_DUPLICATE_CCB 0x19 /* Duplicate CCB */ +#define CCB_INVALID_CCB 0x1A /* Invalid CCB - bad parameter */ + +/* Byte 15 Target Status + + See scsi.h files for these statuses. + Bytes 16 and 17 Reserved (must be 0) + Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block */ + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Reserved1 :3, + ControlByte :2, + TagQueued :1, + QueueTag :2; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint32_t DataLength; + uint32_t DataPointer; + uint8_t Reserved2[2]; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Id; + uint8_t Lun :5, + LegacyTagEnable :1, + LegacyQueueTag :2; + uint8_t Cdb[12]; + uint8_t Reserved3[6]; + uint32_t SensePointer; +} CCB32; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Lun :3, + ControlByte :2, + Id :3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + addr24 DataLength; + addr24 DataPointer; + addr24 LinkPointer; + uint8_t LinkId; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved[2]; + uint8_t Cdb[12]; +} CCB; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Pad1 :3, + ControlByte :2, + Pad2 :3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint8_t Pad3[9]; + uint8_t CompletionCode; /* Only used by the 1542C/CF(/CP?) BIOS mailboxes */ + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Pad4[2]; + uint8_t Cdb[12]; +} CCBC; +#pragma pack(pop) + +#pragma pack(push,1) +typedef union { + CCB32 new; + CCB old; + CCBC common; +} CCBU; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + CCBU CmdBlock; + uint8_t *RequestSenseBuffer; + uint32_t CCBPointer; + int Is24bit; + uint8_t TargetID, + LUN, + HostStatus, + TargetStatus, + MailboxCompletionCode; +} Req_t; +#pragma pack(pop) + +typedef struct { + int8_t type; /* type of device */ + + char vendor[16]; /* name of device vendor */ + char name[16]; /* name of device */ + + volatile + int8_t Irq; + volatile + uint8_t IrqEnabled; + + int8_t DmaChannel; + int8_t HostID; + uint32_t Base; + uint8_t pos_regs[8]; /* MCA */ + + wchar_t *bios_path; /* path to BIOS image file */ + uint32_t rom_addr; /* address of BIOS ROM */ + uint16_t rom_ioaddr; /* offset in BIOS of I/O addr */ + uint16_t rom_shram; /* index to shared RAM */ + uint16_t rom_shramsz; /* size of shared RAM */ + uint16_t rom_fwhigh; /* offset in BIOS of ver ID */ + rom_t bios; /* BIOS memory descriptor */ + rom_t uppersck; /* BIOS memory descriptor */ + uint8_t *rom1; /* main BIOS image */ + uint8_t *rom2; /* SCSI-Select image */ + + wchar_t *nvr_path; /* path to NVR image file */ + uint8_t *nvr; /* EEPROM buffer */ + + int64_t ResetCB; + + volatile uint8_t /* for multi-threading, keep */ + Status, /* these volatile */ + Interrupt; + + Req_t Req; + uint8_t Geometry; + uint8_t Control; + uint8_t Command; + uint8_t CmdBuf[128]; + uint8_t CmdParam; + uint8_t CmdParamLeft; + uint8_t DataBuf[65536]; + uint16_t DataReply; + uint16_t DataReplyLeft; + + volatile + uint32_t MailboxInit, + MailboxCount, + MailboxOutAddr, + MailboxOutPosCur, + MailboxInAddr, + MailboxInPosCur, + MailboxReq; + + volatile + int Mbx24bit, + MailboxOutInterrupts; + + volatile + int PendingInterrupt, + Lock; + + volatile + uint8_t shadow_ram[128]; + + volatile + uint8_t MailboxIsBIOS, + ToRaise; + + uint8_t shram_mode; + + volatile + uint8_t dma_buffer[128]; + + volatile + uint32_t BIOSMailboxInit, + BIOSMailboxCount, + BIOSMailboxOutAddr, + BIOSMailboxOutPosCur, + BIOSMailboxReq, + Residue; + + volatile + uint8_t BusOnTime, + BusOffTime, + ATBusSpeed; + + char *fw_rev; /* The 4 bytes of the revision command information + 2 extra bytes for BusLogic */ + uint8_t bus; /* Basically a copy of device flags */ + uint8_t setup_info_len; + uint8_t max_id; + + uint32_t reset_duration; + + uint8_t pci_slot; + + mem_mapping_t mmio_mapping; + + uint8_t int_geom_writable; + + /* Pointer to a structure of vendor-specific data that only the vendor-specific code can understand */ + void *ven_data; + + /* Pointer to a function that performs vendor-specific operation during the thread */ + void (*ven_thread)(void *p); + /* Pointer to a function that executes the second parameter phase of the vendor-specific command */ + void (*ven_cmd_phase1)(void *p); + /* Pointer to a function that gets the host adapter ID in case it has to be read from a non-standard location */ + uint8_t (*ven_get_host_id)(void *p); + /* Pointer to a function that updates the IRQ in the vendor-specific space */ + uint8_t (*ven_get_irq)(void *p); + /* Pointer to a function that updates the DMA channel in the vendor-specific space */ + uint8_t (*ven_get_dma)(void *p); + /* Pointer to a function that returns whether command is fast */ + uint8_t (*ven_cmd_is_fast)(void *p); + /* Pointer to a function that executes vendor-specific fast path commands */ + uint8_t (*ven_fast_cmds)(void *p, uint8_t cmd); + /* Pointer to a function that gets the parameter length for vendor-specific commands */ + uint8_t (*get_ven_param_len)(void *p); + /* Pointer to a function that executes vendor-specific commands and returns whether or not to suppress the IRQ */ + uint8_t (*ven_cmds)(void *p); + /* Pointer to a function that fills in the vendor-specific setup data */ + void (*get_ven_data)(void *p); + /* Pointer to a function that determines if the mode is aggressive */ + uint8_t (*is_aggressive_mode)(void *p); + /* Pointer to a function that returns interrupt type (0 = edge, 1 = level) */ + uint8_t (*interrupt_type)(void *p); + /* Pointer to a function that resets vendor-specific data */ + void (*ven_reset)(void *p); +} x54x_t; + + +#pragma pack(push,1) +typedef struct +{ + uint8_t command; + uint8_t lun:3, + reserved:2, + id:3; + union { + struct { + uint16_t cyl; + uint8_t head; + uint8_t sec; + } chs; + struct { + uint8_t lba0; /* MSB */ + uint8_t lba1; + uint8_t lba2; + uint8_t lba3; /* LSB */ + } lba; + } u; + uint8_t secount; + addr24 dma_address; +} BIOSCMD; +#pragma pack(pop) +#define lba32_blk(p) ((uint32_t)(p->u.lba.lba0<<24) | (p->u.lba.lba1<<16) | \ + (p->u.lba.lba2<<8) | p->u.lba.lba3) + + + +extern void x54x_reset_ctrl(x54x_t *dev, uint8_t Reset); +extern void x54x_busy_set(void); +extern void x54x_thread_start(x54x_t *dev); +extern void x54x_busy_clear(void); +extern uint8_t x54x_busy(void); +extern void x54x_buf_alloc(uint8_t id, uint8_t lun, int length); +extern void x54x_buf_free(uint8_t id, uint8_t lun); +extern uint8_t x54x_mbo_process(x54x_t *dev); +extern void x54x_wait_for_poll(void); +extern void x54x_io_set(x54x_t *dev, uint32_t base); +extern void x54x_io_remove(x54x_t *dev, uint32_t base); +extern void x54x_mem_init(x54x_t *dev, uint32_t addr); +extern void x54x_mem_enable(x54x_t *dev); +extern void x54x_mem_set_addr(x54x_t *dev, uint32_t base); +extern void x54x_mem_disable(x54x_t *dev); +extern void *x54x_init(device_t *info); +extern void x54x_close(void *priv); +extern void x54x_device_reset(void *priv); + + + +#endif diff --git a/src/sound/midi_fluidsynth.c b/src/sound/midi_fluidsynth.c index 07f93a725..cce894675 100644 --- a/src/sound/midi_fluidsynth.c +++ b/src/sound/midi_fluidsynth.c @@ -326,10 +326,20 @@ void fluidsynth_close(void* p) fluidsynth_t* data = &fsdev; - if (data->sound_font != -1) + if (data->sound_font != -1) { f_fluid_synth_sfunload(data->synth, data->sound_font, 1); - f_delete_fluid_synth(data->synth); - f_delete_fluid_settings(data->settings); + data->sound_font = -1; + } + + if (data->synth) { + f_delete_fluid_synth(data->synth); + data->synth = NULL; + } + + if (data->settings) { + f_delete_fluid_settings(data->settings); + data->settings = NULL; + } midi_close(); diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c new file mode 100644 index 000000000..60f0fb3d6 --- /dev/null +++ b/src/sound/snd_audiopci.c @@ -0,0 +1,1086 @@ +#include +#include +#include +#include "../ibm.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../timer.h" +#include "sound.h" +#include "snd_audiopci.h" + +typedef struct es1371_t +{ + uint8_t pci_command, pci_serr; + + uint32_t base_addr; + + uint8_t int_line; + + uint16_t pmcsr; + + uint32_t int_ctrl; + uint32_t int_status; + + uint32_t legacy_ctrl; + + int mem_page; + + uint32_t si_cr; + + uint32_t sr_cir; + uint16_t sr_ram[128]; + + uint8_t uart_ctrl; + uint8_t uart_status; + + uint16_t codec_regs[64]; + uint32_t codec_ctrl; + + struct + { + uint32_t addr, addr_latch; + uint16_t count, size; + + uint16_t samp_ct, curr_samp_ct; + + int64_t time, latch; + + uint32_t vf, ac; + + int16_t buffer_l[64], buffer_r[64]; + int buffer_pos, buffer_pos_end; + + int16_t out_l, out_r; + + int32_t vol_l, vol_r; + } dac[2]; + + int64_t dac_latch, dac_time; + + int master_vol_l, master_vol_r; + + int card; + + int pos; + int16_t buffer[SOUNDBUFLEN * 2]; +} es1371_t; + +#define LEGACY_SB_ADDR (1 << 29) +#define LEGACY_SSCAPE_ADDR_SHIFT 27 +#define LEGACY_CODEC_ADDR_SHIFT 25 +#define LEGACY_FORCE_IRQ (1 << 24) +#define LEGACY_CAPTURE_SLAVE_DMA (1 << 23) +#define LEGACY_CAPTURE_SLAVE_PIC (1 << 22) +#define LEGACY_CAPTURE_MASTER_DMA (1 << 21) +#define LEGACY_CAPTURE_MASTER_PIC (1 << 20) +#define LEGACY_CAPTURE_ADLIB (1 << 19) +#define LEGACY_CAPTURE_SB (1 << 18) +#define LEGACY_CAPTURE_CODEC (1 << 17) +#define LEGACY_CAPTURE_SSCAPE (1 << 16) +#define LEGACY_EVENT_SSCAPE (0 << 8) +#define LEGACY_EVENT_CODEC (1 << 8) +#define LEGACY_EVENT_SB (2 << 8) +#define LEGACY_EVENT_ADLIB (3 << 8) +#define LEGACY_EVENT_MASTER_PIC (4 << 8) +#define LEGACY_EVENT_MASTER_DMA (5 << 8) +#define LEGACY_EVENT_SLAVE_PIC (6 << 8) +#define LEGACY_EVENT_SLAVE_DMA (7 << 8) +#define LEGACY_EVENT_MASK (7 << 8) +#define LEGACY_EVENT_ADDR_SHIFT 3 +#define LEGACY_EVENT_ADDR_MASK (0x1f << 3) +#define LEGACY_EVENT_TYPE_RW (1 << 2) +#define LEGACY_INT (1 << 0) + +#define SRC_RAM_WE (1 << 24) + +#define CODEC_READ (1 << 23) +#define CODEC_READY (1 << 31) + +#define INT_DAC1_EN (1 << 6) +#define INT_DAC2_EN (1 << 5) + +#define SI_P2_INTR_EN (1 << 9) +#define SI_P1_INTR_EN (1 << 8) + +#define INT_STATUS_INTR (1 << 31) +#define INT_STATUS_DAC1 (1 << 2) +#define INT_STATUS_DAC2 (1 << 1) + +#define FORMAT_MONO_8 0 +#define FORMAT_STEREO_8 1 +#define FORMAT_MONO_16 2 +#define FORMAT_STEREO_16 3 + +const int32_t codec_attn[]= +{ + 25,32,41,51,65,82,103,130,164,206,260,327,412,519,653, + 822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044, + 16422,20674,26027,32767 +}; + +static void es1371_fetch(es1371_t *es1371, int dac_nr); +static void update_legacy(es1371_t *es1371); + +static void es1371_update_irqs(es1371_t *es1371) +{ + int irq = 0; + + if ((es1371->int_status & INT_STATUS_DAC1) && (es1371->si_cr & SI_P1_INTR_EN)) + irq = 1; + if ((es1371->int_status & INT_STATUS_DAC2) && (es1371->si_cr & SI_P2_INTR_EN)) + irq = 1; + + if (irq) + es1371->int_status |= INT_STATUS_INTR; + else + es1371->int_status &= ~INT_STATUS_INTR; + + if (es1371->legacy_ctrl & LEGACY_FORCE_IRQ) + irq = 1; + + if (irq) + { + pci_set_irq(es1371->card, PCI_INTA); +// pclog("Raise IRQ\n"); + } + else + { + pci_clear_irq(es1371->card, PCI_INTA); +// pclog("Drop IRQ\n"); + } +} + +static uint8_t es1371_inb(uint16_t port, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + uint8_t ret = 0; + + switch (port & 0x3f) + { + case 0x00: + ret = es1371->int_ctrl & 0xff; + break; + case 0x01: + ret = (es1371->int_ctrl >> 8) & 0xff; + break; + case 0x02: + ret = (es1371->int_ctrl >> 16) & 0xff; + break; + case 0x03: + ret = (es1371->int_ctrl >> 24) & 0xff; + break; + + case 0x04: + ret = es1371->int_status & 0xff; + break; + case 0x05: + ret = (es1371->int_status >> 8) & 0xff; + break; + case 0x06: + ret = (es1371->int_status >> 16) & 0xff; + break; + case 0x07: + ret = (es1371->int_status >> 24) & 0xff; + break; + + + case 0x09: + ret = es1371->uart_status; + break; + + case 0x1a: + ret = es1371->legacy_ctrl >> 16; + break; + case 0x1b: + ret = es1371->legacy_ctrl >> 24; + break; + + case 0x20: + ret = es1371->si_cr & 0xff; + break; + case 0x21: + ret = es1371->si_cr >> 8; + break; + case 0x22: + ret = (es1371->si_cr >> 16) | 0x80; + break; + case 0x23: + ret = 0xff; + break; + + default: + pclog("Bad es1371_inb: port=%04x\n", port); + } + +// pclog("es1371_inb: port=%04x ret=%02x\n", port, ret); +// output = 3; + return ret; +} +static uint16_t es1371_inw(uint16_t port, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + uint16_t ret = 0; + + switch (port & 0x3e) + { + case 0x00: + ret = es1371->int_ctrl & 0xffff; + break; + case 0x02: + ret = (es1371->int_ctrl >> 16) & 0xffff; + break; + + case 0x18: + ret = es1371->legacy_ctrl & 0xffff; +// pclog("Read legacy ctrl %04x\n", ret); + break; + + case 0x26: + ret = es1371->dac[0].curr_samp_ct; + break; + + case 0x2a: + ret = es1371->dac[1].curr_samp_ct; + break; + + case 0x36: + switch (es1371->mem_page) + { + case 0xc: + ret = es1371->dac[0].count; + break; + + default: + pclog("Bad es1371_inw: mem_page=%x port=%04x\n", es1371->mem_page, port); + } + break; + + case 0x3e: + switch (es1371->mem_page) + { + case 0xc: + ret = es1371->dac[1].count; + break; + + default: + pclog("Bad es1371_inw: mem_page=%x port=%04x\n", es1371->mem_page, port); + } + break; + + default: + pclog("Bad es1371_inw: port=%04x\n", port); + } + +// pclog("es1371_inw: port=%04x ret=%04x %04x:%08x\n", port, ret, CS,cpu_state.pc); + return ret; +} +static uint32_t es1371_inl(uint16_t port, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + uint32_t ret = 0; + + switch (port & 0x3c) + { + case 0x00: + ret = es1371->int_ctrl; + break; + case 0x04: + ret = es1371->int_status; + break; + + case 0x10: + ret = es1371->sr_cir & ~0xffff; + ret |= es1371->sr_ram[es1371->sr_cir >> 25]; + break; + + case 0x14: + ret = es1371->codec_ctrl & 0x00ff0000; + ret |= es1371->codec_regs[(es1371->codec_ctrl >> 16) & 0x3f]; + ret |= CODEC_READY; + break; + + default: + pclog("Bad es1371_inl: port=%04x\n", port); + } + +// pclog("es1371_inl: port=%04x ret=%08x %08x\n", port, ret, cpu_state.pc); + return ret; +} + +static void es1371_outb(uint16_t port, uint8_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + +// pclog("es1371_outb: port=%04x val=%02x %04x:%08x\n", port, val, cs, cpu_state.pc); + switch (port & 0x3f) + { + case 0x00: + if (!(es1371->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN)) + { + es1371->dac[0].addr = es1371->dac[0].addr_latch; + es1371->dac[0].buffer_pos = 0; + es1371->dac[0].buffer_pos_end = 0; + es1371_fetch(es1371, 0); + } + if (!(es1371->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) + { + es1371->dac[1].addr = es1371->dac[1].addr_latch; + es1371->dac[1].buffer_pos = 0; + es1371->dac[1].buffer_pos_end = 0; + es1371_fetch(es1371, 1); + } + es1371->int_ctrl = (es1371->int_ctrl & 0xffffff00) | val; + break; + case 0x01: + es1371->int_ctrl = (es1371->int_ctrl & 0xffff00ff) | (val << 8); + break; + case 0x02: + es1371->int_ctrl = (es1371->int_ctrl & 0xff00ffff) | (val << 16); + break; + case 0x03: + es1371->int_ctrl = (es1371->int_ctrl & 0x00ffffff) | (val << 24); + break; + + case 0x09: + es1371->uart_ctrl = val; + break; + + case 0x0c: + es1371->mem_page = val & 0xf; + break; + + case 0x18: + es1371->legacy_ctrl |= LEGACY_INT; + nmi = 0; + break; + case 0x1a: + es1371->legacy_ctrl = (es1371->legacy_ctrl & 0xff00ffff) | (val << 16); + update_legacy(es1371); + break; + case 0x1b: + es1371->legacy_ctrl = (es1371->legacy_ctrl & 0x00ffffff) | (val << 24); + es1371_update_irqs(es1371); +// output = 3; + update_legacy(es1371); + break; + + case 0x20: + es1371->si_cr = (es1371->si_cr & 0xffff00) | val; + break; + case 0x21: + es1371->si_cr = (es1371->si_cr & 0xff00ff) | (val << 8); + if (!(es1371->si_cr & SI_P1_INTR_EN)) + es1371->int_status &= ~INT_STATUS_DAC1; + if (!(es1371->si_cr & SI_P2_INTR_EN)) + es1371->int_status &= ~INT_STATUS_DAC2; + es1371_update_irqs(es1371); + break; + case 0x22: + es1371->si_cr = (es1371->si_cr & 0x00ffff) | (val << 16); + break; + + default: + pclog("Bad es1371_outb: port=%04x val=%02x\n", port, val); + } +} +static void es1371_outw(uint16_t port, uint16_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + +// pclog("es1371_outw: port=%04x val=%04x\n", port, val); + switch (port & 0x3f) + { + case 0x0c: + es1371->mem_page = val & 0xf; + break; + + case 0x24: + es1371->dac[0].samp_ct = val; + break; + + case 0x28: + es1371->dac[1].samp_ct = val; + break; + + default: + pclog("Bad es1371_outw: port=%04x val=%04x\n", port, val); + } +} +static void es1371_outl(uint16_t port, uint32_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + +// pclog("es1371_outl: port=%04x val=%08x %04x:%08x\n", port, val, CS, cpu_state.pc); + switch (port & 0x3f) + { + case 0x04: + break; + + case 0x0c: + es1371->mem_page = val & 0xf; + break; + + case 0x10: + es1371->sr_cir = val; + if (es1371->sr_cir & SRC_RAM_WE) + { +// pclog("Write SR RAM %02x %04x\n", es1371->sr_cir >> 25, val & 0xffff); + es1371->sr_ram[es1371->sr_cir >> 25] = val & 0xffff; + switch (es1371->sr_cir >> 25) + { + case 0x71: + es1371->dac[0].vf = (es1371->dac[0].vf & ~0x1f8000) | ((val & 0xfc00) << 5); + es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7f8000) | ((val & 0x00ff) << 15); + break; + case 0x72: + es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7fff) | (val & 0x7fff); + break; + case 0x73: + es1371->dac[0].vf = (es1371->dac[0].vf & ~0x7fff) | (val & 0x7fff); + break; + + case 0x75: + es1371->dac[1].vf = (es1371->dac[1].vf & ~0x1f8000) | ((val & 0xfc00) << 5); + es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7f8000) | ((val & 0x00ff) << 15); + break; + case 0x76: + es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7fff) | (val & 0x7fff); + break; + case 0x77: + es1371->dac[1].vf = (es1371->dac[1].vf & ~0x7fff) | (val & 0x7fff); + break; + + case 0x7c: + es1371->dac[0].vol_l = (int32_t)(int16_t)(val & 0xffff); + break; + case 0x7d: + es1371->dac[0].vol_r = (int32_t)(int16_t)(val & 0xffff); + break; + case 0x7e: + es1371->dac[1].vol_l = (int32_t)(int16_t)(val & 0xffff); + break; + case 0x7f: + es1371->dac[1].vol_r = (int32_t)(int16_t)(val & 0xffff); + break; + } + } + break; + + case 0x14: + es1371->codec_ctrl = val; + if (!(val & CODEC_READ)) + { +// pclog("Write codec %02x %04x\n", (val >> 16) & 0x3f, val & 0xffff); + es1371->codec_regs[(val >> 16) & 0x3f] = val & 0xffff; + switch ((val >> 16) & 0x3f) + { + case 0x02: /*Master volume*/ + if (val & 0x8000) + es1371->master_vol_l = es1371->master_vol_r = 0; + else + { + if (val & 0x2000) + es1371->master_vol_l = codec_attn[0]; + else + es1371->master_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)]; + if (val & 0x20) + es1371->master_vol_r = codec_attn[0]; + else + es1371->master_vol_r = codec_attn[0x1f - (val & 0x1f)]; + } + break; + case 0x12: /*CD volume*/ + if (val & 0x8000) + sound_set_cd_volume(0, 0); + else + sound_set_cd_volume(codec_attn[0x1f - ((val >> 8) & 0x1f)] * 2, codec_attn[0x1f - (val & 0x1f)] * 2); + break; + } + } + break; + + case 0x24: + es1371->dac[0].samp_ct = val & 0xffff; + break; + + case 0x28: + es1371->dac[1].samp_ct = val & 0xffff; + break; + + case 0x30: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[0].addr_latch = val; +// pclog("DAC1 addr %08x\n", val); + break; + + default: + pclog("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + case 0x34: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[0].size = val & 0xffff; + es1371->dac[0].count = val >> 16; + if (es1371->dac[0].count) + es1371->dac[0].count -= 4; + break; + + default: + pclog("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + case 0x38: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[1].addr_latch = val; + break; + + case 0xd: + break; + + default: + pclog("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + case 0x3c: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[1].size = val & 0xffff; + es1371->dac[1].count = val >> 16; + break; + + case 0xd: + break; + + default: + pclog("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + + default: + pclog("Bad es1371_outl: port=%04x val=%08x\n", port, val); + } +} + +static void capture_event(es1371_t *es1371, int type, int rw, uint16_t port) +{ + es1371->legacy_ctrl &= ~(LEGACY_EVENT_MASK | LEGACY_EVENT_ADDR_MASK); + es1371->legacy_ctrl |= type; + if (rw) + es1371->legacy_ctrl |= LEGACY_EVENT_TYPE_RW; + else + es1371->legacy_ctrl &= ~LEGACY_EVENT_TYPE_RW; + es1371->legacy_ctrl |= ((port << LEGACY_EVENT_ADDR_SHIFT) & LEGACY_EVENT_ADDR_MASK); + es1371->legacy_ctrl &= ~LEGACY_INT; + nmi = 1; +// pclog("Event! %s %04x\n", rw ? "write" : "read", port); +} + +static void capture_write_sscape(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SSCAPE, 1, port); +} +static void capture_write_codec(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_CODEC, 1, port); +} +static void capture_write_sb(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SB, 1, port); +} +static void capture_write_adlib(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_ADLIB, 1, port); +} +static void capture_write_master_pic(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_PIC, 1, port); +} +static void capture_write_master_dma(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_DMA, 1, port); +} +static void capture_write_slave_pic(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_PIC, 1, port); +} +static void capture_write_slave_dma(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_DMA, 1, port); +} + +static uint8_t capture_read_sscape(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SSCAPE, 0, port); + return 0xff; +} +static uint8_t capture_read_codec(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_CODEC, 0, port); + return 0xff; +} +static uint8_t capture_read_sb(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SB, 0, port); + return 0xff; +} +static uint8_t capture_read_adlib(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_ADLIB, 0, port); + return 0xff; +} +static uint8_t capture_read_master_pic(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_PIC, 0, port); + return 0xff; +} +static uint8_t capture_read_master_dma(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_DMA, 0, port); + return 0xff; +} +static uint8_t capture_read_slave_pic(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_PIC, 0, port); + return 0xff; +} +static uint8_t capture_read_slave_dma(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_DMA, 0, port); + return 0xff; +} + +static void update_legacy(es1371_t *es1371) +{ + io_removehandler(0x0320, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); + io_removehandler(0x0330, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); + io_removehandler(0x0340, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); + io_removehandler(0x0350, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); + + io_removehandler(0x5300, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); + io_removehandler(0xe800, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); + io_removehandler(0xf400, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); + + io_removehandler(0x0220, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + io_removehandler(0x0240, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + + io_removehandler(0x0388, 0x0004, capture_read_adlib,NULL,NULL, capture_write_adlib,NULL,NULL, es1371); + + io_removehandler(0x0020, 0x0002, capture_read_master_pic,NULL,NULL, capture_write_master_pic,NULL,NULL, es1371); + io_removehandler(0x0000, 0x0010, capture_read_master_dma,NULL,NULL, capture_write_master_dma,NULL,NULL, es1371); + io_removehandler(0x00a0, 0x0002, capture_read_slave_pic,NULL,NULL, capture_write_slave_pic,NULL,NULL, es1371); + io_removehandler(0x00c0, 0x0020, capture_read_slave_dma,NULL,NULL, capture_write_slave_dma,NULL,NULL, es1371); + + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SSCAPE) + { + switch ((es1371->legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3) + { + case 0: io_sethandler(0x0320, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 1: io_sethandler(0x0330, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 2: io_sethandler(0x0340, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 3: io_sethandler(0x0350, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + } + } + if (es1371->legacy_ctrl & LEGACY_CAPTURE_CODEC) + { + switch ((es1371->legacy_ctrl >> LEGACY_CODEC_ADDR_SHIFT) & 3) + { + case 0: io_sethandler(0x5300, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + case 2: io_sethandler(0xe800, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + case 3: io_sethandler(0xf400, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + } + } + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SB) + { + if (!(es1371->legacy_ctrl & LEGACY_SB_ADDR)) + io_sethandler(0x0220, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + else + io_sethandler(0x0240, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + } + if (es1371->legacy_ctrl & LEGACY_CAPTURE_ADLIB) + io_sethandler(0x0388, 0x0004, capture_read_adlib,NULL,NULL, capture_write_adlib,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_MASTER_PIC) + io_sethandler(0x0020, 0x0002, capture_read_master_pic,NULL,NULL, capture_write_master_pic,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_MASTER_DMA) + io_sethandler(0x0000, 0x0010, capture_read_master_dma,NULL,NULL, capture_write_master_dma,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SLAVE_PIC) + io_sethandler(0x00a0, 0x0002, capture_read_slave_pic,NULL,NULL, capture_write_slave_pic,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SLAVE_DMA) + io_sethandler(0x00c0, 0x0020, capture_read_slave_dma,NULL,NULL, capture_write_slave_dma,NULL,NULL, es1371); +} + + +static uint8_t es1371_pci_read(int func, int addr, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + if (func) + return 0; + + //pclog("ES1371 PCI read %08X PC=%08x\n", addr, cpu_state.pc); + + switch (addr) + { + case 0x00: return 0x74; /*Ensoniq*/ + case 0x01: return 0x12; + + case 0x02: return 0x71; /*ES1371*/ + case 0x03: return 0x13; + + case 0x04: return es1371->pci_command; + case 0x05: return es1371->pci_serr; + + case 0x06: return 0x10; /*Supports ACPI*/ + case 0x07: return 0; + + case 0x08: return 2; /*Revision ID*/ + case 0x09: return 0x00; /*Multimedia audio device*/ + case 0x0a: return 0x01; + case 0x0b: return 0x04; + + case 0x10: return 0x01 | (es1371->base_addr & 0xc0); /*memBaseAddr*/ + case 0x11: return es1371->base_addr >> 8; + case 0x12: return es1371->base_addr >> 16; + case 0x13: return es1371->base_addr >> 24; + + case 0x2c: return 0x74; /*Subsystem vendor ID*/ + case 0x2d: return 0x12; + case 0x2e: return 0x71; + case 0x2f: return 0x13; + + case 0x34: return 0xdc; /*Capabilites pointer*/ + + case 0x3c: return es1371->int_line; + case 0x3d: return 0x01; /*INTA*/ + + case 0x3e: return 0xc; /*Minimum grant*/ + case 0x3f: return 0x80; /*Maximum latency*/ + + case 0xdc: return 0x01; /*Capabilities identifier*/ + case 0xdd: return 0x00; /*Next item pointer*/ + case 0xde: return 0x31; /*Power management capabilities*/ + case 0xdf: return 0x6c; + + case 0xe0: return es1371->pmcsr & 0xff; + case 0xe1: return es1371->pmcsr >> 8; + } + return 0; +} + +static void es1371_pci_write(int func, int addr, uint8_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + if (func) + return; + +// pclog("ES1371 PCI write %04X %02X PC=%08x\n", addr, val, cpu_state.pc); + + switch (addr) + { + case 0x04: + if (es1371->pci_command & PCI_COMMAND_IO) + io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + es1371->pci_command = val & 0x05; + if (es1371->pci_command & PCI_COMMAND_IO) + io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + break; + case 0x05: + es1371->pci_serr = val & 1; + break; + + case 0x10: + if (es1371->pci_command & PCI_COMMAND_IO) + io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + es1371->base_addr = (es1371->base_addr & 0xffffff00) | (val & 0xc0); + if (es1371->pci_command & PCI_COMMAND_IO) + io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + break; + case 0x11: + if (es1371->pci_command & PCI_COMMAND_IO) + io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + es1371->base_addr = (es1371->base_addr & 0xffff00c0) | (val << 8); + if (es1371->pci_command & PCI_COMMAND_IO) + io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + break; + case 0x12: + es1371->base_addr = (es1371->base_addr & 0xff00ffc0) | (val << 16); + break; + case 0x13: + es1371->base_addr = (es1371->base_addr & 0x00ffffc0) | (val << 24); + break; + + case 0x3c: + es1371->int_line = val; + break; + + case 0xe0: + es1371->pmcsr = (es1371->pmcsr & 0xff00) | (val & 0x03); + break; + case 0xe1: + es1371->pmcsr = (es1371->pmcsr & 0x00ff) | ((val & 0x01) << 8); + break; + } +// pclog("es1371->base_addr %08x\n", es1371->base_addr); +} + +static void es1371_fetch(es1371_t *es1371, int dac_nr) +{ + int format = dac_nr ? ((es1371->si_cr >> 2) & 3) : (es1371->si_cr & 3); + int pos = es1371->dac[dac_nr].buffer_pos & 63; + int c; + +//pclog("Fetch format=%i %08x %08x %08x %08x %08x\n", format, es1371->dac[dac_nr].count, es1371->dac[dac_nr].size, es1371->dac[dac_nr].curr_samp_ct,es1371->dac[dac_nr].samp_ct, es1371->dac[dac_nr].addr); + switch (format) + { + case FORMAT_MONO_8: + for (c = 0; c < 32; c += 4) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+1) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+2) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+2) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+2) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+3) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+3) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+3) ^ 0x80) << 8; + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end += 4; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + case FORMAT_STEREO_8: + for (c = 0; c < 16; c += 2) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 1) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 2) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 3) ^ 0x80) << 8; + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end += 2; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + case FORMAT_MONO_16: + for (c = 0; c < 16; c += 2) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr); + es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr + 2); + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end += 2; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + case FORMAT_STEREO_16: + for (c = 0; c < 4; c++) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr); + es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr + 2); +// pclog("Fetch %02x %08x %04x %04x\n", (pos+c) & 63, es1371->dac[dac_nr].addr, es1371->dac[dac_nr].buffer_l[(pos+c) & 63], es1371->dac[dac_nr].buffer_r[(pos+c) & 63]); + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end++; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + } +} + +static void es1371_next_sample(es1371_t *es1371, int dac_nr) +{ + if ((es1371->dac[dac_nr].buffer_pos - es1371->dac[dac_nr].buffer_pos_end) >= 0) + { + es1371_fetch(es1371, dac_nr); + } + + es1371->dac[dac_nr].out_l = es1371->dac[dac_nr].buffer_l[es1371->dac[dac_nr].buffer_pos & 63]; + es1371->dac[dac_nr].out_r = es1371->dac[dac_nr].buffer_r[es1371->dac[dac_nr].buffer_pos & 63]; +// pclog("Use %02x %04x %04x\n", es1371->dac[dac_nr].buffer_pos & 63, es1371->dac[dac_nr].out_l, es1371->dac[dac_nr].out_r); + + es1371->dac[dac_nr].buffer_pos++; +// pclog("Next sample %08x %08x %08x\n", es1371->dac[dac_nr].buffer_pos, es1371->dac[dac_nr].buffer_pos_end, es1371->dac[dac_nr].curr_samp_ct); +} + +//static FILE *es1371_f;//,*es1371_f2; +static void es1371_poll(void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + es1371->dac[1].time += es1371->dac[1].latch; + + if (es1371->int_ctrl & INT_DAC1_EN) + { +// pclog("1Samp %i %i %08x\n", es1371->dac[0].curr_samp_ct, es1371->dac[0].samp_ct, es1371->dac[0].ac); + es1371->dac[0].ac += es1371->dac[0].vf; + if (es1371->dac[0].ac & (~0 << (15+4))) + { + es1371->dac[0].ac &= ~(~0 << (15+4)); + es1371_next_sample(es1371, 0); + + es1371->dac[0].curr_samp_ct++; + if (es1371->dac[0].curr_samp_ct == es1371->dac[0].samp_ct) + { +// pclog("DAC1 IRQ\n"); + es1371->int_status |= INT_STATUS_DAC1; + es1371_update_irqs(es1371); + } + if (es1371->dac[0].curr_samp_ct > es1371->dac[0].samp_ct) + { + es1371->dac[0].curr_samp_ct = 0; + } + } + } + + if (es1371->int_ctrl & INT_DAC2_EN) + { +// pclog("2Samp %i %i %08x\n", es1371->dac[1].curr_samp_ct, es1371->dac[1].samp_ct, es1371->dac[1].ac); + es1371->dac[1].ac += es1371->dac[1].vf; + if (es1371->dac[1].ac & (~0 << (15+4))) + { + es1371->dac[1].ac &= ~(~0 << (15+4)); + es1371_next_sample(es1371, 1); + + es1371->dac[1].curr_samp_ct++; + if (es1371->dac[1].curr_samp_ct > es1371->dac[1].samp_ct) + { + es1371->dac[1].curr_samp_ct = 0; +// pclog("DAC2 IRQ\n"); + es1371->int_status |= INT_STATUS_DAC2; + es1371_update_irqs(es1371); + } + } + } + + for (; es1371->pos < sound_pos_global; es1371->pos++) + { + int32_t l, r; + + l = (es1371->dac[0].out_l * es1371->dac[0].vol_l) >> 12; + l += ((es1371->dac[1].out_l * es1371->dac[1].vol_l) >> 12); + r = (es1371->dac[0].out_r * es1371->dac[0].vol_r) >> 12; + r += ((es1371->dac[1].out_r * es1371->dac[1].vol_r) >> 12); + + l >>= 1; + r >>= 1; + + l = (l * es1371->master_vol_l) >> 15; + r = (r * es1371->master_vol_r) >> 15; + + if (l < -32768) + l = -32768; + else if (l > 32767) + l = 32767; + if (r < -32768) + r = -32768; + else if (r > 32767) + r = 32767; + + es1371->buffer[es1371->pos*2] = l; + es1371->buffer[es1371->pos*2 + 1] = r; + } +} + +static void es1371_get_buffer(int32_t *buffer, int len, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + int c; + + for (c = 0; c < len * 2; c++) + buffer[c] += (es1371->buffer[c] / 2); + + es1371->pos = 0; +} + +static void *es1371_init() +{ + es1371_t *es1371 = malloc(sizeof(es1371_t)); + memset(es1371, 0, sizeof(es1371_t)); + + sound_add_handler(es1371_get_buffer, es1371); + + es1371->card = pci_add_card(PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, es1371); + + timer_add(es1371_poll, &es1371->dac[1].time, TIMER_ALWAYS_ENABLED, es1371); + + return es1371; +} + +static void es1371_close(void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + free(es1371); +} + +static void es1371_speed_changed(void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + es1371->dac[1].latch = (int)((double)TIMER_USEC * (1000000.0 / 48000.0)); +} + +device_t es1371_device = +{ + "Ensoniq AudioPCI (ES1371)", + DEVICE_PCI, + 0, + es1371_init, + es1371_close, + NULL, + NULL, + es1371_speed_changed, + NULL, + NULL, + NULL +}; diff --git a/src/sound/snd_audiopci.h b/src/sound/snd_audiopci.h new file mode 100644 index 000000000..5aff3d024 --- /dev/null +++ b/src/sound/snd_audiopci.h @@ -0,0 +1 @@ +extern device_t es1371_device; diff --git a/src/sound/snd_emu8k.c b/src/sound/snd_emu8k.c index 9237dca3e..40d4bc221 100644 --- a/src/sound/snd_emu8k.c +++ b/src/sound/snd_emu8k.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -13,15 +14,19 @@ #include "sound.h" #include "snd_emu8k.h" - #if !defined FILTER_INITIAL && !defined FILTER_MOOG && !defined FILTER_CONSTANT +//#define FILTER_INITIAL #define FILTER_MOOG +//#define FILTER_CONSTANT #endif #if !defined RESAMPLER_LINEAR && !defined RESAMPLER_CUBIC +//#define RESAMPLER_LINEAR #define RESAMPLER_CUBIC #endif +//#define EMU8K_DEBUG_REGISTERS + char *PORT_NAMES[][8] = { /* Data 0 ( 0x620/0x622) */ @@ -53,8 +58,8 @@ char *PORT_NAMES[][8] = "AWE_HWCF2" "AWE_HWCF3" */ - 0, - 0, + 0,//"AWE_INIT1", + 0,//"AWE_INIT3", "AWE_ENVVOL", "AWE_DCYSUSV", "AWE_ENVVAL", @@ -63,8 +68,8 @@ char *PORT_NAMES[][8] = /* Data 2 0xA22 */ { "AWE_CCCA", 0, - 0, - 0, + 0,//"AWE_INIT2", + 0,//"AWE_INIT4", "AWE_ATKHLDV", "AWE_LFO1VAL", "AWE_ATKHLD", @@ -88,7 +93,9 @@ enum ENV_DELAY = 1, ENV_ATTACK = 2, ENV_HOLD = 3, + //ENV_DECAY = 4, ENV_SUSTAIN = 5, + //ENV_RELEASE = 6, ENV_RAMP_DOWN = 7, ENV_RAMP_UP = 8 }; @@ -231,15 +238,15 @@ uint32_t rep_count_w = 0; # define READ16(addr, var) READ16_SWITCH(addr, var) \ { \ const char *name=0; \ - switch(addr) \ + switch(addr&0xF02) \ { \ - case 0x620: case 0x622: \ + case 0x600: case 0x602: \ name = PORT_NAMES[0][emu8k->cur_reg]; \ break; \ - case 0xA20: \ + case 0xA00: \ name = PORT_NAMES[1][emu8k->cur_reg]; \ break; \ - case 0xA22: \ + case 0xA02: \ name = PORT_NAMES[2][emu8k->cur_reg]; \ break; \ } \ @@ -255,15 +262,15 @@ uint32_t rep_count_w = 0; # define WRITE16(addr, var, val) WRITE16_SWITCH(addr, var, val) \ { \ const char *name=0; \ - switch(addr) \ + switch(addr&0xF02) \ { \ - case 0x620: case 0x622: \ + case 0x600: case 0x602: \ name = PORT_NAMES[0][emu8k->cur_reg]; \ break; \ - case 0xA20: \ + case 0xA00: \ name = PORT_NAMES[1][emu8k->cur_reg]; \ break; \ - case 0xA22: \ + case 0xA02: \ name = PORT_NAMES[2][emu8k->cur_reg]; \ break; \ } \ @@ -280,7 +287,7 @@ uint32_t rep_count_w = 0; #else # define READ16(addr, var) READ16_SWITCH(addr, var) # define WRITE16(addr, var, val) WRITE16_SWITCH(addr, var, val) -#endif /* EMU8K_DEBUG_REGISTERS */ +#endif //EMU8K_DEBUG_REGISTERS static inline int16_t EMU8K_READ(emu8k_t *emu8k, uint32_t addr) @@ -312,7 +319,7 @@ static inline int32_t EMU8K_READ_INTERP_CUBIC(emu8k_t *emu8k, uint32_t int_addr, * the card could use two oscillators (usually 31 and 32) where it would * be writing the OPL3 output, and to which, chorus and reverb could be applied to get * those effects for OPL3 sounds.*/ -/* if ((addr & EMU8K_FM_MEM_ADDRESS) == EMU8K_FM_MEM_ADDRESS) {} */ +// if ((addr & EMU8K_FM_MEM_ADDRESS) == EMU8K_FM_MEM_ADDRESS) {} /* This is cubic interpolation. * Not the same than 3-point interpolation, but a better approximation than linear @@ -389,7 +396,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p) last_read=tmpz; pclog("EMU8K READ RAM I/O or configuration or clock \n"); } - /* pclog("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); */ + //pclog("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); } else if ((addr&0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3)) { @@ -404,7 +411,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p) last_read=tmpz; pclog("EMU8K READ INIT \n"); } - /* pclog("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); */ + //pclog("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); } else { @@ -472,7 +479,7 @@ uint16_t emu8k_inw(uint16_t addr, void *p) } rep_count_r++; } -#endif /* EMU8K_DEBUG_REGISTERS */ +#endif // EMU8K_DEBUG_REGISTERS switch (addr & 0xF02) @@ -724,7 +731,7 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) #ifdef EMU8K_DEBUG_REGISTERS if (addr == 0xE22) { - /* pclog("EMU8K WRITE POINTER: %d\n", val); */ + //pclog("EMU8K WRITE POINTER: %d\n", val); } else if ((addr&0xF00) == 0x600) { @@ -759,7 +766,7 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) last_write=tmpz; pclog("EMU8K WRITE RAM I/O or configuration \n"); } - /* pclog("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); */ + //pclog("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); } else if ((addr&0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3)) { @@ -774,12 +781,12 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) last_write=tmpz; pclog("EMU8K WRITE INIT \n"); } - /* pclog("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); */ + //pclog("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); } else if (addr != 0xE22) { uint32_t tmpz = (addr << 16)|(emu8k->cur_reg<<5)| emu8k->cur_voice; - /* if (tmpz != last_write) */ + //if (tmpz != last_write) if(1) { char* name = 0; @@ -814,7 +821,7 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) } rep_count_w++; } -#endif /* EMU8K_DEBUG_REGISTERS */ +#endif //EMU8K_DEBUG_REGISTERS switch (addr & 0xF02) @@ -954,15 +961,15 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) break; case 0x9: emu8k->reverb_engine.reflections[0].feedback = (val&0xF)/15.0; break; - case 0xB: /* emu8k->reverb_engine.reflections[0].feedback_r = (val&0xF)/15.0; */ + case 0xB: //emu8k->reverb_engine.reflections[0].feedback_r = (val&0xF)/15.0; break; case 0x11:emu8k->reverb_engine.reflections[1].feedback = (val&0xF)/15.0; break; - case 0x13: /* emu8k->reverb_engine.reflections[1].feedback_r = (val&0xF)/15.0; */ + case 0x13: //emu8k->reverb_engine.reflections[1].feedback_r = (val&0xF)/15.0; break; case 0x19: emu8k->reverb_engine.reflections[2].feedback = (val&0xF)/15.0; break; - case 0x1B: /* emu8k->reverb_engine.reflections[2].feedback_r = (val&0xF)/15.0; */ + case 0x1B: //emu8k->reverb_engine.reflections[2].feedback_r = (val&0xF)/15.0; break; } } @@ -979,12 +986,13 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) emu8k->chorus_engine.feedback = (val&0xFF); break; case 12: - emu8k->chorus_engine.delay_samples_central = val; + /* Limiting this to a sane value given our buffer. */ + emu8k->chorus_engine.delay_samples_central = (val&0x1FFF); break; case 1: emu8k->reverb_engine.refl_in_amp = val&0xFF; break; - case 3: /* emu8k->reverb_engine.refl_in_amp_r = val&0xFF; */ + case 3: //emu8k->reverb_engine.refl_in_amp_r = val&0xFF; break; } } @@ -1005,17 +1013,17 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) if (emu8k->voice[emu8k->cur_voice].env_engine_on && old_on != emu8k->voice[emu8k->cur_voice].env_engine_on) { - if (emu8k->hwcf3 != 0x04 && emu8k->cur_voice == 31) + if (emu8k->hwcf3 != 0x04) { /* This is a hack for some programs like Doom or cubic player 1.7 that don't initialize the hwcfg and init registers (doom does not init the card at all. only tests the cfg registers) */ emu8k->hwcf3 = 0x04; } - /* reset lfos. */ + //reset lfos. emu8k->voice[emu8k->cur_voice].lfo1_count.addr = 0; emu8k->voice[emu8k->cur_voice].lfo2_count.addr = 0; - /* Trigger envelopes */ + // Trigger envelopes if (ATKHLDV_TRIGGER(emu8k->voice[emu8k->cur_voice].atkhldv)) { vol_env->value_amp_hz = 0; @@ -1092,7 +1100,7 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) case 7: { - /* TODO: Look for a bug on delay (first trigger it works, next trigger it doesn't) */ + //TODO: Look for a bug on delay (first trigger it works, next trigger it doesn't) emu8k->voice[emu8k->cur_voice].dcysus = val; emu8k_envelope_t* const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; /* Converting the input in octaves to envelope value range. */ @@ -1137,7 +1145,9 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) if (emu8k->init1[0] != 0x03FF) { /*(1/256th of a 44Khz sample) */ - emu8k->chorus_engine.delay_offset_samples_right = ((double)emu8k->hwcf4)/256.0; + /* clip the value to a reasonable value given our buffer */ + int32_t tmp = emu8k->hwcf4&0x1FFFFF; + emu8k->chorus_engine.delay_offset_samples_right = ((double)tmp)/256.0; } return; case 10: @@ -1147,9 +1157,14 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) { /* The scale of this value is unknown. I've taken it as milliHz. * Another interpretation could be periods. (and so, Hz = 1/period)*/ - double osc_speed = emu8k->hwcf5;/* *1.316; */ + double osc_speed = emu8k->hwcf5;//*1.316; +#if 1 // milliHz /*milliHz to lfotable samples.*/ osc_speed *= 65.536/44100.0; +#elif 0 //periods + /* 44.1Khz ticks to lfotable samples.*/ + osc_speed = 65.536/osc_speed; +#endif /*left shift 32bits for 32.32 fixed.point*/ osc_speed *= 65536.0*65536.0; emu8k->chorus_engine.lfo_inc.addr = (uint64_t)osc_speed; @@ -1235,15 +1250,15 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) break; case 0x1: emu8k->reverb_engine.reflections[3].feedback = (val&0xF)/15.0; break; - case 0x3: /* emu8k->reverb_engine.reflections[3].feedback_r = (val&0xF)/15.0; */ + case 0x3: //emu8k->reverb_engine.reflections[3].feedback_r = (val&0xF)/15.0; break; case 0x9: emu8k->reverb_engine.reflections[4].feedback = (val&0xF)/15.0; break; - case 0xb: /* emu8k->reverb_engine.reflections[4].feedback_r = (val&0xF)/15.0; */ + case 0xb: //emu8k->reverb_engine.reflections[4].feedback_r = (val&0xF)/15.0; break; case 0x11: emu8k->reverb_engine.reflections[5].feedback = (val&0xF)/15.0; break; - case 0x13: /* emu8k->reverb_engine.reflections[5].feedback_r = (val&0xF)/15.0; */ + case 0x13: //emu8k->reverb_engine.reflections[5].feedback_r = (val&0xF)/15.0; break; } } @@ -1260,6 +1275,7 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) { int32_t samples = ((val&0xFF)*emu8k->chorus_engine.delay_samples_central) >> 8; emu8k->chorus_engine.lfodepth_multip = samples; + } break; @@ -1386,8 +1402,8 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) if ((val&0xFF) == 0 && the_voice->cvcf_curr_volume == 0 && the_voice->vtft_vol_target == 0 && the_voice->dcysusv == 0x80 && the_voice->ip == 0) { - /* Patch to avoid some clicking noises with Impulse tracker or other software that sets different values to 0 - to set noteoff, but here, 0 means no attenuation = full volume. */ + // Patch to avoid some clicking noises with Impulse tracker or other software that sets + // different values to 0 to set noteoff, but here, 0 means no attenuation = full volume. return; } the_voice->ifatn = val; @@ -1496,7 +1512,7 @@ void emu8k_work_chorus(int32_t *inbuf, int32_t *outbuf, emu8k_chorus_eng_t *engi for (pos = 0; pos < count; pos++) { double lfo_inter1 = chortable[engine->lfo_pos.int_address]; - /* double lfo_inter2 = chortable[(engine->lfo_pos.int_address+1)&0xFFFF]; */ + // double lfo_inter2 = chortable[(engine->lfo_pos.int_address+1)&0xFFFF]; double offset_lfo =lfo_inter1; //= lfo_inter1 + ((lfo_inter2-lfo_inter1)*engine->lfo_pos.fract_address/65536.0); offset_lfo *= engine->lfodepth_multip; @@ -1505,18 +1521,16 @@ void emu8k_work_chorus(int32_t *inbuf, int32_t *outbuf, emu8k_chorus_eng_t *engi double readdouble = (double)engine->write - (double)engine->delay_samples_central - offset_lfo; int read = (int32_t)floor(readdouble); int fraction_part = (readdouble - (double)read)*65536.0; - if (read < 0) - read = 0; int next_value = read + 1; if(read < 0) { - read += SOUNDBUFLEN; - if(next_value < 0) next_value += SOUNDBUFLEN; + read += EMU8K_LFOCHORUS_SIZE; + if(next_value < 0) next_value += EMU8K_LFOCHORUS_SIZE; } - else if(next_value >= SOUNDBUFLEN) + else if(next_value >= EMU8K_LFOCHORUS_SIZE) { - next_value -= SOUNDBUFLEN; - if(read >= SOUNDBUFLEN) read -= SOUNDBUFLEN; + next_value -= EMU8K_LFOCHORUS_SIZE; + if(read >= EMU8K_LFOCHORUS_SIZE) read -= EMU8K_LFOCHORUS_SIZE; } int32_t dat1 = engine->chorus_left_buffer[read]; int32_t dat2 = engine->chorus_left_buffer[next_value]; @@ -1528,18 +1542,16 @@ void emu8k_work_chorus(int32_t *inbuf, int32_t *outbuf, emu8k_chorus_eng_t *engi /* Work right */ readdouble = (double)engine->write - (double)engine->delay_samples_central - engine->delay_offset_samples_right - offset_lfo; read = (int32_t)floor(readdouble); - if (read < 0) - read = 0; next_value = read + 1; if(read < 0) { - read += SOUNDBUFLEN; - if(next_value < 0) next_value += SOUNDBUFLEN; + read += EMU8K_LFOCHORUS_SIZE; + if(next_value < 0) next_value += EMU8K_LFOCHORUS_SIZE; } - else if(next_value >= SOUNDBUFLEN) + else if(next_value >= EMU8K_LFOCHORUS_SIZE) { - next_value -= SOUNDBUFLEN; - if(read >= SOUNDBUFLEN) read -= SOUNDBUFLEN; + next_value -= EMU8K_LFOCHORUS_SIZE; + if(read >= EMU8K_LFOCHORUS_SIZE) read -= EMU8K_LFOCHORUS_SIZE; } int32_t dat3 = engine->chorus_right_buffer[read]; int32_t dat4 = engine->chorus_right_buffer[next_value]; @@ -1548,7 +1560,7 @@ void emu8k_work_chorus(int32_t *inbuf, int32_t *outbuf, emu8k_chorus_eng_t *engi engine->chorus_right_buffer[engine->write] = *inbuf + ((dat3 * engine->feedback)>>8); ++engine->write; - engine->write %= SOUNDBUFLEN; + engine->write %= EMU8K_LFOCHORUS_SIZE; engine->lfo_pos.addr +=engine->lfo_inc.addr; engine->lfo_pos.int_address &= 0xFFFF; @@ -1598,10 +1610,10 @@ int32_t emu8k_reverb_tail_work(emu8k_reverb_combfilter_t* comb, emu8k_reverb_com /* store new value in delayed buffer */ comb->reflection[comb->read_pos] = in; - /* output = emu8k_reverb_allpass_work(&allpasses[0],output); */ + //output = emu8k_reverb_allpass_work(&allpasses[0],output); output = emu8k_reverb_diffuser_work(&allpasses[1],output); output = emu8k_reverb_diffuser_work(&allpasses[2],output); - /* output = emu8k_reverb_allpass_work(&allpasses[3],output); */ + //output = emu8k_reverb_allpass_work(&allpasses[3],output); if(++comb->read_pos>=comb->bufsize) comb->read_pos = 0; @@ -1664,7 +1676,7 @@ void emu8k_work_reverb(int32_t *inbuf, int32_t *outbuf, emu8k_reverb_eng_t *engi } void emu8k_work_eq(int32_t *inoutbuf, int count) { - /* TODO: Work EQ over buf */ + // TODO: Work EQ over buf } @@ -1683,6 +1695,9 @@ int32_t emu8k_vol_slide(emu8k_slide_t* slide, int32_t target) return slide->last; } +//int32_t old_pitch[32]={0}; +//int32_t old_cut[32]={0}; +//int32_t old_vol[32]={0}; void emu8k_update(emu8k_t *emu8k) { int new_pos = (sound_pos_global * 44100) / 48000; @@ -2055,6 +2070,12 @@ I've recopilated these sentences to get an idea of how to loop /* Update EMU voice registers. */ emu_voice->ccca = (((uint32_t)emu_voice->ccca_qcontrol) << 24) | emu_voice->addr.int_address; emu_voice->cpf_curr_frac_addr = emu_voice->addr.fract_address; + + //if ( emu_voice->cvcf_curr_volume != old_vol[c]) { + // pclog("EMUVOL (%d):%d\n", c, emu_voice->cvcf_curr_volume); + // old_vol[c]=emu_voice->cvcf_curr_volume; + //} + //pclog("EMUFILT :%d\n", emu_voice->cvcf_curr_filt_ctoff); } @@ -2063,7 +2084,7 @@ I've recopilated these sentences to get an idea of how to loop emu8k_work_chorus(&emu8k->chorus_in_buffer[emu8k->pos], buf, &emu8k->chorus_engine, new_pos-emu8k->pos); emu8k_work_eq(buf, new_pos-emu8k->pos); - /* Clip signal */ + // Clip signal for (pos = emu8k->pos; pos < new_pos; pos++) { if (buf[0] < -32768) @@ -2085,7 +2106,7 @@ I've recopilated these sentences to get an idea of how to loop emu8k->pos = new_pos; } /* onboard_ram in kilobytes */ -void emu8k_init(emu8k_t *emu8k, int onboard_ram) +void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram) { uint32_t const BLOCK_SIZE_WORDS = 0x10000; FILE *f; @@ -2145,9 +2166,9 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram) } - io_sethandler(0x0620, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); - io_sethandler(0x0a20, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); - io_sethandler(0x0e20, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(emu_addr, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(emu_addr+0x400, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(emu_addr+0x800, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); /*Create frequency table. (Convert initial pitch register value to a linear speed change) * The input is encoded such as 0xe000 is center note (no pitch shift) @@ -2178,6 +2199,8 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram) out = 65535.0; for (c = 0; c < 0x10000; c++) { + //double db = -(c*6.0205999/65535.0)*16.0; + //out = powf(10.f,db/20.f) * 65536.0; env_vol_db_to_vol_target[c] = (int32_t)out; /* calculated from the 65536th root of 65536 */ out /= 1.00016923970; @@ -2283,12 +2306,13 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram) filt_coeffs[qidx][c][0] = (int32_t)(coef0 * 16777216.0); filt_coeffs[qidx][c][1] = (int32_t)(coef1 * 16777216.0); filt_coeffs[qidx][c][2] = (int32_t)(coef2 * 16777216.0); -#endif /* FILTER_TYPE */ +#endif //FILTER_TYPE /* 42.66 divisions per octave (the doc says quarter seminotes which is 48, but then it would be almost an octave less) */ out *= 1.016378315; /* 42 divisions. This moves the max frequency to 8.5Khz.*/ - /* out *= 1.0166404394; */ + //out *= 1.0166404394; /* This is a linear increment method, that corresponds to the NRPN table, but contradicts the EMU8KPRM doc: */ + //out = 100.0 + (c+1.0)*31.25; //31.25Hz steps */ } } /* NOTE! read_pos and buffer content is implicitly initialized to zero by the sb_t structure memset on sb_awe32_init() */ @@ -2321,8 +2345,8 @@ void emu8k_init(emu8k_t *emu8k, int onboard_ram) cubic_table[c*4+2] = (-1.5 * x * x * x + 2.0 * x * x + 0.5 * x) ; cubic_table[c*4+3] = ( 0.5 * x * x * x - 0.5 * x * x) ; } - /* If this is not set here, AWE card is not detected on Windows with Aweman driver. It's weird that the EMU8k says that this - * has to be set by applications, and the AWE driver does not set it. */ + /* Even when the documentation says that this has to be written by applications to initialize the card, + * several applications and drivers ( aweman on windows, linux oss driver..) read it to detect an AWE card. */ emu8k->hwcf1 = 0x59; emu8k->hwcf2 = 0x20; /* Initial state is muted. 0x04 is unmuted. */ diff --git a/src/sound/snd_emu8k.h b/src/sound/snd_emu8k.h index aa0f0be02..16323a13b 100644 --- a/src/sound/snd_emu8k.h +++ b/src/sound/snd_emu8k.h @@ -1,34 +1,34 @@ + /* All these defines are in samples, not in bytes. */ #define EMU8K_MEM_ADDRESS_MASK 0xFFFFFF #define EMU8K_RAM_MEM_START 0x200000 #define EMU8K_FM_MEM_ADDRESS 0xFFFFE0 #define EMU8K_RAM_POINTERS_MASK 0x3F #define EMU8K_LFOCHORUS_SIZE 0x4000 - /* - Everything in this file assumes little endian - - used for the increment of oscillator position */ + * Everything in this file assumes little endian + */ +/* used for the increment of oscillator position*/ typedef struct emu8k_mem_internal_t { union { - uint64_t addr; - struct { - uint16_t fract_lw_address; - uint16_t fract_address; - uint32_t int_address; - }; + uint64_t addr; + struct { + uint16_t fract_lw_address; + uint16_t fract_address; + uint32_t int_address; + }; }; } emu8k_mem_internal_t; /* used for access to ram pointers from oscillator position. */ typedef struct emu8k_mem_pointers_t { union { - uint32_t addr; - struct { - uint16_t lw_address; - uint8_t hb_address; - uint8_t unused_address; - }; + uint32_t addr; + struct { + uint16_t lw_address; + uint8_t hb_address; + uint8_t unused_address; + }; }; } emu8k_mem_pointers_t; @@ -58,23 +58,29 @@ typedef struct emu8k_mem_pointers_t { The volume envelope operates in dB, with the attack peak providing a full scale output, appropriately scaled by the initial volume. The zero value, however, is actually zero gain. The implementation in the EMU8000 provides for 96 dB of amplitude control. - When 96 dB of attenuation is reached in the final gain amplifier, an abrupt jump to zero gain (infinite dB of attenuation) occurs. In a 16-bit system, this jump is inaudible + When 96 dB of attenuation is reached in the final gain amplifier, an abrupt jump to zero gain + (infinite dB of attenuation) occurs. In a 16-bit system, this jump is inaudible */ /* It seems that the envelopes don't really have a decay/release stage, - but instead they have a volume ramper that can be triggered - automatically (after hold period), or manually (by activating release) - and the "sustain" value is the target of any of both cases. - Some programs like cubic player and AWEAmp use this, and it was - described in the following way in Vince Vu/Judge Dredd's awe32p10.txt: - If the MSB (most significant bit or bit 15) of this register is set, - the Decay/Release will begin immediately, overriding the Delay, Attack, - and Hold. Otherwise the Decay/Release will wait until the Delay, Attack, - and Hold are finished. If you set the MSB of this register, you can use - it as a volume ramper, as on the GUS. The upper byte (except the MSB), - contains the destination volume, and the lower byte contains the ramp time. */ + * but instead they have a volume ramper that can be triggered + * automatically (after hold period), or manually (by activating release) + * and the "sustain" value is the target of any of both cases. + * Some programs like cubic player and AWEAmp use this, and it was + * described in the following way in Vince Vu/Judge Dredd's awe32p10.txt: + * If the MSB (most significant bit or bit 15) of this register is set, + * the Decay/Release will begin immediately, overriding the Delay, Attack, + * and Hold. Otherwise the Decay/Release will wait until the Delay, Attack, + * and Hold are finished. If you set the MSB of this register, you can use + * it as a volume ramper, as on the GUS. The upper byte (except the MSB), + * contains the destination volume, and the lower byte contains the ramp time. + */ -/* attack_amount is linear amplitude (added directly to value). ramp_amount_db is linear dB (added directly to value too, but needs conversion to get linear amplitude). - value range is 21bits for both, linear amplitude being 1<<21 = 0dBFS and 0 = -96dBFS (which is shortcut to silence), and db amplutide being 0 = 0dBFS and -(1<<21) = -96dBFS (which is shortcut to silence). This allows to operate db values by simply adding them. */ +/* attack_amount is linear amplitude (added directly to value). + * ramp_amount_db is linear dB (added directly to value too, but needs conversion to get linear amplitude). + * value range is 21bits for both, linear amplitude being 1<<21 = 0dBFS and 0 = -96dBFS (which is shortcut to silence), + * and db amplutide being 0 = 0dBFS and -(1<<21) = -96dBFS (which is shortcut to silence). + * This allows to operate db values by simply adding them. + */ typedef struct emu8k_envelope_t { int state; int32_t delay_samples, hold_samples, attack_samples; @@ -351,8 +357,6 @@ typedef struct emu8k_t uint16_t wc; - uint16_t c02_read; - uint16_t id; /* The empty block is used to act as an unallocated memory returning zero. */ @@ -364,8 +368,6 @@ typedef struct emu8k_t int cur_reg, cur_voice; - int timer_count; - int16_t out_l, out_r; emu8k_chorus_eng_t chorus_engine; @@ -379,7 +381,395 @@ typedef struct emu8k_t -void emu8k_init(emu8k_t *emu8k, int onboard_ram); +void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram); void emu8k_close(emu8k_t *emu8k); void emu8k_update(emu8k_t *emu8k); + + + + +/* + +Section E - Introduction to the EMU8000 Chip + + The EMU8000 has its roots in E-mu's Proteus sample playback + modules and their renowned Emulator sampler. The EMU8000 has + 32 individual oscillators, each playing back at 44.1 kHz. By + incorporating sophisticated sample interpolation algorithms + and digital filtering, the EMU8000 is capable of producing + high fidelity sample playback. + + The EMU8000 has an extensive modulation capability using two + sine-wave LFOs (Low Frequency Oscillator) and two multi- + stage envelope generators. + + What exactly does modulation mean? Modulation means to + dynamically change a parameter of an audio signal, whether + it be the volume (amplitude modulation, or tremolo), pitch + (frequency modulation, or vibrato) or filter cutoff + frequency (filter modulation, or wah-wah). To modulate + something we would require a modulation source, and a + modulation destination. In the EMU8000, the modulation + sources are the LFOs and the envelope generators, and the + modulation destinations can be the pitch, the volume or the + filter cutoff frequency. + + The EMU8000's LFOs and envelope generators provide a complex + modulation environment. Each sound producing element of the + EMU8000 consists of a resonant low-pass filter, two LFOs, in + which one modulates the pitch (LFO2), and the other + modulates pitch, filter cutoff and volume (LFO1) + simultaneously. There are two envelope generators; envelope + 1 contours both pitch and filter cutoff simultaneously, and + envelope 2 contours volume. The output stage consists of an + effects engine that mixes the dry signals with the + Reverb/chorus level signals to produce the final mix. + + What are the EMU8000 sound elements? + + Each of the sound elements in an EMU8000 consists of the + following: + + Oscillator + An oscillator is the source of an audio signal. + + Low Pass Filter + The low pass filter is responsible for modifying the + timbres of an instrument. The low pass filter's filter + cutoff values can be varied from 100 Hz to 8000 Hz. By + changing the values of the filter cutoff, a myriad of + analogue sounding filter sweeps can be achieved. An + example of a GM instrument that makes use of filter sweep + is instrument number 87, Lead 7 (fifths). + + Amplifier + The amplifier determines the loudness of an audio signal. + + LFO1 + An LFO, or Low Frequency Oscillator, is normally used to + periodically modulate, that is, change a sound parameter, + whether it be volume (amplitude modulation), pitch + (frequency modulation) or filter cutoff (filter + modulation). It operates at sub-audio frequency from + 0.042 Hz to 10.71 Hz. The LFO1 in the EMU8000 modulates + the pitch, volume and filter cutoff simultaneously. + + LFO2 + The LFO2 is similar to the LFO1, except that it modulates + the pitch of the audio signal only. + + Resonance + A filter alone would be like an equalizer, making a + bright audio signal duller, but the addition of resonance + greatly increases the creative potential of a filter. + Increasing the resonance of a filter makes it emphasize + signals at the cutoff frequency, giving the audio signal + a subtle wah-wah, that is, imagine a siren sound going + from bright to dull to bright again periodically. + + LFO1 to Volume (Tremolo) + The LFO1's output is routed to the amplifier, with the + depth of oscillation determined by LFO1 to Volume. LFO1 + to Volume produces tremolo, which is a periodic + fluctuation of volume. Lets say you are listening to a + piece of music on your home stereo system. When you + rapidly increase and decrease the playback volume, you + are creating tremolo effect, and the speed in which you + increases and decreases the volume is the tremolo rate + (which corresponds to the speed at which the LFO is + oscillating). An example of a GM instrument that makes + use of LFO1 to Volume is instrument number 45, Tremolo + Strings. + + LFO1 to Filter Cutoff (Wah-Wah) + The LFO1's output is routed to the filter, with the depth + of oscillation determined by LFO1 to Filter. LFO1 to + Filter produces a periodic fluctuation in the filter + cutoff frequency, producing an effect very similar to + that of a wah-wah guitar (see resonance for a description + of wah-wah) An example of a GM instrument that makes + use of LFO1 to Filter Cutoff is instrument number 19, + Rock Organ. + + LFO1 to Pitch (Vibrato) + The LFO1's output is routed to the oscillator, with the + depth of oscillation determined by LFO1 to Pitch. LFO1 to + Pitch produces a periodic fluctuation in the pitch of the + oscillator, producing a vibrato effect. An example of a + GM instrument that makes use of LFO1 to Pitch is + instrument number 57, Trumpet. + + LFO2 to Pitch (Vibrato) + The LFO1 in the EMU8000 can simultaneously modulate + pitch, volume and filter. LFO2, on the other hand, + modulates only the pitch, with the depth of modulation + determined by LFO2 to Pitch. LFO2 to Pitch produces a + periodic fluctuation in the pitch of the oscillator, + producing a vibrato effect. When this is coupled with + LFO1 to Pitch, a complex vibrato effect can be achieved. + + Volume Envelope + The character of a musical instrument is largely + determined by its volume envelope, the way in which the + level of the sound changes with time. For example, + percussive sounds usually start suddenly and then die + away, whereas a bowed sound might take quite some time to + start and then sustain at a more or less fixed level. + + A six-stage envelope makes up the volume envelope of the + EMU8000. The six stages are delay, attack, hold, decay, + sustain and release. The stages can be described as + follows: + + Delay The time between when a key is played and when + the attack phase begins + Attack The time it takes to go from zero to the peak + (full) level. + Hold The time the envelope will stay at the peak + level before starting the decay phase. + Decay The time it takes the envelope to go from the + peak level to the sustain level. + Sustain The level at which the envelope remains as long + as a key is held down. + Release The time it takes the envelope to fall to the + zero level after the key is released. + + Using these six parameters can yield very realistic + reproduction of the volume envelope characteristics of + many musical instruments. + + Pitch and Filter Envelope + The pitch and filter envelope is similar to the volume + envelope in that it has the same envelope stages. The + difference between them is that whereas the volume + envelope contours the volume of the instrument over time, + the pitch and filter envelope contours the pitch and + filter values of the instrument over time. The pitch + envelope is particularly useful in putting the finishing + touches in simulating a natural instrument. For example, + some wind instruments tend to go slightly sharp when they + are first blown, and this characteristic can be simulated + by setting up a pitch envelope with a fairly fast attack + and decay. The filter envelope, on the other hand, is + useful in creating synthetic sci-fi sound textures. An + example of a GM instrument that makes use of the filter + envelope is instrument number 86, Pad 8 (Sweep). + + Pitch/Filter Envelope Modulation + These two parameters determine the modulation depth of + the pitch and filter envelope. In the wind instrument + example above, a small amount of pitch envelope + modulation is desirable to simulate its natural pitch + characteristics. + + This rich modulation capability of the EMU8000 is fully + exploited by the SB AWE32 MIDI drivers. The driver also + provides you with a means to change these parameters over + MIDI in real time. Refer to the section "How do I change an + instrument's sound parameter in real time" for more + information. + + + + + Room 1 - 3 + This group of reverb variation simulates the natural + ambiance of a room. Room 1 simulates a small room, Room 2 + simulates a slightly bigger room, and Room 3 simulates a + big room. + + Hall 1 - 2 + This group of reverb variation simulates the natural + ambiance of a concert hall. It has greater depth than the + room variations. Again, Hall 1 simulates a small hall, + and Hall 2 simulates a larger hall. + + Plate + Back in the old days, reverb effects were sometimes + produced using a metal plate, and this type of reverb + produces a metallic echo. The SB AWE32's Plate variation + simulates this form of reverb. + + Delay + This reverb produces a delay, that is, echo effect. + + Panning Delay + This reverb variation produces a delay effect that is + continuously panned left and right. + + Chorus 1 - 4 + Chorus produces a "beating" effect. The chorus effects + are more prominent going from chorus 1 to chorus 4. + + Feedback Chorus + This chorus variation simulates a soft "swishing" effect. + + Flanger + This chorus variation produces a more prominent feedback + chorus effect. + + Short Delay + This chorus variation simulates a delay repeated in a + short time. + + Short Delay (feed back) + This chorus variation simulates a short delay repeated + (feedback) many times. + + + +Registers to write the Chorus Parameters to (all are 16-bit, unless noted): +(codified as in register,port,voice. port 0=0x620, 2=0x622, 4=0xA20, 6=0xA22, 8=0xE20) +( 3409 = register 3, port A20, voice 9) + +0x3409 +0x340C +0x3603 +0x1409 (32-Bit) +0x140A (32-Bit) +then write 0x8000 to 0x140D (32-Bit) +and then 0x0000 to 0x140E (32-Bit) + +Chorus Parameters: + +Chorus 1 Chorus 2 Chorus 3 Chorus 4 Feedback Flanger + +0xE600 0xE608 0xE610 0xE620 0xE680 0xE6E0 +0x03F6 0x031A 0x031A 0x0269 0x04D3 0x044E +0xBC2C 0xBC6E 0xBC84 0xBC6E 0xBCA6 0xBC37 +0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 +0x006D 0x017C 0x0083 0x017C 0x005B 0x0026 + +Short Delay Short Delay + Feedback + +0xE600 0xE6C0 +0x0B06 0x0B06 +0xBC00 0xBC00 +0xE000 0xE000 +0x0083 0x0083 + +// Chorus Params +typedef struct { + WORD FbkLevel; // Feedback Level (0xE600-0xE6FF) + WORD Delay; // Delay (0-0x0DA3) [1/44100 sec] + WORD LfoDepth; // LFO Depth (0xBC00-0xBCFF) + DWORD DelayR; // Right Delay (0-0xFFFFFFFF) [1/256/44100 sec] + DWORD LfoFreq; // LFO Frequency (0-0xFFFFFFFF) + } CHORUS_TYPE; + + +Registers to write the Reverb Parameters to (they are all 16-bit): +(codified as in register,port,voice. port 0=0x620, 2=0x622, 4=0xA20, 6=0xA22, 8=0xE20) +( 3409 = register 3, port A20, voice 9) + +0x2403,0x2405,0x361F,0x2407,0x2614,0x2616,0x240F,0x2417, +0x241F,0x2607,0x260F,0x2617,0x261D,0x261F,0x3401,0x3403, +0x2409,0x240B,0x2411,0x2413,0x2419,0x241B,0x2601,0x2603, +0x2609,0x260B,0x2611,0x2613 + +Reverb Parameters: + +Room 1: + +0xB488,0xA450,0x9550,0x84B5,0x383A,0x3EB5,0x72F4,0x72A4, +0x7254,0x7204,0x7204,0x7204,0x4416,0x4516,0xA490,0xA590, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Room 2: + +0xB488,0xA458,0x9558,0x84B5,0x383A,0x3EB5,0x7284,0x7254, +0x7224,0x7224,0x7254,0x7284,0x4448,0x4548,0xA440,0xA540, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Room 3: + +0xB488,0xA460,0x9560,0x84B5,0x383A,0x3EB5,0x7284,0x7254, +0x7224,0x7224,0x7254,0x7284,0x4416,0x4516,0xA490,0xA590, +0x842C,0x852C,0x842C,0x852C,0x842B,0x852B,0x842B,0x852B, +0x842A,0x852A,0x842A,0x852A + +Hall 1: + +0xB488,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7284,0x7254, +0x7224,0x7224,0x7254,0x7284,0x4448,0x4548,0xA440,0xA540, +0x842B,0x852B,0x842B,0x852B,0x842A,0x852A,0x842A,0x852A, +0x8429,0x8529,0x8429,0x8529 + +Hall 2: + +0xB488,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7254,0x7234, +0x7224,0x7254,0x7264,0x7294,0x44C3,0x45C3,0xA404,0xA504, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Plate: + +0xB4FF,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7234,0x7234, +0x7234,0x7234,0x7234,0x7234,0x4448,0x4548,0xA440,0xA540, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Delay: + +0xB4FF,0xA470,0x9500,0x84B5,0x333A,0x39B5,0x7204,0x7204, +0x7204,0x7204,0x7204,0x72F4,0x4400,0x4500,0xA4FF,0xA5FF, +0x8420,0x8520,0x8420,0x8520,0x8420,0x8520,0x8420,0x8520, +0x8420,0x8520,0x8420,0x8520 + +Panning Delay: + +0xB4FF,0xA490,0x9590,0x8474,0x333A,0x39B5,0x7204,0x7204, +0x7204,0x7204,0x7204,0x72F4,0x4400,0x4500,0xA4FF,0xA5FF, +0x8420,0x8520,0x8420,0x8520,0x8420,0x8520,0x8420,0x8520, +0x8420,0x8520,0x8420,0x8520 + +Registers to write the EQ Parameters to (16-Bit): +(codified as in register,port,voice. port 0=0x620, 2=0x622, 4=0xA20, 6=0xA22, 8=0xE20) +( 3409 = register 3, port A20, voice 9) + +Bass: + +0x3601 +0x3611 + +Treble: + +0x3411 +0x3413 +0x341B +0x3607 +0x360B +0x360D +0x3617 +0x3619 + +Total: + +write the 0x0263 + 3rd parameter of the Bass EQ + 9th parameter of Treble EQ to 0x3615. +write the 0x8363 + 3rd parameter of the Bass EQ + 9th parameter of Treble EQ to 0x3615. + + +Bass Parameters: + +0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: + +0xD26A 0xD25B 0xD24C 0xD23D 0xD21F 0xC208 0xC219 0xC22A 0xC24C 0xC26E 0xC248 0xC26A +0xD36A 0xD35B 0xD34C 0xD33D 0xC31F 0xC308 0xC308 0xC32A 0xC34C 0xC36E 0xC384 0xC36A +0x0000 0x0000 0x0000 0x0000 0x0000 0x0001 0x0001 0x0001 0x0001 0x0001 0x0002 0x0002 + +Treble Parameters: + +0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: +0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821D 0x821C +0xC26A 0xC25B 0xC24C 0xC23D 0xC21F 0xD208 0xD208 0xD208 0xD208 0xD208 0xD219 0xD22A +0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031D 0x031C +0xC36A 0xC35B 0xC34C 0xC33D 0xC31F 0xD308 0xD308 0xD308 0xD308 0xD308 0xD319 0xD32A +0x021E 0x021E 0x021E 0x021E 0x021E 0x021E 0x021D 0x021C 0x021A 0x0219 0x0219 0x0219 +0xD208 0xD208 0xD208 0xD208 0xD208 0xD208 0xD219 0xD22A 0xD24C 0xD26E 0xD26E 0xD26E +0x831E 0x831E 0x831E 0x831E 0x831E 0x831E 0x831D 0x831C 0x831A 0x8319 0x8319 0x8319 +0xD308 0xD308 0xD308 0xD308 0xD308 0xD308 0xD3019 0xD32A 0xD34C 0xD36E 0xD36E 0xD36E +0x0001 0x0001 0x0001 0x0001 0x0001 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002 +*/ diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 9fdd87be9..8a43f1f3d 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -36,34 +36,109 @@ #include "snd_sb.h" #include "snd_sb_dsp.h" +//#define SB_DSP_RECORD_DEBUG -typedef struct sb_mixer_t +#ifdef SB_DSP_RECORD_DEBUG +FILE* soundfsb = 0/*NULL*/; +FILE* soundfsbin = 0/*NULL*/; +#endif + + + +/* SB 2.0 CD version */ +typedef struct sb_ct1335_mixer_t { - int master_l, master_r; - int voice_l, voice_r; - int fm_l, fm_r; - int cd_l, cd_r; + int32_t master; + int32_t voice; + int32_t fm; + int32_t cd; + + uint8_t index; + uint8_t regs[256]; +} sb_ct1335_mixer_t; +/* SB PRO */ +typedef struct sb_ct1345_mixer_t +{ + int32_t master_l, master_r; + int32_t voice_l, voice_r; + int32_t fm_l, fm_r; + int32_t cd_l, cd_r; + int32_t line_l, line_r; + int32_t mic; + /*see sb_ct1745_mixer for values for input selector*/ + int32_t input_selector; + + int input_filter; + int in_filter_freq; + int output_filter; + + int stereo; + int stereo_isleft; + + uint8_t index; + uint8_t regs[256]; + +} sb_ct1345_mixer_t; +/* SB16 and AWE32 */ +typedef struct sb_ct1745_mixer_t +{ + int32_t master_l, master_r; + int32_t voice_l, voice_r; + int32_t fm_l, fm_r; + int32_t cd_l, cd_r; + int32_t line_l, line_r; + int32_t mic; + int32_t speaker; + int bass_l, bass_r; int treble_l, treble_r; - int filter; + + int output_selector; + #define OUTPUT_MIC 1 + #define OUTPUT_CD_R 2 + #define OUTPUT_CD_L 4 + #define OUTPUT_LINE_R 8 + #define OUTPUT_LINE_L 16 - int index; + int input_selector_left; + int input_selector_right; + #define INPUT_MIC 1 + #define INPUT_CD_R 2 + #define INPUT_CD_L 4 + #define INPUT_LINE_R 8 + #define INPUT_LINE_L 16 + #define INPUT_MIDI_R 32 + #define INPUT_MIDI_L 64 + + int mic_agc; + + int32_t input_gain_L; + int32_t input_gain_R; + int32_t output_gain_L; + int32_t output_gain_R; + + uint8_t index; uint8_t regs[256]; -} sb_mixer_t; +} sb_ct1745_mixer_t; typedef struct sb_t { opl_t opl; sb_dsp_t dsp; - sb_mixer_t mixer; - mpu_t mpu; + union { + sb_ct1335_mixer_t mixer_sb2; + sb_ct1345_mixer_t mixer_sbpro; + sb_ct1745_mixer_t mixer_sb16; + }; + mpu_t mpu; emu8k_t emu8k; int pos; - + uint8_t pos_regs[8]; + + int opl_emu; } sb_t; - /* 0 to 7 -> -14dB to 0dB i 2dB steps. 8 to 15 -> 0 to +14dB in 2dB steps. Note that for positive dB values, this is not amplitude, it is amplitude-1. */ const float sb_bass_treble_4bits[]= { @@ -71,17 +146,27 @@ const float sb_bass_treble_4bits[]= { 0, 0.25892541, 0.584893192, 1, 1.511886431, 2.16227766, 3, 4.011872336 }; -static int sb_att[]= +/* Attenuation tables for the mixer. Max volume = 32767 in order to give 6dB of + * headroom and avoid integer overflow */ +const int32_t sb_att_2dbstep_5bits[]= { - 50,65,82,103,130,164,207,260,328,413,520,655,825,1038,1307, - 1645,2072,2608,3283,4134,5205,6553,8250,10385,13075,16461,20724,26089, - 32845,41349,52055,65535 + 25,32,41,51,65,82,103,130,164,206,260,327,412,519,653, + 822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044, + 16422,20674,26027,32767 +}; +const int32_t sb_att_4dbstep_3bits[]= +{ + 164,2067,3276,5193,8230,13045,20675,32767 +}; +const int32_t sb_att_7dbstep_2bits[]= +{ + 164,6537,14637,32767 }; -static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p) +/* sb 1, 1.5, 2, 2 mvc do not have a mixer, so signal is hardwired */ +static void sb_get_buffer_sb2(int32_t *buffer, int len, void *p) { sb_t *sb = (sb_t *)p; - sb_mixer_t *mixer = &sb->mixer; int c; @@ -89,40 +174,13 @@ static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p) sb_dsp_update(&sb->dsp); for (c = 0; c < len * 2; c += 2) { - int32_t out_l, out_r; - - out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * 51000) >> 16); - out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * 51000) >> 16); - - if (sb->mixer.filter) - { - out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16; - out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16; - } - else - { - out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16; - out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; - } - - out_l = (out_l * mixer->master_l) >> 15; - out_r = (out_r * mixer->master_r) >> 15; - - if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) - { - /* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */ - if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]); - if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]); - if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]); - if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]); - if (mixer->bass_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->bass_l])); - if (mixer->bass_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->bass_r])); - if (mixer->treble_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->treble_l])); - if (mixer->treble_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->treble_r])); - } - - buffer[c] += out_l; - buffer[c + 1] += out_r; + int32_t out; + out = ((sb->opl.buffer[c] * 51000) >> 16); + //TODO: Recording: Mic and line In with AGC + out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * 65536) / 3) >> 16; + + buffer[c] += out; + buffer[c + 1] += out; } sb->pos = 0; @@ -130,49 +188,71 @@ static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p) sb->dsp.pos = 0; } -static void sb_get_buffer_opl3(int32_t *buffer, int len, void *p) +static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p) { sb_t *sb = (sb_t *)p; - sb_mixer_t *mixer = &sb->mixer; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; int c; - opl3_update2(&sb->opl); + opl2_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) + { + int32_t out; + + out = ((((sb->opl.buffer[c] * mixer->fm) >> 16) * 51000) >> 15); + /* TODO: Recording : I assume it has direct mic and line in like sb2 */ + /* It is unclear from the docs if it has a filter, but it probably does */ + out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice) / 3) >> 15; + + out = (out * mixer->master) >> 15; + + buffer[c] += out; + buffer[c + 1] += out; + } + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; +} + +static void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + + int c; + + if (sb->dsp.sb_type == SBPRO) + opl2_update2(&sb->opl); + else + opl3_update2(&sb->opl); + sb_dsp_update(&sb->dsp); for (c = 0; c < len * 2; c += 2) { int32_t out_l, out_r; - out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (opl3_type ? 47000 : 51000)) >> 16); - out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (opl3_type ? 47000 : 51000)) >> 16); - - if (sb->mixer.filter) + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + + /*TODO: Implement the stereo switch on the mixer instead of on the dsp? */ + if (mixer->output_filter) { - out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16; - out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16; + out_l += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 15; + out_r += (int32_t)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 15; } else { - out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16; - out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; + out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 15; + out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 15; } + //TODO: recording CD, Mic with AGC or line in. Note: mic volume does not affect recording. out_l = (out_l * mixer->master_l) >> 15; out_r = (out_r * mixer->master_r) >> 15; - if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) - { - /* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */ - if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]); - if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]); - if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]); - if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]); - if (mixer->bass_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->bass_l])); - if (mixer->bass_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->bass_r])); - if (mixer->treble_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->treble_l])); - if (mixer->treble_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->treble_r])); - } - buffer[c] += out_l; buffer[c + 1] += out_r; } @@ -180,41 +260,114 @@ static void sb_get_buffer_opl3(int32_t *buffer, int len, void *p) sb->pos = 0; sb->opl.pos = 0; sb->dsp.pos = 0; - sb->emu8k.pos = 0; } +static void sb_get_buffer_sb16(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + + int c; + + opl3_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + const int dsp_rec_pos = sb->dsp.record_pos_write; + for (c = 0; c < len * 2; c += 2) + { + int32_t out_l, out_r, in_l, in_r; + + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + + /*TODO: multi-recording mic with agc/+20db, cd and line in with channel inversion */ + in_l = (mixer->input_selector_left&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_left&INPUT_MIDI_R) ? out_r : 0; + in_r = (mixer->input_selector_right&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_right&INPUT_MIDI_R) ? out_r : 0; + + /*TODO: CT1745 features dynamic filtering. https://www.vogons.org/viewtopic.php?f=62&t=51514 */ + out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 15; + out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 15; + + out_l = (out_l * mixer->master_l) >> 15; + out_r = (out_r * mixer->master_r) >> 15; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + /* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */ + if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]); + if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]); + if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]); + if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]); + if (mixer->bass_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->bass_l])); + if (mixer->bass_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->bass_r])); + if (mixer->treble_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->treble_l])); + if (mixer->treble_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->treble_r])); + } + if (sb->dsp.sb_enable_i) + { + int c_record = dsp_rec_pos; + c_record +=(((c/2) * sb->dsp.sb_freq) / 48000)*2; + in_l <<= mixer->input_gain_L; + in_r <<= mixer->input_gain_R; + // Clip signal + if (in_l < -32768) + in_l = -32768; + else if (in_l > 32767) + in_l = 32767; + + if (in_r < -32768) + in_r = -32768; + else if (in_r > 32767) + in_r = 32767; + sb->dsp.record_buffer[c_record&0xFFFF] = in_l; + sb->dsp.record_buffer[(c_record+1)&0xFFFF] = in_r; + } + + buffer[c] += (out_l << mixer->output_gain_L); + buffer[c + 1] += (out_r << mixer->output_gain_R); + } + sb->dsp.record_pos_write+=((len * sb->dsp.sb_freq) / 48000)*2; + sb->dsp.record_pos_write&=0xFFFF; + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; +} +#ifdef SB_DSP_RECORD_DEBUG +int old_dsp_rec_pos=0; +int buf_written=0; +int last_crecord=0; +#endif static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) { sb_t *sb = (sb_t *)p; - sb_mixer_t *mixer = &sb->mixer; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; int c; opl3_update2(&sb->opl); - sb_dsp_update(&sb->dsp); emu8k_update(&sb->emu8k); + sb_dsp_update(&sb->dsp); + const int dsp_rec_pos = sb->dsp.record_pos_write; for (c = 0; c < len * 2; c += 2) { + int32_t out_l, out_r, in_l, in_r; int c_emu8k = (((c/2) * 44100) / 48000)*2; - int32_t out_l, out_r; - out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (opl3_type ? 47000 : 51000)) >> 16); - out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (opl3_type ? 47000 : 51000)) >> 16); + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 15) * (sb->opl_emu ? 47000 : 51000)) >> 16); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 15) * (sb->opl_emu ? 47000 : 51000)) >> 16); - out_l += ((sb->emu8k.buffer[c_emu8k] * mixer->fm_l) >> 16); - out_r += ((sb->emu8k.buffer[c_emu8k + 1] * mixer->fm_l) >> 16); - - if (sb->mixer.filter) - { - out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16; - out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16; - } - else - { - out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16; - out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; - } + out_l += ((sb->emu8k.buffer[c_emu8k] * mixer->fm_l) >> 15); + out_r += ((sb->emu8k.buffer[c_emu8k + 1] * mixer->fm_r) >> 15); + /*TODO: multi-recording mic with agc/+20db, cd and line in with channel inversion */ + in_l = (mixer->input_selector_left&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_left&INPUT_MIDI_R) ? out_r : 0; + in_r = (mixer->input_selector_right&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_right&INPUT_MIDI_R) ? out_r : 0; + + + /*TODO: CT1745 features dynamic filtering. https://www.vogons.org/viewtopic.php?f=62&t=51514 */ + out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 15; + out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 15; + out_l = (out_l * mixer->master_l) >> 15; out_r = (out_r * mixer->master_r) >> 15; @@ -225,55 +378,240 @@ static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]); if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]); if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]); - if (mixer->bass_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->bass_l])); - if (mixer->bass_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->bass_r])); - if (mixer->treble_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.0-sb_bass_treble_4bits[mixer->treble_l])); - if (mixer->treble_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.0-sb_bass_treble_4bits[mixer->treble_r])); + if (mixer->bass_l<8) out_l = (int32_t)(out_l *sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->bass_l])); + if (mixer->bass_r<8) out_r = (int32_t)(out_r *sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->bass_r])); + if (mixer->treble_l<8) out_l = (int32_t)(out_l *sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->treble_l])); + if (mixer->treble_r<8) out_r = (int32_t)(out_r *sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->treble_r])); } - - buffer[c] += out_l; - buffer[c + 1] += out_r; - } + if (sb->dsp.sb_enable_i) + { +// in_l += (mixer->input_selector_left&INPUT_CD_L) ? audio_cd_buffer[cd_read_pos+c_emu8k] : 0 + (mixer->input_selector_left&INPUT_CD_R) ? audio_cd_buffer[cd_read_pos+c_emu8k+1] : 0; +// in_r += (mixer->input_selector_right&INPUT_CD_L) ? audio_cd_buffer[cd_read_pos+c_emu8k]: 0 + (mixer->input_selector_right&INPUT_CD_R) ? audio_cd_buffer[cd_read_pos+c_emu8k+1] : 0; + int c_record = dsp_rec_pos; + c_record +=(((c/2) * sb->dsp.sb_freq) / 48000)*2; + #ifdef SB_DSP_RECORD_DEBUG + if (c_record > 0xFFFF && !buf_written) + { + if (!soundfsb) soundfsb=plat_fopen(L"sound_sb.pcm",L"wb"); + fwrite(sb->dsp.record_buffer,2,0x10000,soundfsb); + old_dsp_rec_pos = dsp_rec_pos; + buf_written=1; + } + #endif + in_l <<= mixer->input_gain_L; + in_r <<= mixer->input_gain_R; + // Clip signal + if (in_l < -32768) + in_l = -32768; + else if (in_l > 32767) + in_l = 32767; + + if (in_r < -32768) + in_r = -32768; + else if (in_r > 32767) + in_r = 32767; + sb->dsp.record_buffer[c_record&0xFFFF] = in_l; + sb->dsp.record_buffer[(c_record+1)&0xFFFF] = in_r; + #ifdef SB_DSP_RECORD_DEBUG + if (c_record != last_crecord) + { + if (!soundfsbin) soundfsbin=plat_fopen(L"sound_sb_in.pcm",L"wb"); + fwrite(&sb->dsp.record_buffer[c_record&0xFFFF],2,2,soundfsbin); + last_crecord=c_record; + } + #endif + } + + buffer[c] += (out_l << mixer->output_gain_L); + buffer[c + 1] += (out_r << mixer->output_gain_R); + } + #ifdef SB_DSP_RECORD_DEBUG + if (old_dsp_rec_pos > dsp_rec_pos) + { + buf_written=0; + old_dsp_rec_pos=dsp_rec_pos; + } + #endif + + sb->dsp.record_pos_write+=((len * sb->dsp.sb_freq) / 48000)*2; + sb->dsp.record_pos_write&=0xFFFF; sb->pos = 0; sb->opl.pos = 0; sb->dsp.pos = 0; sb->emu8k.pos = 0; } -void sb_pro_mixer_write(uint16_t addr, uint8_t val, void *p) + +void sb_ct1335_mixer_write(uint16_t addr, uint8_t val, void *p) { sb_t *sb = (sb_t *)p; - sb_mixer_t *mixer = &sb->mixer; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; if (!(addr & 1)) - mixer->index = val & 0xff; + { + mixer->index = val; + mixer->regs[0x01] = val; + } else { - mixer->regs[mixer->index] = val; - - mixer->master_l = sb_att[(mixer->regs[0x22] >> 4) | 0x11]; - mixer->master_r = sb_att[(mixer->regs[0x22] & 0xf) | 0x11]; - mixer->voice_l = sb_att[(mixer->regs[0x04] >> 4) | 0x11]; - mixer->voice_r = sb_att[(mixer->regs[0x04] & 0xf) | 0x11]; - mixer->fm_l = sb_att[(mixer->regs[0x26] >> 4) | 0x11]; - mixer->fm_r = sb_att[(mixer->regs[0x26] & 0xf) | 0x11]; - mixer->cd_l = sb_att[(mixer->regs[0x28] >> 4) | 0x11]; - mixer->cd_r = sb_att[(mixer->regs[0x28] & 0xf) | 0x11]; - mixer->filter = !(mixer->regs[0xe] & 0x20); - mixer->bass_l = mixer->bass_r = 8; - mixer->treble_l = mixer->treble_r = 8; - sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, - ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); - if (mixer->index == 0xe) - sb_dsp_set_stereo(&sb->dsp, val & 2); + if (mixer->index == 0) + { + /* Reset */ + mixer->regs[0x02] = 4 << 1; + mixer->regs[0x06] = 4 << 1; + mixer->regs[0x08] = 0 << 1; + /* changed default from -46dB to 0dB*/ + mixer->regs[0x0A] = 3 << 1; + } + else + { + mixer->regs[mixer->index] = val; + switch (mixer->index) + { + case 0x00: case 0x02: case 0x06: case 0x08: case 0x0A: + break; + + default: + pclog("sb_ct1335: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + } + mixer->master = sb_att_4dbstep_3bits[(mixer->regs[0x02] >> 1)&0x7]; + mixer->fm = sb_att_4dbstep_3bits[(mixer->regs[0x06] >> 1)&0x7]; + mixer->cd = sb_att_4dbstep_3bits[(mixer->regs[0x08] >> 1)&0x7]; + mixer->voice = sb_att_7dbstep_2bits[(mixer->regs[0x0A] >> 1)&0x3]; + + sound_set_cd_volume(((uint32_t)mixer->master * (uint32_t)mixer->cd) / 65535, + ((uint32_t)mixer->master * (uint32_t)mixer->cd) / 65535); } } -uint8_t sb_pro_mixer_read(uint16_t addr, void *p) +uint8_t sb_ct1335_mixer_read(uint16_t addr, void *p) { sb_t *sb = (sb_t *)p; - sb_mixer_t *mixer = &sb->mixer; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; + + if (!(addr & 1)) + return mixer->index; + + switch (mixer->index) + { + case 0x00: case 0x02: case 0x06: case 0x08: case 0x0A: + return mixer->regs[mixer->index]; + default: + pclog("sb_ct1335: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + + return 0xff; +} + +void sb_ct1335_mixer_reset(sb_t* sb) +{ + sb_ct1335_mixer_write(0x254,0,sb); + sb_ct1335_mixer_write(0x255,0,sb); +} + +void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + + if (!(addr & 1)) + { + mixer->index = val; + mixer->regs[0x01] = val; + } + else + { + if (mixer->index == 0) + { + /* Reset */ + mixer->regs[0x0A] = 0 << 1; + mixer->regs[0x0C] = (0 << 5) | (0 << 3) | (0 << 1); + mixer->regs[0x0E] = (0 << 5) | (0 << 1); + /* changed default from -11dB to 0dB */ + mixer->regs[0x04] = (7 << 5) | (7 << 1); + mixer->regs[0x22] = (7 << 5) | (7 << 1); + mixer->regs[0x26] = (7 << 5) | (7 << 1); + mixer->regs[0x28] = (0 << 5) | (0 << 1); + mixer->regs[0x2E] = (0 << 5) | (0 << 1); + sb_dsp_set_stereo(&sb->dsp, mixer->regs[0x0E] & 2); + } + else + { + mixer->regs[mixer->index] = val; + switch (mixer->index) + { + /* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */ + case 0x02: case 0x06: + mixer->regs[mixer->index+0x20]=((val&0xE) << 4)|(val&0xE) << 4; + break; + + case 0x22: case 0x26: + mixer->regs[mixer->index-0x20]=(val&0xE); + break; + + /* More compatibility: SoundBlaster Pro selects register 020h for 030h, 022h for 032h, 026h for 036h,028h for 038h. */ + case 0x30: case 0x32: case 0x36: case 0x38: + mixer->regs[mixer->index-0x10]=(val&0xEE); + break; + + case 0x00: case 0x04: case 0x0a: case 0x0c: case 0x0e: + case 0x28: case 0x2e: + break; + + + default: + pclog("sb_ct1345: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + } + + mixer->voice_l = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 5)&0x7]; + mixer->voice_r = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 1)&0x7]; + mixer->master_l = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 5)&0x7]; + mixer->master_r = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 1)&0x7]; + mixer->fm_l = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 5)&0x7]; + mixer->fm_r = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 1)&0x7]; + mixer->cd_l = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 5)&0x7]; + mixer->cd_r = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 1)&0x7]; + mixer->line_l = sb_att_4dbstep_3bits[(mixer->regs[0x2E] >> 5)&0x7]; + mixer->line_r = sb_att_4dbstep_3bits[(mixer->regs[0x2E] >> 1)&0x7]; + + mixer->mic = sb_att_7dbstep_2bits[(mixer->regs[0x0A] >> 1)&0x3]; + + mixer->output_filter = !(mixer->regs[0xE] & 0x20); + mixer->input_filter = !(mixer->regs[0xC] & 0x20); + mixer->in_filter_freq = ((mixer->regs[0xC] & 0x8) == 0) ? 3200 : 8800; + mixer->stereo = mixer->regs[0xE] & 2; + if (mixer->index == 0xE) + sb_dsp_set_stereo(&sb->dsp, val & 2); + + switch ((mixer->regs[0xc]&6)) + { + case 2: + mixer->input_selector = INPUT_CD_L|INPUT_CD_R; + break; + case 6: + mixer->input_selector = INPUT_LINE_L|INPUT_LINE_R; + break; + default: + mixer->input_selector = INPUT_MIC; + break; + } + + /* TODO: pcspeaker volume? Or is it not worth? */ + sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, + ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); + } +} + +uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; if (!(addr & 1)) return mixer->index; @@ -281,144 +619,251 @@ uint8_t sb_pro_mixer_read(uint16_t addr, void *p) switch (mixer->index) { case 0x00: case 0x04: case 0x0a: case 0x0c: case 0x0e: - case 0x22: case 0x26: case 0x28: case 0x2e: + case 0x22: case 0x26: case 0x28: case 0x2e: case 0x02: case 0x06: + case 0x30: case 0x32: case 0x36: case 0x38: return mixer->regs[mixer->index]; + + default: + pclog("sb_ct1345: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; } return 0xff; } +void sb_ct1345_mixer_reset(sb_t* sb) +{ + sb_ct1345_mixer_write(4,0,sb); + sb_ct1345_mixer_write(5,0,sb); +} -void sb_16_mixer_write(uint16_t addr, uint8_t val, void *p) +void sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p) { sb_t *sb = (sb_t *)p; - sb_mixer_t *mixer = &sb->mixer; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; if (!(addr & 1)) + { mixer->index = val; + } else { - mixer->regs[mixer->index] = val; + // TODO: and this? 001h: + /*DESCRIPTION + Contains previously selected register value. Mixer Data Register value + NOTES + * SoundBlaster 16 sets bit 7 if previous mixer index invalid. + * Status bytes initially 080h on startup for all but level bytes (SB16) + */ + + if (mixer->index == 0) + { + /* Reset */ + /* Changed defaults from -14dB to 0dB*/ + mixer->regs[0x30]=31 << 3; + mixer->regs[0x31]=31 << 3; + mixer->regs[0x32]=31 << 3; + mixer->regs[0x33]=31 << 3; + mixer->regs[0x34]=31 << 3; + mixer->regs[0x35]=31 << 3; + mixer->regs[0x36]=0 << 3; + mixer->regs[0x37]=0 << 3; + mixer->regs[0x38]=0 << 3; + mixer->regs[0x39]=0 << 3; + + mixer->regs[0x3A]=0 << 3; + mixer->regs[0x3B]=0 << 6; + mixer->regs[0x3C] = OUTPUT_MIC|OUTPUT_CD_R|OUTPUT_CD_L|OUTPUT_LINE_R|OUTPUT_LINE_L; + mixer->regs[0x3D] = INPUT_MIC|INPUT_CD_L|INPUT_LINE_L|INPUT_MIDI_L; + mixer->regs[0x3E] = INPUT_MIC|INPUT_CD_R|INPUT_LINE_R|INPUT_MIDI_R; + + mixer->regs[0x3F] = mixer->regs[0x40] = 0 << 6; + mixer->regs[0x41] = mixer->regs[0x42] = 0 << 6; + + mixer->regs[0x44] = mixer->regs[0x45] = 8 << 4; + mixer->regs[0x46] = mixer->regs[0x47] = 8 << 4; + + mixer->regs[0x43] = 0; + } + else + { + mixer->regs[mixer->index] = val; + } switch (mixer->index) { + /* SBPro compatibility. Copy values to sb16 registers. */ case 0x22: - mixer->regs[0x30] = ((mixer->regs[0x22] >> 4) | 0x11) << 3; - mixer->regs[0x31] = ((mixer->regs[0x22] & 0xf) | 0x11) << 3; + mixer->regs[0x30] = (mixer->regs[0x22] & 0xF0) | 0x8; + mixer->regs[0x31] = ((mixer->regs[0x22] & 0xf) << 4) | 0x8; break; case 0x04: - mixer->regs[0x32] = ((mixer->regs[0x04] >> 4) | 0x11) << 3; - mixer->regs[0x33] = ((mixer->regs[0x04] & 0xf) | 0x11) << 3; + mixer->regs[0x32] = (mixer->regs[0x04] & 0xF0) | 0x8; + mixer->regs[0x33] = ((mixer->regs[0x04] & 0xf) << 4) | 0x8; break; case 0x26: - mixer->regs[0x34] = ((mixer->regs[0x26] >> 4) | 0x11) << 3; - mixer->regs[0x35] = ((mixer->regs[0x26] & 0xf) | 0x11) << 3; + mixer->regs[0x34] = (mixer->regs[0x26] & 0xF0) | 0x8; + mixer->regs[0x35] = ((mixer->regs[0x26] & 0xf) << 4) | 0x8; break; case 0x28: - mixer->regs[0x36] = ((mixer->regs[0x28] >> 4) | 0x11) << 3; - mixer->regs[0x37] = ((mixer->regs[0x28] & 0xf) | 0x11) << 3; + mixer->regs[0x36] = (mixer->regs[0x28] & 0xF0) | 0x8; + mixer->regs[0x37] = ((mixer->regs[0x28] & 0xf) << 4) | 0x8; break; + case 0x2E: + mixer->regs[0x38] = (mixer->regs[0x2E] & 0xF0) | 0x8; + mixer->regs[0x39] = ((mixer->regs[0x2E] & 0xf) << 4) | 0x8; + break; + case 0x0A: + mixer->regs[0x3A] = (mixer->regs[0x0A]*3)+10; + break; + + /* + (DSP 4.xx feature) The Interrupt Setup register, addressed as register 80h on the Mixer register map, is used to configure or determine the Interrupt request line. The DMA setup register, addressed as register 81h on the Mixer register map, is used to configure or determine the DMA channels. + + Note: Registers 80h and 81h are Read-only for PnP boards. + */ case 0x80: - if (val & 1) sb->dsp.sb_irqnum = 2; - if (val & 2) sb->dsp.sb_irqnum = 5; - if (val & 4) sb->dsp.sb_irqnum = 7; - if (val & 8) sb->dsp.sb_irqnum = 10; - case 0x81: - if (val & 1) sb->dsp.sb_8_dmanum = 0; - if (val & 2) sb->dsp.sb_8_dmanum = 1; - if (val & 8) sb->dsp.sb_8_dmanum = 3; - if (val & 0x20) sb->dsp.sb_16_dmanum = 5; - if (val & 0x40) sb->dsp.sb_16_dmanum = 6; - if (val & 0x80) sb->dsp.sb_16_dmanum = 7; + if (val & 1) sb_dsp_setirq(&sb->dsp,2); + if (val & 2) sb_dsp_setirq(&sb->dsp,5); + if (val & 4) sb_dsp_setirq(&sb->dsp,7); + if (val & 8) sb_dsp_setirq(&sb->dsp,10); + break; + + case 0x81: + /* The documentation is confusing. sounds as if multple dma8 channels could be set. */ + if (val & 1) sb_dsp_setdma8(&sb->dsp,0); + if (val & 2) sb_dsp_setdma8(&sb->dsp,1); + if (val & 8) sb_dsp_setdma8(&sb->dsp,3); + if (val & 0x20) sb_dsp_setdma16(&sb->dsp,5); + if (val & 0x40) sb_dsp_setdma16(&sb->dsp,6); + if (val & 0x80) sb_dsp_setdma16(&sb->dsp,7); break; } - mixer->master_l = sb_att[mixer->regs[0x30] >> 3]; - mixer->master_r = sb_att[mixer->regs[0x31] >> 3]; - mixer->voice_l = sb_att[mixer->regs[0x32] >> 3]; - mixer->voice_r = sb_att[mixer->regs[0x33] >> 3]; - mixer->fm_l = sb_att[mixer->regs[0x34] >> 3]; - mixer->fm_r = sb_att[mixer->regs[0x35] >> 3]; - mixer->cd_l = sb_att[mixer->regs[0x36] >> 3]; - mixer->cd_r = sb_att[mixer->regs[0x37] >> 3]; + + mixer->output_selector = mixer->regs[0x3C]; + mixer->input_selector_left = mixer->regs[0x3D]; + mixer->input_selector_right = mixer->regs[0x3E]; + + mixer->master_l = sb_att_2dbstep_5bits[mixer->regs[0x30] >> 3]; + mixer->master_r = sb_att_2dbstep_5bits[mixer->regs[0x31] >> 3]; + mixer->voice_l = sb_att_2dbstep_5bits[mixer->regs[0x32] >> 3]; + mixer->voice_r = sb_att_2dbstep_5bits[mixer->regs[0x33] >> 3]; + mixer->fm_l = sb_att_2dbstep_5bits[mixer->regs[0x34] >> 3]; + mixer->fm_r = sb_att_2dbstep_5bits[mixer->regs[0x35] >> 3]; + mixer->cd_l = (mixer->output_selector&OUTPUT_CD_L) ? sb_att_2dbstep_5bits[mixer->regs[0x36] >> 3] : 0; + mixer->cd_r = (mixer->output_selector&OUTPUT_CD_R) ? sb_att_2dbstep_5bits[mixer->regs[0x37] >> 3] : 0; + mixer->line_l = (mixer->output_selector&OUTPUT_LINE_L) ? sb_att_2dbstep_5bits[mixer->regs[0x38] >> 3] : 0; + mixer->line_r = (mixer->output_selector&OUTPUT_LINE_R) ? sb_att_2dbstep_5bits[mixer->regs[0x39] >> 3] : 0; + + mixer->mic = sb_att_2dbstep_5bits[mixer->regs[0x3A] >> 3]; + mixer->speaker = sb_att_2dbstep_5bits[mixer->regs[0x3B]*3 + 22]; + + + mixer->input_gain_L = (mixer->regs[0x3F] >> 6); + mixer->input_gain_R = (mixer->regs[0x40] >> 6); + mixer->output_gain_L = (mixer->regs[0x41] >> 6); + mixer->output_gain_R = (mixer->regs[0x42] >> 6); + mixer->bass_l = mixer->regs[0x46] >> 4; mixer->bass_r = mixer->regs[0x47] >> 4; mixer->treble_l = mixer->regs[0x44] >> 4; mixer->treble_r = mixer->regs[0x45] >> 4; - mixer->filter = 0; + + /*TODO: pcspeaker volume, with "output_selector" check? or better not? */ sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); +// pclog("sb_ct1745: Received register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); } } -uint8_t sb_16_mixer_read(uint16_t addr, void *p) +uint8_t sb_ct1745_mixer_read(uint16_t addr, void *p) { sb_t *sb = (sb_t *)p; - sb_mixer_t *mixer = &sb->mixer; - uint8_t temp = 0; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; if (!(addr & 1)) return mixer->index; +// pclog("sb_ct1745: received register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + + if (mixer->index>=0x30 && mixer->index<=0x47) + { + return mixer->regs[mixer->index]; + } switch (mixer->index) { + case 0x00: case 0x04: case 0x0A: case 0x22: case 0x26: case 0x28: case 0x2E: + return mixer->regs[mixer->index]; + + case 0x48: + // Undocumented. The Creative Windows Mixer calls this after calling 3C (input selector). even when writing. + // Also, the version I have (5.17) does not use the MIDI.L/R input selectors. it uses the volume to mute (Affecting the output, obviously) + return mixer->regs[mixer->index]; + case 0x80: + /*TODO: Unaffected by mixer reset or soft reboot. + * Enabling multiple bits enables multiple IRQs. + */ + switch (sb->dsp.sb_irqnum) { - case 2: return 1; /*IRQ 2*/ - case 5: return 2; /*IRQ 5*/ - case 7: return 4; /*IRQ 7*/ - case 10: return 8; /*IRQ 10*/ + case 2: return 1; + case 5: return 2; + case 7: return 4; + case 10: return 8; } break; + case 0x81: - switch (sb->dsp.sb_8_dmanum) - { - case 0: - temp = 1; - break; - case 1: - temp = 2; - break; - case 3: - temp = 8; - break; - default: - temp = 0; - break; - } - switch (sb->dsp.sb_16_dmanum) - { - case 5: - temp |= 0x20; - break; - case 6: - temp |= 0x40; - break; - case 7: - temp |= 0x80; - break; - default: - temp |= 0x00; - break; - } - return temp; + { + /* TODO: Unaffected by mixer reset or soft reboot. + * Enabling multiple 8 or 16-bit DMA bits enables multiple DMA channels. + * Disabling all 8-bit DMA channel bits disables 8-bit DMA requests, + including translated 16-bit DMA requests. + * Disabling all 16-bit DMA channel bits enables translation of 16-bit DMA + requests to 8-bit ones, using the selected 8-bit DMA channel.*/ + + uint8_t result=0; + switch (sb->dsp.sb_8_dmanum) + { + case 0: result |= 1; break; + case 1: result |= 2; break; + case 3: result |= 8; break; + } + switch (sb->dsp.sb_16_dmanum) + { + case 5: result |= 0x20; break; + case 6: result |= 0x40; break; + case 7: result |= 0x80; break; + } + return result; + } + + /* The Interrupt status register, addressed as register 82h on the Mixer register map, + is used by the ISR to determine whether the interrupt is meant for it or for some other ISR, + in which case it should chain to the previous routine. + */ case 0x82: - return ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0); + /* 0 = none, 1 = digital 8bit or SBMIDI, 2 = digital 16bit, 4 = MPU-401 */ + /* 0x02000 DSP v4.04, 0x4000 DSP v4.05 0x8000 DSP v4.12. I haven't seen this making any difference, but I'm keeping it for now. */ + return ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0) | 0x4000; + + /* TODO: creative drivers read and write on 0xFE and 0xFF. not sure what they are supposed to be. */ + + + default: + pclog("sb_ct1745: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; } - return mixer->regs[mixer->index]; + + return 0xff; } -void sb_mixer_init(sb_mixer_t *mixer) +void sb_ct1745_mixer_reset(sb_t* sb) { - mixer->master_l = mixer->master_r = 65535; - mixer->voice_l = mixer->voice_r = 65535; - mixer->fm_l = mixer->fm_r = 65535; - mixer->cd_l = mixer->cd_r = 65535; - mixer->bass_l = mixer->bass_r = 8; - mixer->treble_l = mixer->treble_r = 8; - mixer->filter = 1; - sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, - ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); + sb_ct1745_mixer_write(4,0,sb); + sb_ct1745_mixer_write(5,0,sb); } + static uint16_t sb_mcv_addr[8] = {0x200, 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x270}; uint8_t sb_mcv_read(int port, void *p) @@ -443,6 +888,7 @@ void sb_mcv_write(int port, uint8_t val, void *p) addr = sb_mcv_addr[sb->pos_regs[4] & 7]; io_removehandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&sb->dsp, 0); sb->pos_regs[port & 7] = val; @@ -453,6 +899,7 @@ void sb_mcv_write(int port, uint8_t val, void *p) 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); + /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&sb->dsp, addr); } } @@ -482,7 +929,8 @@ void sb_pro_mcv_write(int port, uint8_t val, void *p) io_removehandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_removehandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_removehandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); + io_removehandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&sb->dsp, 0); sb->pos_regs[port & 7] = val; @@ -494,16 +942,20 @@ void sb_pro_mcv_write(int port, uint8_t val, void *p) io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); - + io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&sb->dsp, addr); } sb_dsp_setirq(&sb->dsp, sb_pro_mcv_irqs[(sb->pos_regs[5] >> 4) & 3]); sb_dsp_setdma8(&sb->dsp, sb->pos_regs[4] & 3); } - -void *sb_1_init(device_t *info) + +void *sb_1_init() { + /*sb1/2 port mappings, 210h to 260h in 10h steps + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip*/ sb_t *sb = malloc(sizeof(sb_t)); uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); @@ -513,14 +965,19 @@ void *sb_1_init(device_t *info) sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sb_mixer_init(&sb->mixer); + /* CMS I/O handler is activated on the dedicated sound_cms module + DSP I/O handler is activated in sb_dsp_setaddr */ 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); - sound_add_handler(sb_get_buffer_opl2, sb); + sound_add_handler(sb_get_buffer_sb2, sb); return sb; } -void *sb_15_init(device_t *info) +void *sb_15_init() { + /*sb1/2 port mappings, 210h to 260h in 10h steps + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip*/ sb_t *sb = malloc(sizeof(sb_t)); uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); @@ -530,32 +987,43 @@ void *sb_15_init(device_t *info) sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sb_mixer_init(&sb->mixer); + /* CMS I/O handler is activated on the dedicated sound_cms module + DSP I/O handler is activated in sb_dsp_setaddr */ 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); - sound_add_handler(sb_get_buffer_opl2, sb); + sound_add_handler(sb_get_buffer_sb2, sb); return sb; } -void *sb_mcv_init(device_t *info) +void *sb_mcv_init() { + /*sb1/2 port mappings, 210h to 260h in 10h steps + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip*/ sb_t *sb = malloc(sizeof(sb_t)); memset(sb, 0, sizeof(sb_t)); opl2_init(&sb->opl); sb_dsp_init(&sb->dsp, SB15); - sb_dsp_setaddr(&sb->dsp, 0); + sb_dsp_setaddr(&sb->dsp, 0);//addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sb_mixer_init(&sb->mixer); - sound_add_handler(sb_get_buffer_opl2, sb); + sound_add_handler(sb_get_buffer_sb2, sb); + /* I/O handlers activated in sb_mcv_write */ mca_add(sb_mcv_read, sb_mcv_write, sb); sb->pos_regs[0] = 0x84; sb->pos_regs[1] = 0x50; return sb; } -void *sb_2_init(device_t *info) +void *sb_2_init() { + /*sb2 port mappings. 220h or 240h. + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip + "CD version" also uses 250h or 260h for + 2x0 to 2x3 -> CDROM interface + 2x4 to 2x5 -> Mixer interface*/ sb_t *sb = malloc(sizeof(sb_t)); uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); @@ -565,15 +1033,32 @@ void *sb_2_init(device_t *info) sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sb_mixer_init(&sb->mixer); + sb_ct1335_mixer_reset(sb); + /* CMS I/O handler is activated on the dedicated sound_cms module + DSP I/O handler is activated in sb_dsp_setaddr */ 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); - sound_add_handler(sb_get_buffer_opl2, sb); + + int mixer_addr = device_get_config_int("mixaddr"); + if (mixer_addr > 0) + { + io_sethandler(mixer_addr+4, 0x0002, sb_ct1335_mixer_read, NULL, NULL, sb_ct1335_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sb2_mixer, sb); + } + else + sound_add_handler(sb_get_buffer_sb2, sb); + return sb; } -void *sb_pro_v1_init(device_t *info) +void *sb_pro_v1_init() { + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip, Left and Right (9*2 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices) + 2x0+10 to 2x0+13 CDROM interface.*/ sb_t *sb = malloc(sizeof(sb_t)); uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); @@ -583,25 +1068,26 @@ void *sb_pro_v1_init(device_t *info) sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sb_mixer_init(&sb->mixer); + sb_ct1345_mixer_reset(sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ io_sethandler(addr+0, 0x0002, opl2_l_read, NULL, NULL, opl2_l_write, NULL, NULL, &sb->opl); io_sethandler(addr+2, 0x0002, opl2_r_read, NULL, NULL, opl2_r_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); - io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); - sound_add_handler(sb_get_buffer_opl2, sb); - - sb->mixer.regs[0x22] = 0xff; - sb->mixer.regs[0x04] = 0xff; - sb->mixer.regs[0x26] = 0xff; - sb->mixer.regs[0x28] = 0xff; - sb->mixer.regs[0xe] = 0; + io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sbpro, sb); return sb; } -void *sb_pro_v2_init(device_t *info) +void *sb_pro_v2_init() { + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices) + 2x0+10 to 2x0+13 CDROM interface.*/ sb_t *sb = malloc(sizeof(sb_t)); uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); @@ -611,38 +1097,34 @@ void *sb_pro_v2_init(device_t *info) sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); - sb_mixer_init(&sb->mixer); + sb_ct1345_mixer_reset(sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); - sound_add_handler(sb_get_buffer_opl3, sb); - - sb->mixer.regs[0x22] = 0xff; - sb->mixer.regs[0x04] = 0xff; - sb->mixer.regs[0x26] = 0xff; - sb->mixer.regs[0x28] = 0xff; - sb->mixer.regs[0xe] = 0; + io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sbpro, sb); return sb; } -void *sb_pro_mcv_init(device_t *info) +void *sb_pro_mcv_init() { + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip, Left and Right (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices)*/ sb_t *sb = malloc(sizeof(sb_t)); memset(sb, 0, sizeof(sb_t)); opl3_init(&sb->opl); sb_dsp_init(&sb->dsp, SBPRO2); - sb_mixer_init(&sb->mixer); - io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - sound_add_handler(sb_get_buffer_opl3, sb); - - sb->mixer.regs[0x22] = 0xff; - sb->mixer.regs[0x04] = 0xff; - sb->mixer.regs[0x26] = 0xff; - sb->mixer.regs[0xe] = 0; + sb_ct1345_mixer_reset(sb); + /* I/O handlers activated in sb_mcv_write */ + sound_add_handler(sb_get_buffer_sbpro, sb); + /* I/O handlers activated in sb_pro_mcv_write */ mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb); sb->pos_regs[0] = 0x03; sb->pos_regs[1] = 0x51; @@ -650,7 +1132,7 @@ void *sb_pro_mcv_init(device_t *info) return sb; } -void *sb_16_init(device_t *info) +void *sb_16_init() { sb_t *sb = malloc(sizeof(sb_t)); uint16_t addr = device_get_config_hex16("base"); @@ -662,84 +1144,66 @@ void *sb_16_init(device_t *info) sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16")); - sb_mixer_init(&sb->mixer); - io_sethandler(addr + 0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + sb_ct1745_mixer_reset(sb); + io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr + 4, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); - sound_add_handler(sb_get_buffer_opl3, sb); + 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); mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq401"), device_get_config_int("mode401")); - sb->mixer.regs[0x30] = 31 << 3; - sb->mixer.regs[0x31] = 31 << 3; - sb->mixer.regs[0x32] = 31 << 3; - sb->mixer.regs[0x33] = 31 << 3; - sb->mixer.regs[0x34] = 31 << 3; - sb->mixer.regs[0x35] = 31 << 3; - sb->mixer.regs[0x36] = 31 << 3; - sb->mixer.regs[0x37] = 31 << 3; - sb->mixer.regs[0x44] = 8 << 4; - sb->mixer.regs[0x45] = 8 << 4; - sb->mixer.regs[0x46] = 8 << 4; - sb->mixer.regs[0x47] = 8 << 4; - sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4); - sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4); - sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4); - sb->mixer.regs[0x28] = (sb->mixer.regs[0x36] & 0xf0) | (sb->mixer.regs[0x37] >> 4); return sb; } -int sb_awe32_available(void) +int sb_awe32_available() { return rom_present(L"roms/sound/awe32.raw"); } -void *sb_awe32_init(device_t *info) +void *sb_awe32_init() { sb_t *sb = malloc(sizeof(sb_t)); - uint16_t addr = device_get_config_hex16("base"); + uint16_t addr = device_get_config_hex16("base"); + uint16_t emu_addr = device_get_config_hex16("emu_base"); int onboard_ram = device_get_config_int("onboard_ram"); memset(sb, 0, sizeof(sb_t)); + opl3_init(&sb->opl); sb_dsp_init(&sb->dsp, SB16 + 1); sb_dsp_setaddr(&sb->dsp, addr); sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16")); - sb_mixer_init(&sb->mixer); - io_sethandler(addr + 0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr + 8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + sb_ct1745_mixer_reset(sb); + io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_sethandler(addr + 4, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); + 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); mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq401"), device_get_config_int("mode401")); - emu8k_init(&sb->emu8k, onboard_ram); + emu8k_init(&sb->emu8k, emu_addr, onboard_ram); - sb->mixer.regs[0x30] = 31 << 3; - sb->mixer.regs[0x31] = 31 << 3; - sb->mixer.regs[0x32] = 31 << 3; - sb->mixer.regs[0x33] = 31 << 3; - sb->mixer.regs[0x34] = 31 << 3; - sb->mixer.regs[0x35] = 31 << 3; - sb->mixer.regs[0x36] = 31 << 3; - sb->mixer.regs[0x37] = 31 << 3; - sb->mixer.regs[0x44] = 8 << 4; - sb->mixer.regs[0x45] = 8 << 4; - sb->mixer.regs[0x46] = 8 << 4; - sb->mixer.regs[0x47] = 8 << 4; - sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4); - sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4); - sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4); - sb->mixer.regs[0x28] = (sb->mixer.regs[0x36] & 0xf0) | (sb->mixer.regs[0x37] >> 4); - return sb; } void sb_close(void *p) { sb_t *sb = (sb_t *)p; + sb_dsp_close(&sb->dsp); + #ifdef SB_DSP_RECORD_DEBUG + if (soundfsb != 0) + { + fclose(soundfsb); + soundfsb=0; + } + if (soundfsbin!= 0) + { + fclose(soundfsbin); + soundfsbin=0; + } + #endif free(sb); } @@ -750,7 +1214,7 @@ void sb_awe32_close(void *p) emu8k_close(&sb->emu8k); - free(sb); + sb_close(sb); } void sb_speed_changed(void *p) @@ -1072,6 +1536,26 @@ static device_config_t sb_awe32_config[] = } } }, + { + "emu_addr", "EMU8000 Address", CONFIG_HEX16, "", 0x620, + { + { + "0x620", 0x620 + }, + { + "0x640", 0x640 + }, + { + "0x660", 0x660 + }, + { + "0x680", 0x680 + }, + { + .description = "" + } + } + }, { "base401", "MPU-401 Address", CONFIG_HEX16, "", 0x330, { diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 1ce9796df..9acff4646 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -3,10 +3,10 @@ 486-33 - 20kHz 486-50 - 32kHz Pentium - 45kHz*/ + #include #include #include -#include #include "../ibm.h" #include "../io.h" #include "../pic.h" @@ -18,11 +18,22 @@ #include "snd_mpu401.h" #include "snd_sb_dsp.h" -mpu_t mpu; +/*The recording safety margin is intended for uneven "len" calls to the get_buffer mixer calls on sound_sb*/ +#define SB_DSP_REC_SAFEFTY_MARGIN 4096 void pollsb(void *p); void sb_poll_i(void *p); +//#define SB_DSP_RECORD_DEBUG +//#define SB_TEST_RECORDING_SAW + +#ifdef SB_DSP_RECORD_DEBUG +FILE* soundf = 0/*NULL*/; +#endif + +#ifdef SB_TEST_RECORDING_SAW +int counttest; +#endif static int sbe2dat[4][9] = { { 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 }, @@ -103,6 +114,7 @@ uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405, 0x void sb_irq(sb_dsp_t *dsp, int irq8) { +// pclog("IRQ %i %02X\n",irq8,pic.mask); if (irq8) dsp->sb_irq8 = 1; else dsp->sb_irq16 = 1; picint(1 << dsp->sb_irqnum); @@ -135,9 +147,20 @@ void sb_dsp_reset(sb_dsp_t *dsp) dsp->sbreset = 0; dsp->sbenable = dsp->sb_enable_i = dsp->sb_count_i = 0; + dsp->record_pos_read=0; + dsp->record_pos_write=SB_DSP_REC_SAFEFTY_MARGIN; + picintc(1 << dsp->sb_irqnum); dsp->asp_data_len = 0; + + #ifdef SB_DSP_RECORD_DEBUG + if (soundf != 0) + { + fclose(soundf); + soundf=0; + } + #endif } void sb_doreset(sb_dsp_t *dsp) @@ -158,14 +181,14 @@ void sb_doreset(sb_dsp_t *dsp) void sb_dsp_speed_changed(sb_dsp_t *dsp) { if (dsp->sb_timeo < 256) - dsp->sblatcho = TIMER_USEC * (256LL - dsp->sb_timeo); + dsp->sblatcho = TIMER_USEC * (256 - dsp->sb_timeo); else - dsp->sblatcho = (int64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256LL))); + dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256))); if (dsp->sb_timei < 256) dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_timei); else - dsp->sblatchi = (int64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256LL))); + dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256))); } void sb_add_data(sb_dsp_t *dsp, uint8_t v) @@ -195,6 +218,7 @@ void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len timer_update_outstanding(); dsp->sbleftright = 0; dsp->sbdacpos = 0; +// pclog("Start 8-bit DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); } else { @@ -206,8 +230,9 @@ void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0; dsp->sb_16_output = 1; timer_process(); - dsp->sbenable = dsp->sb_16_enable; - timer_update_outstanding(); + dsp->sbenable = dsp->sb_16_enable; + timer_update_outstanding(); +// pclog("Start 16-bit DMA addr %06X len %04X\n",dma16.ac[1]+(dma16.page[1]<<16),len); } } @@ -215,6 +240,13 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l { if (dma8) { +#ifdef SB_TEST_RECORDING_SAW + switch (dsp->sb_8_format) + { + case 00:case 20:counttest=0x80;break; + case 10:case 30:counttest=0;break; + } +#endif dsp->sb_8_length = len; dsp->sb_8_format = format; dsp->sb_8_autoinit = autoinit; @@ -225,9 +257,17 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l timer_process(); dsp->sb_enable_i = dsp->sb_8_enable; timer_update_outstanding(); +// pclog("Start 8-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); } else { +#ifdef SB_TEST_RECORDING_SAW + switch (dsp->sb_16_format) + { + case 00:case 20:counttest=0x8000;break; + case 10:case 30:counttest=0;break; + } +#endif dsp->sb_16_length = len; dsp->sb_16_format = format; dsp->sb_16_autoinit = autoinit; @@ -238,7 +278,18 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l timer_process(); dsp->sb_enable_i = dsp->sb_16_enable; timer_update_outstanding(); +// pclog("Start 16-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); } + memset(dsp->record_buffer,0,sizeof(dsp->record_buffer)); + + #ifdef SB_DSP_RECORD_DEBUG + if (soundf != 0) + { + fclose(soundf); + soundf=0; + } + #endif + } int sb_8_read_dma(sb_dsp_t *dsp) @@ -248,14 +299,23 @@ int sb_8_read_dma(sb_dsp_t *dsp) void sb_8_write_dma(sb_dsp_t *dsp, uint8_t val) { dma_channel_write(dsp->sb_8_dmanum, val); +#ifdef SB_DSP_RECORD_DEBUG + if (!soundf) soundf=fopen("sound_dsp.pcm","wb"); + fwrite(&val,1,1,soundf); +#endif } uint16_t sb_16_read_dma(sb_dsp_t *dsp) { return dma_channel_read(dsp->sb_16_dmanum); } -void sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) +int sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) { - dma_channel_write(dsp->sb_16_dmanum, val); + int ret = dma_channel_write(dsp->sb_16_dmanum, val); +#ifdef SB_DSP_RECORD_DEBUG + if (!soundf) soundf=fopen("sound_dsp.pcm","wb"); + fwrite(&val,2,1,soundf); +#endif + return (ret == DMA_NODATA); } void sb_dsp_setirq(sb_dsp_t *dsp, int irq) @@ -272,10 +332,10 @@ void sb_dsp_setdma16(sb_dsp_t *dsp, int dma) { dsp->sb_16_dmanum = dma; } - void sb_exec_command(sb_dsp_t *dsp) { int temp,c; +// pclog("sb_exec_command : SB command %02X\n", dsp->sb_command); switch (dsp->sb_command) { case 0x01: /*???*/ @@ -295,6 +355,7 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x17: /*2-bit ADPCM output with reference*/ dsp->sbref = sb_8_read_dma(dsp); dsp->sbstep = 0; +// pclog("Ref byte 2 %02X\n",sbref); case 0x16: /*2-bit ADPCM output*/ sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); dsp->sbdat2 = sb_8_read_dma(dsp); @@ -311,7 +372,19 @@ void sb_exec_command(sb_dsp_t *dsp) dsp->sb_8_length--; break; case 0x20: /*8-bit direct input*/ - sb_add_data(dsp, 0); + sb_add_data(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8) ^0x80); + /*Due to the current implementation, I need to emulate a samplerate, even if this + * mode does not imply such samplerate. Position is increased in sb_poll_i*/ + if (dsp->sb_enable_i==0) + { + dsp->sb_timei = 256 - 22; + dsp->sblatchi = TIMER_USEC * 22; + temp = 1000000 / 22; + dsp->sb_freq = temp; + timer_process(); + dsp->sb_enable_i = 1; + timer_update_outstanding(); + } break; case 0x24: /*8-bit single cycle DMA input*/ sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); @@ -320,40 +393,36 @@ void sb_exec_command(sb_dsp_t *dsp) if (dsp->sb_type < SB15) break; sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); break; + case 0x30: + case 0x31: + break; + case 0x34: + dsp->uart_midi = 1; + dsp->uart_irq = 0; + break; + case 0x35: + dsp->uart_midi = 1; + dsp->uart_irq = 1; + break; + case 0x36: + case 0x37: + break; + case 0x38: + dsp->onebyte_midi = 1; + break; case 0x40: /*Set time constant*/ dsp->sb_timei = dsp->sb_timeo = dsp->sb_data[0]; - dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256LL - dsp->sb_data[0]); + dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]); temp = 256 - dsp->sb_data[0]; temp = 1000000 / temp; +// pclog("Sample rate - %ihz (%i)\n",temp, dsp->sblatcho); dsp->sb_freq = temp; break; - - case 0x30: - case 0x31: - break; - - case 0x34: - dsp->uart_midi = 1; - dsp->uart_irq = 0; - break; - - case 0x35: - dsp->uart_midi = 1; - dsp->uart_irq = 1; - break; - - case 0x36: - case 0x37: - break; - - case 0x38: - dsp->onebyte_midi = 1; - break; - case 0x41: /*Set output sampling rate*/ case 0x42: /*Set input sampling rate*/ if (dsp->sb_type < SB16) break; - dsp->sblatcho = (int64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); + dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); +// pclog("Sample rate - %ihz (%i)\n",dsp->sb_data[1]+(dsp->sb_data[0]<<8), dsp->sblatcho); dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8); dsp->sb_timeo = 256 + dsp->sb_freq; dsp->sblatchi = dsp->sblatcho; @@ -365,6 +434,7 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x75: /*4-bit ADPCM output with reference*/ dsp->sbref = sb_8_read_dma(dsp); dsp->sbstep = 0; +// pclog("Ref byte 4 %02X\n",sbref); case 0x74: /*4-bit ADPCM output*/ sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); dsp->sbdat2 = sb_8_read_dma(dsp); @@ -373,6 +443,7 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x77: /*2.6-bit ADPCM output with reference*/ dsp->sbref = sb_8_read_dma(dsp); dsp->sbstep = 0; +// pclog("Ref byte 26 %02X\n",sbref); case 0x76: /*2.6-bit ADPCM output*/ sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); dsp->sbdat2 = sb_8_read_dma(dsp); @@ -392,28 +463,31 @@ void sb_exec_command(sb_dsp_t *dsp) break; case 0x80: /*Pause DAC*/ dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8); - timer_process(); +// pclog("SB pause %04X\n",sb_pausetime); + timer_process(); dsp->sbenable = 1; timer_update_outstanding(); break; case 0x90: /*High speed 8-bit autoinit DMA output*/ - if (dsp->sb_type < SB2) break; + if (dsp->sb_type < SB2 || dsp->sb_type > SBPRO2) 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) break; + if (dsp->sb_type < SB2 || dsp->sb_type > SBPRO2) 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) break; + if (dsp->sb_type < SB2 || dsp->sb_type > SBPRO2) 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) break; + if (dsp->sb_type < SB2 || dsp->sb_type > SBPRO2) break; sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen); break; case 0xA0: /*Set input mode to mono*/ case 0xA8: /*Set input mode to stereo*/ + if (dsp->sb_type < SB2 || dsp->sb_type > SBPRO2) break; + //TODO: Implement. 3.xx-only command. break; case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: /*16-bit DMA output*/ @@ -443,9 +517,17 @@ void sb_exec_command(sb_dsp_t *dsp) dsp->sb_8_pause = 1; break; case 0xD1: /*Speaker on*/ + if (dsp->sb_type < SB15 ) + dsp->sb_8_pause = 1; + else if ( dsp->sb_type < SB16 ) + dsp->muted = 0; dsp->sb_speaker = 1; break; case 0xD3: /*Speaker off*/ + if (dsp->sb_type < SB15 ) + dsp->sb_8_pause = 1; + else if ( dsp->sb_type < SB16 ) + dsp->muted = 1; dsp->sb_speaker = 0; break; case 0xD4: /*Continue 8-bit DMA*/ @@ -497,8 +579,13 @@ void sb_exec_command(sb_dsp_t *dsp) sb_add_data(dsp, dsp->sb_test); break; case 0xF2: /*Trigger 8-bit IRQ*/ +// pclog("Trigger IRQ\n"); sb_irq(dsp, 1); break; + case 0xF3: /*Trigger 16-bit IRQ*/ +// pclog("Trigger IRQ\n"); + sb_irq(dsp, 0); + break; case 0xE7: /*???*/ case 0xFA: /*???*/ break; @@ -512,10 +599,13 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x0E: /*ASP set register*/ if (dsp->sb_type < SB16) break; dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1]; +// pclog("ASP write reg %02X %02X\n", sb_data[0], sb_data[1]); break; case 0x0F: /*ASP get register*/ if (dsp->sb_type < SB16) break; +// sb_add_data(0); sb_add_data(dsp, dsp->sb_asp_regs[dsp->sb_data[0]]); +// pclog("ASP read reg %02X %02X\n", sb_data[0], sb_asp_regs[sb_data[0]]); break; case 0xF8: if (dsp->sb_type >= SB16) break; @@ -530,12 +620,31 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x04: case 0x05: break; +// default: +// fatal("Exec bad SB command %02X\n",sb_command); + + + /*TODO: Some more data about the DSP registeres + * http://the.earth.li/~tfm/oldpage/sb_dsp.html + * http://www.synchrondata.com/pheaven/www/area19.htm + * http://www.dcee.net/Files/Programm/Sound/ + 0E3h DSP Copyright SBPro2??? + 0F0h Sine Generator SB + 0F1h DSP Auxiliary Status (Obsolete) SB-Pro2 + 0F2h IRQ Request, 8-bit SB + 0F3h IRQ Request, 16-bit SB16 + 0FBh DSP Status SB16 + 0FCh DSP Auxiliary Status SB16 + 0FDh DSP Command Status SB16 + */ + } } void sb_write(uint16_t a, uint8_t v, void *priv) { sb_dsp_t *dsp = (sb_dsp_t *)priv; +// pclog("sb_write : Write soundblaster %04X %02X %04X:%04X %02X\n",a,v,CS,pc,dsp->sb_command); switch (a&0xF) { case 6: /*Reset*/ @@ -547,18 +656,13 @@ void sb_write(uint16_t a, uint8_t v, void *priv) dsp->sbreset = v; return; case 0xC: /*Command/data write*/ - if (dsp->uart_midi || dsp->onebyte_midi) - { - midi_write(v); - dsp->onebyte_midi = 0; - return; - } timer_process(); - dsp->wb_time = TIMER_USEC * 1LL; + dsp->wb_time = TIMER_USEC * 1; dsp->wb_full = 1; timer_update_outstanding(); if (dsp->asp_data_len) { +// pclog("ASP data %i\n", dsp->asp_data_len); dsp->asp_data_len--; if (!dsp->asp_data_len) sb_add_data(dsp, 0); @@ -569,6 +673,8 @@ void sb_write(uint16_t a, uint8_t v, void *priv) dsp->sb_command = v; if (v == 0x01) sb_add_data(dsp, 0); +// if (sb_commands[v]==-1) +// fatal("Bad SB command %02X\n",v); dsp->sb_data_stat++; } else @@ -585,19 +691,17 @@ void sb_write(uint16_t a, uint8_t v, void *priv) uint8_t sb_read(uint16_t a, void *priv) { sb_dsp_t *dsp = (sb_dsp_t *)priv; +// pclog("sb_read : Read soundblaster %04X %04X:%04X\n",a,CS,pc); switch (a & 0xf) { case 0xA: /*Read data*/ - if (dsp->uart_midi) - { - return MPU401_ReadData(&mpu); - } dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; if (dsp->sb_read_rp != dsp->sb_read_wp) { dsp->sb_read_rp++; dsp->sb_read_rp &= 0xFF; } +// pclog("SB read %02X\n",sbreaddat); return dsp->sbreaddat; case 0xC: /*Write data ready*/ if (dsp->wb_full) @@ -622,14 +726,15 @@ static void sb_wb_clear(void *p) { sb_dsp_t *dsp = (sb_dsp_t *)p; - dsp->wb_time = 0LL; + dsp->wb_time = 0; } void sb_dsp_init(sb_dsp_t *dsp, int type) { dsp->sb_type = type; - dsp->sb_irqnum = 5; + // Default values. Use sb_dsp_setxxx() methods to change. + dsp->sb_irqnum = 7; dsp->sb_8_dmanum = 1; dsp->sb_16_dmanum = 5; @@ -642,6 +747,7 @@ void sb_dsp_init(sb_dsp_t *dsp, int type) void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr) { +// pclog("sb_dsp_setaddr : %04X\n", addr); io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); dsp->sb_addr = addr; @@ -663,11 +769,13 @@ void pollsb(void *p) int tempi,ref; dsp->sbcount += dsp->sblatcho; +// pclog("PollSB %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output) { int data[2]; sb_dsp_update(dsp); +// pclog("Dopoll %i %02X %i\n", sb_8_length, sb_8_format, sblatcho); switch (dsp->sb_8_format) { case 0x00: /*Mono unsigned*/ @@ -684,7 +792,7 @@ void pollsb(void *p) dsp->sbleftright = !dsp->sbleftright; } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; dsp->sb_8_length--; break; case 0x10: /*Mono signed*/ @@ -699,7 +807,7 @@ void pollsb(void *p) dsp->sbleftright = !dsp->sbleftright; } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; dsp->sb_8_length--; break; case 0x20: /*Stereo unsigned*/ @@ -751,7 +859,7 @@ void pollsb(void *p) dsp->sbleftright = !dsp->sbleftright; } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; break; case ADPCM_26: @@ -785,7 +893,7 @@ void pollsb(void *p) dsp->sbleftright = !dsp->sbleftright; } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; break; case ADPCM_2: @@ -815,8 +923,11 @@ void pollsb(void *p) dsp->sbleftright = !dsp->sbleftright; } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; break; + +// default: + //fatal("Unrecognised SB 8-bit format %02X\n",sb_8_format); } if (dsp->sb_8_length < 0) @@ -850,10 +961,13 @@ void pollsb(void *p) dsp->sbdatr = sb_16_read_dma(dsp); dsp->sb_16_length -= 2; break; +// default: +// fatal("Unrecognised SB 16-bit format %02X\n",sb_16_format); } if (dsp->sb_16_length < 0) { +// pclog("16DMA over %i\n",dsp->sb_16_autoinit); if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; else dsp->sb_16_enable = dsp->sbenable = 0; sb_irq(dsp, 0); @@ -866,6 +980,7 @@ void pollsb(void *p) { sb_irq(dsp, 1); dsp->sbenable = dsp->sb_8_enable; +// pclog("SB pause over\n"); } } } @@ -873,80 +988,169 @@ void pollsb(void *p) void sb_poll_i(void *p) { sb_dsp_t *dsp = (sb_dsp_t *)p; - + int processed=0; dsp->sb_count_i += dsp->sblatchi; +// pclog("PollSBi %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && !dsp->sb_8_output) { switch (dsp->sb_8_format) { - case 0x00: /*Mono unsigned*/ - sb_8_write_dma(dsp, 0x80); +#ifdef SB_TEST_RECORDING_SAW + case 0x00: /*Unsigned mono. As the manual says, only the left channel is recorded*/ + case 0x10: /*Signed mono. As the manual says, only the left channel is recorded*/ + sb_8_write_dma(dsp, counttest); + counttest+=0x10; + counttest&=0xFF; dsp->sb_8_length--; break; - case 0x10: /*Mono signed*/ - sb_8_write_dma(dsp, 0x00); + case 0x20: /*Unsigned stereo*/ + case 0x30: /*Signed stereo*/ + sb_8_write_dma(dsp, counttest); + sb_8_write_dma(dsp, counttest); + counttest+=0x10; + counttest&=0xFF; + dsp->sb_8_length -= 2; + break; +#else + case 0x00: /*Mono unsigned As the manual says, only the left channel is recorded*/ + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8) ^0x80); dsp->sb_8_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x10: /*Mono signed As the manual says, only the left channel is recorded*/ + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)); + dsp->sb_8_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; break; case 0x20: /*Stereo unsigned*/ - sb_8_write_dma(dsp, 0x80); - sb_8_write_dma(dsp, 0x80); + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)^0x80); + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read+1]>>8)^0x80); dsp->sb_8_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; break; case 0x30: /*Stereo signed*/ - sb_8_write_dma(dsp, 0x00); - sb_8_write_dma(dsp, 0x00); + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)); + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read+1]>>8)); dsp->sb_8_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; break; +#endif +// default: +// fatal("Unrecognised SB 8-bit input format %02X\n",sb_8_format); } if (dsp->sb_8_length < 0) { +// pclog("Input DMA over %i\n",sb_8_autoinit); if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; - else dsp->sb_8_enable = dsp->sbenable = 0; + else dsp->sb_8_enable = dsp->sb_enable_i = 0; sb_irq(dsp, 1); } + processed=1; } if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && !dsp->sb_16_output) { switch (dsp->sb_16_format) { - case 0x00: /*Unsigned mono*/ - sb_16_write_dma(dsp, 0x8000); - dsp->sb_16_length--; - break; - case 0x10: /*Signed mono*/ - sb_16_write_dma(dsp, 0); +#ifdef SB_TEST_RECORDING_SAW + case 0x00: /*Unsigned mono. As the manual says, only the left channel is recorded*/ + case 0x10: /*Signed mono. As the manual says, only the left channel is recorded*/ + if (sb_16_write_dma(dsp, counttest)) + return; + counttest+=0x1000; + counttest&=0xFFFF; dsp->sb_16_length--; break; case 0x20: /*Unsigned stereo*/ - sb_16_write_dma(dsp, 0x8000); - sb_16_write_dma(dsp, 0x8000); + case 0x30: /*Signed stereo*/ + if (sb_16_write_dma(dsp, counttest)) + return; + sb_16_write_dma(dsp, counttest); + counttest+=0x1000; + counttest&=0xFFFF; dsp->sb_16_length -= 2; break; +#else + case 0x00: /*Unsigned mono. As the manual says, only the left channel is recorded*/ + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read]^0x8000)) + return; + dsp->sb_16_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x10: /*Signed mono. As the manual says, only the left channel is recorded*/ + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read])) + return; + dsp->sb_16_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x20: /*Unsigned stereo*/ + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read]^0x8000)) + return; + sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read+1]^0x8000); + dsp->sb_16_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; case 0x30: /*Signed stereo*/ - sb_16_write_dma(dsp, 0); - sb_16_write_dma(dsp, 0); + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read])) + return; + sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read+1]); dsp->sb_16_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; break; +#endif +// default: +// fatal("Unrecognised SB 16-bit input format %02X\n",sb_16_format); } if (dsp->sb_16_length < 0) { +// pclog("16iDMA over %i\n",sb_16_autoinit); if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; - else dsp->sb_16_enable = dsp->sbenable = 0; + else dsp->sb_16_enable = dsp->sb_enable_i = 0; sb_irq(dsp, 0); } + processed=1; + } + //Assume this is direct mode + if (!processed) + { + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; } } void sb_dsp_update(sb_dsp_t *dsp) { + /*this "if" implements two things: speaker on/off and buffer cleanup after stopping audio. */ + if (!dsp->sbenable || dsp->muted) + { + dsp->sbdatl=0; + dsp->sbdatr=0; + } for (; dsp->pos < sound_pos_global; dsp->pos++) { dsp->buffer[dsp->pos*2] = dsp->sbdatl; dsp->buffer[dsp->pos*2 + 1] = dsp->sbdatr; } } +void sb_dsp_close(sb_dsp_t *dsp) +{ + #ifdef SB_DSP_RECORD_DEBUG + if (soundf != 0) + { + fclose(soundf); + soundf=0; + } + #endif +} void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp) { diff --git a/src/sound/snd_sb_dsp.h b/src/sound/snd_sb_dsp.h index ea5923f11..60656be8f 100644 --- a/src/sound/snd_sb_dsp.h +++ b/src/sound/snd_sb_dsp.h @@ -1,9 +1,5 @@ typedef struct sb_dsp_t -{ - int uart_midi; - int uart_irq; - int onebyte_midi; - +{ int sb_type; int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; @@ -15,8 +11,12 @@ typedef struct sb_dsp_t uint8_t sb_read_data[256]; int sb_read_wp, sb_read_rp; int sb_speaker; + int muted; int sb_data_stat; + int uart_midi; + int uart_irq; + int onebyte_midi; int sb_irqnum; @@ -61,12 +61,16 @@ typedef struct sb_dsp_t int asp_data_len; int64_t wb_time, wb_full; - + + int record_pos_read; + int record_pos_write; + int16_t record_buffer[0xFFFF]; int16_t buffer[SOUNDBUFLEN * 2]; int pos; } sb_dsp_t; void sb_dsp_init(sb_dsp_t *dsp, int type); +void sb_dsp_close(sb_dsp_t *dsp); void sb_dsp_setirq(sb_dsp_t *dsp, int irq); void sb_dsp_setdma8(sb_dsp_t *dsp, int dma); diff --git a/src/sound/sound.c b/src/sound/sound.c index a45a88df1..825b2e955 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -31,6 +31,7 @@ #include "snd_opl.h" #include "snd_adlib.h" #include "snd_adlibgold.h" +#include "snd_audiopci.h" #if defined(DEV_BRANCH) && defined(USE_PAS16) # include "snd_pas16.h" #endif @@ -67,9 +68,11 @@ static SOUND_CARD sound_cards[] = { "[ISA] Pro Audio Spectrum 16","pas16", &pas16_device }, #endif { "[ISA] Windows Sound System", "wss", &wss_device }, - { "[MCA] Adlib", "adlib_mca", &adlib_mca_device }, - { "[MCA] Sound Blaster MCV","sbmcv", &sb_mcv_device }, + { "[MCA] Adlib", "adlib_mca", &adlib_mca_device }, + { "[MCA] Sound Blaster MCV", "sbmcv", &sb_mcv_device }, { "[MCA] Sound Blaster Pro MCV","sbpromcv", &sb_pro_mcv_device }, + { "[PCI] Ensoniq AudioPCI (ES1371)","es1371", &es1371_device}, + { "[PCI] Sound Blaster PCI 128", "sbpci128", &es1371_device}, { "", "", NULL } }; diff --git a/src/win/win.c b/src/win/win.c index 8f3f4217a..633dc408c 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -94,7 +94,6 @@ uint64_t main_time; HWND hwndMain; HMENU menuMain; HANDLE ghMutex; -HANDLE slirpMutex; HINSTANCE hinstance; HICON hIcon[512]; RECT oldclip; @@ -1275,9 +1274,6 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nFunsterStil) endblit(); } - /* Move this to SLiRP. */ - slirpMutex = CreateMutex(NULL, FALSE, L"86Box.SlirpMutex"); - /* All done, fire up the actual emulated machine. */ if (! pc_init_modules()) { /* Dang, no ROMs found at all! */ @@ -1633,20 +1629,6 @@ endblit(void) } -void -startslirp(void) -{ - WaitForSingleObject(slirpMutex, INFINITE); -} - - -void -endslirp(void) -{ - ReleaseMutex(slirpMutex); -} - - void updatewindowsize(int x, int y) { diff --git a/src/win/win_thread.c b/src/win/win_thread.c index 4a62fc393..cefec74f7 100644 --- a/src/win/win_thread.c +++ b/src/win/win_thread.c @@ -46,6 +46,10 @@ thread_create(void (*thread_rout)(void *param), void *param) void thread_kill(void *handle) { + if (handle == NULL) { + return; + } + TerminateThread(handle, 0); } @@ -71,6 +75,10 @@ thread_create_event(void) void thread_set_event(event_t *_event) { + if (_event == NULL) { + return; + } + win_event_t *event = (win_event_t *)_event; SetEvent(event->handle); @@ -80,6 +88,10 @@ thread_set_event(event_t *_event) void thread_reset_event(event_t *_event) { + if (_event == NULL) { + return; + } + win_event_t *event = (win_event_t *)_event; ResetEvent(event->handle); @@ -89,6 +101,10 @@ thread_reset_event(event_t *_event) int thread_wait_event(event_t *_event, int timeout) { + if (_event == NULL) { + return 0; + } + win_event_t *event = (win_event_t *)_event; if (timeout == -1) @@ -105,6 +121,10 @@ thread_destroy_event(event_t *_event) { win_event_t *event = (win_event_t *)_event; + if (_event == NULL) { + return; + } + CloseHandle(event->handle); free(event); @@ -121,6 +141,10 @@ thread_create_mutex(wchar_t *name) void thread_close_mutex(void *mutex) { + if (mutex == NULL) { + return; + } + CloseHandle((HANDLE)mutex); } @@ -128,6 +152,10 @@ thread_close_mutex(void *mutex) uint8_t thread_wait_mutex(void *mutex) { + if (mutex == NULL) { + return 0; + } + DWORD dwres = WaitForSingleObject((HANDLE)mutex, INFINITE); switch (dwres) { @@ -144,5 +172,9 @@ thread_wait_mutex(void *mutex) uint8_t thread_release_mutex(void *mutex) { + if (mutex == NULL) { + return 0; + } + return(!!ReleaseMutex((HANDLE)mutex)); }