diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 9228c4814..0dead893e 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -4,13 +4,13 @@ CC = gcc.exe WINDRES = windres.exe CFLAGS = -O3 -march=native -mtune=native -fbranch-probabilities -fvpt -fpeel-loops -ftracer -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse -mstackrealign DFLAGS = -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign -OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-iso.o \ +OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o aha154x.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-iso.o \ cdrom-null.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o dac.o \ device.o disc.o disc_86f.o disc_fdi.o disc_imd.o disc_img.o disc_random.o disc_td0.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \ i430nx.o i430vx.o i440fx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o memregs.o model.o mouse.o mouse_amstrad.o mouse_ps2.o \ mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \ - scat.o serial.o sis496.o sis85c471.o sio.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o \ + scat.o scattergather.o scsi.o scsi_cdrom.o serial.o sis496.o sis85c471.o sio.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o \ sound_dbopl.o sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o \ soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ diff --git a/src/Makefile.mingw64 b/src/Makefile.mingw64 index 7aff5e6f3..4c611f349 100644 --- a/src/Makefile.mingw64 +++ b/src/Makefile.mingw64 @@ -4,13 +4,13 @@ CC = gcc.exe WINDRES = windres.exe CFLAGS = -O3 -march=native -mtune=native -fbranch-probabilities -fvpt -fpeel-loops -ftracer -fomit-frame-pointer -ffast-math -msse -msse2 -msse3 -mssse3 -mfpmath=sse -mstackrealign DFLAGS = -O3 -fomit-frame-pointer -msse2 -OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-iso.o \ +OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o acerm3a.o aha154x.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-iso.o \ cdrom-null.o codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.o compaq.o config.o cpu.o dac.o \ device.o disc.o disc_86f.o disc_fdi.o disc_imd.o disc_img.o disc_random.o disc_td0.o dma.o fdc.o fdc37c665.o fdc37c932fr.o fdd.o fdi2raw.o gameport.o headland.o i430hx.o i430lx.o i430fx.o \ i430nx.o i430vx.o i440fx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o memregs.o model.o mouse.o mouse_amstrad.o mouse_ps2.o \ mouse_serial.o ne2000.o neat.o nethandler.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pc87306.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o rtc.o \ - scat.o serial.o sis496.o sis85c471.o sio.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o \ + scat.o scattergather.o scsi.o scsi_cdrom.o serial.o sis496.o sis85c471.o sio.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o \ sound_dbopl.o sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o \ soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ diff --git a/src/aha154x.c b/src/aha154x.c new file mode 100644 index 000000000..571e602f3 --- /dev/null +++ b/src/aha154x.c @@ -0,0 +1,1115 @@ +/* Copyright holders: SA1988 + see COPYING for more details +*/ +/*Adaptec 154x SCSI emulation*/ +#include +#include +#include +#include + +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "dma.h" +#include "rom.h" +#include "pic.h" +#include "timer.h" + +#include "cdrom.h" +#include "scsi.h" + +#include "aha154x.h" + +typedef struct +{ + uint8_t hi; + uint8_t mid; + uint8_t lo; +} addr24; + +#define ADDR_TO_U32(x) (((x).hi << 16) | ((x).mid << 8) | (x).lo & 0xFF) +#define U32_TO_ADDR(a, x) do {(a).hi = (x) >> 16; (a).mid = (x) >> 8; (a).lo = (x) & 0xFF;} while(0) + +// I/O Port interface +// 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) + +// READ STATUS flags +#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 INTERRUPT STATUS flags +#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 + +// 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/WRITE DATA commands +#define CMD_NOP 0x00 // No operation +#define CMD_MBINIT 0x01 // mailbox initialization +#define CMD_START_SCSI 0x02 // Start SCSI 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 + +typedef struct MailboxInit_t +{ + uint8_t Count; + addr24 Address; +} MailboxInit_t; + +typedef struct MailboxInitExtended_t +{ + uint8_t Count; + uint32_t Address; +} MailboxInitExtended_t; + +/////////////////////////////////////////////////////////////////////////////// +// +// 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 + +typedef struct Mailbox_t +{ + uint8_t CmdStatus; + addr24 CCBPointer; +} Mailbox_t; + +typedef struct Mailbox32_t +{ + uint8_t CmdStatus; + uint32_t CCBPointer; +} Mailbox32_t; + + +/////////////////////////////////////////////////////////////////////////////// +// +// CCB - Adaptec 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 interrupt +#define CCB_SELECTION_TIMEOUT 0x11 // Set SCSI selection timed out +#define CCB_DATA_OVER_UNDER_RUN 0x12 +#define CCB_UNEXPECTED_BUS_FREE 0x13 // Target dropped SCSI BSY +#define CCB_PHASE_SEQUENCE_FAIL 0x14 // Target bus phase sequence failure +#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 different from first +#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 +// + +typedef struct CCB +{ + uint8_t Opcode; + uint8_t Lun:3; + uint8_t ControlByte:2; + uint8_t 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; + +/////////////////////////////////////////////////////////////////////////////// +// +// Scatter/Gather Segment List Definitions +// +/////////////////////////////////////////////////////////////////////////////// + +// +// Adapter limits +// + +#define MAX_SG_DESCRIPTORS 17 + +typedef struct SGE +{ + addr24 Segment; + addr24 SegmentPointer; +} SGE; + +typedef struct AdaptecRequests_t +{ + CCB CmdBlock; + uint8_t *RequestSenseBuffer; + uint32_t CCBPointer; +} AdaptecRequests_t; + +typedef struct Adaptec_t +{ + AdaptecRequests_t AdaptecRequests; + uint8_t Status; + uint8_t Interrupt; + uint8_t Geometry; + uint8_t Command; + uint8_t CmdBuf[5]; + uint8_t CmdParam; + uint8_t CmdParamLeft; + uint8_t DataBuf[64]; + uint8_t DataReply; + uint8_t DataReplyLeft; + uint32_t MailboxCount; + uint32_t MailboxOutAddr; + uint32_t MailboxOutPosCur; + uint32_t MailboxInAddr; + uint32_t MailboxInPosCur; + int Irq; + int DmaChannel; + int DmaPort1, DmaData1; + int DmaPort2, DmaData2; + int BusOn; + int BusOff; + int DmaSpeed; + int ScsiBios; +} Adaptec_t; + +Adaptec_t AdaptecLUN; + +static void AdaptecStartMailbox(Adaptec_t *Adaptec); + +typedef void (*AdaptecMemCopyCallback)(Adaptec_t *Adaptec, uint32_t Addr, SGBUF *SegmentBuffer, + uint32_t Copy, uint32_t *Skip); + +int aha154x_do_log = 0; + +void AdaptecLog(const char *format, ...) +{ + if (aha154x_do_log) + { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +} + +static void AdaptecSetDMAChannel(int DmaPort1, int DmaData1, int DmaPort2, int DmaData2) +{ + dma_channel_write(DmaPort1, DmaData1); + dma_channel_write(DmaPort2, DmaData2); +} + +static void AdaptecClearInterrupt(Adaptec_t *Adaptec) +{ + AdaptecLog("Adaptec: Clearing Interrupt 0x%02X\n", Adaptec->Interrupt); + Adaptec->Interrupt = 0; + picintc(1 << Adaptec->Irq); +} + +static void AdaptecReset(Adaptec_t *Adaptec) +{ + Adaptec->Status = STAT_IDLE | STAT_INIT; + Adaptec->Geometry = 0x80; + Adaptec->Command = 0xFF; + Adaptec->CmdParam = 0; + Adaptec->CmdParamLeft = 0; + Adaptec->MailboxOutPosCur = 0; + Adaptec->MailboxInPosCur = 0; + + AdaptecClearInterrupt(Adaptec); +} + +static void AdaptecCommandComplete(Adaptec_t *Adaptec) +{ + Adaptec->Status |= STAT_IDLE; + Adaptec->DataReply = 0; + + if (Adaptec->Command != CMD_START_SCSI) + { + Adaptec->Status &= ~STAT_DFULL; + Adaptec->Interrupt = INTR_ANY | INTR_HACC; + picint(1 << Adaptec->Irq); + } + + Adaptec->Command = 0xFF; + Adaptec->CmdParam = 0; +} + +static void AdaptecInitReset(Adaptec_t *Adaptec, int Reset) +{ + AdaptecReset(Adaptec); + if (Reset) + { + Adaptec->Status |= STAT_STST; + Adaptec->Status &= ~STAT_IDLE; + } +} + +static void AdaptecMailboxLogInformation(Mailbox_t *Mailbox) +{ + AdaptecLog("Adaptec: Mailbox Dump Log\n"); + AdaptecLog("CCB Pointer=%#x\n", ADDR_TO_U32(Mailbox->CCBPointer)); + AdaptecLog("Command or Status Code=%02X\n", Mailbox->CmdStatus); +} + +static void AdaptecCCBLogInformation(CCB *CmdBlock) +{ + pclog("Adaptec: CCB Dump Log\n"); + pclog("Opcode=%#x\n", CmdBlock->Opcode); + pclog("Data Direction=%u\n", CmdBlock->ControlByte); + pclog("Cdb Length=%d\n", CmdBlock->CdbLength); + pclog("Sense Length=%u\n", CmdBlock->RequestSenseLength); + pclog("Data Length=%u\n", ADDR_TO_U32(CmdBlock->DataLength)); + pclog("Data Pointer=%u\n", ADDR_TO_U32(CmdBlock->DataPointer)); + pclog("Host Adapter Status=0x%02X\n", CmdBlock->HostStatus); + pclog("Target Device Status=0x%02X\n", CmdBlock->TargetStatus); + pclog("Cdb[0]=%#x\n", CmdBlock->Cdb[0]); + pclog("Cdb[1]=%#x\n", CmdBlock->Cdb[1]); +} + +static void AdaptecMailboxIn(Adaptec_t *Adaptec, uint32_t CCBPointer, CCB *CmdBlock, uint8_t HostStatus, uint8_t TargetStatus, uint8_t MailboxCompletionCode) +{ + Mailbox32_t Mailbox32; + Mailbox_t MailboxIn; + + Mailbox32.CCBPointer = CCBPointer; + Mailbox32.CmdStatus = MailboxCompletionCode; + + uint32_t Incoming = Adaptec->MailboxInAddr + (Adaptec->MailboxInPosCur * sizeof(Mailbox_t)); + + if (MailboxCompletionCode != MBI_NOT_FOUND) + { + CmdBlock->HostStatus = HostStatus; + CmdBlock->TargetStatus = TargetStatus; + + uint32_t CCBSize = offsetof(CCB, Cdb); + const void *Data = (const void *)&CmdBlock; + uint32_t l = PageLengthReadWrite(CCBPointer, CCBSize); + //AdaptecBufferWrite(&Adaptec->AdaptecRequests, Incoming, &MailboxIn, sizeof(Mailbox_t)); + memcpy(&ram[CCBPointer], Data, l); + CCBPointer += l; + Data -= l; + CCBSize += l; + } + + MailboxIn.CmdStatus = Mailbox32.CmdStatus; + U32_TO_ADDR(MailboxIn.CCBPointer, Mailbox32.CCBPointer); + AdaptecLog("Adaptec: Mailbox: status code=0x%02X, CCB at 0x%08X\n", MailboxIn.CmdStatus, ADDR_TO_U32(MailboxIn.CCBPointer)); + + uint32_t MailboxSize = sizeof(Mailbox_t); + const void *Data = (const void *)&MailboxIn; + uint32_t l = PageLengthReadWrite(Incoming, MailboxSize); + //AdaptecBufferWrite(&Adaptec->AdaptecRequests, Incoming, &MailboxIn, sizeof(Mailbox_t)); + memcpy(&ram[Incoming], Data, l); + Incoming += l; + Data -= l; + MailboxSize += l; + + Adaptec->MailboxInPosCur++; + if (Adaptec->MailboxInPosCur > Adaptec->MailboxCount) + Adaptec->MailboxInPosCur = 0; + + Adaptec->Interrupt = INTR_MBIF | INTR_ANY; + picint(1 << Adaptec->Irq); +} + +static void AdaptecReadSGEntries(uint32_t SGList, uint32_t Entries, SGE *SG) +{ + uint32_t SGSize = Entries * sizeof(SGE); + void *Data = (void *)SG; + uint32_t l = PageLengthReadWrite(SGList, SGSize); + //AdaptecBufferRead(&Adaptec->AdaptecRequests, SGList, SG, Entries * sizeof(SGE)); + memcpy(Data, &ram[SGList], l); + SGList += l; + Data -= l; + SGSize += l; +} + +static void AdaptecQueryDataBufferSize(Adaptec_t *Adaptec, CCB *CmdBlock, uint32_t *pBufferSize) +{ + uint32_t BufferSize = 0; + + DataPointer = ADDR_TO_U32(CmdBlock->DataPointer); + DataLength = ADDR_TO_U32(CmdBlock->DataLength); + + if (DataLength) + { + if (CmdBlock->Opcode == SCATTER_GATHER_COMMAND || + CmdBlock->Opcode == SCATTER_GATHER_COMMAND_RES) + { + uint32_t ScatterGatherRead; + uint32_t ScatterEntry; + SGE ScatterGatherBuffer[MAX_SG_DESCRIPTORS]; + uint32_t ScatterGatherLeft = DataLength / sizeof(SGE); + uint32_t ScatterGatherAddrCurrent = DataPointer; + + do + { + ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer)) + ? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer); + + ScatterGatherLeft -= ScatterGatherRead; + + AdaptecReadSGEntries(ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer); + + for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++) + BufferSize += ADDR_TO_U32(ScatterGatherBuffer[ScatterEntry].Segment); + + ScatterGatherAddrCurrent += ScatterGatherRead * sizeof(SGE); + } while (ScatterGatherLeft > 0); + + AdaptecLog("Adaptec: Data Buffer Size=%u\n", BufferSize); + } + else if (CmdBlock->Opcode == SCSI_INITIATOR_COMMAND || + CmdBlock->Opcode == SCSI_INITIATOR_COMMAND_RES) + BufferSize = DataLength; + } + + *pBufferSize = BufferSize; +} + +static void AdaptecCopyBufferFromGuestWorker(Adaptec_t *Adaptec, uint32_t Address, SGBUF *SegmentBuffer, + uint32_t Copy, uint32_t *pSkip) +{ + uint32_t Skipped = MIN(Copy, *pSkip); + Copy -= Skipped; + Address += Skipped; + *pSkip -= Skipped; + + while (Copy) + { + uint32_t Segment = Copy; + uint8_t *SegmentPointer = SegmentBufferGetNextSegment(SegmentBuffer, Segment); + + uint32_t SegmentSize = Segment; + void *Data = (void *)SegmentPointer; + uint32_t l = PageLengthReadWrite(Address, SegmentSize); + //AdaptecBufferRead(&Adaptec->AdaptecRequests, Address, SegmentPointer, Segment); + memcpy(Data, &ram[Address], l); + Address += l; + Data -= l; + SegmentSize += l; + + Address += Segment; + Copy -= Segment; + } +} + +static void AdaptecCopyBufferToGuestWorker(Adaptec_t *Adaptec, uint32_t Address, SGBUF *SegmentBuffer, + uint32_t Copy, uint32_t *pSkip) +{ + uint32_t Skipped = MIN(Copy, *pSkip); + Copy -= Skipped; + Address += Skipped; + *pSkip -= Skipped; + + while (Copy) + { + uint32_t Segment = Copy; + uint8_t *SegmentPointer = SegmentBufferGetNextSegment(SegmentBuffer, Segment); + + uint32_t SegmentSize = Segment; + const void *Data = (const void *)SegmentPointer; + uint32_t l = PageLengthReadWrite(Address, SegmentSize); + //AdaptecBufferWrite(&Adaptec->AdaptecRequests, Address, SegmentPointer, Segment); + memcpy(&ram[Address], Data, l); + Address += l; + Data -= l; + SegmentSize += l; + + Address += Segment; + Copy -= Segment; + } +} + +static int AdaptecScatterGatherBufferWalker(Adaptec_t *Adaptec, AdaptecRequests_t *AdaptecRequests, + AdaptecMemCopyCallback IoCopyWorker, SGBUF *SegmentBuffer, + uint32_t Skip, uint32_t Copy) +{ + uint32_t Copied = 0; + + Copy += Skip; + + DataPointer = ADDR_TO_U32(AdaptecRequests->CmdBlock.DataPointer); + DataLength = ADDR_TO_U32(AdaptecRequests->CmdBlock.DataLength); + + if (AdaptecRequests->CmdBlock.Cdb[0] == GPCMD_TEST_UNIT_READY) + { + AdaptecRequests->CmdBlock.ControlByte = 3; + DataLength = 6; + } + + AdaptecLog("Adaptec: S/G Buffer Walker\n"); + AdaptecLog("Data Length=%u\n", DataLength); + AdaptecLog("Data Buffer Copy=%u\n", Copy); + + if ((DataLength > 0) && (AdaptecRequests->CmdBlock.ControlByte == CCB_DATA_XFER_IN || + AdaptecRequests->CmdBlock.ControlByte == CCB_DATA_XFER_OUT)) + { + if (AdaptecRequests->CmdBlock.Opcode == SCATTER_GATHER_COMMAND || + AdaptecRequests->CmdBlock.Opcode == SCATTER_GATHER_COMMAND_RES) + { + uint32_t ScatterGatherRead; + uint32_t ScatterEntry; + SGE ScatterGatherBuffer[MAX_SG_DESCRIPTORS]; + uint32_t ScatterGatherLeft = DataLength / sizeof(SGE); + uint32_t ScatterGatherAddrCurrent = DataPointer; + + do + { + ScatterGatherRead = (ScatterGatherLeft < ELEMENTS(ScatterGatherBuffer)) + ? ScatterGatherLeft : ELEMENTS(ScatterGatherBuffer); + + ScatterGatherLeft -= ScatterGatherRead; + + AdaptecReadSGEntries(ScatterGatherAddrCurrent, ScatterGatherRead, ScatterGatherBuffer); + + for (ScatterEntry = 0; ScatterEntry < ScatterGatherRead; ScatterEntry++) + { + uint32_t Address; + uint32_t CopyThis; + + AdaptecLog("Adaptec: Scatter Entry=%u\n", ScatterEntry); + + Address = ADDR_TO_U32(ScatterGatherBuffer[ScatterEntry].SegmentPointer); + CopyThis = MIN(Copy, ADDR_TO_U32(ScatterGatherBuffer[ScatterEntry].Segment)); + + AdaptecLog("Adaptec: S/G Address=0x%04X, Copy=%u", Address, CopyThis); + + IoCopyWorker(Adaptec, Address, SegmentBuffer, CopyThis, &Skip); + Copied += CopyThis; + Copy -= CopyThis; + } + + ScatterGatherAddrCurrent += ScatterGatherRead * sizeof(SGE); + } while (ScatterGatherLeft > 0 && Copy > 0); + } + else if (AdaptecRequests->CmdBlock.Opcode == SCSI_INITIATOR_COMMAND || + AdaptecRequests->CmdBlock.Opcode == SCSI_INITIATOR_COMMAND_RES) + { + uint32_t Address = DataPointer; + + AdaptecLog("Adaptec: Non-scattered buffer\n"); + pclog("Data Pointer=%#x\n", DataPointer); + pclog("Data Length=%u\n", DataLength); + AdaptecLog("Pointer Address=%#x\n", Address); + + IoCopyWorker(Adaptec, Address, SegmentBuffer, MIN(DataLength, Copy), &Skip); + Copied += MIN(DataLength, Copy); + } + } + + return Copied - MIN(Skip, Copied); +} + +static int AdaptecCopySegmentBufferToGuest(Adaptec_t *Adaptec, AdaptecRequests_t *AdaptecRequests, + SGBUF *SegmentBuffer, uint32_t Skip, uint32_t Copy) +{ + return AdaptecScatterGatherBufferWalker(Adaptec, AdaptecRequests, AdaptecCopyBufferToGuestWorker, SegmentBuffer, Skip, Copy); +} + +static int AdaptecCopySegmentBufferFromGuest(Adaptec_t *Adaptec, AdaptecRequests_t *AdaptecRequests, + SGBUF *SegmentBuffer, uint32_t Skip, uint32_t Copy) +{ + return AdaptecScatterGatherBufferWalker(Adaptec, AdaptecRequests, AdaptecCopyBufferFromGuestWorker, SegmentBuffer, Skip, Copy); +} + +uint8_t AdaptecRead(uint16_t Port, void *p) +{ + Adaptec_t *Adaptec = &AdaptecLUN; + uint8_t Temp; + + switch (Port & 3) + { + case 0: + Temp = Adaptec->Status; + if (Adaptec->Status & STAT_STST) + { + Adaptec->Status &= ~STAT_STST; + Adaptec->Status |= STAT_IDLE; + Temp = Adaptec->Status; + } + break; + + case 1: + Temp = Adaptec->DataBuf[Adaptec->DataReply]; + if (Adaptec->DataReplyLeft) + { + Adaptec->DataReply++; + Adaptec->DataReplyLeft--; + if (!Adaptec->DataReplyLeft) + { + AdaptecCommandComplete(Adaptec); + } + } + break; + + case 2: + Temp = Adaptec->Interrupt; + if (Adaptec->ScsiBios) + { + Adaptec->Interrupt = INTR_MBIF | INTR_ANY; + picint(1 << Adaptec->Irq); + } + break; + + case 3: + Temp = Adaptec->Geometry; + break; + } + + AdaptecLog("Adaptec: Read Port 0x%02X, Returned Value %02X\n", Port, Temp); + return Temp; +} + +void AdaptecWrite(uint16_t Port, uint8_t Val, void *p) +{ + Adaptec_t *Adaptec = &AdaptecLUN; + AdaptecLog("Adaptec: Write Port 0x%02X, Value %02X\n", Port, Val); + + switch (Port & 3) + { + case 0: + if ((Val & CTRL_HRST) || (Val & CTRL_SRST)) + { + int HardReset = !!(Val & CTRL_HRST); + + AdaptecLog("Adaptec: %s reset\n", HardReset ? "hard" : "soft"); + AdaptecInitReset(Adaptec, HardReset); + break; + } + + if (Val & CTRL_IRST) + AdaptecClearInterrupt(Adaptec); + break; + + case 1: + if ((Val == 0x02) && (Adaptec->Command == 0xFF)) + { + if (Adaptec->MailboxCount) + { + ScsiCallback[scsi_cdrom_id] = 1; + } + break; + } + + if (Adaptec->Command == 0xFF) + { + Adaptec->Command = Val; + Adaptec->CmdParam = 0; + + Adaptec->Status &= ~(STAT_INVCMD | STAT_IDLE); + AdaptecLog("Adaptec: Operation Code 0x%02X\n", Val); + switch (Adaptec->Command) + { + case 0x03: + case 0x00: + case 0x04: + case 0x84: + case 0x85: + case 0x0A: + case 0x0B: + Adaptec->CmdParamLeft = 0; + break; + + case 0x07: + case 0x08: + case 0x09: + case 0x0D: + case 0x1F: + Adaptec->CmdParamLeft = 1; + break; + + case 0x06: + Adaptec->CmdParamLeft = 4; + break; + + case 0x01: + Adaptec->CmdParamLeft = sizeof(MailboxInit_t); + break; + + case 0x28: + case 0x29: + Adaptec->CmdParamLeft = 0; + break; + } + } + else + { + Adaptec->CmdBuf[Adaptec->CmdParam] = Val; + Adaptec->CmdParam++; + Adaptec->CmdParamLeft--; + } + + if (!Adaptec->CmdParamLeft) + { + switch (Adaptec->Command) + { + case 0x00: + Adaptec->DataReplyLeft = 0; + break; + + case 0x01: + { + MailboxInit_t *MailboxInit = (MailboxInit_t *)Adaptec->CmdBuf; + + Adaptec->MailboxCount = MailboxInit->Count; + Adaptec->MailboxOutAddr = ADDR_TO_U32(MailboxInit->Address); + Adaptec->MailboxInAddr = Adaptec->MailboxOutAddr + (Adaptec->MailboxCount * sizeof(Mailbox_t)); + + AdaptecLog("Adaptec Initialize Mailbox Command\n"); + AdaptecLog("Mailbox Out Address=0x%08X\n", Adaptec->MailboxOutAddr); + AdaptecLog("Mailbox In Address=0x%08X\n", Adaptec->MailboxInAddr); + AdaptecLog("Initialized Mailbox, %d entries at 0x%08X\n", MailboxInit->Count, ADDR_TO_U32(MailboxInit->Address)); + + Adaptec->Status &= ~STAT_INIT; + Adaptec->DataReplyLeft = 0; + } + break; + + case 0x03: + break; + + case 0x04: + Adaptec->DataBuf[0] = 'A'; + Adaptec->DataBuf[1] = '0'; + Adaptec->DataBuf[2] = '3'; + Adaptec->DataBuf[3] = '1'; + Adaptec->DataReplyLeft = 4; + break; + + case 0x84: + Adaptec->DataBuf[0] = '0'; + Adaptec->DataReplyLeft = 1; + break; + + case 0x85: + Adaptec->DataBuf[0] = 'A'; + Adaptec->DataReplyLeft = 1; + break; + + case 0x06: + Adaptec->DataReplyLeft = 0; + break; + + case 0x07: + Adaptec->BusOn = Adaptec->CmdBuf[0]; + Adaptec->DataReplyLeft = 0; + break; + + case 0x08: + Adaptec->BusOff = Adaptec->CmdBuf[0]; + Adaptec->DataReplyLeft = 0; + break; + + case 0x09: + Adaptec->DmaSpeed = Adaptec->CmdBuf[0]; + Adaptec->DataReplyLeft = 0; + break; + + case 0x0A: + if (ScsiDrives[scsi_cdrom_id].LunType == SCSI_CDROM) + Adaptec->DataBuf[scsi_cdrom_id] = 1; + + Adaptec->DataBuf[7] = 0; + Adaptec->DataReplyLeft = 8; + break; + + case 0x0B: + Adaptec->DataBuf[0] = (1 << Adaptec->DmaChannel); + + if (Adaptec->DmaChannel >= 0) + AdaptecSetDMAChannel(Adaptec->DmaPort1, Adaptec->DmaData1, + Adaptec->DmaPort2, Adaptec->DmaData2); + + Adaptec->DataBuf[1] = (1 << (Adaptec->Irq - 9)); + Adaptec->DataBuf[2] = 7; + Adaptec->DataReplyLeft = 3; + break; + + case 0x0D: + Adaptec->DataReplyLeft = Adaptec->CmdBuf[0]; + Adaptec->DataBuf[1] = Adaptec->DmaSpeed; + Adaptec->DataBuf[2] = Adaptec->BusOn; + Adaptec->DataBuf[3] = Adaptec->BusOff; + Adaptec->DataBuf[4] = Adaptec->MailboxCount; + Adaptec->DataBuf[5] = Adaptec->MailboxOutAddr&0xFF; + Adaptec->DataBuf[6] = (Adaptec->MailboxOutAddr>>8); + Adaptec->DataBuf[7] = (Adaptec->MailboxOutAddr>>16); + Adaptec->DataBuf[8+scsi_cdrom_id] = 1; + break; + + case 0x1F: + Adaptec->DataBuf[0] = Adaptec->CmdBuf[0]; + Adaptec->DataReplyLeft = 1; + break; + + case 0x28: + case 0x29: + Adaptec->DataReplyLeft = 0; + Adaptec->Status |= STAT_INVCMD; + break; + } + } + + if (Adaptec->DataReplyLeft) + Adaptec->Status |= STAT_DFULL; + else if (!Adaptec->CmdParamLeft) + AdaptecCommandComplete(Adaptec); + break; + + case 2: + break; + + case 3: + break; + } +} + +static uint8_t AdaptecConvertSenseLength(uint8_t RequestSenseLength) +{ + if (RequestSenseLength == 0) + RequestSenseLength = 14; + else if (RequestSenseLength == 1) + RequestSenseLength = 0; + + return RequestSenseLength; +} + +static void AdaptecSenseBufferAllocate(AdaptecRequests_t *AdaptecRequests) +{ + uint8_t SenseLength = AdaptecConvertSenseLength(AdaptecRequests->CmdBlock.RequestSenseLength); + + AdaptecRequests->RequestSenseBuffer = malloc(SenseLength); +} + +static void AdaptecSenseBufferFree(AdaptecRequests_t *AdaptecRequests, int Copy) +{ + uint8_t SenseLength = AdaptecConvertSenseLength(AdaptecRequests->CmdBlock.RequestSenseLength); + + if (Copy && SenseLength) + { + uint32_t SenseBufferAddress; + + SenseBufferAddress = AdaptecRequests->CCBPointer; + SenseBufferAddress += AdaptecRequests->CmdBlock.CdbLength + offsetof(CCB, Cdb); + + uint32_t SenseSize = SenseLength; + const void *Data = (const void *)AdaptecRequests->RequestSenseBuffer; + uint32_t l = PageLengthReadWrite(SenseBufferAddress, SenseSize); + //AdaptecBufferWrite(AdaptecRequests, SenseBufferAddress, AdaptecRequests->RequestSenseBuffer, SenseLength); + memcpy(&ram[SenseBufferAddress], Data, l); + SenseBufferAddress += l; + Data -= l; + SenseSize += l; + } + free(AdaptecRequests->RequestSenseBuffer); +} + +static void AdaptecRequestComplete(SCSI *Scsi, Adaptec_t *Adaptec, + AdaptecRequests_t *AdaptecRequests) +{ + if (AdaptecRequests->RequestSenseBuffer) + AdaptecSenseBufferFree(AdaptecRequests, (ScsiStatus != SCSI_STATUS_OK)); + + if (AdaptecRequests->CmdBlock.Opcode == SCSI_INITIATOR_COMMAND_RES || + AdaptecRequests->CmdBlock.Opcode == SCATTER_GATHER_COMMAND_RES) + { + uint32_t Residual = 0; + SCSIQueryResidual(Scsi, &Residual); + U32_TO_ADDR(AdaptecRequests->CmdBlock.DataLength, Residual); + } + + uint8_t Status = ScsiStatus; + uint32_t CCBPointer = AdaptecRequests->CCBPointer; + CCB CmdBlock; + memcpy(&CmdBlock, &AdaptecRequests->CmdBlock, sizeof(CCB)); + + if (Status == SCSI_STATUS_OK) + AdaptecMailboxIn(Adaptec, CCBPointer, &CmdBlock, CCB_COMPLETE, SCSI_STATUS_OK, + MBI_SUCCESS); + else if (Status == SCSI_STATUS_CHECK_CONDITION) + AdaptecMailboxIn(Adaptec, CCBPointer, &CmdBlock, CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, + MBI_ERROR); +} + +uint32_t AdaptecIoRequestCopyFromBuffer(uint32_t OffDst, SGBUF *SegmentBuffer, uint32_t Copy) +{ + Adaptec_t *Adaptec = &AdaptecLUN; + uint32_t Copied = 0; + + Copied = AdaptecCopySegmentBufferToGuest(Adaptec, &Adaptec->AdaptecRequests, SegmentBuffer, OffDst, Copy); + + return Copied; +} + +uint32_t AdaptecIoRequestCopyToBuffer(uint32_t OffSrc, SGBUF *SegmentBuffer, uint32_t Copy) +{ + Adaptec_t *Adaptec = &AdaptecLUN; + uint32_t Copied = 0; + + Copied = AdaptecCopySegmentBufferFromGuest(Adaptec, &Adaptec->AdaptecRequests, SegmentBuffer, OffSrc, Copy); + + return Copied; +} + +static void AdaptecSCSIRequestSetup(Adaptec_t *Adaptec, uint32_t CCBPointer) +{ + AdaptecRequests_t *AdaptecRequests = &Adaptec->AdaptecRequests; + CCB CmdBlock; + + uint32_t CCBUSize = sizeof(CCB); + void *Data = (void *)&CmdBlock; + uint32_t l = PageLengthReadWrite(CCBPointer, CCBUSize); + //AdaptecBufferRead(&Adaptec->AdaptecRequests, CCBPointer, &CmdBlock, sizeof(CCBU)); + memcpy(Data, &ram[CCBPointer], l); + CCBPointer += l; + Data -= l; + CCBUSize += l; + + pclog("Scanning SCSI Target ID %d\n", CmdBlock.Id); + + if (CmdBlock.Id == scsi_cdrom_id && CmdBlock.Lun == 0) + { + if (CmdBlock.Cdb[0] == GPCMD_TEST_UNIT_READY) + CmdBlock.ControlByte = 3; + + pclog("SCSI Target ID %d detected and working\n", CmdBlock.Id); + + SCSI *Scsi = &ScsiDrives[CmdBlock.Id]; + + AdaptecRequests->CCBPointer = CCBPointer - 30; + + memcpy(&AdaptecRequests->CmdBlock, &CmdBlock, sizeof(CmdBlock)); + + AdaptecSenseBufferAllocate(AdaptecRequests); + + uint32_t BufferSize = 0; + AdaptecQueryDataBufferSize(Adaptec, &CmdBlock, &BufferSize); + + uint8_t SenseLength = AdaptecConvertSenseLength(CmdBlock.RequestSenseLength); + + pclog("Control Byte Transfer Direction %02X\n", CmdBlock.ControlByte); + + if (CmdBlock.ControlByte == 3) + { + pclog("Adaptec No Transfer\n"); + SCSINoTransfer(Scsi, CmdBlock.Id); + } + else if (CmdBlock.ControlByte == CCB_DATA_XFER_OUT) + { + pclog("Adaptec Write Transfer\n"); + SCSIWriteTransfer(Scsi, CmdBlock.Id); + } + else if (CmdBlock.ControlByte == CCB_DATA_XFER_IN) + { + pclog("Adaptec Read Transfer\n"); + SCSIReadTransfer(Scsi, CmdBlock.Id); + } + + SCSISendCommand(Scsi, CmdBlock.Id, CmdBlock.Cdb, CmdBlock.CdbLength, BufferSize, AdaptecRequests->RequestSenseBuffer, SenseLength); + + AdaptecRequestComplete(Scsi, Adaptec, AdaptecRequests); + } +} + +static uint32_t AdaptecMailboxOut(Adaptec_t *Adaptec, Mailbox32_t *Mailbox32) +{ + Mailbox_t MailboxOut; + uint32_t Outgoing; + + Outgoing = Adaptec->MailboxOutAddr + (Adaptec->MailboxOutPosCur * sizeof(Mailbox_t)); + uint32_t MailboxSize = sizeof(Mailbox_t); + void *Data = (void *)&MailboxOut; + uint32_t l = PageLengthReadWrite(Outgoing, MailboxSize); + //AdaptecBufferRead(&Adaptec->AdaptecRequests, Outgoing, &MailboxOut, sizeof(Mailbox_t)); + memcpy(Data, &ram[Outgoing], l); + Outgoing += l; + Data -= l; + MailboxSize += l; + + Mailbox32->CCBPointer = ADDR_TO_U32(MailboxOut.CCBPointer); + Mailbox32->CmdStatus = MailboxOut.CmdStatus; + + return Outgoing; +} + +static void AdaptecStartMailbox(Adaptec_t *Adaptec) +{ + Mailbox32_t Mailbox32; + Mailbox_t MailboxOut; + uint32_t Outgoing; + + uint8_t MailboxPosCur = Adaptec->MailboxOutPosCur; + + do + { + Outgoing = AdaptecMailboxOut(Adaptec, &Mailbox32); + Adaptec->MailboxOutPosCur = (Adaptec->MailboxOutPosCur + 1) % Adaptec->MailboxCount; + + } while ((MailboxPosCur != Adaptec->MailboxOutPosCur) && (Mailbox32.CmdStatus == MBO_FREE)); + + AdaptecLog("Adaptec: Got loaded mailbox at slot %u, CCB phys 0x%08X\n", Adaptec->MailboxOutPosCur, Mailbox32.CCBPointer); + + uint8_t CmdStatus = MBO_FREE; + unsigned CodeOffset = offsetof(Mailbox_t, CmdStatus); + + uint32_t MailboxOffset = Outgoing + CodeOffset; + uint32_t CmdStatusSize = sizeof(CmdStatus); + const void *Data = (const void *)&CmdStatus; + uint32_t l = PageLengthReadWrite(MailboxOffset, CmdStatusSize); + //AdaptecBufferRead(&Adaptec->AdaptecRequests, Outgoing, &MailboxOut, sizeof(Mailbox_t)); + memcpy(&ram[MailboxOffset], Data, l); + MailboxOffset += l; + Data -= l; + CmdStatusSize += l; + + Mailbox32.CmdStatus = MBO_START; + AdaptecSCSIRequestSetup(Adaptec, Mailbox32.CCBPointer); +} + +void AdaptecCallback(void *p) +{ + Adaptec_t *Adaptec = &AdaptecLUN; + + ScsiCallback[scsi_cdrom_id] = 0; + + if (Adaptec->MailboxCount) + { + AdaptecStartMailbox(Adaptec); + } +} + +void AdaptecInit(uint8_t Id) +{ + AdaptecLUN.Irq = 11; + AdaptecLUN.DmaChannel = 6; + + AdaptecLUN.DmaPort1 = 0xD6; + AdaptecLUN.DmaData1 = 0xD4; + AdaptecLUN.DmaPort2 = 0xC2; + AdaptecLUN.DmaData2 = 0x02; + + pfnIoRequestCopyFromBuffer = AdaptecIoRequestCopyFromBuffer; + pfnIoRequestCopyToBuffer = AdaptecIoRequestCopyToBuffer; + + io_sethandler(0x0334, 0x0004, AdaptecRead, NULL, NULL, AdaptecWrite, NULL, NULL, NULL); + timer_add(AdaptecCallback, &ScsiCallback[Id], &ScsiCallback[Id], NULL); + + AdaptecReset(&AdaptecLUN); +} diff --git a/src/aha154x.h b/src/aha154x.h new file mode 100644 index 000000000..4037ef2bf --- /dev/null +++ b/src/aha154x.h @@ -0,0 +1 @@ +extern void AdaptecInit(uint8_t Id); \ No newline at end of file diff --git a/src/cdrom-ioctl.c b/src/cdrom-ioctl.c index 9159655a1..d49cb1fad 100644 --- a/src/cdrom-ioctl.c +++ b/src/cdrom-ioctl.c @@ -7,16 +7,16 @@ #include #include "ntddcdrm.h" #include "ibm.h" -#include "ide.h" +#include "cdrom.h" #include "cdrom-ioctl.h" int cdrom_drive; int old_cdrom_drive; -static ATAPI ioctl_atapi; +static CDROM ioctl_cdrom; static uint32_t last_block = 0; -static uint32_t cdrom_capacity = 0; +uint32_t cdrom_capacity = 0; static int ioctl_inited = 0; static char ioctl_path[8]; void ioctl_close(void); @@ -273,7 +273,6 @@ static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, i DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&lbtoc,sizeof(lbtoc),&size,NULL); ioctl_close(); tocvalid=1; - d=0; for (c=d;c<=lbtoc.LastTrack;c++) { uint32_t address; @@ -701,7 +700,7 @@ int ioctl_open(char d) { //fatal("IOCTL"); } - atapi=&ioctl_atapi; + cdrom=&ioctl_cdrom; if (!ioctl_inited) { ioctl_inited=1; @@ -727,7 +726,7 @@ static void ioctl_exit(void) tocvalid=0; } -static ATAPI ioctl_atapi= +static CDROM ioctl_cdrom= { ioctl_ready, ioctl_medium_changed, diff --git a/src/cdrom-ioctl.h b/src/cdrom-ioctl.h index faa87a5bb..3c1f54981 100644 --- a/src/cdrom-ioctl.h +++ b/src/cdrom-ioctl.h @@ -7,6 +7,8 @@ /* this header file lists the functions provided by various platform specific cdrom-ioctl files */ +extern uint32_t cdrom_capacity; + extern int ioctl_open(char d); extern void ioctl_reset(); diff --git a/src/cdrom-iso.c b/src/cdrom-iso.c index 7cd85d1ce..8820e4f81 100644 --- a/src/cdrom-iso.c +++ b/src/cdrom-iso.c @@ -4,13 +4,13 @@ /*ISO CD-ROM support*/ #include "ibm.h" -#include "ide.h" +#include "cdrom.h" #include "cdrom-iso.h" #include -static ATAPI iso_atapi; +static CDROM iso_cdrom; -static uint32_t last_block = 0; +uint32_t last_block = 0; static uint64_t image_size = 0; static int iso_inited = 0; char iso_path[1024]; @@ -157,6 +157,7 @@ static void lba_to_msf(uint8_t *buf, int lba) static void iso_readsector_raw(uint8_t *b, int sector) { + uint32_t temp; if (!cdrom_drive) return; iso_image = fopen(iso_path, "rb"); fseek(iso_image, sector*2048, SEEK_SET); @@ -313,7 +314,7 @@ static uint32_t iso_size() { unsigned char b[4096]; - atapi->readtoc(b, 0, 0, 4096, 0); + cdrom->readtoc(b, 0, 0, 4096, 0); return last_block; } @@ -345,7 +346,7 @@ int iso_open(char *fn) pclog("Path is %s\n", iso_path); } iso_image = fopen(iso_path, "rb"); - atapi = &iso_atapi; + cdrom = &iso_cdrom; if (!iso_inited || iso_changed) { if (!iso_inited) iso_inited = 1; @@ -375,7 +376,7 @@ static int iso_is_track_audio(uint32_t pos, int ismsf) return 0; } -static ATAPI iso_atapi = +static CDROM iso_cdrom = { iso_ready, iso_medium_changed, diff --git a/src/cdrom-iso.h b/src/cdrom-iso.h index 39c405f02..4dbcfca2e 100644 --- a/src/cdrom-iso.h +++ b/src/cdrom-iso.h @@ -7,6 +7,8 @@ /* this header file lists the functions provided by various platform specific cdrom-ioctl files */ +extern uint32_t last_block; + extern char iso_path[1024]; extern int iso_open(char *fn); diff --git a/src/cdrom-null.c b/src/cdrom-null.c index 1162520e4..a54844633 100644 --- a/src/cdrom-null.c +++ b/src/cdrom-null.c @@ -2,12 +2,12 @@ see COPYING for more details */ #include "ibm.h" -#include "ide.h" +#include "cdrom.h" #include "cdrom-ioctl.h" int cdrom_drive; -static ATAPI null_atapi; +static CDROM null_cdrom; void cdrom_null_audio_callback(int16_t *output, int len) { @@ -101,7 +101,7 @@ void cdrom_null_reset() int cdrom_null_open(char d) { - atapi = &null_atapi; + cdrom = &null_cdrom; return 0; } @@ -118,7 +118,7 @@ static int null_is_track_audio(uint32_t pos, int ismsf) return 0; } -static ATAPI null_atapi = +static CDROM null_cdrom = { null_ready, null_medium_changed, diff --git a/src/cdrom.h b/src/cdrom.h new file mode 100644 index 000000000..b9aec4277 --- /dev/null +++ b/src/cdrom.h @@ -0,0 +1,30 @@ +#ifndef __CDROM_H__ +#define __CDROM_H__ + +/*CD-ROM stuff*/ +typedef struct CDROM +{ + int (*ready)(void); + int (*medium_changed)(void); + int (*readtoc)(uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); + int (*readtoc_session)(uint8_t *b, int msf, int maxlen); + int (*readtoc_raw)(uint8_t *b, int maxlen); + uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf); + void (*readsector)(uint8_t *b, int sector); + void (*readsector_raw)(uint8_t *b, int sector); + void (*playaudio)(uint32_t pos, uint32_t len, int ismsf); + void (*seek)(uint32_t pos); + void (*load)(void); + void (*eject)(void); + void (*pause)(void); + void (*resume)(void); + uint32_t (*size)(void); + int (*status)(void); + int (*is_track_audio)(uint32_t pos, int ismsf); + void (*stop)(void); + void (*exit)(void); +} CDROM; + +extern CDROM *cdrom; + +#endif \ No newline at end of file diff --git a/src/dma.c b/src/dma.c index bb28c6668..d677a3b7a 100644 --- a/src/dma.c +++ b/src/dma.c @@ -422,3 +422,16 @@ int dma_channel_write(int channel, uint16_t val) } return 0; } + +size_t PageLengthReadWrite(uint32_t Address, size_t TotalSize) +{ + size_t l; + uint32_t Page; + + Page = Address & 4095; + l = (Page + 4096) - Address; + if (l > TotalSize) + l = TotalSize; + + return l; +} diff --git a/src/dma.h b/src/dma.h index 00311731a..3200144e5 100644 --- a/src/dma.h +++ b/src/dma.h @@ -1,4 +1,4 @@ -/* Copyright holders: Sarah Walker +/* Copyright holders: Sarah Walker, SA1988 see COPYING for more details */ void dma_init(); @@ -17,3 +17,5 @@ void writedma2(uint8_t temp); int dma_channel_read(int channel); int dma_channel_write(int channel, uint16_t val); + +size_t PageLengthReadWrite(uint32_t Address, size_t TotalSize); \ No newline at end of file diff --git a/src/ibm.h b/src/ibm.h index 9e5edda49..5484ee6f8 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -351,7 +351,7 @@ int driveempty[2]; #define PCJR (romset == ROM_IBMPCJR) #define AMIBIOS (romset==ROM_AMI386 || romset==ROM_AMI486 || romset == ROM_WIN486) -int GAMEBLASTER, GUS, SSI2001, voodoo_enabled; +int GAMEBLASTER, GUS, SSI2001, voodoo_enabled, aha154x_enabled; extern int AMSTRAD, AT, is286, is386, PCI, TANDY; enum @@ -571,6 +571,7 @@ extern int cdrom_drive; extern int old_cdrom_drive; extern int idecallback[3]; extern int cdrom_enabled; +extern int atapi_cdrom_enabled, scsi_cdrom_enabled; #define CD_STATUS_EMPTY 0 #define CD_STATUS_DATA_ONLY 1 @@ -578,11 +579,14 @@ extern int cdrom_enabled; #define CD_STATUS_PAUSED 3 #define CD_STATUS_STOPPED 4 -extern uint32_t atapi_get_cd_channel(int channel); -extern uint32_t atapi_get_cd_volume(int channel); +extern uint32_t SCSIGetCDVolume(int channel); +extern uint32_t SCSIGetCDChannel(int channel); extern int ide_ter_enabled; +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define ELEMENTS(Array) (sizeof(Array) / sizeof((Array)[0])) + extern int ui_writeprot[2]; void pclog(const char *format, ...); diff --git a/src/ide.c b/src/ide.c index aa23f5652..2da874e3b 100644 --- a/src/ide.c +++ b/src/ide.c @@ -1,4 +1,4 @@ -/* Copyright holders: Sarah Walker, Tenshi +/* Copyright holders: Sarah Walker, Tenshi, SA1988 see COPYING for more details */ //#define RPCEMU_IDE @@ -28,6 +28,8 @@ #include "pic.h" #include "timer.h" #endif +#include "cdrom.h" +#include "scsi.h" #include "ide.h" /* Bits of 'atastat' */ @@ -71,210 +73,8 @@ #define WIN_SET_FEATURES 0xEF #define WIN_READ_NATIVE_MAX 0xF8 -/* ATAPI Commands */ -#define GPCMD_TEST_UNIT_READY 0x00 -#define GPCMD_REQUEST_SENSE 0x03 -#define GPCMD_READ_6 0x08 -#define GPCMD_INQUIRY 0x12 -#define GPCMD_MODE_SELECT_6 0x15 -#define GPCMD_MODE_SENSE_6 0x1a -#define GPCMD_START_STOP_UNIT 0x1b -#define GPCMD_PREVENT_REMOVAL 0x1e -#define GPCMD_READ_CDROM_CAPACITY 0x25 -#define GPCMD_READ_10 0x28 -#define GPCMD_SEEK 0x2b -#define GPCMD_READ_SUBCHANNEL 0x42 -#define GPCMD_READ_TOC_PMA_ATIP 0x43 -#define GPCMD_READ_HEADER 0x44 -#define GPCMD_PLAY_AUDIO_10 0x45 -#define GPCMD_GET_CONFIGURATION 0x46 -#define GPCMD_PLAY_AUDIO_MSF 0x47 -#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a -#define GPCMD_PAUSE_RESUME 0x4b -#define GPCMD_STOP_PLAY_SCAN 0x4e -#define GPCMD_READ_DISC_INFORMATION 0x51 -#define GPCMD_MODE_SELECT_10 0x55 -#define GPCMD_MODE_SENSE_10 0x5a -#define GPCMD_PLAY_AUDIO_12 0xa5 -#define GPCMD_READ_12 0xa8 -#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ -#define GPCMD_SET_SPEED 0xbb -#define GPCMD_MECHANISM_STATUS 0xbd -#define GPCMD_READ_CD 0xbe -#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ - -/* Mode page codes for mode sense/set */ -#define GPMODE_R_W_ERROR_PAGE 0x01 -#define GPMODE_CDROM_PAGE 0x0d -#define GPMODE_CDROM_AUDIO_PAGE 0x0e -#define GPMODE_CAPABILITIES_PAGE 0x2a -#define GPMODE_ALL_PAGES 0x3f - -/* ATAPI Sense Keys */ -#define SENSE_NONE 0 -#define SENSE_NOT_READY 2 -#define SENSE_ILLEGAL_REQUEST 5 -#define SENSE_UNIT_ATTENTION 6 - -/* ATAPI Additional Sense Codes */ -#define ASC_AUDIO_PLAY_OPERATION 0x00 -#define ASC_ILLEGAL_OPCODE 0x20 -#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 -#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 -#define ASC_INCOMPATIBLE_FORMAT 0x30 -#define ASC_MEDIUM_NOT_PRESENT 0x3a -#define ASC_DATA_PHASE_ERROR 0x4b -#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 - -#define ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS 0x11 -#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12 -#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13 - -/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw). - Not that it means anything */ -#define CDROM_SPEED 706 - /** Evaluate to non-zero if the currently selected drive is an ATAPI device */ #define IDE_DRIVE_IS_CDROM(ide) (ide->type == IDE_CDROM) -/* -\ - (!ide.drive)*/ - -/* Some generally useful CD-ROM information */ -#define CD_MINS 75 /* max. minutes per CD */ -#define CD_SECS 60 /* seconds per minute */ -#define CD_FRAMES 75 /* frames per second */ -#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ -#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) -#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) - -/* Event notification classes for GET EVENT STATUS NOTIFICATION */ -#define GESN_NO_EVENTS 0 -#define GESN_OPERATIONAL_CHANGE 1 -#define GESN_POWER_MANAGEMENT 2 -#define GESN_EXTERNAL_REQUEST 3 -#define GESN_MEDIA 4 -#define GESN_MULTIPLE_HOSTS 5 -#define GESN_DEVICE_BUSY 6 - -/* Event codes for MEDIA event status notification */ -#define MEC_NO_CHANGE 0 -#define MEC_EJECT_REQUESTED 1 -#define MEC_NEW_MEDIA 2 -#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ -#define MEC_MEDIA_CHANGED 4 /* only for media changers */ -#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ -#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ -#define MS_TRAY_OPEN 1 -#define MS_MEDIA_PRESENT 2 - -/* - * The MMC values are not IDE specific and might need to be moved - * to a common header if they are also needed for the SCSI emulation - */ - -/* Profile list from MMC-6 revision 1 table 91 */ -#define MMC_PROFILE_NONE 0x0000 -#define MMC_PROFILE_CD_ROM 0x0008 -#define MMC_PROFILE_CD_R 0x0009 -#define MMC_PROFILE_CD_RW 0x000A -#define MMC_PROFILE_DVD_ROM 0x0010 -#define MMC_PROFILE_DVD_R_SR 0x0011 -#define MMC_PROFILE_DVD_RAM 0x0012 -#define MMC_PROFILE_DVD_RW_RO 0x0013 -#define MMC_PROFILE_DVD_RW_SR 0x0014 -#define MMC_PROFILE_DVD_R_DL_SR 0x0015 -#define MMC_PROFILE_DVD_R_DL_JR 0x0016 -#define MMC_PROFILE_DVD_RW_DL 0x0017 -#define MMC_PROFILE_DVD_DDR 0x0018 -#define MMC_PROFILE_DVD_PLUS_RW 0x001A -#define MMC_PROFILE_DVD_PLUS_R 0x001B -#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A -#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B -#define MMC_PROFILE_BD_ROM 0x0040 -#define MMC_PROFILE_BD_R_SRM 0x0041 -#define MMC_PROFILE_BD_R_RRM 0x0042 -#define MMC_PROFILE_BD_RE 0x0043 -#define MMC_PROFILE_HDDVD_ROM 0x0050 -#define MMC_PROFILE_HDDVD_R 0x0051 -#define MMC_PROFILE_HDDVD_RAM 0x0052 -#define MMC_PROFILE_HDDVD_RW 0x0053 -#define MMC_PROFILE_HDDVD_R_DL 0x0058 -#define MMC_PROFILE_HDDVD_RW_DL 0x005A -#define MMC_PROFILE_INVALID 0xFFFF - -#define NONDATA 4 -#define CHECK_READY 2 -#define ALLOW_UA 1 - -/* Table of all ATAPI commands and their flags, needed for the new disc change / not ready handler. */ -uint8_t atapi_cmd_table[0x100] = -{ - [GPCMD_TEST_UNIT_READY] = CHECK_READY | NONDATA, - [GPCMD_REQUEST_SENSE] = ALLOW_UA, - [GPCMD_READ_6] = CHECK_READY, - [GPCMD_INQUIRY] = ALLOW_UA, - [GPCMD_MODE_SELECT_6] = 0, - [GPCMD_MODE_SENSE_6] = 0, - [GPCMD_START_STOP_UNIT] = 0, - [GPCMD_PREVENT_REMOVAL] = CHECK_READY, - [GPCMD_READ_CDROM_CAPACITY] = CHECK_READY, - [GPCMD_READ_10] = CHECK_READY, - [GPCMD_SEEK] = CHECK_READY | NONDATA, - [GPCMD_READ_SUBCHANNEL] = CHECK_READY, - [GPCMD_READ_TOC_PMA_ATIP] = CHECK_READY | ALLOW_UA, /* Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS */ - [GPCMD_READ_HEADER] = CHECK_READY, - [GPCMD_PLAY_AUDIO_10] = CHECK_READY, - [GPCMD_GET_CONFIGURATION] = ALLOW_UA, - [GPCMD_PLAY_AUDIO_MSF] = CHECK_READY, - [GPCMD_GET_EVENT_STATUS_NOTIFICATION] = ALLOW_UA, - [GPCMD_PAUSE_RESUME] = CHECK_READY, - [GPCMD_STOP_PLAY_SCAN] = CHECK_READY, - [GPCMD_READ_DISC_INFORMATION] = CHECK_READY, - [GPCMD_MODE_SELECT_10] = 0, - [GPCMD_MODE_SENSE_10] = 0, - [GPCMD_PLAY_AUDIO_12] = CHECK_READY, - [GPCMD_READ_12] = CHECK_READY, - [GPCMD_READ_DVD_STRUCTURE] = CHECK_READY, /* Read DVD structure (NOT IMPLEMENTED YET) */ - [GPCMD_SET_SPEED] = 0, - [GPCMD_MECHANISM_STATUS] = 0, - [GPCMD_READ_CD] = CHECK_READY, - [GPCMD_SEND_DVD_STRUCTURE] = CHECK_READY /* Send DVD structure (NOT IMPLEMENTED YET) */ -}; - -#define IMPLEMENTED 1 - -uint8_t mode_sense_pages[0x40] = -{ - [GPMODE_R_W_ERROR_PAGE] = IMPLEMENTED, - [GPMODE_CDROM_PAGE] = IMPLEMENTED, - [GPMODE_CDROM_AUDIO_PAGE] = IMPLEMENTED, - [GPMODE_CAPABILITIES_PAGE] = IMPLEMENTED, - [GPMODE_ALL_PAGES] = IMPLEMENTED -}; - -ATAPI *atapi; - -int atapi_command = 0; -int readcdmode = 0; - -int cdrom_channel = 2; - -int ide_ter_enabled = 0; - -/* Mode sense/select stuff. */ -uint8_t mode_pages_in[256][256]; -#define PAGE_CHANGEABLE 1 -#define PAGE_CHANGED 2 -uint8_t page_flags[256] = -{ - [GPMODE_R_W_ERROR_PAGE] = 0, - [GPMODE_CDROM_PAGE] = 0, - [GPMODE_CDROM_AUDIO_PAGE] = PAGE_CHANGEABLE, - [GPMODE_CAPABILITIES_PAGE] = 0, -}; -uint8_t prefix_len; -uint8_t page_current; #define ATAPI_STATUS_IDLE 0 #define ATAPI_STATUS_COMMAND 1 @@ -359,6 +159,12 @@ int idecallback[3] = {0, 0, 0}; int cur_ide[3]; +int atapi_command = 0; + +int atapi_cdrom_channel = 2; + +int ide_ter_enabled = 0; + uint8_t getstat(IDE *ide) { return ide->atastat; } int image_is_hdi(const char *s) @@ -540,38 +346,23 @@ static void ide_identify(IDE *ide) //ide->buffer[1] = 101; /* Cylinders */ -#ifdef RPCEMU_IDE - ide->buffer[1] = 65535; /* Cylinders */ - ide->buffer[3] = 16; /* Heads */ - ide->buffer[6] = 63; /* Sectors */ -#else ide->buffer[1] = hdc[cur_ide[ide->board]].tracks; /* Cylinders */ ide->buffer[3] = hdc[cur_ide[ide->board]].hpc; /* Heads */ ide->buffer[6] = hdc[cur_ide[ide->board]].spt; /* Sectors */ -#endif ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide_padstr((char *) (ide->buffer + 23), "v1.0", 8); /* Firmware */ -#ifdef RPCEMU_IDE - ide_padstr((char *) (ide->buffer + 27), "RPCemuHD", 40); /* Model */ -#else + ide_padstr((char *) (ide->buffer + 23), emulator_version, 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "86BoxHD", 40); /* Model */ -#endif - ide->buffer[20] = 3; /*Buffer type*/ - ide->buffer[21] = 512; /*Buffer size*/ - ide->buffer[47] = 16; /*Max sectors on multiple transfer command*/ - ide->buffer[48] = 1; /*Dword transfers supported*/ + ide->buffer[20] = 3; /*Buffer type*/ + ide->buffer[21] = 512; /*Buffer size*/ + ide->buffer[47] = 16; /*Max sectors on multiple transfer command*/ + ide->buffer[48] = 1; /*Dword transfers supported*/ ide->buffer[49] = (1 << 9) | (1 << 8); /* LBA and DMA supported */ ide->buffer[50] = 0x4000; /* Capabilities */ ide->buffer[51] = 2 << 8; /*PIO timing mode*/ ide->buffer[52] = 2 << 8; /*DMA timing mode*/ ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; -#ifdef RPCEMU_IDE - ide->buffer[60] = (65535 * 16 * 63) & 0xFFFF; /* Total addressable sectors (LBA) */ - ide->buffer[61] = (65535 * 16 * 63) >> 16; -#else ide->buffer[60] = (hdc[cur_ide[ide->board]].tracks * hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt) & 0xFFFF; /* Total addressable sectors (LBA) */ ide->buffer[61] = (hdc[cur_ide[ide->board]].tracks * hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt) >> 16; -#endif // ide->buffer[63] = 7; /*Multiword DMA*/ ide->buffer[62] = ide->dma_identify_data[0]; ide->buffer[63] = ide->dma_identify_data[1]; @@ -588,122 +379,14 @@ static void ide_atapi_identify(IDE *ide) ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ - ide_padstr((char *) (ide->buffer + 23), "v1.0", 8); /* Firmware */ -#ifdef RPCEMU_IDE - ide_padstr((char *) (ide->buffer + 27), "RPCemuCD", 40); /* Model */ -#else + ide_padstr((char *) (ide->buffer + 23), emulator_version, 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "86BoxCD", 40); /* Model */ -#endif ide->buffer[49] = 0x300; /* LBA and DMA supported */ ide->buffer[62] = ide->dma_identify_data[0]; ide->buffer[63] = ide->dma_identify_data[1]; ide->buffer[88] = ide->dma_identify_data[2]; } -/** - * Fill in ide->buffer with the output of the ATAPI "MODE SENSE" command - * - * @param pos Offset within the buffer to start filling in data - * - * @return Offset within the buffer after the end of the data - */ -static uint32_t ide_atapi_mode_sense(IDE *ide, uint32_t pos, uint8_t type) -{ - uint8_t *buf = (uint8_t *) ide->buffer; -// pclog("ide_atapi_mode_sense %02X\n",type); - if (type==GPMODE_ALL_PAGES || type==GPMODE_R_W_ERROR_PAGE) - { - /* &01 - Read error recovery */ - buf[pos++] = GPMODE_R_W_ERROR_PAGE; - buf[pos++] = 6; /* Page length */ - buf[pos++] = 0; /* Error recovery parameters */ - buf[pos++] = 5; /* Read retry count */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - } - - if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_PAGE) - { - /* &0D - CD-ROM Parameters */ - buf[pos++] = GPMODE_CDROM_PAGE; - buf[pos++] = 6; /* Page length */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 1; /* Inactivity time multiplier *NEEDED BY RISCOS* value is a guess */ - buf[pos++] = 0; buf[pos++] = 60; /* MSF settings */ - buf[pos++] = 0; buf[pos++] = 75; /* MSF settings */ - } - - if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_AUDIO_PAGE) - { - /* &0e - CD-ROM Audio Control Parameters */ - buf[pos++] = GPMODE_CDROM_AUDIO_PAGE; - buf[pos++] = 0xE; /* Page length */ - if (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) - { - int i; - - for (i = 0; i < 14; i++) - { - buf[pos++] = mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][i]; - } - } - else - { - buf[pos++] = 4; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; buf[pos++] = 75; /* Logical audio block per second */ - buf[pos++] = 1; /* CDDA Output Port 0 Channel Selection */ - buf[pos++] = 0xFF; /* CDDA Output Port 0 Volume */ - buf[pos++] = 2; /* CDDA Output Port 1 Channel Selection */ - buf[pos++] = 0xFF; /* CDDA Output Port 1 Volume */ - buf[pos++] = 0; /* CDDA Output Port 2 Channel Selection */ - buf[pos++] = 0; /* CDDA Output Port 2 Volume */ - buf[pos++] = 0; /* CDDA Output Port 3 Channel Selection */ - buf[pos++] = 0; /* CDDA Output Port 3 Volume */ - } - } - - if (type==GPMODE_ALL_PAGES || type==GPMODE_CAPABILITIES_PAGE) - { -// pclog("Capabilities page\n"); - /* &2A - CD-ROM capabilities and mechanical status */ - buf[pos++] = GPMODE_CAPABILITIES_PAGE; - buf[pos++] = 0x12; /* Page length */ - buf[pos++] = 0; buf[pos++] = 0; /* CD-R methods */ - buf[pos++] = 1; /* Supports audio play, not multisession */ - buf[pos++] = 0; /* Some other stuff not supported */ - buf[pos++] = 0; /* Some other stuff not supported (lock state + eject) */ - buf[pos++] = 0; /* Some other stuff not supported */ - buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); - buf[pos++] = (uint8_t) CDROM_SPEED; /* Maximum speed */ - buf[pos++] = 0; buf[pos++] = 2; /* Number of audio levels - on and off only */ - buf[pos++] = 0; buf[pos++] = 0; /* Buffer size - none */ - buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); - buf[pos++] = (uint8_t) CDROM_SPEED; /* Current speed */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Drive digital format */ - buf[pos++] = 0; /* Reserved */ - buf[pos++] = 0; /* Reserved */ - } - - return pos; -} - -uint32_t atapi_get_cd_channel(int channel) -{ - return (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 8 : 6] : (channel + 1); -} - -uint32_t atapi_get_cd_volume(int channel) -{ - // return ((page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) && (mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 8 : 6] != 0)) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 9 : 7] : 0xFF; - return (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 9 : 7] : 0xFF; -} - /* * Return the sector offset for the current register values */ @@ -940,22 +623,16 @@ void resetide(void) page_flags[GPMODE_CDROM_AUDIO_PAGE] &= 0xFD; /* Clear changed flag for CDROM AUDIO mode page. */ memset(mode_pages_in[GPMODE_CDROM_AUDIO_PAGE], 0, 256); /* Clear the page itself. */ - idecallback[0]=idecallback[1]=0; -#ifdef RPCEMU_IDE - loadhd(&ide_drives[0], 0, "hd4.hdf"); - if (!config.cdromenabled) { - loadhd(&ide_drives[1], 1, "hd5.hdf"); - } - else - ide_drives[1].type = IDE_CDROM; -#else + idecallback[0]=idecallback[1]=0; + for (d = 0; d < 4; d++) { ide_drives[d].packetstatus = 0xFF; - if ((cdrom_channel == d) && cdrom_enabled) + if ((atapi_cdrom_channel == d) && atapi_cdrom_enabled) { - ide_drives[d].type = IDE_CDROM; + if (cdrom_enabled) + ide_drives[d].type = IDE_CDROM; } else { @@ -977,9 +654,10 @@ void resetide(void) { ide_drives[d].packetstatus = 0xFF; - if ((cdrom_channel == d) && cdrom_enabled) + if ((atapi_cdrom_channel == d) && atapi_cdrom_enabled) { - ide_drives[d].type = IDE_CDROM; + if (cdrom_enabled) + ide_drives[d].type = IDE_CDROM; } else { @@ -993,8 +671,7 @@ void resetide(void) ide_drives[d].dma_identify_data[2] = 0x3f; } /* REMOVE WHEN SUBMITTING TO MAINLINE - END */ -#endif - + cur_ide[0] = 0; cur_ide[1] = 2; @@ -1013,27 +690,18 @@ void writeidew(int ide_board, uint16_t val) /*Some software issue excess writes after the 12 bytes required by the command, this will have all of them ignored*/ if (ide->packetstatus && (ide->packetstatus != ATAPI_STATUS_PACKET_REQ)) return; -#ifndef RPCEMU_IDE -/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) - { -// pclog("Failed write IDE %04X:%08X\n",CS,pc); - return; - }*/ -#endif -#ifdef _RPCEMU_BIG_ENDIAN - val=(val>>8)|(val<<8); -#endif + // pclog("Write IDEw %04X\n",val); ide->buffer[ide->pos >> 1] = val; ide->pos+=2; if (ide->packetstatus == ATAPI_STATUS_PACKET_REQ) { - if ((ide->pos>=prefix_len+4) && (page_flags[page_current] & PAGE_CHANGEABLE)) - { - mode_pages_in[page_current][ide->pos - prefix_len - 4] = ((uint8_t *) ide->buffer)[ide->pos - 2]; - mode_pages_in[page_current][ide->pos - prefix_len - 3] = ((uint8_t *) ide->buffer)[ide->pos - 1]; - } + if ((ide->pos>=prefix_len+4) && (page_flags[page_current] & PAGE_CHANGEABLE)) + { + mode_pages_in[page_current][ide->pos - prefix_len - 4] = ((uint8_t *) ide->buffer)[ide->pos - 2]; + mode_pages_in[page_current][ide->pos - prefix_len - 3] = ((uint8_t *) ide->buffer)[ide->pos - 1]; + } if (ide->pos>=(ide->packlen+2)) { ide->packetstatus = ATAPI_STATUS_PACKET_RECEIVED; @@ -1089,13 +757,7 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) { IDE *ide = &ide_drives[cur_ide[ide_board]]; IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; -#ifndef RPCEMU_IDE -/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) - { -// pclog("Failed write IDE %04X:%08X\n",CS,pc); - return; - }*/ -#endif + // if ((cr0&1) && !(eflags&VM_FLAG)) // pclog("WriteIDE %04X %02X from %04X(%08X):%08X %i\n", addr, val, CS, cs, pc, ins); // return; @@ -1390,13 +1052,7 @@ uint8_t readide(int ide_board, uint16_t addr) /* ONLY FOR EXPERIMENTAL */ addr|=0x10; /* 1F0 | 10 = 1F0, 1E8 | 10 = 1F8 */ addr&=0xFFF7; /* 1F0 & FFF7 = 1F0, 1F8 | FFF7 = 1F0 */ -#ifndef RPCEMU_IDE -/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) - { -// pclog("Failed read IDE %04X:%08X\n",CS,pc); - return 0xFF; - }*/ -#endif + // if ((cr0&1) && !(eflags&VM_FLAG)) // pclog("ReadIDE %04X from %04X(%08X):%08X\n", addr, CS, cs, pc); // return 0xFF; @@ -1492,22 +1148,14 @@ uint16_t readidew(int ide_board) { IDE *ide = &ide_drives[cur_ide[ide_board]]; uint16_t temp; -#ifndef RPCEMU_IDE -/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) - { -// pclog("Failed read IDEw %04X:%08X\n",CS,pc); - return 0xFFFF; - }*/ -#endif + // return 0xFFFF; // pclog("Read IDEw %04X %04X:%04X %02X %i %i\n",ide->buffer[ide->pos >> 1],CS,pc,opcode,ins, ide->pos); //if (idedebug) pclog("Read IDEW %08X\n",PC); temp = ide->buffer[ide->pos >> 1]; - #ifdef _RPCEMU_BIG_ENDIAN - temp=(temp>>8)|(temp<<8); - #endif + ide->pos+=2; if ((ide->command == WIN_PACKETCMD) && ((ide->packetstatus == ATAPI_STATUS_REQ_SENSE) || (ide->packetstatus==8))) { @@ -1589,22 +1237,22 @@ void callbackide(int ide_board) if (IDE_DRIVE_IS_CDROM(ide)) { ide->cylinder=0xEB14; - atapi->stop(); + cdrom->stop(); } if (ide->type == IDE_NONE) { ide->cylinder=0xFFFF; - atapi->stop(); + cdrom->stop(); } if (IDE_DRIVE_IS_CDROM(ide_other)) { ide_other->cylinder=0xEB14; - atapi->stop(); + cdrom->stop(); } if (ide_other->type == IDE_NONE) { ide_other->cylinder=0xFFFF; - atapi->stop(); + cdrom->stop(); } // pclog("Reset callback\n"); return; @@ -1880,9 +1528,6 @@ void callbackide(int ide_board) case WIN_SPECIFY: /* Initialize Drive Parameters */ if (IDE_DRIVE_IS_CDROM(ide)) { -#ifndef RPCEMU_IDE - pclog("IS CDROM - ABORT\n"); -#endif goto abort_cmd; } ide->spt=ide->secount; @@ -1931,9 +1576,6 @@ void callbackide(int ide_board) case WIN_SET_MULTIPLE_MODE: if (IDE_DRIVE_IS_CDROM(ide)) { -#ifndef RPCEMU_IDE - pclog("IS CDROM - ABORT\n"); -#endif goto abort_cmd; } ide->blocksize = ide->secount; @@ -2087,170 +1729,7 @@ void ide_callback_ter() } /*ATAPI CD-ROM emulation*/ - -struct -{ - int sensekey,asc,ascq; -} atapi_sense; - -static uint8_t atapi_set_profile(uint8_t *buf, uint8_t *index, uint16_t profile) -{ - uint8_t *buf_profile = buf + 12; /* start of profiles */ - - buf_profile += ((*index) * 4); /* start of indexed profile */ - buf_profile[0] = (profile >> 8) & 0xff; - buf_profile[1] = profile & 0xff; - buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7])); - - /* each profile adds 4 bytes to the response */ - (*index)++; - buf[11] += 4; /* Additional Length */ - - return 4; -} - -static int atapi_read_structure(IDE *ide, int format, - const uint8_t *packet, uint8_t *buf) -{ - switch (format) { - case 0x0: /* Physical format information */ - { - int layer = packet[6]; - uint64_t total_sectors; - total_sectors = (uint64_t) atapi->size(); - - if (layer != 0) - return -ASC_INV_FIELD_IN_CMD_PACKET; - - total_sectors >>= 2; - if (total_sectors == 0) - return -ASC_MEDIUM_NOT_PRESENT; - - buf[4] = 1; /* DVD-ROM, part version 1 */ - buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ - buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ - buf[7] = 0; /* default densities */ - - /* FIXME: 0x30000 per spec? */ - buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ - buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ - buf[13] = (total_sectors >> 16) & 0xff; - buf[14] = (total_sectors >> 8) & 0xff; - buf[15] = total_sectors & 0xff; - - buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ - buf[17] = (total_sectors >> 16) & 0xff; - buf[18] = (total_sectors >> 8) & 0xff; - buf[19] = total_sectors & 0xff; - - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048+2)>>8)&0xff; - buf[1] = (2048+2)&0xff; - - /* 2k data + 4 byte header */ - return (2048 + 4); - } - - case 0x01: /* DVD copyright information */ - buf[4] = 0; /* no copyright data */ - buf[5] = 0; /* no region restrictions */ - - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((4+2)>>8)&0xff; - buf[1] = (4+2)&0xff; - - /* 4 byte header + 4 byte data */ - return (4 + 4); - - case 0x03: /* BCA information - invalid field for no BCA info */ - return -ASC_INV_FIELD_IN_CMD_PACKET; - - case 0x04: /* DVD disc manufacturing information */ - /* Size of buffer, not including 2 byte size field */ - buf[0] = ((2048+2)>>8)&0xff; - buf[1] = (2048+2)&0xff; - - /* 2k data + 4 byte header */ - return (2048 + 4); - - case 0xff: - /* - * This lists all the command capabilities above. Add new ones - * in order and update the length and buffer return values. - */ - - buf[4] = 0x00; /* Physical format */ - buf[5] = 0x40; /* Not writable, is readable */ - buf[6] = ((2048+4)>>8)&0xff; - buf[7] = (2048+4)&0xff; - - buf[8] = 0x01; /* Copyright info */ - buf[9] = 0x40; /* Not writable, is readable */ - buf[10] = ((4+4)>>8)&0xff; - buf[11] = (4+4)&0xff; - - buf[12] = 0x03; /* BCA info */ - buf[13] = 0x40; /* Not writable, is readable */ - buf[14] = ((188+4)>>8)&0xff; - buf[15] = (188+4)&0xff; - - buf[16] = 0x04; /* Manufacturing info */ - buf[17] = 0x40; /* Not writable, is readable */ - buf[18] = ((2048+4)>>8)&0xff; - buf[19] = (2048+4)&0xff; - - /* Size of buffer, not including 2 byte size field */ - buf[6] = ((16+2)>>8)&0xff; - buf[7] = (16+2)&0xff; - - /* data written + 4 byte header */ - return (16 + 4); - - default: /* TODO: formats beyond DVD-ROM requires */ - return -ASC_INV_FIELD_IN_CMD_PACKET; - } -} - -static uint32_t atapi_event_status(IDE *ide, uint8_t *buffer) -{ - uint8_t event_code, media_status = 0; - - if (buffer[5]) - { - media_status = MS_TRAY_OPEN; - atapi->stop(); - } - else - { - media_status = MS_MEDIA_PRESENT; - } - - event_code = MEC_NO_CHANGE; - if (media_status != MS_TRAY_OPEN) - { - if (!buffer[4]) - { - event_code = MEC_NEW_MEDIA; - atapi->load(); - } - else if (buffer[4]==2) - { - event_code = MEC_EJECT_REQUESTED; - atapi->eject(); - } - } - - buffer[4] = event_code; - buffer[5] = media_status; - buffer[6] = 0; - buffer[7] = 0; - - return 8; -} - -static int changed_status = 0; - -void atapi_cmd_error(IDE *ide, uint8_t sensekey, uint8_t asc) +void atapi_cmd_error(IDE *ide, uint8_t sensekey, uint8_t asc, uint8_t ascq) { ide->error = (sensekey << 4); ide->atastat = READY_STAT | ERR_STAT; @@ -2262,13 +1741,6 @@ void atapi_cmd_error(IDE *ide, uint8_t sensekey, uint8_t asc) uint8_t atapi_prev; int toctimes=0; -void atapi_insert_cdrom() -{ - atapi_sense.sensekey=SENSE_UNIT_ATTENTION; - atapi_sense.asc=ASC_MEDIUM_MAY_HAVE_CHANGED; - atapi_sense.ascq=0; -} - void atapi_command_send_init(IDE *ide, uint8_t command, int req_length, int alloc_length) { if (ide->cylinder == 0xffff) @@ -2312,29 +1784,26 @@ static void atapi_command_ready(int ide_board, int packlen) static void atapi_sense_clear(int command, int ignore_ua) { - if ((atapi_sense.sensekey == SENSE_UNIT_ATTENTION) || ignore_ua) + if ((SCSISense.SenseKey == SENSE_UNIT_ATTENTION) || ignore_ua) { atapi_prev=command; - atapi_sense.sensekey=0; - atapi_sense.asc=0; - atapi_sense.ascq=0; + SCSISense.SenseKey=0; + SCSISense.Asc=0; + SCSISense.Ascq=0; } } -int cd_status = CD_STATUS_EMPTY; -int prev_status; - static void atapicommand(int ide_board) { - IDE *ide = &ide_drives[cur_ide[ide_board]]; - uint8_t *idebufferb = (uint8_t *) ide->buffer; + IDE *ide = &ide_drives[cur_ide[ide_board]]; + uint8_t *idebufferb = (uint8_t *) ide->buffer; uint8_t rcdmode = 0; - int c; - int len; - int msf; - int pos=0; - unsigned char temp; - uint32_t size; + int c; + int len; + int msf; + int pos=0; + unsigned char temp; + uint32_t size; int is_error; uint8_t page_code; int max_len; @@ -2350,32 +1819,36 @@ static void atapicommand(int ide_board) int format; int ret; -#ifndef RPCEMU_IDE - // pclog("New ATAPI command %02X %i\n",idebufferb[0],ins); +#if 0 + pclog("ATAPI command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, %i\n",idebufferb[0],SCSISense.SenseKey,SCSISense.Asc,SCSISense.Ascq,ins); + + int CdbLength; + for (CdbLength = 1; CdbLength < 12; CdbLength++) + pclog("ATAPI CDB[%d] = 0x%02X\n", CdbLength, idebufferb[CdbLength]); #endif -// readflash=1; - msf=idebufferb[1]&2; - ide->cdlen=0; + + msf=idebufferb[1]&2; + ide->cdlen=0; is_error = 0; - if (atapi->medium_changed()) + if (cdrom->medium_changed()) { - atapi_insert_cdrom(); + SCSICDROM_Insert(); } /*If UNIT_ATTENTION is set, error out with NOT_READY. VIDE-CDD.SYS will then issue a READ_TOC, which can pass through UNIT_ATTENTION and will clear sense. NT 3.1 / AZTIDECD.SYS will then issue a REQUEST_SENSE, which can also pass through UNIT_ATTENTION but will clear sense AFTER sending it back. In any case, if the command cannot pass through, set our state to errored.*/ - if (!(atapi_cmd_table[idebufferb[0]] & ALLOW_UA) && atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + if (!(SCSICommandTable[idebufferb[0]] & ALLOW_UA) && SCSISense.SenseKey == SENSE_UNIT_ATTENTION) { - atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + atapi_cmd_error(ide, SCSISense.SenseKey, SCSISense.Asc, SCSISense.Ascq); is_error = 1; } /*Unless the command issued was a REQUEST_SENSE or TEST_UNIT_READY, clear sense. This is important because both VIDE-CDD.SYS and NT 3.1 / AZTIDECD.SYS rely on this behaving VERY specifically. VIDE-CDD.SYS will clear sense through READ_TOC, while NT 3.1 / AZTIDECD.SYS will issue a REQUEST_SENSE.*/ - if ((idebufferb[0]!=GPCMD_REQUEST_SENSE) && (idebufferb[0]!=GPCMD_TEST_UNIT_READY)) + if ((idebufferb[0]!=GPCMD_REQUEST_SENSE) && (idebufferb[0]!=GPCMD_TEST_UNIT_READY)) { /* GPCMD_TEST_UNIT_READY is NOT supposed to clear sense! */ atapi_sense_clear(idebufferb[0], 1); @@ -2388,17 +1861,17 @@ static void atapicommand(int ide_board) return; } - if ((atapi_cmd_table[idebufferb[0]] & CHECK_READY) && !atapi->ready()) + if ((SCSICommandTable[idebufferb[0]] & CHECK_READY) && !cdrom->ready()) { - atapi_cmd_error(ide, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); - atapi_sense.sensekey = SENSE_NOT_READY; - atapi_sense.asc = ASC_MEDIUM_NOT_PRESENT; - atapi_sense.ascq = 0; + atapi_cmd_error(ide, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); + SCSISense.SenseKey = SENSE_NOT_READY; + SCSISense.Asc = ASC_MEDIUM_NOT_PRESENT; + SCSISense.Ascq = 0; return; } prev_status = cd_status; - cd_status = atapi->status(); + cd_status = cdrom->status(); if (((prev_status == CD_STATUS_PLAYING) || (prev_status == CD_STATUS_PAUSED)) && ((cd_status != CD_STATUS_PLAYING) && (cd_status != CD_STATUS_PAUSED))) { completed = 1; @@ -2408,8 +1881,8 @@ static void atapicommand(int ide_board) completed = 0; } - switch (idebufferb[0]) - { + switch (idebufferb[0]) + { case GPCMD_TEST_UNIT_READY: ide->packetstatus = ATAPI_STATUS_COMPLETE; idecallback[ide_board]=50*IDE_TIME; @@ -2425,7 +1898,7 @@ static void atapicommand(int ide_board) idebufferb[0]=0x80|0x70; - if ((atapi_sense.sensekey > 0) || (cd_status < CD_STATUS_PLAYING)) + if ((SCSISense.SenseKey > 0) || (cd_status < CD_STATUS_PLAYING)) { if (completed) { @@ -2435,9 +1908,9 @@ static void atapicommand(int ide_board) } else { - idebufferb[2]=atapi_sense.sensekey; - idebufferb[12]=atapi_sense.asc; - idebufferb[13]=atapi_sense.ascq; + idebufferb[2]=SCSISense.SenseKey; + idebufferb[12]=SCSISense.Asc; + idebufferb[13]=SCSISense.Ascq; } } else @@ -2461,7 +1934,7 @@ static void atapicommand(int ide_board) idecallback[ide_board]=50*IDE_TIME; break; - case GPCMD_MECHANISM_STATUS: /*0xbd*/ + case GPCMD_MECHANISM_STATUS: len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; if (len == 0) @@ -2495,24 +1968,24 @@ static void atapicommand(int ide_board) case 0: /*Normal*/ // pclog("ATAPI: READ TOC type requested: Normal\n"); len=idebufferb[8]+(idebufferb[7]<<8); - len=atapi->readtoc(idebufferb,idebufferb[6],msf,len,0); + len=cdrom->readtoc(idebufferb,idebufferb[6],msf,len,0); break; case 1: /*Multi session*/ // pclog("ATAPI: READ TOC type requested: Multi-session\n"); len=idebufferb[8]+(idebufferb[7]<<8); - len=atapi->readtoc_session(idebufferb,msf,len); + len=cdrom->readtoc_session(idebufferb,msf,len); idebufferb[0]=0; idebufferb[1]=0xA; break; case 2: /*Raw*/ // pclog("ATAPI: READ TOC type requested: Raw TOC\n"); len=idebufferb[8]+(idebufferb[7]<<8); - len=atapi->readtoc_raw(idebufferb,len); + len=cdrom->readtoc_raw(idebufferb,len); break; default: // pclog("ATAPI: Unknown READ TOC type requested: %i\n", (idebufferb[9]>>6)); ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) ide->error |= MCR_ERR; ide->packetstatus = ATAPI_STATUS_ERROR; idecallback[ide_board]=50*IDE_TIME; @@ -2540,9 +2013,9 @@ static void atapicommand(int ide_board) { ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) ide->error |= MCR_ERR; - atapi_sense.asc = ASC_ILLEGAL_OPCODE; + SCSISense.Asc = ASC_ILLEGAL_OPCODE; ide->packetstatus = ATAPI_STATUS_ERROR; idecallback[ide_board]=50*IDE_TIME; break; @@ -2558,9 +2031,9 @@ static void atapicommand(int ide_board) ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; // pclog("Read at %08X %08X\n",ide.cdpos,ide.cdpos*2048); if (rcdmode == 0x10) - atapi->readsector(idebufferb,ide->cdpos); + cdrom->readsector(idebufferb,ide->cdpos); else - atapi->readsector_raw(idebufferb,ide->cdpos); + cdrom->readsector_raw(idebufferb,ide->cdpos); #ifndef RPCEMU_IDE readflash=1; #endif @@ -2608,7 +2081,7 @@ static void atapicommand(int ide_board) break; } - atapi->readsector(idebufferb,ide->cdpos); + cdrom->readsector(idebufferb,ide->cdpos); #ifndef RPCEMU_IDE readflash=1; #endif @@ -2630,11 +2103,9 @@ static void atapicommand(int ide_board) { ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) - { + if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) ide->error |= MCR_ERR; - } - atapi_sense.asc = ASC_ILLEGAL_OPCODE; + SCSISense.SenseKey = ASC_ILLEGAL_OPCODE; ide->packetstatus = ATAPI_STATUS_ERROR; idecallback[ide_board]=50*IDE_TIME; break; @@ -2660,7 +2131,7 @@ static void atapicommand(int ide_board) if (temp_command == GPCMD_MODE_SENSE_6) len=idebufferb[4]; else - len=(idebufferb[8]|(idebufferb[7]<<8)); + len=(idebufferb[8]|(idebufferb[7]<<8)); temp=idebufferb[2] & 0x3F; @@ -2672,24 +2143,24 @@ static void atapicommand(int ide_board) // ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; idecallback[ide_board]=50*IDE_TIME; - atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + atapi_cmd_error(ide, SCSISense.SenseKey, SCSISense.Asc, SCSISense.Ascq); ide->atastat = 0x53; ide->packetstatus = ATAPI_STATUS_ERROR; - atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; - atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; - atapi_sense.ascq = 0; + SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST; + SCSISense.Asc = ASC_INV_FIELD_IN_CMD_PACKET; + SCSISense.Ascq = 0; return; } if (temp_command == GPCMD_MODE_SENSE_6) { - len = ide_atapi_mode_sense(ide,4,temp); + len = SCSICDROMModeSense(idebufferb,4,temp); idebufferb[0] = len - 1; idebufferb[1]=3; /*120mm data CD-ROM*/ } else { - len = ide_atapi_mode_sense(ide,8,temp); + len = SCSICDROMModeSense(idebufferb,8,temp); idebufferb[0]=(len - 2)>>8; idebufferb[1]=(len - 2)&255; idebufferb[2]=3; /*120mm data CD-ROM*/ @@ -2701,7 +2172,7 @@ static void atapicommand(int ide_board) return; case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: + case GPCMD_MODE_SELECT_10: if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) { ide->atastat = READY_STAT; @@ -2756,9 +2227,9 @@ static void atapicommand(int ide_board) { ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) - ide->error |= MCR_ERR; - atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + SCSISense.Asc = ASC_INV_FIELD_IN_CMD_PACKET; ide->packetstatus = ATAPI_STATUS_ERROR; idecallback[ide_board]=50*IDE_TIME; return; @@ -2791,8 +2262,8 @@ static void atapicommand(int ide_board) } idebufferb[10] = 0x02 | 0x01; /* persistent and current */ alloc_length = 12; /* headers: 8 + 4 */ - alloc_length += atapi_set_profile(idebufferb, &index, MMC_PROFILE_DVD_ROM); - alloc_length += atapi_set_profile(idebufferb, &index, MMC_PROFILE_CD_ROM); + alloc_length += SCSICDROMSetProfile(idebufferb, &index, MMC_PROFILE_DVD_ROM); + alloc_length += SCSICDROMSetProfile(idebufferb, &index, MMC_PROFILE_CD_ROM); idebufferb[0] = ((alloc_length-4) >> 24) & 0xff; idebufferb[1] = ((alloc_length-4) >> 16) & 0xff; idebufferb[2] = ((alloc_length-4) >> 8) & 0xff; @@ -2804,10 +2275,9 @@ static void atapicommand(int ide_board) } break; - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: /*0x4a*/ - temp_command = idebufferb[0]; - alloc_length = len; - + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + temp_command = idebufferb[0]; + alloc_length = len; { struct { @@ -2837,12 +2307,12 @@ static void atapicommand(int ide_board) /* Only pollign is supported, asynchronous mode is not. */ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; idecallback[ide_board]=50*IDE_TIME; - atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + atapi_cmd_error(ide, SCSISense.SenseKey, SCSISense.Asc, SCSISense.Ascq); ide->atastat = 0x53; ide->packetstatus=0x80; - atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; - atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; - atapi_sense.ascq = 0; + SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST; + SCSISense.Asc = ASC_INV_FIELD_IN_CMD_PACKET; + SCSISense.Ascq = 0; return; } @@ -2873,7 +2343,7 @@ static void atapicommand(int ide_board) if (gesn_cdb->class & (1 << GESN_MEDIA)) { gesn_event_header->notification_class |= GESN_MEDIA; - used_len = atapi_event_status(ide, idebufferb); + used_len = SCSICDROMEventStatus(idebufferb); } else { @@ -2930,20 +2400,20 @@ static void atapicommand(int ide_board) if ((cdrom_drive < 1) || (cdrom_drive == CDROM_ISO) || (cd_status <= CD_STATUS_DATA_ONLY) || - !atapi->is_track_audio(pos, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0)) + !cdrom->is_track_audio(pos, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0)) { ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; - atapi_sense.asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; - atapi_sense.ascq = 0; + SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST; + SCSISense.Asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; + SCSISense.Ascq = 0; ide->packetstatus = ATAPI_STATUS_ERROR; idecallback[ide_board]=50*IDE_TIME; - atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + atapi_cmd_error(ide, SCSISense.SenseKey, SCSISense.Asc, SCSISense.Ascq); break; } - atapi->playaudio(pos, len, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0); + cdrom->playaudio(pos, len, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0); ide->packetstatus = ATAPI_STATUS_COMPLETE; idecallback[ide_board]=50*IDE_TIME; break; @@ -2955,10 +2425,9 @@ static void atapicommand(int ide_board) // pclog("Read subchannel check condition %02X\n",idebufferb[3]); ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) ide->error |= MCR_ERR; - // ide->discchanged=1; /* Fixes some bugs with NT 3.1. */ - atapi_sense.asc = ASC_ILLEGAL_OPCODE; + SCSISense.Asc = ASC_ILLEGAL_OPCODE; ide->packetstatus = ATAPI_STATUS_ERROR; idecallback[ide_board]=50*IDE_TIME; break; @@ -2974,9 +2443,9 @@ static void atapicommand(int ide_board) idebufferb[pos++]=0; /*Audio status*/ idebufferb[pos++]=0; idebufferb[pos++]=0; /*Subchannel length*/ idebufferb[pos++]=1; /*Format code*/ - idebufferb[1]=atapi->getcurrentsubchannel(&idebufferb[5],msf); + idebufferb[1]=cdrom->getcurrentsubchannel(&idebufferb[5],msf); // pclog("Read subchannel complete - audio status %02X\n",idebufferb[1]); - len=11+5; + len=16; if (!temp) len=4; ide->packetstatus = ATAPI_STATUS_DATA; ide->cylinder=len; @@ -2998,16 +2467,16 @@ static void atapicommand(int ide_board) if (len <= CD_MAX_SECTORS) { ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - atapi_sense.asc = ASC_INCOMPATIBLE_FORMAT; + SCSISense.Asc = ASC_INCOMPATIBLE_FORMAT; ide->packetstatus = ATAPI_STATUS_ERROR; idecallback[ide_board]=50*IDE_TIME; break; } else { ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) ide->error |= MCR_ERR; - atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + SCSISense.Asc = ASC_INV_FIELD_IN_CMD_PACKET; ide->packetstatus = ATAPI_STATUS_ERROR; idecallback[ide_board]=50*IDE_TIME; return; @@ -3021,10 +2490,10 @@ static void atapicommand(int ide_board) case 0x00 ... 0x7f: case 0xff: if (media == 0) { - ret = atapi_read_structure(ide, format, idebufferb, idebufferb); + ret = SCSICDROMReadDVDStructure(format, idebufferb, idebufferb); if (ret < 0) - atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, -ret); + atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, -ret, 0); else { atapi_command_send_init(ide, temp_command, len, alloc_length); @@ -3044,9 +2513,9 @@ static void atapicommand(int ide_board) default: ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) ide->error |= MCR_ERR; - atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + SCSISense.Asc = ASC_INV_FIELD_IN_CMD_PACKET; ide->packetstatus = ATAPI_STATUS_ERROR; idecallback[ide_board]=50*IDE_TIME; return; @@ -3058,9 +2527,9 @@ static void atapicommand(int ide_board) { ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) ide->error |= MCR_ERR; - atapi_sense.asc = ASC_ILLEGAL_OPCODE; + SCSISense.Asc = ASC_ILLEGAL_OPCODE; ide->packetstatus = ATAPI_STATUS_ERROR; idecallback[ide_board]=50*IDE_TIME; break; @@ -3070,9 +2539,9 @@ static void atapicommand(int ide_board) pclog("%02X\n",idebufferb[c]); exit(-1);*/ } - if (!idebufferb[4]) atapi->stop(); - else if (idebufferb[4]==2) atapi->eject(); - else atapi->load(); + if (!idebufferb[4]) cdrom->stop(); + else if (idebufferb[4]==2) cdrom->eject(); + else cdrom->load(); ide->packetstatus = ATAPI_STATUS_COMPLETE; idecallback[ide_board]=50*IDE_TIME; break; @@ -3103,9 +2572,9 @@ static void atapicommand(int ide_board) case 0x83: if (idx + 24 > max_len) { - atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_DATA_PHASE_ERROR); - atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; - atapi_sense.asc = ASC_DATA_PHASE_ERROR; + atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_DATA_PHASE_ERROR, 0); + SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST; + SCSISense.Asc = ASC_DATA_PHASE_ERROR; return; } idebufferb[idx++] = 0x02; @@ -3123,18 +2592,18 @@ static void atapicommand(int ide_board) idebufferb[idx++] = 0x01; idebufferb[idx++] = 0x00; idebufferb[idx++] = 68; - ide_padstr8(idebufferb + idx, 8, "PCem"); /* Vendor */ + ide_padstr8(idebufferb + idx, 8, "86Box"); /* Vendor */ idx += 8; - ide_padstr8(idebufferb + idx, 40, "PCemCD v1.0"); /* Product */ + ide_padstr8(idebufferb + idx, 40, "86BoxCD v1.0"); /* Product */ idx += 40; ide_padstr8(idebufferb + idx, 20, "53R141"); /* Product */ idx += 20; break; default: - atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); - atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; - atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0); + SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST; + SCSISense.Asc = ASC_INV_FIELD_IN_CMD_PACKET; return; } } @@ -3151,13 +2620,8 @@ static void atapicommand(int ide_board) idebufferb[5] = 0; idebufferb[6] = 0; idebufferb[7] = 0; -#ifdef RPCEMU_IDE - ide_padstr8(idebufferb + 8, 8, "RPCemu"); /* Vendor */ - ide_padstr8(idebufferb + 16, 16, "RPCemuCD"); /* Product */ -#else ide_padstr8(idebufferb + 8, 8, "86Box"); /* Vendor */ ide_padstr8(idebufferb + 16, 16, "86BoxCD"); /* Product */ -#endif ide_padstr8(idebufferb + 32, 4, emulator_version); /* Revision */ idx = 36; @@ -3178,22 +2642,22 @@ atapi_out: break; case GPCMD_PAUSE_RESUME: - if (idebufferb[8]&1) atapi->resume(); - else atapi->pause(); + if (idebufferb[8]&1) cdrom->resume(); + else cdrom->pause(); ide->packetstatus = ATAPI_STATUS_COMPLETE; idecallback[ide_board]=50*IDE_TIME; break; case GPCMD_SEEK: pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - atapi->seek(pos); + cdrom->seek(pos); ide->packetstatus = ATAPI_STATUS_COMPLETE; idecallback[ide_board]=50*IDE_TIME; break; case GPCMD_READ_CDROM_CAPACITY: atapi_command_send_init(ide, temp_command, 8, 8); - size = atapi->size(); + size = cdrom->size(); idebufferb[0] = (size >> 24) & 0xff; idebufferb[1] = (size >> 16) & 0xff; idebufferb[2] = (size >> 8) & 0xff; @@ -3210,16 +2674,16 @@ atapi_out: default: ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) ide->error |= MCR_ERR; - atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; - atapi_sense.asc = ASC_ILLEGAL_OPCODE; + SCSISense.SenseKey = SENSE_ILLEGAL_REQUEST; + SCSISense.Asc = ASC_ILLEGAL_OPCODE; ide->packetstatus = ATAPI_STATUS_ERROR; idecallback[ide_board]=50*IDE_TIME; break; case GPCMD_STOP_PLAY_SCAN: - atapi->stop(); + cdrom->stop(); ide->packetstatus = ATAPI_STATUS_COMPLETE; idecallback[ide_board]=50*IDE_TIME; break; @@ -3266,9 +2730,9 @@ static void callreadcd(IDE *ide) ide->atastat = BUSY_STAT; if (readcdmode) - atapi->readsector_raw((uint8_t *) ide->buffer, ide->cdpos); + cdrom->readsector_raw((uint8_t *) ide->buffer, ide->cdpos); else - atapi->readsector((uint8_t *) ide->buffer, ide->cdpos); + cdrom->readsector((uint8_t *) ide->buffer, ide->cdpos); #ifndef RPCEMU_IDE readflash=1; #endif diff --git a/src/ide.h b/src/ide.h index 38dd8e822..d478ab946 100644 --- a/src/ide.h +++ b/src/ide.h @@ -1,4 +1,4 @@ -/* Copyright holders: Sarah Walker, Tenshi +/* Copyright holders: Sarah Walker, Tenshi, SA1988 see COPYING for more details */ #ifndef __IDE__ @@ -22,42 +22,12 @@ extern void ide_sec_disable(); extern void ide_ter_disable(); extern void ide_set_bus_master(int (*read_sector)(int channel, uint8_t *data), int (*write_sector)(int channel, uint8_t *data), void (*set_irq)(int channel)); -/*ATAPI stuff*/ -typedef struct ATAPI -{ - int (*ready)(void); - int (*medium_changed)(void); - int (*readtoc)(uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); - int (*readtoc_session)(uint8_t *b, int msf, int maxlen); - int (*readtoc_raw)(uint8_t *b, int maxlen); - uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf); - void (*readsector)(uint8_t *b, int sector); - void (*readsector_raw)(uint8_t *b, int sector); - void (*playaudio)(uint32_t pos, uint32_t len, int ismsf); - void (*seek)(uint32_t pos); - void (*load)(void); - void (*eject)(void); - void (*pause)(void); - void (*resume)(void); - uint32_t (*size)(void); - int (*status)(void); - int (*is_track_audio)(uint32_t pos, int ismsf); - void (*stop)(void); - void (*exit)(void); -} ATAPI; - -extern ATAPI *atapi; - -void atapi_discchanged(); - -void atapi_insert_cdrom(); - extern int ideboard; extern int idecallback[3]; extern char ide_fn[4][512]; -extern int cdrom_channel; +extern int atapi_cdrom_channel; #endif //__IDE__ diff --git a/src/model.c b/src/model.c index c40ca222d..d84dd59f4 100644 --- a/src/model.c +++ b/src/model.c @@ -402,7 +402,7 @@ void at_ali1429_init() at_init(); ali1429_init(); mouse_serial_init(); - if (cdrom_channel <= 1) ide_sec_disable(); + if (atapi_cdrom_channel <= 1) ide_sec_disable(); } /* void at_um8881f_init() @@ -419,7 +419,7 @@ void at_dtk486_init() memregs_init(); mouse_serial_init(); sis85c471_init(); - if (cdrom_channel <= 1) ide_sec_disable(); + if (atapi_cdrom_channel <= 1) ide_sec_disable(); } void at_sis496_init() @@ -440,7 +440,7 @@ void at_r418_init() pci_init(PCI_CONFIG_TYPE_1, 0, 31); fdc37c665_init(); device_add(&sis496_device); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } void at_batman_init() @@ -453,7 +453,7 @@ void at_batman_init() fdc37c665_init(); intel_batman_init(); device_add(&intel_flash_bxt_ami_device); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } void at_586mc1_init() @@ -465,7 +465,7 @@ void at_586mc1_init() i430lx_init(); sio_init(1); device_add(&intel_flash_bxt_device); - if (cdrom_channel <= 1) ide_sec_disable(); + if (atapi_cdrom_channel <= 1) ide_sec_disable(); } void at_plato_init() @@ -479,7 +479,7 @@ void at_plato_init() /* It seems it uses the same interface as Batman. */ intel_batman_init(); device_add(&intel_flash_bxt_ami_device); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } void at_advanced_common_init() @@ -491,7 +491,7 @@ void at_advanced_common_init() piix_init(7); // pc87306_init(); intel_endeavor_init(); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } void at_endeavor_init() @@ -518,7 +518,7 @@ void at_mb500n_init() fdc37c665_init(); intel_endeavor_init(); device_add(&intel_flash_bxt_device); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } #if 0 @@ -533,7 +533,7 @@ void at_p54tp4xe_init() fdc37c665_init(); intel_endeavor_init(); device_add(&intel_flash_bxt_device); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } #endif @@ -548,7 +548,7 @@ void at_acerm3a_init() fdc37c932fr_init(); acerm3a_io_init(); device_add(&intel_flash_bxb_device); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } void at_acerv35n_init() @@ -562,7 +562,7 @@ void at_acerv35n_init() fdc37c932fr_init(); acerm3a_io_init(); device_add(&intel_flash_bxb_device); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } #if 0 @@ -576,7 +576,7 @@ void at_p55t2p4_init() piix3_init(7); w83877f_init(); device_add(&intel_flash_bxt_device); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } #endif @@ -590,7 +590,7 @@ void at_i430vx_init() piix3_init(7); um8669f_init(); device_add(&intel_flash_bxt_device); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } // rom_t ami_ec_rom; @@ -612,7 +612,7 @@ void at_p55tvp4_init() intel_endeavor_init(); */ - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } #endif @@ -626,7 +626,7 @@ void at_p55va_init() piix3_init(7); fdc37c932fr_init(); device_add(&intel_flash_bxt_device); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } void at_i440fx_init() @@ -639,7 +639,7 @@ void at_i440fx_init() piix3_init(7); fdc37c665_init(); device_add(&intel_flash_bxt_device); - if (cdrom_channel >= 4) ide_ter_init(); + if (atapi_cdrom_channel >= 4) ide_ter_init(); } void model_init() diff --git a/src/pc.c b/src/pc.c index 2027f6a2f..afa67a09b 100644 --- a/src/pc.c +++ b/src/pc.c @@ -24,6 +24,9 @@ #include "fdd.h" #include "gameport.h" #include "sound_gus.h" +#include "aha154x.h" +#include "cdrom.h" +#include "scsi.h" #include "ide.h" #include "keyboard.h" #include "keyboard_at.h" @@ -57,6 +60,7 @@ int window_w, window_h, window_x, window_y, window_remember; int start_in_fullscreen = 0; int frame = 0; +int scsi_cdrom_enabled, atapi_cdrom_enabled; int cdrom_enabled; int CPUID; int vid_resize, vid_api; @@ -289,6 +293,12 @@ void initpc(int argc, char *argv[]) loadnvr(); sound_init(); resetide(); + if (aha154x_enabled) + { + SCSIReset(&ScsiDrives[scsi_cdrom_id], scsi_cdrom_id); + AdaptecInit(scsi_cdrom_id); + } + if ((cdrom_drive == -1) || (cdrom_drive == 0)) cdrom_null_open(cdrom_drive); else @@ -407,7 +417,13 @@ void resetpchard() pc_reset(); resetide(); - + + if (aha154x_enabled) + { + SCSIReset(&ScsiDrives[scsi_cdrom_id], scsi_cdrom_id); + AdaptecInit(scsi_cdrom_id); + } + loadnvr(); // cpuspeed2 = (AT)?2:1; @@ -567,7 +583,7 @@ void speedchanged() void closepc() { - atapi->exit(); + cdrom->exit(); // ioctl_close(); dumppic(); // output=7; @@ -611,6 +627,7 @@ void loadconfig(char *fn) GUS = config_get_int(NULL, "gus", 0); SSI2001 = config_get_int(NULL, "ssi2001", 0); voodoo_enabled = config_get_int(NULL, "voodoo", 0); + aha154x_enabled = config_get_int(NULL, "aha154x", 0); //network ethif = config_get_int(NULL, "netinterface", 1); @@ -653,8 +670,12 @@ void loadconfig(char *fn) old_cdrom_drive = cdrom_drive; cdrom_enabled = config_get_int(NULL, "cdrom_enabled", 0); - cdrom_channel = config_get_int(NULL, "cdrom_channel", 2); + atapi_cdrom_enabled = config_get_int(NULL, "atapi_cdrom_enabled", 1); + atapi_cdrom_channel = config_get_int(NULL, "atapi_cdrom_channel", 2); + scsi_cdrom_enabled = config_get_int(NULL, "scsi_cdrom_enabled", 0); + scsi_cdrom_id = config_get_int(NULL, "scsi_cdrom_id", 3); + p = (char *)config_get_string(NULL, "cdrom_path", ""); if (p) strcpy(iso_path, p); else strcpy(iso_path, ""); @@ -769,6 +790,7 @@ void saveconfig() config_set_int(NULL, "gus", GUS); config_set_int(NULL, "ssi2001", SSI2001); config_set_int(NULL, "voodoo", voodoo_enabled); + config_set_int(NULL, "aha154x", aha154x_enabled); config_set_int(NULL, "netinterface", ethif); config_set_int(NULL, "netcard", network_card_current); @@ -793,7 +815,13 @@ void saveconfig() config_set_int(NULL, "mem_size", mem_size); config_set_int(NULL, "cdrom_drive", cdrom_drive); config_set_int(NULL, "cdrom_enabled", cdrom_enabled); - config_set_int(NULL, "cdrom_channel", cdrom_channel); + + config_set_int(NULL, "atapi_cdrom_enabled", atapi_cdrom_enabled); + config_set_int(NULL, "atapi_cdrom_channel", atapi_cdrom_channel); + + config_set_int(NULL, "scsi_cdrom_enabled", scsi_cdrom_enabled); + config_set_int(NULL, "scsi_cdrom_id", scsi_cdrom_id); + config_set_string(NULL, "cdrom_path", iso_path); config_set_int(NULL, "vid_resize", vid_resize); config_set_int(NULL, "vid_api", vid_api); diff --git a/src/resources.h b/src/resources.h index 0f66fa0df..f852af7e2 100644 --- a/src/resources.h +++ b/src/resources.h @@ -54,6 +54,7 @@ #define IDC_CHECKSSI 1015 #define IDC_CHECKVOODOO 1016 #define IDC_CHECKDYNAREC 1017 +#define IDC_CHECK_AHA154X 1018 #define IDC_STATIC 1020 #define IDC_CHECKFORCE43 1021 #define IDC_CHECKOVERSCAN 1022 diff --git a/src/scattergather.c b/src/scattergather.c new file mode 100644 index 000000000..a14fcaa29 --- /dev/null +++ b/src/scattergather.c @@ -0,0 +1,128 @@ +/* Copyright holders: SA1988 + see COPYING for more details +*/ +/*Scatter/Gather emulation*/ +#include +#include +#include "ibm.h" + +#include "scattergather.h" + +static uint8_t *SegmentBufferGet(SGBUF *SegmentBuf, uint32_t Data) +{ + uint32_t DataSize; + uint8_t *Buffer; + + if (SegmentBuf->SegmentIndex == SegmentBuf->SegmentNum + && !SegmentBuf->SegmentLeft) + { + Data = 0; + return NULL; + } + + DataSize = MIN(Data, SegmentBuf->SegmentLeft); + Buffer = SegmentBuf->SegmentPtrCur; + SegmentBuf->SegmentLeft -= Data; + + if (!SegmentBuf->SegmentLeft) + { + SegmentBuf->SegmentIndex++; + + if (SegmentBuf->SegmentIndex < SegmentBuf->SegmentNum) + { + SegmentBuf->SegmentPtrCur = SegmentBuf->SegmentPtr[SegmentBuf->SegmentIndex].Address; + SegmentBuf->SegmentLeft = SegmentBuf->SegmentPtr[SegmentBuf->SegmentIndex].Length; + } + + Data = DataSize; + } + else + SegmentBuf->SegmentPtrCur = (uint8_t *)SegmentBuf->SegmentPtrCur + DataSize; + + return Buffer; +} + +uint8_t *SegmentBufferGetNextSegment(SGBUF *SegmentBuf, uint32_t Segment) +{ + if (!Segment) + Segment = SegmentBuf->SegmentLeft; + + return SegmentBufferGet(SegmentBuf, Segment); +} + +uint32_t SegmentBufferCopy(SGBUF *SegmentDst, SGBUF *SegmentSrc, uint32_t Copy) +{ + uint32_t Left = Copy; + while (Left) + { + uint32_t ThisCopy = MIN(MIN(SegmentDst->SegmentLeft, Left), SegmentSrc->SegmentLeft); + if (!ThisCopy) + break; + + uint32_t Tmp = ThisCopy; + uint8_t *BufDst = SegmentBufferGet(SegmentDst, Tmp); + uint8_t *BufSrc = SegmentBufferGet(SegmentSrc, Tmp); + + memcpy(BufSrc, BufDst, ThisCopy); + + BufDst += ThisCopy; + BufSrc -= ThisCopy; + Left -= ThisCopy; + } + + return Copy - Left; +} + +uint32_t SegmentBufferCopyFromBuf(SGBUF *SegmentBuf, uint8_t *BufSrc, uint32_t Copy) +{ + uint32_t Left = Copy; + + while (Left) + { + uint32_t ThisCopy = Left; + uint8_t *BufDst = SegmentBufferGet(SegmentBuf, ThisCopy); + + if (!ThisCopy) + break; + + BufDst += ThisCopy; + Left -= ThisCopy; + BufSrc = (void *)((uintptr_t)BufSrc + ThisCopy); + } + + return Copy - Left; +} + +uint32_t SegmentBufferAdvance(SGBUF *SegmentBuf, uint32_t Advance) +{ + uint32_t Left = Advance; + while (Left) + { + uint32_t ThisAdvance = Left; + SegmentBufferGet(SegmentBuf, ThisAdvance); + if (!ThisAdvance) + break; + + Left -= ThisAdvance; + } + + return Advance - Left; +} + +void SegmentBufferInit(SGBUF *SegmentBuf, const SGSEG *SegmentPtr, uint32_t Segments) +{ + SegmentBuf->SegmentPtr = SegmentPtr; + SegmentBuf->SegmentNum = (unsigned)Segments; + SegmentBuf->SegmentIndex = 0; + + if (Segments && SegmentPtr) + { + SegmentBuf->SegmentPtrCur = SegmentPtr[0].Address; + SegmentBuf->SegmentLeft = SegmentPtr[0].Length; + } + else + { + SegmentBuf->SegmentPtrCur = NULL; + SegmentBuf->SegmentLeft = 0; + } +} \ No newline at end of file diff --git a/src/scattergather.h b/src/scattergather.h new file mode 100644 index 000000000..4c8b98b42 --- /dev/null +++ b/src/scattergather.h @@ -0,0 +1,24 @@ +#ifndef _SCATTERGATHER_H_ +#define _SCATTERGATHER_H_ + +typedef struct SGSEG +{ + uint8_t Address[128*512]; + uint32_t Length; +} SGSEG; + +typedef struct SGBUF +{ + const SGSEG *SegmentPtr; + unsigned SegmentNum; + unsigned SegmentIndex; + uint8_t *SegmentPtrCur; + uint32_t SegmentLeft; +} SGBUF; + +uint32_t SegmentBufferCopy(SGBUF *SegmentDst, SGBUF *SegmentSrc, uint32_t Copy); +uint8_t *SegmentBufferGetNextSegment(SGBUF *SegmentBuf, uint32_t Segment); +uint32_t SegmentBufferAdvance(SGBUF *SegmentBuf, uint32_t Advance); +void SegmentBufferInit(SGBUF *SegmentBuf, const SGSEG *SegmentPtr, uint32_t Segments); + +#endif \ No newline at end of file diff --git a/src/scsi.c b/src/scsi.c new file mode 100644 index 000000000..be1ccef84 --- /dev/null +++ b/src/scsi.c @@ -0,0 +1,149 @@ +/* Copyright holders: SA1988 + see COPYING for more details +*/ +/*SCSI layer emulation*/ +#include +#include +#include "86box.h" +#include "ibm.h" +#include "device.h" + +#include "cdrom.h" +#include "scsi.h" + +int ScsiCallback[7] = {0,0,0,0,0,0,0}; +uint8_t scsi_cdrom_id = 3; /*common setting*/ + +uint8_t SCSIDeviceIsPresent(SCSI *Scsi) +{ + return (scsi_cdrom_id < 7 && Scsi->LunType != SCSI_NONE); +} + +void SCSINoTransfer(SCSI *Scsi, uint8_t Id) +{ + pclog("SCSI: No Transfer\n"); + SGBUF SegmentBuffer; + SegmentBufferInit(&SegmentBuffer, &Scsi->SegmentData, 1); + pfnIoRequestCopyFromBuffer(0, &SegmentBuffer, Scsi->SegmentData.Length); +} + +void SCSIReadTransfer(SCSI *Scsi, uint8_t Id) +{ + if (Scsi->LunType == SCSI_CDROM) + { + SCSICDROM_CallRead(Scsi, Id); + } + + pclog("SCSI: Read Transfer\n"); + SGBUF SegmentBuffer; + SegmentBufferInit(&SegmentBuffer, &Scsi->SegmentData, 1); + pfnIoRequestCopyFromBuffer(0, &SegmentBuffer, Scsi->SegmentData.Length); +} + +void SCSIWriteTransfer(SCSI *Scsi, uint8_t Id) +{ + if (Scsi->LunType == SCSI_CDROM) + { + if ((Scsi->CdbLength >= prefix_len + 4) && (page_flags[page_current] & PAGE_CHANGEABLE)) + { + mode_pages_in[page_current][Scsi->CdbLength - prefix_len - 4] = Scsi->Cdb[Scsi->CdbLength - 2]; + mode_pages_in[page_current][Scsi->CdbLength - prefix_len - 3] = Scsi->Cdb[Scsi->CdbLength - 1]; + } + } + + pclog("SCSI: Write Transfer\n"); + + SGBUF SegmentBuffer; + SegmentBufferInit(&SegmentBuffer, &Scsi->SegmentData, 1); + pfnIoRequestCopyToBuffer(0, &SegmentBuffer, Scsi->SegmentData.Length); +} + +void SCSIQueryResidual(SCSI *Scsi, uint32_t *Residual) +{ + *Residual = ScsiStatus == SCSI_STATUS_OK ? 0 : Scsi->SegmentData.Length; +} + +static uint32_t SCSICopyFromBuffer(uint32_t OffDst, SGBUF *SegmentBuffer, + uint32_t Copy) +{ + const SGSEG *SegmentArray = SegmentBuffer->SegmentPtr; + unsigned SegmentNum = SegmentBuffer->SegmentNum; + uint32_t Copied = 0; + + SGBUF SegmentBuffer2; + SegmentBufferInit(&SegmentBuffer2, SegmentArray, SegmentNum); + + SegmentBufferAdvance(&SegmentBuffer2, OffDst); + Copied = SegmentBufferCopy(&SegmentBuffer2, SegmentBuffer, Copy); + + return Copied; +} + +static uint32_t SCSICopyToBuffer(uint32_t OffSrc, SGBUF *SegmentBuffer, + uint32_t Copy) +{ + const SGSEG *SegmentArray = SegmentBuffer->SegmentPtr; + unsigned SegmentNum = SegmentBuffer->SegmentNum; + uint32_t Copied = 0; + + SGBUF SegmentBuffer2; + SegmentBufferInit(&SegmentBuffer2, SegmentArray, SegmentNum); + + SegmentBufferAdvance(&SegmentBuffer2, OffSrc); + Copied = SegmentBufferCopy(&SegmentBuffer2, SegmentBuffer, Copy); + + return Copied; +} + +void SCSISendCommand(SCSI *Scsi, uint8_t Id, uint8_t *Cdb, uint8_t CdbLength, + uint32_t BufferLength, uint8_t *SenseBufferPointer, + uint8_t SenseBufferLength) +{ + uint32_t i; + for (i = 0; i < CdbLength; i++) + pclog("Cdb[%d]=%02X\n", i, Cdb[i]); + + Scsi->SegmentData.Length = BufferLength; + Scsi->CdbLength = CdbLength; + + if (SCSIDeviceIsPresent(Scsi)) + { + if (Scsi->LunType == SCSI_CDROM) + { + pclog("SCSI CD-ROM in ID %d\n", Id); + SCSICDROM_RunCommand(Scsi, Id, Cdb); + } + } + else + { + pclog("SCSI Device not present\n"); + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, 0x00, 0x00); + } +} + +void SCSIReset(SCSI *Scsi, uint8_t Id) +{ + page_flags[GPMODE_CDROM_AUDIO_PAGE] &= 0xFD; /* Clear changed flag for CDROM AUDIO mode page. */ + memset(mode_pages_in[GPMODE_CDROM_AUDIO_PAGE], 0, 256); /* Clear the page itself. */ + + ScsiCallback[Id] = 0; + + if (scsi_cdrom_enabled) + { + if (cdrom_enabled) + { + Scsi->LunType = SCSI_CDROM; + } + } + else + { + Scsi->LunType = SCSI_NONE; + } + + + pfnIoRequestCopyFromBuffer = SCSICopyFromBuffer; + pfnIoRequestCopyToBuffer = SCSICopyToBuffer; + + page_flags[GPMODE_CDROM_AUDIO_PAGE] &= ~PAGE_CHANGED; +} \ No newline at end of file diff --git a/src/scsi.h b/src/scsi.h new file mode 100644 index 000000000..3b3c6471c --- /dev/null +++ b/src/scsi.h @@ -0,0 +1,220 @@ +/* Copyright holders: SA1988 + see COPYING for more details +*/ +#ifndef __SCSI_H__ +#define __SCSI_H__ + +#include "scattergather.h" + +/* SCSI Commands */ +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_READ_6 0x08 +#define GPCMD_INQUIRY 0x12 +#define GPCMD_MODE_SELECT_6 0x15 +#define GPCMD_MODE_SENSE_6 0x1a +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_PREVENT_REMOVAL 0x1e +#define GPCMD_READ_CDROM_CAPACITY 0x25 +#define GPCMD_READ_10 0x28 +#define GPCMD_SEEK 0x2b +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_READ_DISC_INFORMATION 0x51 +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PLAY_AUDIO_12 0xa5 +#define GPCMD_READ_12 0xa8 +#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ +#define GPCMD_SET_SPEED 0xbb +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_READ_CD 0xbe +#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_CDROM_AUDIO_PAGE 0x0e +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f + +/* SCSI Status Codes */ +#define SCSI_STATUS_OK 0 +#define SCSI_STATUS_CHECK_CONDITION 2 + +/* SCSI Sense Keys */ +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +/* SCSI Additional Sense Codes */ +#define ASC_AUDIO_PLAY_OPERATION 0x00 +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_INCOMPATIBLE_FORMAT 0x30 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_DATA_PHASE_ERROR 0x4b +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 + +#define ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS 0x11 +#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12 +#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13 + +/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw). + Not that it means anything */ +#define CDROM_SPEED 706 + +/* Some generally useful CD-ROM information */ +#define CD_MINS 75 /* max. minutes per CD */ +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) +#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) + +/* Event notification classes for GET EVENT STATUS NOTIFICATION */ +#define GESN_NO_EVENTS 0 +#define GESN_OPERATIONAL_CHANGE 1 +#define GESN_POWER_MANAGEMENT 2 +#define GESN_EXTERNAL_REQUEST 3 +#define GESN_MEDIA 4 +#define GESN_MULTIPLE_HOSTS 5 +#define GESN_DEVICE_BUSY 6 + +/* Event codes for MEDIA event status notification */ +#define MEC_NO_CHANGE 0 +#define MEC_EJECT_REQUESTED 1 +#define MEC_NEW_MEDIA 2 +#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ +#define MEC_MEDIA_CHANGED 4 /* only for media changers */ +#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ +#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ +#define MS_TRAY_OPEN 1 +#define MS_MEDIA_PRESENT 2 + +/* + * The MMC values are not IDE specific and might need to be moved + * to a common header if they are also needed for the SCSI emulation + */ + +/* Profile list from MMC-6 revision 1 table 91 */ +#define MMC_PROFILE_NONE 0x0000 +#define MMC_PROFILE_CD_ROM 0x0008 +#define MMC_PROFILE_CD_R 0x0009 +#define MMC_PROFILE_CD_RW 0x000A +#define MMC_PROFILE_DVD_ROM 0x0010 +#define MMC_PROFILE_DVD_R_SR 0x0011 +#define MMC_PROFILE_DVD_RAM 0x0012 +#define MMC_PROFILE_DVD_RW_RO 0x0013 +#define MMC_PROFILE_DVD_RW_SR 0x0014 +#define MMC_PROFILE_DVD_R_DL_SR 0x0015 +#define MMC_PROFILE_DVD_R_DL_JR 0x0016 +#define MMC_PROFILE_DVD_RW_DL 0x0017 +#define MMC_PROFILE_DVD_DDR 0x0018 +#define MMC_PROFILE_DVD_PLUS_RW 0x001A +#define MMC_PROFILE_DVD_PLUS_R 0x001B +#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A +#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B +#define MMC_PROFILE_BD_ROM 0x0040 +#define MMC_PROFILE_BD_R_SRM 0x0041 +#define MMC_PROFILE_BD_R_RRM 0x0042 +#define MMC_PROFILE_BD_RE 0x0043 +#define MMC_PROFILE_HDDVD_ROM 0x0050 +#define MMC_PROFILE_HDDVD_R 0x0051 +#define MMC_PROFILE_HDDVD_RAM 0x0052 +#define MMC_PROFILE_HDDVD_RW 0x0053 +#define MMC_PROFILE_HDDVD_R_DL 0x0058 +#define MMC_PROFILE_HDDVD_RW_DL 0x005A +#define MMC_PROFILE_INVALID 0xFFFF + +#define NONDATA 4 +#define CHECK_READY 2 +#define ALLOW_UA 1 + +extern uint8_t SCSICommandTable[0x100]; + +#define IMPLEMENTED 1 + +extern uint8_t mode_sense_pages[0x40]; + +extern int readcdmode; + +/* Mode sense/select stuff. */ +extern uint8_t mode_pages_in[256][256]; +#define PAGE_CHANGEABLE 1 +#define PAGE_CHANGED 2 + +extern uint8_t page_flags[256]; +extern uint8_t prefix_len; +extern uint8_t page_current; + +uint32_t DataLength; +uint32_t DataPointer; + +extern uint8_t ScsiStatus; +extern int ScsiCallback[7]; +extern uint8_t scsi_cdrom_id; + +struct +{ + uint8_t SenseKey; + uint8_t Asc; + uint8_t Ascq; +} SCSISense; + +extern int cd_status; +extern int prev_status; + +#define SCSI_NONE 0 +#define SCSI_HDD 1 /*not present yet*/ +#define SCSI_CDROM 2 + +typedef struct SCSI +{ + uint8_t Cdb[32]; + uint8_t CdbLength; + SGBUF SegmentBuffer; + int SectorLen; + int SectorLba; + int BufferPosition; + SGSEG SegmentData; + int LunType; + void *p; +} SCSI; + +SCSI ScsiDrives[7]; + +void SCSIQueryResidual(SCSI *Scsi, uint32_t *Residual); + +void SCSISendCommand(SCSI *Scsi, uint8_t Id, uint8_t *Cdb, uint8_t CdbLength, + uint32_t BufferLength, uint8_t *SenseBufferPointer, + uint8_t SenseBufferLength); + +uint32_t (*pfnIoRequestCopyFromBuffer)(uint32_t OffDst, SGBUF *SegmentBuffer, + uint32_t Copy); +uint32_t (*pfnIoRequestCopyToBuffer)(uint32_t OffSrc, SGBUF *SegmentBuffer, + uint32_t Copy); + +void SCSINoTransfer(SCSI *Scsi, uint8_t Id); +void SCSIReadTransfer(SCSI *Scsi, uint8_t Id); +void SCSIWriteTransfer(SCSI *Scsi, uint8_t Id); + +extern void SCSIReset(SCSI *Scsi, uint8_t Id); + +extern uint32_t SCSICDROMModeSense(uint8_t *buf, uint32_t pos, uint8_t type); +extern uint8_t SCSICDROMSetProfile(uint8_t *buf, uint8_t *index, uint16_t profile); +extern int SCSICDROMReadDVDStructure(int format, const uint8_t *packet, uint8_t *buf); +extern uint32_t SCSICDROMEventStatus(uint8_t *buffer); + +extern void SCSICDROM_Insert(); + +#endif \ No newline at end of file diff --git a/src/scsi_cdrom.c b/src/scsi_cdrom.c new file mode 100644 index 000000000..3ba7b20d5 --- /dev/null +++ b/src/scsi_cdrom.c @@ -0,0 +1,1215 @@ +/* Copyright holders: SA1988 + see COPYING for more details +*/ +/*SCSI CD-ROM emulation*/ +#include +#include +#include "86box.h" +#include "ibm.h" + +#include "cdrom.h" +#include "scsi.h" + +#include "timer.h" + +#define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT)) + +uint8_t ScsiStatus = SCSI_STATUS_OK; + +/* Table of all ATAPI commands and their flags, needed for the new disc change / not ready handler. */ +uint8_t SCSICommandTable[0x100] = +{ + [GPCMD_TEST_UNIT_READY] = CHECK_READY | NONDATA, + [GPCMD_REQUEST_SENSE] = ALLOW_UA, + [GPCMD_READ_6] = CHECK_READY, + [GPCMD_INQUIRY] = ALLOW_UA, + [GPCMD_MODE_SELECT_6] = 0, + [GPCMD_MODE_SENSE_6] = 0, + [GPCMD_START_STOP_UNIT] = 0, + [GPCMD_PREVENT_REMOVAL] = CHECK_READY, + [GPCMD_READ_CDROM_CAPACITY] = CHECK_READY, + [GPCMD_READ_10] = CHECK_READY, + [GPCMD_SEEK] = CHECK_READY | NONDATA, + [GPCMD_READ_SUBCHANNEL] = CHECK_READY, + [GPCMD_READ_TOC_PMA_ATIP] = CHECK_READY | ALLOW_UA, /* Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS */ + [GPCMD_READ_HEADER] = CHECK_READY, + [GPCMD_PLAY_AUDIO_10] = CHECK_READY, + [GPCMD_GET_CONFIGURATION] = ALLOW_UA, + [GPCMD_PLAY_AUDIO_MSF] = CHECK_READY, + [GPCMD_GET_EVENT_STATUS_NOTIFICATION] = ALLOW_UA, + [GPCMD_PAUSE_RESUME] = CHECK_READY, + [GPCMD_STOP_PLAY_SCAN] = CHECK_READY, + [GPCMD_READ_DISC_INFORMATION] = CHECK_READY, + [GPCMD_MODE_SELECT_10] = 0, + [GPCMD_MODE_SENSE_10] = 0, + [GPCMD_PLAY_AUDIO_12] = CHECK_READY, + [GPCMD_READ_12] = CHECK_READY, + [GPCMD_READ_DVD_STRUCTURE] = CHECK_READY, + [GPCMD_SET_SPEED] = 0, + [GPCMD_MECHANISM_STATUS] = 0, + [GPCMD_READ_CD] = CHECK_READY, + [GPCMD_SEND_DVD_STRUCTURE] = CHECK_READY +}; + +uint8_t mode_sense_pages[0x40] = +{ + [GPMODE_R_W_ERROR_PAGE] = IMPLEMENTED, + [GPMODE_CDROM_PAGE] = IMPLEMENTED, + [GPMODE_CDROM_AUDIO_PAGE] = IMPLEMENTED, + [GPMODE_CAPABILITIES_PAGE] = IMPLEMENTED, + [GPMODE_ALL_PAGES] = IMPLEMENTED +}; + +uint8_t page_flags[256] = +{ + [GPMODE_R_W_ERROR_PAGE] = 0, + [GPMODE_CDROM_PAGE] = 0, + [GPMODE_CDROM_AUDIO_PAGE] = PAGE_CHANGEABLE, + [GPMODE_CAPABILITIES_PAGE] = 0, +}; + +CDROM *cdrom; + +int readcdmode = 0; + +uint8_t mode_pages_in[256][256]; +uint8_t prefix_len; +uint8_t page_current; + +/*SCSI Sense Initialization*/ +void SCSISenseCodeOk(void) +{ + SCSISense.SenseKey=SENSE_NONE; + SCSISense.Asc=0; + SCSISense.Ascq=0; +} + +void SCSISenseCodeError(uint8_t SenseKey, uint8_t Asc, uint8_t Ascq) +{ + SCSISense.SenseKey=SenseKey; + SCSISense.Asc=Asc; + SCSISense.Ascq=Ascq; +} + +static void +ScsiPadStr8(uint8_t *buf, int buf_size, const char *src) +{ + int i; + + for (i = 0; i < buf_size; i++) { + if (*src != '\0') { + buf[i] = *src++; + } else { + buf[i] = ' '; + } + } +} + +uint32_t SCSIGetCDChannel(int channel) +{ + return (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 8 : 6] : (channel + 1); +} + +uint32_t SCSIGetCDVolume(int channel) +{ + // return ((page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) && (mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 8 : 6] != 0)) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 9 : 7] : 0xFF; + return (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 9 : 7] : 0xFF; +} + +/*SCSI Mode Sense 6/10*/ +uint32_t SCSICDROMModeSense(uint8_t *buf, uint32_t pos, uint8_t type) +{ + if (type==GPMODE_ALL_PAGES || type==GPMODE_R_W_ERROR_PAGE) + { + /* &01 - Read error recovery */ + buf[pos++] = GPMODE_R_W_ERROR_PAGE; + buf[pos++] = 6; /* Page length */ + buf[pos++] = 0; /* Error recovery parameters */ + buf[pos++] = 5; /* Read retry count */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_PAGE) + { + /* &0D - CD-ROM Parameters */ + buf[pos++] = GPMODE_CDROM_PAGE; + buf[pos++] = 6; /* Page length */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 1; /* Inactivity time multiplier *NEEDED BY RISCOS* value is a guess */ + buf[pos++] = 0; buf[pos++] = 60; /* MSF settings */ + buf[pos++] = 0; buf[pos++] = 75; /* MSF settings */ + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_AUDIO_PAGE) + { + /* &0e - CD-ROM Audio Control Parameters */ + buf[pos++] = GPMODE_CDROM_AUDIO_PAGE; + buf[pos++] = 0xE; /* Page length */ + if (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) + { + int i; + for (i = 0; i < 14; i++) + { + buf[pos++] = mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][i]; + } + } + else + { + buf[pos++] = 4; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; buf[pos++] = 75; /* Logical audio block per second */ + buf[pos++] = 1; /* CDDA Output Port 0 Channel Selection */ + buf[pos++] = 0xFF; /* CDDA Output Port 0 Volume */ + buf[pos++] = 2; /* CDDA Output Port 1 Channel Selection */ + buf[pos++] = 0xFF; /* CDDA Output Port 1 Volume */ + buf[pos++] = 0; /* CDDA Output Port 2 Channel Selection */ + buf[pos++] = 0; /* CDDA Output Port 2 Volume */ + buf[pos++] = 0; /* CDDA Output Port 3 Channel Selection */ + buf[pos++] = 0; /* CDDA Output Port 3 Volume */ + } + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CAPABILITIES_PAGE) + { +// pclog("Capabilities page\n"); + /* &2A - CD-ROM capabilities and mechanical status */ + buf[pos++] = GPMODE_CAPABILITIES_PAGE; + buf[pos++] = 0x12; /* Page length */ + buf[pos++] = 0; buf[pos++] = 0; /* CD-R methods */ + buf[pos++] = 1; /* Supports audio play, not multisession */ + buf[pos++] = 0; /* Some other stuff not supported */ + buf[pos++] = 0; /* Some other stuff not supported (lock state + eject) */ + buf[pos++] = 0; /* Some other stuff not supported */ + buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); + buf[pos++] = (uint8_t) CDROM_SPEED; /* Maximum speed */ + buf[pos++] = 0; buf[pos++] = 2; /* Number of audio levels - on and off only */ + buf[pos++] = 0; buf[pos++] = 0; /* Buffer size - none */ + buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); + buf[pos++] = (uint8_t) CDROM_SPEED; /* Current speed */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Drive digital format */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + } + + return pos; +} + +/*SCSI Get Configuration*/ +uint8_t SCSICDROMSetProfile(uint8_t *buf, uint8_t *index, uint16_t profile) +{ + uint8_t *buf_profile = buf + 12; /* start of profiles */ + + buf_profile += ((*index) * 4); /* start of indexed profile */ + buf_profile[0] = (profile >> 8) & 0xff; + buf_profile[1] = profile & 0xff; + buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7])); + + /* each profile adds 4 bytes to the response */ + (*index)++; + buf[11] += 4; /* Additional Length */ + + return 4; +} + +/*SCSI Read DVD Structure*/ +int SCSICDROMReadDVDStructure(int format, const uint8_t *packet, uint8_t *buf) +{ + switch (format) { + case 0x0: /* Physical format information */ + { + int layer = packet[6]; + uint64_t total_sectors; + total_sectors = (uint64_t) cdrom->size(); + + if (layer != 0) + return -ASC_INV_FIELD_IN_CMD_PACKET; + + total_sectors >>= 2; + if (total_sectors == 0) + return -ASC_MEDIUM_NOT_PRESENT; + + buf[4] = 1; /* DVD-ROM, part version 1 */ + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[7] = 0; /* default densities */ + + /* FIXME: 0x30000 per spec? */ + buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ + buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ + buf[13] = (total_sectors >> 16) & 0xff; + buf[14] = (total_sectors >> 8) & 0xff; + buf[15] = total_sectors & 0xff; + + buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ + buf[17] = (total_sectors >> 16) & 0xff; + buf[18] = (total_sectors >> 8) & 0xff; + buf[19] = total_sectors & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048+2)>>8)&0xff; + buf[1] = (2048+2)&0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + } + + case 0x01: /* DVD copyright information */ + buf[4] = 0; /* no copyright data */ + buf[5] = 0; /* no region restrictions */ + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((4+2)>>8)&0xff; + buf[1] = (4+2)&0xff; + + /* 4 byte header + 4 byte data */ + return (4 + 4); + + case 0x03: /* BCA information - invalid field for no BCA info */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + + case 0x04: /* DVD disc manufacturing information */ + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048+2)>>8)&0xff; + buf[1] = (2048+2)&0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buf[4] = 0x00; /* Physical format */ + buf[5] = 0x40; /* Not writable, is readable */ + buf[6] = ((2048+4)>>8)&0xff; + buf[7] = (2048+4)&0xff; + + buf[8] = 0x01; /* Copyright info */ + buf[9] = 0x40; /* Not writable, is readable */ + buf[10] = ((4+4)>>8)&0xff; + buf[11] = (4+4)&0xff; + + buf[12] = 0x03; /* BCA info */ + buf[13] = 0x40; /* Not writable, is readable */ + buf[14] = ((188+4)>>8)&0xff; + buf[15] = (188+4)&0xff; + + buf[16] = 0x04; /* Manufacturing info */ + buf[17] = 0x40; /* Not writable, is readable */ + buf[18] = ((2048+4)>>8)&0xff; + buf[19] = (2048+4)&0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[6] = ((16+2)>>8)&0xff; + buf[7] = (16+2)&0xff; + + /* data written + 4 byte header */ + return (16 + 4); + + default: /* TODO: formats beyond DVD-ROM requires */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + } +} + +/*SCSI Get Event Status Notification*/ +uint32_t SCSICDROMEventStatus(uint8_t *buffer) +{ + uint8_t event_code, media_status = 0; + + if (buffer[5]) + { + media_status = MS_TRAY_OPEN; + cdrom->stop(); + } + else + { + media_status = MS_MEDIA_PRESENT; + } + + event_code = MEC_NO_CHANGE; + if (media_status != MS_TRAY_OPEN) + { + if (!buffer[4]) + { + event_code = MEC_NEW_MEDIA; + cdrom->load(); + } + else if (buffer[4]==2) + { + event_code = MEC_EJECT_REQUESTED; + cdrom->eject(); + } + } + + buffer[4] = event_code; + buffer[5] = media_status; + buffer[6] = 0; + buffer[7] = 0; + + return 8; +} + +void SCSICDROM_Insert() +{ + SCSISense.SenseKey=SENSE_UNIT_ATTENTION; + SCSISense.Asc=ASC_MEDIUM_MAY_HAVE_CHANGED; + SCSISense.Ascq=0; +} + +int cd_status = CD_STATUS_EMPTY; +int prev_status; + +static uint8_t ScsiPrev; +static int SenseCompleted; + +void SCSIClearSense(uint8_t Command, int IgnoreUA) +{ + if ((SCSISense.SenseKey == SENSE_UNIT_ATTENTION) || IgnoreUA) + { + ScsiPrev=Command; + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + } +} + +void SCSICDROM_RunCommand(SCSI *Scsi, uint8_t Id, uint8_t *Cdb) +{ + uint8_t RCdMode = 0; + int c; + int Msf; + unsigned char Temp; + uint32_t Size; + uint8_t PageCode; + unsigned Idx = 0; + unsigned SizeIndex; + unsigned PreambleLen; + int TocFormat; + uint8_t Index = 0; + int Media; + int Format; + int DVDRet; + + memcpy(Scsi->Cdb, Cdb, 32); + + Msf = Scsi->Cdb[1]&2; + + if (cdrom->medium_changed()) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSICDROM_Insert(); + } + + if ((Scsi->Cdb[0]!=GPCMD_REQUEST_SENSE) && (Scsi->Cdb[0]!=GPCMD_TEST_UNIT_READY)) + { + /* GPCMD_TEST_UNIT_READY is NOT supposed to clear sense! */ + SCSIClearSense(Scsi->Cdb[0], 1); + } + + if ((SCSICommandTable[Scsi->Cdb[0]] & CHECK_READY) && !cdrom->ready()) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); + return; + } + + prev_status = cd_status; + cd_status = cdrom->status(); + if (((prev_status == CD_STATUS_PLAYING) || (prev_status == CD_STATUS_PAUSED)) && ((cd_status != CD_STATUS_PLAYING) && (cd_status != CD_STATUS_PAUSED))) + { + SenseCompleted = 1; + } + else + { + SenseCompleted = 0; + } + + pclog("SCSI Command 0x%02X, Status %02X, Sense Key %02X, Asc %02X, Ascq %02X\n", Scsi->Cdb[0], ScsiStatus, SCSISense.SenseKey, SCSISense.Asc, SCSISense.Ascq); + + switch (Scsi->Cdb[0]) + { + case GPCMD_TEST_UNIT_READY: + SCSINoTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=50*SCSI_TIME; + break; + + case GPCMD_REQUEST_SENSE: + /*Will return 18 bytes of 0*/ + memset(Scsi->SegmentData.Address, 0, 512); + + Scsi->SegmentData.Address[0]=0x80|0x70; + + if ((SCSISense.SenseKey >= 0) || (cd_status < CD_STATUS_PLAYING)) + { + if (SenseCompleted) + { + Scsi->SegmentData.Address[2]=SENSE_ILLEGAL_REQUEST; + Scsi->SegmentData.Address[12]=ASC_AUDIO_PLAY_OPERATION; + Scsi->SegmentData.Address[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; + } + else + { + Scsi->SegmentData.Address[2]=SCSISense.SenseKey; + Scsi->SegmentData.Address[12]=SCSISense.Asc; + Scsi->SegmentData.Address[13]=SCSISense.Ascq; + } + } + else + { + Scsi->SegmentData.Address[2]=SENSE_ILLEGAL_REQUEST; + Scsi->SegmentData.Address[12]=ASC_AUDIO_PLAY_OPERATION; + Scsi->SegmentData.Address[13]=(cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; + } + + Scsi->SegmentData.Address[7]=10; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, 18); + SCSIReadTransfer(Scsi, Id); + + SCSIClearSense(Scsi->Cdb[0], 0); + ScsiCallback[Id]=60*SCSI_TIME; + break; + + case GPCMD_SET_SPEED: + SCSINoTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=50*SCSI_TIME; + break; + + case GPCMD_MECHANISM_STATUS: + Scsi->SegmentData.Length=(Scsi->Cdb[7]<<16)|(Scsi->Cdb[8]<<8)|Scsi->Cdb[9]; + + Scsi->SegmentData.Address[0] = 0; + Scsi->SegmentData.Address[1] = 0; + Scsi->SegmentData.Address[2] = 0; + Scsi->SegmentData.Address[3] = 0; + Scsi->SegmentData.Address[4] = 0; + Scsi->SegmentData.Address[5] = 1; + Scsi->SegmentData.Address[6] = 0; + Scsi->SegmentData.Address[7] = 0; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, 8); + SCSIReadTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + break; + + case GPCMD_READ_TOC_PMA_ATIP: + TocFormat = Scsi->Cdb[2] & 0xf; + if (TocFormat == 0) + TocFormat = (Scsi->Cdb[9]>>6) & 3; + switch (TocFormat) + { + case 0: /*Normal*/ + Scsi->SegmentData.Length = Scsi->Cdb[8]|(Scsi->Cdb[7]<<8); + Scsi->SegmentData.Length = cdrom->readtoc(Scsi->SegmentData.Address, Scsi->Cdb[6], Msf, Scsi->SegmentData.Length, 0); + break; + + case 1: /*Multi session*/ + Scsi->SegmentData.Length = Scsi->Cdb[8]|(Scsi->Cdb[7]<<8); + Scsi->SegmentData.Length = cdrom->readtoc_session(Scsi->SegmentData.Address, Msf, Scsi->SegmentData.Length); + Scsi->SegmentData.Address[0] = 0; + Scsi->SegmentData.Address[1] = 0xA; + break; + + case 2: /*Raw*/ + Scsi->SegmentData.Length = Scsi->Cdb[8]|(Scsi->Cdb[7]<<8); + Scsi->SegmentData.Length = cdrom->readtoc_raw(Scsi->SegmentData.Address, Scsi->SegmentData.Length); + break; + + default: + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + return; + } + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); + SCSIReadTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + return; + + case GPCMD_READ_CD: + RCdMode = Scsi->Cdb[9] & 0xF8; + if ((RCdMode != 0x10) && (RCdMode != 0xF8)) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + break; + } + + Scsi->SectorLen=(Scsi->Cdb[6]<<16)|(Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; + Scsi->SectorLba=(Scsi->Cdb[2]<<24)|(Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; + + if (RCdMode == 0x10) + cdrom->readsector(Scsi->SegmentData.Address,Scsi->SectorLba); + else + cdrom->readsector_raw(Scsi->SegmentData.Address,Scsi->SectorLba); + + readcdmode = (RCdMode == 0xF8); + + Scsi->SectorLba++; + Scsi->SectorLen--; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, (Scsi->Cdb[9]==0x10) ? 2048 : 2352); + SCSIReadTransfer(Scsi, Id); + + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + return; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + { + readcdmode = 0; + + if (Scsi->Cdb[0] == GPCMD_READ_6) + { + Scsi->SectorLen=Scsi->Cdb[4]; + Scsi->SectorLba=((((uint32_t) Scsi->Cdb[1]) & 0x1f)<<16)|(((uint32_t) Scsi->Cdb[2])<<8)|((uint32_t) Scsi->Cdb[3]); + } + else if (Scsi->Cdb[0] == GPCMD_READ_10) + { + Scsi->SectorLen=(Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; + Scsi->SectorLba=(Scsi->Cdb[2]<<24)|(Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; + } + else + { + Scsi->SectorLen=(((uint32_t) Scsi->Cdb[6])<<24)|(((uint32_t) Scsi->Cdb[7])<<16)|(((uint32_t) Scsi->Cdb[8])<<8)|((uint32_t) Scsi->Cdb[9]); + Scsi->SectorLba=(((uint32_t) Scsi->Cdb[2])<<24)|(((uint32_t) Scsi->Cdb[3])<<16)|(((uint32_t) Scsi->Cdb[4])<<8)|((uint32_t) Scsi->Cdb[5]); + } + + if (!Scsi->SectorLen) + { + SCSISenseCodeOk(); + ScsiCallback[Id]=20*SCSI_TIME; + break; + } + + cdrom->readsector(Scsi->SegmentData.Address, Scsi->SectorLba); + + Scsi->SectorLba++; + Scsi->SectorLen--; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, 2048); + SCSIReadTransfer(Scsi, Id); + + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + } + return; + + case GPCMD_READ_HEADER: + if (Msf) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + break; + } + for (c=0;c<4;c++) + Scsi->SegmentData.Address[c+4] = Scsi->SegmentData.Address[c+2]; + + Scsi->SegmentData.Address[0] = 1; /*2048 bytes user data*/ + Scsi->SegmentData.Address[1] = Scsi->SegmentData.Address[2] = Scsi->SegmentData.Address[3] = 0; + + Scsi->SegmentData.Length = 8; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); + SCSIReadTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + if (Scsi->Cdb[0] == GPCMD_MODE_SENSE_6) + { + Scsi->SegmentData.Length = Scsi->Cdb[4]; + } + else + { + Scsi->SegmentData.Length = (Scsi->Cdb[8]|(Scsi->Cdb[7]<<8)); + } + Temp=Scsi->Cdb[2] & 0x3F; + + memset(Scsi->SegmentData.Address, 0, Scsi->SegmentData.Length); + + if (!(mode_sense_pages[Temp] & IMPLEMENTED)) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + ScsiCallback[Id]=60*SCSI_TIME; + break; + } + + if (Scsi->Cdb[0] == GPCMD_MODE_SENSE_6) + { + Scsi->SegmentData.Length = SCSICDROMModeSense(Scsi->SegmentData.Address, 4, Temp); + Scsi->SegmentData.Address[0] = Scsi->SegmentData.Length - 1; + Scsi->SegmentData.Address[1] = 3; /*120mm data CD-ROM*/ + } + else + { + Scsi->SegmentData.Length = SCSICDROMModeSense(Scsi->SegmentData.Address, 8, Temp); + Scsi->SegmentData.Address[0] = (Scsi->SegmentData.Length - 2)>>8; + Scsi->SegmentData.Address[1] = (Scsi->SegmentData.Length - 2)&255; + Scsi->SegmentData.Address[2] = 3; /*120mm data CD-ROM*/ + } + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); + SCSIReadTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (Scsi->Cdb[0] == GPCMD_MODE_SELECT_6) + { + Scsi->SegmentData.Length = Scsi->Cdb[4]; + prefix_len = 6; + } + else + { + Scsi->SegmentData.Length = (Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; + prefix_len = 10; + } + page_current = Scsi->Cdb[2]; + if (page_flags[page_current] & PAGE_CHANGEABLE) + page_flags[GPMODE_CDROM_AUDIO_PAGE] |= PAGE_CHANGED; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); + SCSIWriteTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + return; + + case GPCMD_GET_CONFIGURATION: + { + /* XXX: could result in alignment problems in some architectures */ + Scsi->SegmentData.Length = (Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; + + Index = 0; + + /* only feature 0 is supported */ + if (Scsi->Cdb[2] != 0 || Scsi->Cdb[3] != 0) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + break; + } + + /* + * XXX: avoid overflow for io_buffer if len is bigger than + * the size of that buffer (dimensioned to max number of + * sectors to transfer at once) + * + * Only a problem if the feature/profiles grow. + */ + if (Scsi->SegmentData.Length > 512) /* XXX: assume 1 sector */ + Scsi->SegmentData.Length = 512; + + memset(Scsi->SegmentData.Address, 0, Scsi->SegmentData.Length); + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (Scsi->SegmentData.Length > CD_MAX_SECTORS ) + { + Scsi->SegmentData.Address[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; + Scsi->SegmentData.Address[7] = MMC_PROFILE_DVD_ROM & 0xff; + } + else if (Scsi->SegmentData.Length <= CD_MAX_SECTORS) + { + Scsi->SegmentData.Address[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; + Scsi->SegmentData.Address[7] = MMC_PROFILE_CD_ROM & 0xff; + } + Scsi->SegmentData.Address[10] = 0x02 | 0x01; /* persistent and current */ + Scsi->SegmentData.Length = 12; /* headers: 8 + 4 */ + Scsi->SegmentData.Length += SCSICDROMSetProfile(Scsi->SegmentData.Address, &Index, MMC_PROFILE_DVD_ROM); + Scsi->SegmentData.Length += SCSICDROMSetProfile(Scsi->SegmentData.Address, &Index, MMC_PROFILE_CD_ROM); + Scsi->SegmentData.Address[0] = ((Scsi->SegmentData.Length-4) >> 24) & 0xff; + Scsi->SegmentData.Address[1] = ((Scsi->SegmentData.Length-4) >> 16) & 0xff; + Scsi->SegmentData.Address[2] = ((Scsi->SegmentData.Length-4) >> 8) & 0xff; + Scsi->SegmentData.Address[3] = (Scsi->SegmentData.Length-4) & 0xff; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); + SCSIReadTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + } + break; + + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + { + struct + { + uint8_t opcode; + uint8_t polled; + uint8_t reserved2[2]; + uint8_t class; + uint8_t reserved3[2]; + uint16_t len; + uint8_t control; + } *gesn_cdb; + + struct + { + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; + } *gesn_event_header; + unsigned int used_len = Scsi->SegmentData.Length; + + gesn_cdb = (void *)Scsi->Cdb; + gesn_event_header = (void *)Scsi->SegmentData.Address; + + /* It is fine by the MMC spec to not support async mode operations */ + if (!(gesn_cdb->polled & 0x01)) + { /* asynchronous mode */ + /* Only pollign is supported, asynchronous mode is not. */ + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + return; + } + + /* polling mode operation */ + + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + * Notification class requests and supported event classes are bitmasks, + * but they are built from the same values as the "notification class" + * field. + */ + gesn_event_header->supported_events = 1 << GESN_MEDIA; + + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & (1 << GESN_MEDIA)) + { + gesn_event_header->notification_class |= GESN_MEDIA; + used_len = SCSICDROMEventStatus(Scsi->SegmentData.Address); + } + else + { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + gesn_event_header->len = used_len - sizeof(*gesn_event_header); + + Scsi->SegmentData.Length = used_len; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); + SCSIReadTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + } + break; + + case GPCMD_READ_DISC_INFORMATION: + Scsi->SegmentData.Address[1] = 32; + Scsi->SegmentData.Address[2] = 0xe; /* last session complete, disc finalized */ + Scsi->SegmentData.Address[3] = 1; /* first track on disc */ + Scsi->SegmentData.Address[4] = 1; /* # of sessions */ + Scsi->SegmentData.Address[5] = 1; /* first track of last session */ + Scsi->SegmentData.Address[6] = 1; /* last track of last session */ + Scsi->SegmentData.Address[7] = 0x20; /* unrestricted use */ + Scsi->SegmentData.Address[8] = 0x00; /* CD-ROM */ + Scsi->SegmentData.Length = 34; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); + SCSIReadTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + break; + + case GPCMD_PLAY_AUDIO_10: + case GPCMD_PLAY_AUDIO_12: + case GPCMD_PLAY_AUDIO_MSF: + /*This is apparently deprecated in the SCSI spec, and apparently + has been since 1995 (!). Hence I'm having to guess most of it*/ + if (Scsi->Cdb[0] == GPCMD_PLAY_AUDIO_10) + { + Scsi->BufferPosition = (Scsi->Cdb[2]<<24)|(Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; + Scsi->SegmentData.Length = (Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; + } + else if (Scsi->Cdb[0] == GPCMD_PLAY_AUDIO_MSF) + { + Scsi->BufferPosition = (Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; + Scsi->SegmentData.Length = (Scsi->Cdb[6]<<16)|(Scsi->Cdb[7]<<8)|Scsi->Cdb[8]; + } + else + { + Scsi->BufferPosition = (Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; + Scsi->SegmentData.Length = (Scsi->Cdb[7]<<16)|(Scsi->Cdb[8]<<8)|Scsi->Cdb[9]; + } + + + if ((cdrom_drive < 1) || (cdrom_drive == 200) || (cd_status <= CD_STATUS_DATA_ONLY) || + !cdrom->is_track_audio(Scsi->BufferPosition, (Scsi->Cdb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0)) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_MODE_FOR_THIS_TRACK, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + break; + } + + cdrom->playaudio(Scsi->BufferPosition, Scsi->SegmentData.Length, (Scsi->Cdb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0); + + SCSINoTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=50*SCSI_TIME; + break; + + case GPCMD_READ_SUBCHANNEL: + Temp = Scsi->Cdb[2] & 0x40; + if (Scsi->Cdb[3] != 1) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + break; + } + Scsi->BufferPosition = 0; + Scsi->SegmentData.Address[Scsi->BufferPosition++] = 0; + Scsi->SegmentData.Address[Scsi->BufferPosition++] = 0; /*Audio status*/ + Scsi->SegmentData.Address[Scsi->BufferPosition++] = 0; Scsi->SegmentData.Address[Scsi->BufferPosition++] = 0; /*Subchannel length*/ + Scsi->SegmentData.Address[Scsi->BufferPosition++] = 1; /*Format code*/ + Scsi->SegmentData.Address[1] = cdrom->getcurrentsubchannel(&Scsi->SegmentData.Address[5], Msf); + Scsi->SegmentData.Length = 16; + if (!Temp) + Scsi->SegmentData.Length = 4; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); + SCSIReadTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=1000*SCSI_TIME; + break; + + case GPCMD_READ_DVD_STRUCTURE: + Media = Scsi->Cdb[1]; + Format = Scsi->Cdb[7]; + + Scsi->SegmentData.Length = (Scsi->Cdb[6]<<24)|(Scsi->Cdb[7]<<16)|(Scsi->Cdb[8]<<8)|Scsi->Cdb[9]; + + if (Format < 0xff) { + if (Scsi->SegmentData.Length <= CD_MAX_SECTORS) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INCOMPATIBLE_FORMAT, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + break; + } + else + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + return; + } + } + + memset(Scsi->SegmentData.Address, 0, Scsi->SegmentData.Length > 256 * 512 + 4 ? 256 * 512 + 4 : Scsi->SegmentData.Length); + + switch (Format) + { + case 0x00 ... 0x7f: + case 0xff: + if (Media == 0) + { + DVDRet = SCSICDROMReadDVDStructure(Format, Scsi->Cdb, Scsi->SegmentData.Address); + + if (DVDRet < 0) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, -DVDRet, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + return; + } + else + { + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); + SCSIReadTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + } + break; + } + /* TODO: BD support, fall through for now */ + + /* Generic disk structures */ + case 0x80: /* TODO: AACS volume identifier */ + case 0x81: /* TODO: AACS media serial number */ + case 0x82: /* TODO: AACS media identifier */ + case 0x83: /* TODO: AACS media key block */ + case 0x90: /* TODO: List of recognized format layers */ + case 0xc0: /* TODO: Write protection status */ + default: + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + break; + } + break; + + case GPCMD_START_STOP_UNIT: + if (Scsi->Cdb[4]!=2 && Scsi->Cdb[4]!=3 && Scsi->Cdb[4]) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + break; + } + if (!Scsi->Cdb[4]) cdrom->stop(); + else if (Scsi->Cdb[4]==2) cdrom->eject(); + else cdrom->load(); + SCSINoTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=50*SCSI_TIME; + break; + + case GPCMD_INQUIRY: + PageCode = Scsi->Cdb[2]; + Scsi->SegmentData.Length = Scsi->Cdb[4]; + + pclog("SCSI Inquiry Page %02X\n", Scsi->Cdb[1] & 1); + if (Scsi->Cdb[1] & 1) + { + PreambleLen = 4; + SizeIndex = 3; + + Scsi->SegmentData.Address[Idx++] = 5; + Scsi->SegmentData.Address[Idx++] = PageCode; + Scsi->SegmentData.Address[Idx++] = 0; + + Idx++; + + pclog("SCSI Inquiry Page Code %02X\n", PageCode); + switch (PageCode) + { + case 0x00: + Scsi->SegmentData.Address[Idx++] = 0x00; + Scsi->SegmentData.Address[Idx++] = 0x00; + Scsi->SegmentData.Address[Idx++] = 2; + Scsi->SegmentData.Address[Idx++] = 0x00; + Scsi->SegmentData.Address[Idx++] = 0x80; + Scsi->SegmentData.Address[Idx++] = 0x83; + break; + + case 0x83: + if (Idx + 24 > Scsi->SegmentData.Length) + { + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_DATA_PHASE_ERROR, 0); + ScsiCallback[Id]=500*SCSI_TIME; + return; + } + Scsi->SegmentData.Address[Idx++] = 0x02; + Scsi->SegmentData.Address[Idx++] = 0x00; + Scsi->SegmentData.Address[Idx++] = 0x00; + Scsi->SegmentData.Address[Idx++] = 20; + ScsiPadStr8(Scsi->SegmentData.Address + Idx, 20, "3097165"); /* Serial */ + Idx += 20; + + if (Idx + 72 > Scsi->SegmentData.Length) + { + goto SCSIOut; + } + Scsi->SegmentData.Address[Idx++] = 0x02; + Scsi->SegmentData.Address[Idx++] = 0x01; + Scsi->SegmentData.Address[Idx++] = 0x00; + Scsi->SegmentData.Address[Idx++] = 68; + ScsiPadStr8(Scsi->SegmentData.Address + Idx, 8, "Sony"); /* Vendor */ + Idx += 8; + ScsiPadStr8(Scsi->SegmentData.Address + Idx, 40, "CDU-76S 1.0"); /* Product */ + Idx += 40; + ScsiPadStr8(Scsi->SegmentData.Address + Idx, 20, "3097165"); /* Product */ + Idx += 20; + break; + + default: + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + ScsiCallback[Id]=500*SCSI_TIME; + return; + } + } + else + { + PreambleLen = 5; + SizeIndex = 4; + + Scsi->SegmentData.Address[0] = 5; /*CD-ROM*/ + Scsi->SegmentData.Address[1] = 0x80; /*Removable*/ + Scsi->SegmentData.Address[2] = 0; + Scsi->SegmentData.Address[3] = 0x21; + Scsi->SegmentData.Address[4] = 31; + Scsi->SegmentData.Address[5] = 0; + Scsi->SegmentData.Address[6] = 0; + Scsi->SegmentData.Address[7] = 0; + ScsiPadStr8(Scsi->SegmentData.Address + 8, 8, "Sony"); /* Vendor */ + ScsiPadStr8(Scsi->SegmentData.Address + 16, 16, "CDU-76S"); /* Product */ + ScsiPadStr8(Scsi->SegmentData.Address + 32, 4, "1.0"); /* Revision */ + + Idx = 36; + } + +SCSIOut: + Scsi->SegmentData.Address[SizeIndex] = Idx - PreambleLen; + Scsi->SegmentData.Length=Idx; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); + SCSIReadTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + break; + + case GPCMD_PREVENT_REMOVAL: + SCSINoTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=50*SCSI_TIME; + break; + + case GPCMD_PAUSE_RESUME: + if (Scsi->Cdb[8]&1) cdrom->resume(); + else cdrom->pause(); + SCSINoTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=50*SCSI_TIME; + break; + + case GPCMD_SEEK: + Scsi->BufferPosition = (Scsi->Cdb[3]<<16)|(Scsi->Cdb[4]<<8)|Scsi->Cdb[5]; + cdrom->seek(Scsi->BufferPosition); + + SCSINoTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=50*SCSI_TIME; + break; + + case GPCMD_READ_CDROM_CAPACITY: + Size = cdrom->size(); + Scsi->SegmentData.Address[0] = (Size >> 24) & 0xFF; + Scsi->SegmentData.Address[1] = (Size >> 16) & 0xFF; + Scsi->SegmentData.Address[2] = (Size >> 8) & 0xFF; + Scsi->SegmentData.Address[3] = Size & 0xFF; + Scsi->SegmentData.Address[4] = (2048 >> 24) & 0xFF; + Scsi->SegmentData.Address[5] = (2048 >> 16) & 0xFF; + Scsi->SegmentData.Address[6] = (2048 >> 8) & 0xFF; + Scsi->SegmentData.Address[7] = 2048 & 0xFF; + Scsi->SegmentData.Length = 8; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, Scsi->SegmentData.Length); + + SCSIReadTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; + break; + + case GPCMD_STOP_PLAY_SCAN: + cdrom->stop(); + + SCSINoTransfer(Scsi, Id); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=50*SCSI_TIME; + break; + + default: + ScsiStatus = SCSI_STATUS_CHECK_CONDITION; + SCSISenseCodeError(SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0x00); + ScsiCallback[Id]=50*SCSI_TIME; + return; + } +} + +void SCSICDROM_CallRead(SCSI *Scsi, uint8_t Id) +{ + if (Scsi->SectorLen <= 0) + { + pclog("All done - callback set\n"); + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=20*SCSI_TIME; + return; + } + pclog("Continue Read command! %i blocks left\n", Scsi->SectorLen); + + if (readcdmode) + cdrom->readsector_raw(Scsi->SegmentData.Address, Scsi->SectorLba); + else + cdrom->readsector(Scsi->SegmentData.Address, Scsi->SectorLba); + + Scsi->SectorLba++; + Scsi->SectorLen--; + + SegmentBufferCopyFromBuf(&Scsi->SegmentBuffer, Scsi->SegmentData.Address, readcdmode ? 2352 : 2048); + + ScsiStatus = SCSI_STATUS_OK; + SCSISenseCodeOk(); + ScsiCallback[Id]=60*SCSI_TIME; +} \ No newline at end of file diff --git a/src/sound.c b/src/sound.c index 1fedb4c79..54d1bf032 100644 --- a/src/sound.c +++ b/src/sound.c @@ -110,20 +110,20 @@ static void sound_cd_thread(void *param) ioctl_audio_callback(cd_buffer, CD_BUFLEN*2); if (soundon) { - int32_t atapi_vol_l = atapi_get_cd_volume(0); - int32_t atapi_vol_r = atapi_get_cd_volume(1); + int32_t audio_vol_l = SCSIGetCDVolume(0); + int32_t audio_vol_r = SCSIGetCDVolume(1); int channel_select[2]; - channel_select[0] = atapi_get_cd_channel(0); - channel_select[1] = atapi_get_cd_channel(1); + channel_select[0] = SCSIGetCDChannel(0); + channel_select[1] = SCSIGetCDChannel(1); for (c = 0; c < CD_BUFLEN*2; c += 2) { int32_t cd_buffer_temp[2] = {0, 0}; - /*First, adjust input from drive according to ATAPI volume.*/ - cd_buffer[c] = ((int32_t)cd_buffer[c] * atapi_vol_l) / 255; - cd_buffer[c+1] = ((int32_t)cd_buffer[c+1] * atapi_vol_r) / 255; + /*First, adjust input from drive according to ATAPI/SCSI volume.*/ + cd_buffer[c] = ((int32_t)cd_buffer[c] * audio_vol_l) / 255; + cd_buffer[c+1] = ((int32_t)cd_buffer[c+1] * audio_vol_r) / 255; /*Apply ATAPI channel select*/ if (channel_select[0] & 1) diff --git a/src/vid_voodoo.c b/src/vid_voodoo.c index eba63c43b..5e8667420 100644 --- a/src/vid_voodoo.c +++ b/src/vid_voodoo.c @@ -11,8 +11,6 @@ #include "vid_voodoo.h" #include "vid_voodoo_dither.h" -#define MIN(a, b) ((a) < (b) ? (a) : (b)) - #define CLAMP(x) (((x) < 0) ? 0 : (((x) > 0xff) ? 0xff : (x))) #define CLAMP16(x) (((x) < 0) ? 0 : (((x) > 0xffff) ? 0xffff : (x))) diff --git a/src/win-config.c b/src/win-config.c index 8b765550a..ed3e5c17e 100644 --- a/src/win-config.c +++ b/src/win-config.c @@ -43,6 +43,7 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR int temp_network_interface_current; int temp_always_serial; int temp_joystick_type; + int temp_aha154x; UDACCEL accel; // pclog("Dialog msg %i %08X\n",message,message); @@ -193,6 +194,9 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR h=GetDlgItem(hdlg, IDC_CHECKVOODOO); SendMessage(h, BM_SETCHECK, voodoo_enabled, 0); + h=GetDlgItem(hdlg, IDC_CHECK_AHA154X); + SendMessage(h, BM_SETCHECK, aha154x_enabled, 0); + cpu_flags = models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[cpu].cpu_flags; h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) @@ -349,6 +353,9 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR h = GetDlgItem(hdlg, IDC_CHECKVOODOO); temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + h = GetDlgItem(hdlg, IDC_CHECK_AHA154X); + temp_aha154x = SendMessage(h, BM_GETCHECK, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBOSND); temp_sound_card_current = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; @@ -370,7 +377,7 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR fpu != hasfpu || temp_GAMEBLASTER != GAMEBLASTER || temp_GUS != GUS || temp_SSI2001 != SSI2001 || temp_sound_card_current != sound_card_current || temp_voodoo != voodoo_enabled || temp_dynarec != cpu_use_dynarec || temp_always_serial != mouse_always_serial || - temp_fda_type != fdd_get_type(0) || temp_fdb_type != fdd_get_type(1) || temp_network_card_current != network_card_current) + temp_fda_type != fdd_get_type(0) || temp_fdb_type != fdd_get_type(1) || temp_network_card_current != network_card_current || temp_aha154x != aha154x_enabled) { if (MessageBox(NULL,"This will reset 86Box!\nOkay to continue?","86Box",MB_OKCANCEL)==IDOK) { @@ -386,6 +393,7 @@ static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR SSI2001 = temp_SSI2001; sound_card_current = temp_sound_card_current; voodoo_enabled = temp_voodoo; + aha154x_enabled = temp_aha154x; cpu_use_dynarec = temp_dynarec; fdd_set_type(0, temp_fda_type); diff --git a/src/win-hdconf.c b/src/win-hdconf.c index 1b06e290d..7ee127a88 100644 --- a/src/win-hdconf.c +++ b/src/win-hdconf.c @@ -488,7 +488,7 @@ static BOOL CALLBACK hdconf_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR sprintf(s, "Size: %" PRIu64 " MB", (hd[3].tracks*hd[3].hpc*hd[3].spt) >> 11); SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - new_cdrom_channel = cdrom_channel; + new_cdrom_channel = atapi_cdrom_channel; update_hdd_cdrom(hdlg); return TRUE; @@ -497,7 +497,7 @@ static BOOL CALLBACK hdconf_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR switch (LOWORD(wParam)) { case IDOK: - if (hd_changed || cdrom_channel != new_cdrom_channel) + if (hd_changed || atapi_cdrom_channel != new_cdrom_channel) { if (MessageBox(NULL, "This will reset 86Box!\nOkay to continue?", "86Box", MB_OKCANCEL) == IDOK) { @@ -554,7 +554,7 @@ static BOOL CALLBACK hdconf_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPAR hdc[2] = hd[2]; hdc[3] = hd[3]; - cdrom_channel = new_cdrom_channel; + atapi_cdrom_channel = new_cdrom_channel; saveconfig(); diff --git a/src/win.c b/src/win.c index ca6a0a3fe..0b26190d0 100644 --- a/src/win.c +++ b/src/win.c @@ -25,7 +25,7 @@ #include "video.h" #include "resources.h" #include "cpu.h" -#include "ide.h" +#include "cdrom.h" #include "model.h" #include "nethandler.h" #include "nvr.h" @@ -934,7 +934,7 @@ LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ) return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam ); } -void atapi_close(void) +void cdrom_close(void) { switch (cdrom_drive) { @@ -1141,9 +1141,9 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM { /* Switching from disabled to disabled. Do nothing. */ break; - } - atapi->exit(); - atapi_close(); + } + cdrom->exit(); + cdrom_close(); cdrom_null_open(0); CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_CHECKED); @@ -1173,13 +1173,13 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM /* Switch from empty to empty. Do nothing. */ break; } - atapi->exit(); - atapi_close(); + cdrom->exit(); + cdrom_close(); cdrom_null_open(0); if (cdrom_enabled) { /* Signal disc change to the emulated machine. */ - atapi_insert_cdrom(); + SCSICDROM_Insert(); } CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); @@ -1214,13 +1214,13 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM /* Switching from ISO to the same ISO. Do nothing. */ break; } - atapi->exit(); - atapi_close(); + cdrom->exit(); + cdrom_close(); iso_open(temp_iso_path); if (cdrom_enabled) { /* Signal disc change to the emulated machine. */ - atapi_insert_cdrom(); + SCSICDROM_Insert(); } CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); @@ -1255,13 +1255,13 @@ LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM break; } old_cdrom_drive = cdrom_drive; - atapi->exit(); - atapi_close(); + cdrom->exit(); + cdrom_close(); ioctl_open(new_cdrom_drive); if (cdrom_enabled) { /* Signal disc change to the emulated machine. */ - atapi_insert_cdrom(); + SCSICDROM_Insert(); } CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED);