diff --git a/src/Makefile.am b/src/Makefile.am index 098d4d5..5683bc3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,7 +16,7 @@ amrefresh: pcem_SOURCES = 386.c 386_dynarec.c 386_dynarec_ops.c 808x.c acer386sx.c ali1429.c amstrad.c cbm_io.c cdrom-image.cc cdrom-null.c \ codegen.c codegen_ops.c codegen_timing_486.c codegen_timing_686.c codegen_timing_common.c codegen_timing_pentium.c codegen_timing_winchip.c compaq.c config.c cpu.c \ dells200.c device.c disc.c disc_fdi.c disc_img.c disc_sector.c dma.c esdi_at.c fdc.c fdc37c665.c fdd.c fdi2raw.c gameport.c \ -hdd.c hdd_esdi.c hdd_file.c headland.c i430lx.c i430fx.c i430vx.c ide.c intel.c intel_flash.c io.c jim.c joystick_ch_flightstick_pro.c joystick_standard.c joystick_sw_pad.c \ +hdd.c hdd_esdi.c hdd_file.c headland.c i430lx.c i430fx.c i430vx.c ide.c ide_atapi.c intel.c intel_flash.c io.c jim.c joystick_ch_flightstick_pro.c joystick_standard.c joystick_sw_pad.c \ joystick_tm_fcs.c keyboard.c keyboard_amstrad.c keyboard_at.c keyboard_olim24.c keyboard_pcjr.c keyboard_xt.c \ laserxt.c lpt.c lpt_dac.c lpt_dss.c mca.c mcr.c mem.c mfm_at.c mfm_xebec.c model.c mouse.c mouse_msystems.c mouse_ps2.c mouse_serial.c neat.c nmi.c nvr.c olivetti_m24.c \ opti495.c paths.c pc.c pci.c pic.c piix.c pit.c ppi.c ps1.c ps2.c ps2_mca.c ps2_nvr.c nvr_tc8521.c rom.c rtc.c rtc_tc8521.c scat.c scsi.c scsi_53c400.c scsi_aha1540.c scsi_cd.c scsi_hd.c \ diff --git a/src/Makefile.linux32-wx-sdl2 b/src/Makefile.linux32-wx-sdl2 index ff77aa6..580f1a9 100644 --- a/src/Makefile.linux32-wx-sdl2 +++ b/src/Makefile.linux32-wx-sdl2 @@ -7,7 +7,7 @@ CXXFLAGS = $(CFLAGS) OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl-linux.o cdrom-image.o cdrom-null.o \ codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.c compaq.o config.o cpu.o \ dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \ -hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ +hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o i430vx.o ide.o ide_atapi.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 \ laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o \ opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o \ diff --git a/src/Makefile.linux64-wx-sdl2 b/src/Makefile.linux64-wx-sdl2 index f274909..27108e2 100644 --- a/src/Makefile.linux64-wx-sdl2 +++ b/src/Makefile.linux64-wx-sdl2 @@ -7,7 +7,7 @@ CXXFLAGS = $(CFLAGS) OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl-linux.o cdrom-image.o cdrom-null.o \ codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.c compaq.o config.o cpu.o \ dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \ -hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ +hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o i430vx.o ide.o ide_atapi.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 \ laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o \ opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o \ diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 0022aab..e475974 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -6,7 +6,7 @@ CFLAGS = -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign -Wall -Werro OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl.o cdrom-image.o \ codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o \ dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o \ - i430vx.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 \ + i430vx.o ide.o ide_atapi.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 laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o \ scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_dbopl.o \ diff --git a/src/Makefile.mingw-network b/src/Makefile.mingw-network index 57038f9..64e37e2 100644 --- a/src/Makefile.mingw-network +++ b/src/Makefile.mingw-network @@ -7,7 +7,7 @@ CFLAGS = -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign -Wall -Werro OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl.o cdrom-image.o \ codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o \ dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o \ - i430vx.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 \ + i430vx.o ide.o ide_atapi.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 laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o \ scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_dbopl.o \ diff --git a/src/Makefile.mingw-wx-sdl2 b/src/Makefile.mingw-wx-sdl2 index 2928106..6941bc8 100644 --- a/src/Makefile.mingw-wx-sdl2 +++ b/src/Makefile.mingw-wx-sdl2 @@ -9,7 +9,7 @@ CXXFLAGS = $(CFLAGS) OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl.o cdrom-image.o \ codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o \ device.o dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o \ - i430vx.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 \ + i430vx.o ide.o ide_atapi.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 laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o \ scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_dbopl.o \ diff --git a/src/Makefile.mingw-wx-sdl2-network b/src/Makefile.mingw-wx-sdl2-network index 794d72c..2853360 100644 --- a/src/Makefile.mingw-wx-sdl2-network +++ b/src/Makefile.mingw-wx-sdl2-network @@ -9,7 +9,7 @@ CXXFLAGS = $(CFLAGS) OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl.o cdrom-image.o \ codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o \ device.o dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o \ - i430vx.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 \ + i430vx.o ide.o ide_atapi.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 laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o \ scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_dbopl.o \ diff --git a/src/Makefile.mingw64 b/src/Makefile.mingw64 index be7f9fb..a2fbd9b 100644 --- a/src/Makefile.mingw64 +++ b/src/Makefile.mingw64 @@ -6,7 +6,7 @@ CFLAGS = -O3 -fomit-frame-pointer -msse2 -Wall -Werror -fno-strict-aliasing OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl.o cdrom-image.o \ codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.o compaq.o config.o cpu.o \ dells200.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o \ - i430vx.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 \ + i430vx.o ide.o ide_atapi.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 laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o \ mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o \ scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o serial.o sio.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_cms.o sound_dbopl.o \ diff --git a/src/Makefile.osx64-wx-sdl2 b/src/Makefile.osx64-wx-sdl2 index e88dd86..dd2713b 100644 --- a/src/Makefile.osx64-wx-sdl2 +++ b/src/Makefile.osx64-wx-sdl2 @@ -6,7 +6,7 @@ CFLAGS = -D__unix=1 -DPCEM_RENDER_WITH_TIMER -DPCEM_RENDER_TIMER_LOOP -Dfopen64= OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cbm_io.o cdrom-ioctl-osx.o cdrom-image.o cdrom-null.o \ codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_common.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.c compaq.o config.o cpu.o \ device.o dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \ -hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ +hdd.o hdd_esdi.o hdd_file.o headland.o i430lx.o i430fx.o i430vx.o ide.o ide_atapi.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 \ laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o \ opti495.o paths.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o rtc_tc8521.o scat.o scsi.o scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o \ diff --git a/src/ibm.h b/src/ibm.h index 37e7101..6b10a9e 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -600,3 +600,5 @@ void saveconfig_global_only(); #define UNUSED(x) (void)x #define MIN(a, b) ((a) < (b) ? (a) : (b)) + +void ide_padstr(char *str, const char *src, int len); diff --git a/src/ide.c b/src/ide.c index a9cacd9..56f6f0a 100644 --- a/src/ide.c +++ b/src/ide.c @@ -25,21 +25,11 @@ #include "pic.h" #include "timer.h" #include "hdd_file.h" + #include "scsi.h" + #include "scsi_cd.h" #endif #include "ide.h" -/* Bits of 'atastat' */ -#define ERR_STAT 0x01 -#define DRQ_STAT 0x08 /* Data request */ -#define DSC_STAT 0x10 -#define SERVICE_STAT 0x10 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 - -/* Bits of 'error' */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* Media change request */ - /* ATA Commands */ #define WIN_SRST 0x08 /* ATAPI Device Reset */ #define WIN_RECAL 0x10 @@ -65,172 +55,9 @@ #define WIN_CHECK_POWER_MODE 0xE5 #define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */ -/* 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_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_SEND_DVD_STRUCTURE 0xad -#define GPCMD_SET_SPEED 0xbb -#define GPCMD_MECHANISM_STATUS 0xbd -#define GPCMD_READ_CD 0xbe - -/* 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_LBA_OUT_OF_RANGE 0x21 -#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 -#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 -#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)*/ -/* 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 - -#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, - [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, - [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_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_SEND_DVD_STRUCTURE] = CHECK_READY, /* Read DVD structure (NOT IMPLEMENTED YET) */ - [GPCMD_SET_SPEED] = 0, - [GPCMD_MECHANISM_STATUS] = 0, - [GPCMD_READ_CD] = CHECK_READY, - [0xBF] = 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; - -/* 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 -#define ATAPI_STATUS_COMPLETE 2 -#define ATAPI_STATUS_DATA 3 -#define ATAPI_STATUS_PACKET_REQ 4 -#define ATAPI_STATUS_PACKET_RECEIVED 5 -#define ATAPI_STATUS_READCD 6 -#define ATAPI_STATUS_REQ_SENSE 7 -#define ATAPI_STATUS_ERROR 0x80 -#define ATAPI_STATUS_ERROR_2 0x81 enum { @@ -239,6 +66,8 @@ enum IDE_CDROM }; +struct IDE; + typedef struct IDE { int type; @@ -249,10 +78,6 @@ typedef struct IDE uint8_t command; uint8_t fdisk; int pos; - int packlen; - int packetstatus; - int cdpos,cdlen; - uint8_t asc; int reset; uint16_t buffer[65536]; int irqstat; @@ -270,9 +95,12 @@ typedef struct IDE int tracks; #else hdd_file_t hdd_file; + atapi_device_t atapi; #endif } IDE; +int cdrom_channel = 2; + IDE ide_drives[4]; IDE *ext_ide; @@ -283,17 +111,13 @@ int (*ide_bus_master_read_sector)(int channel, uint8_t *data); int (*ide_bus_master_write_sector)(int channel, uint8_t *data); void (*ide_bus_master_set_irq)(int channel); -static void callnonreadcd(IDE *ide); -static void callreadcd(IDE *ide); -static void atapicommand(int ide_board); - int idecallback[2] = {0, 0}; int cur_ide[2]; uint8_t getstat(IDE *ide) { return ide->atastat; } -static inline void ide_irq_raise(IDE *ide) +void ide_irq_raise(IDE *ide) { // pclog("IDE_IRQ_RAISE\n"); if (!(ide->fdisk&2)) { @@ -353,8 +177,7 @@ void ide_irq_update(IDE *ide) * @param len Length of destination buffer to fill in. Strings shorter than * this length will be padded with spaces. */ -static void -ide_padstr(char *str, const char *src, int len) +void ide_padstr(char *str, const char *src, int len) { int i, v; @@ -368,29 +191,6 @@ ide_padstr(char *str, const char *src, int len) } } -/** - * Copy a string into a buffer, padding with spaces. Does not add string - * terminator. - * - * @param buf Destination buffer - * @param buf_size Size of destination buffer to fill in. Strings shorter than - * this length will be padded with spaces. - * @param src Source string - */ -static void -ide_padstr8(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] = ' '; - } - } -} - /** * Fill in ide->buffer with the output of the "IDENTIFY DEVICE" command */ @@ -436,127 +236,6 @@ static void ide_identify(IDE *ide) ide->buffer[80] = 0xe; /*ATA-1 to ATA-3 supported*/ } -/** - * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command - */ -static void ide_atapi_identify(IDE *ide) -{ - memset(ide->buffer, 0, 512); - - 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 + 27), "PCemCD", 40); /* Model */ -#endif - ide->buffer[49] = 0x200; /* LBA supported */ -} - -/** - * 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 ? 9 : 7] : 0xFF; -} - /* * Return the sector offset for the current register values */ @@ -706,9 +385,6 @@ void resetide(void) ide_drives[d].board = (d & 2) ? 1 : 0; } - 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; if (hdd_controller_current_is_ide()) { @@ -722,11 +398,11 @@ void resetide(void) for (d = 0; d < 4; d++) { ide_drives[d].drive = d; - ide_drives[d].packetstatus = 0xFF; if ((cdrom_channel == d) && cdrom_enabled) { ide_drives[d].type = IDE_CDROM; + scsi_bus_atapi_init(&ide_drives[d].atapi.bus, &scsi_cd, d); } else { @@ -734,26 +410,27 @@ void resetide(void) } ide_set_signature(&ide_drives[d]); + + ide_drives[d].atapi.ide = &ide_drives[d]; + ide_drives[d].atapi.board = (d & 2) ? 1 : 0; + ide_drives[d].atapi.atastat = &ide_drives[d].atastat; + ide_drives[d].atapi.error = &ide_drives[d].error; + ide_drives[d].atapi.cylinder = &ide_drives[d].cylinder; } } #endif + cur_ide[0] = 0; cur_ide[1] = 2; - -// ide_drives[1].type = IDE_CDROM; - - page_flags[GPMODE_CDROM_AUDIO_PAGE] &= ~PAGE_CHANGED; } + int idetimes=0; void writeidew(int ide_board, uint16_t val) { IDE *ide = &ide_drives[cur_ide[ide_board]]; - /*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)) { @@ -764,58 +441,26 @@ void writeidew(int ide_board, uint16_t val) #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->command == WIN_PACKETCMD) + { + atapi_data_write(&ide->atapi, val); + } + else + { + 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>=(ide->packlen+2)) + if (ide->pos>=512) { - ide->packetstatus = ATAPI_STATUS_PACKET_RECEIVED; + ide->pos=0; + ide->atastat = BUSY_STAT; timer_process(); - idecallback[ide_board]=6*IDE_TIME; + if (ide->command == WIN_WRITE_MULTIPLE) + callbackide(ide_board); + else + idecallback[ide_board] = 6 * IDE_TIME; timer_update_outstanding(); -// pclog("Packet over!\n"); - ide_irq_lower(ide); } - return; - } - else if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) - return; - else if (ide->command == WIN_PACKETCMD && ide->pos>=0xC) - { - ide->pos=0; - ide->atastat = BUSY_STAT; - ide->packetstatus = ATAPI_STATUS_COMMAND; -/* idecallback[ide_board]=6*IDE_TIME;*/ - timer_process(); - callbackide(ide_board); - timer_update_outstanding(); -// idecallback[ide_board]=60*IDE_TIME; -// if ((ide->buffer[0]&0xFF)==0x43) idecallback[ide_board]=1*IDE_TIME; -// pclog("Packet now waiting!\n"); -/* if (ide->buffer[0]==0x243) - { - idetimes++; - output=3; - }*/ - } - else if (ide->pos>=512) - { - ide->pos=0; - ide->atastat = BUSY_STAT; - timer_process(); - if (ide->command == WIN_WRITE_MULTIPLE) - callbackide(ide_board); - else - idecallback[ide_board]=6*IDE_TIME; - timer_update_outstanding(); } } @@ -1078,12 +723,19 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) return; case WIN_PACKETCMD: /* ATAPI Packet */ - ide->packetstatus = ATAPI_STATUS_IDLE; + if (ide->type == IDE_CDROM) + atapi_command_start(&ide->atapi); + ide->atastat = BUSY_STAT; timer_process(); + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + + ide->atapi.bus_state = 0; +/* timer_process(); idecallback[ide_board]=1;//30*IDE_TIME; timer_update_outstanding(); - ide->pos=0; + ide->pos=0;*/ return; case 0xF0: @@ -1158,7 +810,10 @@ uint8_t readide(int ide_board, uint16_t addr) case 0x1F2: /* Sector count */ // pclog("Read sector count %02X\n",ide->secount); - temp = (uint8_t)ide->secount; + if (ide->type == IDE_CDROM && ide->command == WIN_PACKETCMD) + temp = atapi_read_iir(&ide->atapi); + else + temp = (uint8_t)ide->secount; break; case 0x1F3: /* Sector */ @@ -1191,6 +846,13 @@ uint8_t readide(int ide_board, uint16_t addr) { // pclog("Read CDROM status %02X\n",(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0)); temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + if (ide->command == WIN_PACKETCMD) + { + if (atapi_read_drq(&ide->atapi)) + temp |= DRQ_STAT; + else + temp &= ~DRQ_STAT; + } } else { @@ -1213,6 +875,13 @@ uint8_t readide(int ide_board, uint16_t addr) { // pclog("Read CDROM status %02X\n",(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0)); temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + if (ide->command == WIN_PACKETCMD) + { + if (atapi_read_drq(&ide->atapi)) + temp |= DRQ_STAT; + else + temp &= ~DRQ_STAT; + } } else { @@ -1241,31 +910,19 @@ uint16_t readidew(int ide_board) // 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))) - { - callnonreadcd(ide); - return temp; - } - if ((ide->pos>=512 && ide->command != WIN_PACKETCMD) || (ide->command == WIN_PACKETCMD && ide->pos>=ide->packlen)) + if (ide->command == WIN_PACKETCMD) { -// pclog("Over! packlen %i %i\n",ide->packlen,ide->pos); - ide->pos=0; - if (ide->command == WIN_PACKETCMD)// && ide.packetstatus==6) - { -// pclog("Call readCD\n"); - callreadcd(ide); - } - else + temp = atapi_data_read(&ide->atapi); + } + else + { + temp = ide->buffer[ide->pos >> 1]; + ide->pos += 2; + if (ide->pos >= 512 && ide->command) { +// pclog("Over! packlen %i %i\n",ide->packlen,ide->pos); + ide->pos = 0; ide->atastat = READY_STAT | DSC_STAT; - ide->packetstatus = ATAPI_STATUS_IDLE; if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) { ide->secount = (ide->secount - 1) & 0xff; @@ -1275,9 +932,9 @@ uint16_t readidew(int ide_board) ide->atastat = BUSY_STAT; timer_process(); if (ide->command == WIN_READ_MULTIPLE) - callbackide(ide_board); + callbackide(ide_board); else - idecallback[ide_board]=6*IDE_TIME; + idecallback[ide_board] = 6 * IDE_TIME; timer_update_outstanding(); // pclog("set idecallback\n"); // callbackide(ide_board); @@ -1287,6 +944,9 @@ uint16_t readidew(int ide_board) } } } +#ifdef _RPCEMU_BIG_ENDIAN + temp=(temp>>8)|(temp<<8); +#endif // pclog("Read IDEw %04X\n",temp); return temp; } @@ -1304,6 +964,7 @@ void callbackide(int ide_board) { IDE *ide = &ide_drives[cur_ide[ide_board]]; IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; + atapi_device_t *atapi_dev = &ide->atapi; #if RPCEMU_IDE off64_t addr; int c; @@ -1672,7 +1333,8 @@ void callbackide(int ide_board) case WIN_PIDENTIFY: /* Identify Packet Device */ if (IDE_DRIVE_IS_CDROM(ide)) { // pclog("ATAPI identify\n"); - ide_atapi_identify(ide); + atapi_dev->bus.devices[0]->atapi_identify(ide->buffer, atapi_dev->bus.device_data[0]); + ide->pos=0; ide->error=0; ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; @@ -1734,77 +1396,9 @@ void callbackide(int ide_board) case WIN_PACKETCMD: /* ATAPI Packet */ if (!IDE_DRIVE_IS_CDROM(ide)) goto abort_cmd; -// pclog("Packet callback! %i %08X\n",ide->packetstatus,ide); - - if (ide->packetstatus == ATAPI_STATUS_IDLE) - { - readcdmode=0; - ide->pos=0; - ide->secount = (uint8_t)((ide->secount&0xF8)|1); - ide->atastat = READY_STAT | DRQ_STAT |(ide->atastat&ERR_STAT); - //ide_irq_raise(ide); -// pclog("1 Preparing to recieve packet max DRQ count %04X\n",ide->cylinder); - } - else if (ide->packetstatus == ATAPI_STATUS_COMMAND) - { - ide->atastat = BUSY_STAT|(ide->atastat&ERR_STAT); -// pclog("Running ATAPI command 2\n"); - atapicommand(ide_board); -// exit(-1); - } - else if (ide->packetstatus == ATAPI_STATUS_COMPLETE) - { -// pclog("packetstatus==2\n"); - ide->atastat = READY_STAT; - ide->secount=3; - ide_irq_raise(ide); -// if (iomd.irqb.mask&2) output=1; - } - else if (ide->packetstatus == ATAPI_STATUS_DATA) - { - ide->atastat = READY_STAT|DRQ_STAT|(ide->atastat&ERR_STAT); -// rpclog("Recieve data packet 3! %02X\n",ide->atastat); - ide_irq_raise(ide); - ide->packetstatus=0xFF; - } - else if (ide->packetstatus == ATAPI_STATUS_PACKET_REQ) - { - ide->atastat = 0x58 | (ide->atastat & ERR_STAT); -// pclog("Send data packet 4!\n"); - ide_irq_raise(ide); -// ide.packetstatus=5; - ide->pos=2; - } - else if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) - { -// pclog("Packetstatus 5 !\n"); - atapicommand(ide_board); - } - else if (ide->packetstatus == ATAPI_STATUS_READCD) /*READ CD callback*/ - { - ide->atastat = DRQ_STAT|(ide->atastat&ERR_STAT); -// pclog("Recieve data packet 6!\n"); - ide_irq_raise(ide); -// ide.packetstatus=0xFF; - } - else if (ide->packetstatus == ATAPI_STATUS_REQ_SENSE) /*REQUEST SENSE callback #1*/ - { - pclog("REQUEST SENSE callback #1: setting status to 0x5A\n"); - ide->atastat = 0x58 | (ide->atastat & ERR_STAT); - ide_irq_raise(ide); - } - else if (ide->packetstatus == ATAPI_STATUS_ERROR) /*Error callback*/ - { -// pclog("Packet error\n"); - ide->atastat = READY_STAT | ERR_STAT; - ide_irq_raise(ide); - } - else if (ide->packetstatus == ATAPI_STATUS_ERROR_2) /*Error callback with atastat already set - needed for the disc change stuff.*/ - { - //pclog("Packet check status\n"); - ide->atastat = ERR_STAT; - ide_irq_raise(ide); - } + + atapi_process_packet(atapi_dev); + return; } @@ -1828,968 +1422,6 @@ void ide_callback_sec() callbackide(1); } -/*ATAPI CD-ROM emulation*/ - -struct -{ - int sensekey,asc,ascq; -} atapi_sense; - -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; -} - -void atapi_cmd_error(IDE *ide, uint8_t sensekey, uint8_t asc) -{ - ide->error = (sensekey << 4); - ide->atastat = READY_STAT | ERR_STAT; - ide->secount = (ide->secount & ~7) | 3; - ide->packetstatus = 0x80; - idecallback[ide->board]=50*IDE_TIME; -} - -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) - ide->cylinder = 0xfffe; - - if ((ide->cylinder & 1) && !(alloc_length <= ide->cylinder)) - { - pclog("Odd byte count (0x%04x) to ATAPI command 0x%02x, using 0x%04x\n", ide->cylinder, command, ide->cylinder - 1); - ide->cylinder--; - } - - if (alloc_length < 0) - fatal("Allocation length < 0\n"); - if (alloc_length == 0) - alloc_length = ide->cylinder; - - // Status: 0x80 (busy), 0x08 (drq), 0x01 (err) - // Interrupt: 0x02 (i_o), 0x01 (c_d) - /* No atastat setting: PCem actually emulates the callback cycle. */ - ide->secount = 2; - - // no bytes transferred yet - ide->pos = 0; - - if ((ide->cylinder > req_length) || (ide->cylinder == 0)) - ide->cylinder = req_length; - if (ide->cylinder > alloc_length) - ide->cylinder = alloc_length; - - //pclog("atapi_command_send_init(ide, %02X, %04X, %04X)\n", command, req_length, alloc_length); - //pclog("IDE settings: Pos=%08X, Secount=%08X, Cylinder=%08X\n", ide->pos, ide->secount, ide->cylinder); -} - -static void atapi_command_ready(int ide_board, int packlen) -{ - IDE *ide = &ide_drives[cur_ide[ide_board]]; - ide->packetstatus = ATAPI_STATUS_REQ_SENSE; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=packlen; -} - -static void atapi_sense_clear(int command, int ignore_ua) -{ - if ((atapi_sense.sensekey == SENSE_UNIT_ATTENTION) || ignore_ua) - { - atapi_prev=command; - atapi_sense.sensekey=0; - atapi_sense.asc=0; - atapi_sense.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; - uint8_t rcdmode = 0; - 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; - unsigned idx = 0; - unsigned size_idx; - unsigned preamble_len; - int toc_format; - int temp_command; - int alloc_length; - int completed; - -#ifndef RPCEMU_IDE - pclog("New ATAPI command %02X %i\n",idebufferb[0],ins); -#endif -// readflash_set(READFLASH_HDD, ide->drive, 1); - msf=idebufferb[1]&2; - ide->cdlen=0; - - is_error = 0; - - if (atapi->medium_changed()) - { - atapi_insert_cdrom(); - } - /*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) - { - atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); - 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)) - { - /* GPCMD_TEST_UNIT_READY is NOT supposed to clear sense! */ - atapi_sense_clear(idebufferb[0], 1); - } - - /*If our state has been set to errored, clear it, and return.*/ - if (is_error) - { - is_error = 0; - return; - } - - if ((atapi_cmd_table[idebufferb[0]] & CHECK_READY) && !atapi->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; - return; - } - - prev_status = cd_status; - cd_status = atapi->status(); - if (((prev_status == CD_STATUS_PLAYING) || (prev_status == CD_STATUS_PAUSED)) && ((cd_status != CD_STATUS_PLAYING) && (cd_status != CD_STATUS_PAUSED))) - { - completed = 1; - } - else - { - completed = 0; - } - - switch (idebufferb[0]) - { - case GPCMD_TEST_UNIT_READY: - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_REQUEST_SENSE: /* Used by ROS 4+ */ - alloc_length = idebufferb[4]; - temp_command = idebufferb[0]; - atapi_command_send_init(ide, temp_command, 18, alloc_length); - - /*Will return 18 bytes of 0*/ - memset(idebufferb,0,512); - - idebufferb[0]=0x80|0x70; - - if ((atapi_sense.sensekey > 0) || (cd_status < CD_STATUS_PLAYING)) - { - if (completed) - { - idebufferb[2]=SENSE_ILLEGAL_REQUEST; - idebufferb[12]=ASC_AUDIO_PLAY_OPERATION; - idebufferb[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; - } - else - { - idebufferb[2]=atapi_sense.sensekey; - idebufferb[12]=atapi_sense.asc; - idebufferb[13]=atapi_sense.ascq; - } - } - else - { - idebufferb[2]=SENSE_ILLEGAL_REQUEST; - idebufferb[12]=ASC_AUDIO_PLAY_OPERATION; - idebufferb[13]=(cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; - } - - idebufferb[7]=10; - - // pclog("REQUEST SENSE start\n"); - atapi_command_ready(ide_board, 18); - - /* Clear the sense stuff as per the spec. */ - atapi_sense_clear(temp_command, 0); - break; - - case GPCMD_SET_SPEED: - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_MECHANISM_STATUS: /*0xbd*/ - alloc_length = (idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; - - if (alloc_length == 0) - fatal("Zero allocation length to MECHANISM STATUS not impl.\n"); - - atapi_command_send_init(ide, idebufferb[0], 8, alloc_length); - - idebufferb[0] = 0; - idebufferb[1] = 0; - idebufferb[2] = 0; - idebufferb[3] = 0; - idebufferb[4] = 0; - idebufferb[5] = 1; - idebufferb[6] = 0; - idebufferb[7] = 0; - // len = 8; - - atapi_command_ready(ide_board, 8); - break; - - case GPCMD_READ_TOC_PMA_ATIP: -// pclog("Read TOC ready? %08X\n",ide); - toctimes++; -// if (toctimes==2) output=3; -// pclog("Read TOC %02X\n",idebufferb[9]); - toc_format = idebufferb[2] & 0xf; - if (toc_format == 0) - toc_format = (idebufferb[9]>>6) & 3; - switch (toc_format) - { - 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); - 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); - 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); - 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) - ide->error |= MCR_ERR; - ide->packetstatus = ATAPI_STATUS_ERROR; - idecallback[ide_board]=50*IDE_TIME; - return; -/* pclog("Bad read TOC format\n"); - pclog("Packet data :\n"); - for (c=0;c<12;c++) - pclog("%02X ",idebufferb[c]); - pclog("\n"); - exit(-1);*/ - } -// pclog("ATAPI buffer len %i\n",len); - ide->packetstatus = ATAPI_STATUS_DATA; - ide->cylinder=len; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=len; - return; - - case GPCMD_READ_CD: -// pclog("Read CD : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]); - rcdmode = idebufferb[9] & 0xF8; - if ((rcdmode != 0x10) && (rcdmode != 0xF8)) - { - 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_ILLEGAL_OPCODE; - ide->packetstatus = ATAPI_STATUS_ERROR; - idecallback[ide_board]=50*IDE_TIME; - break; -// pclog("Bad flags bits %02X\n",idebufferb[9]); -// exit(-1); - } -/* if (idebufferb[6] || idebufferb[7] || (idebufferb[8]!=1)) - { - pclog("More than 1 sector!\n"); - exit(-1); - }*/ - ide->cdlen=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; - 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); - else - atapi->readsector_raw(idebufferb,ide->cdpos); -#ifndef RPCEMU_IDE - readflash_set(READFLASH_HDC, ide->drive); -#endif - readcdmode = (rcdmode == 0xF8); - ide->cdpos++; - ide->cdlen--; - if (ide->cdlen >= 0) - ide->packetstatus = ATAPI_STATUS_READCD; - else - ide->packetstatus = ATAPI_STATUS_DATA; - ide->cylinder=(idebufferb[9] == 0x10) ? 2048 : 2352; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=(idebufferb[9] == 0x10) ? 2048 : 2352; - return; - - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: -// pclog("Read 10 : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]); - - readcdmode = 0; - - if (idebufferb[0] == GPCMD_READ_6) - { - ide->cdlen=idebufferb[4]; - ide->cdpos=((((uint32_t) idebufferb[1]) & 0x1f)<<16)|(((uint32_t) idebufferb[2])<<8)|((uint32_t) idebufferb[3]); - } - else if (idebufferb[0] == GPCMD_READ_10) - { - ide->cdlen=(idebufferb[7]<<8)|idebufferb[8]; - ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - } - else - { - ide->cdlen=(((uint32_t) idebufferb[6])<<24)|(((uint32_t) idebufferb[7])<<16)|(((uint32_t) idebufferb[8])<<8)|((uint32_t) idebufferb[9]); - ide->cdpos=(((uint32_t) idebufferb[2])<<24)|(((uint32_t) idebufferb[3])<<16)|(((uint32_t) idebufferb[4])<<8)|((uint32_t) idebufferb[5]); - } - if (!ide->cdlen) - { -// pclog("All done - callback set\n"); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=20*IDE_TIME; - break; - } - - if (atapi->readsector(idebufferb,ide->cdpos)) - { -// pclog("Read sector failed\n"); - atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; - atapi_sense.asc = ASC_LBA_OUT_OF_RANGE; - atapi_sense.ascq = 0; - - 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_ILLEGAL_OPCODE; - ide->packetstatus = ATAPI_STATUS_ERROR; - idecallback[ide_board]=50*IDE_TIME; - break; - } -#ifndef RPCEMU_IDE - readflash_set(READFLASH_HDC, ide->drive); -#endif - ide->cdpos++; - ide->cdlen--; - if (ide->cdlen >= 0) - ide->packetstatus = ATAPI_STATUS_READCD; - else - ide->packetstatus = ATAPI_STATUS_DATA; - ide->cylinder=2048; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=2048; - return; - - case GPCMD_READ_HEADER: - if (msf) - { - 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_ILLEGAL_OPCODE; - ide->packetstatus = ATAPI_STATUS_ERROR; - idecallback[ide_board]=50*IDE_TIME; - break; -// pclog("Read Header MSF!\n"); -// exit(-1); - } - for (c=0;c<4;c++) idebufferb[c+4]=idebufferb[c+2]; - idebufferb[0]=1; /*2048 bytes user data*/ - idebufferb[1]=idebufferb[2]=idebufferb[3]=0; - - ide->packetstatus = ATAPI_STATUS_DATA; - ide->cylinder=8; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=8; - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - temp_command = idebufferb[0]; - - if (temp_command == GPCMD_MODE_SENSE_6) - len=idebufferb[4]; - else - len=(idebufferb[8]|(idebufferb[7]<<8)); - - temp=idebufferb[2] & 0x3F; - - memset(idebufferb, 0, len); - alloc_length = len; - // for (c=0;catastat = 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); - 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; - return; - } - - if (temp_command == GPCMD_MODE_SENSE_6) - { - len = ide_atapi_mode_sense(ide,4,temp); - idebufferb[0] = len - 1; - idebufferb[1]=3; /*120mm data CD-ROM*/ - } - else - { - len = ide_atapi_mode_sense(ide,8,temp); - idebufferb[0]=(len - 2)>>8; - idebufferb[1]=(len - 2)&255; - idebufferb[2]=3; /*120mm data CD-ROM*/ - } - - atapi_command_send_init(ide, temp_command, len, alloc_length); - - atapi_command_ready(ide_board, len); - return; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) - { - ide->atastat = READY_STAT; - ide->secount=3; -// pclog("Recieve data packet!\n"); - ide_irq_raise(ide); - ide->packetstatus=0xFF; - ide->pos=0; - // pclog("Length - %02X%02X\n",idebufferb[0],idebufferb[1]); -// pclog("Page %02X length %02X\n",idebufferb[8],idebufferb[9]); - } - else - { - if (idebufferb[0] == GPCMD_MODE_SELECT_6) - { - len=idebufferb[4]; - prefix_len = 6; - } - else - { - len=(idebufferb[7]<<8)|idebufferb[8]; - prefix_len = 10; - } - page_current = idebufferb[2]; - if (page_flags[page_current] & PAGE_CHANGEABLE) - page_flags[GPMODE_CDROM_AUDIO_PAGE] |= PAGE_CHANGED; - ide->packetstatus = ATAPI_STATUS_PACKET_REQ; - ide->cylinder=len; - ide->secount=0; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=len; -/* pclog("Waiting for ARM to send packet %i\n",len); - pclog("Packet data :\n"); - for (c=0;c<12;c++) - pclog("%02X ",idebufferb[c]); - pclog("\n");*/ - } - return; - - case GPCMD_GET_EVENT_STATUS_NOTIFICATION: /*0x4a*/ - temp_command = idebufferb[0]; - alloc_length = (idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; - - { - struct __attribute__((__packed__)) - { - 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 __attribute__((__packed__)) - { - uint16_t len; - uint8_t notification_class; - uint8_t supported_events; - } *gesn_event_header; - unsigned int used_len; - - gesn_cdb = (void *)idebufferb; - gesn_event_header = (void *)idebufferb; - - /* 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. */ - ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; - idecallback[ide_board]=50*IDE_TIME; - atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); - 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; - 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 = atapi_event_status(ide, idebufferb); - } - else - { - gesn_event_header->notification_class = 0x80; /* No event available */ - used_len = sizeof(*gesn_event_header); - } - len = used_len; - gesn_event_header->len = used_len - sizeof(*gesn_event_header); - } - - atapi_command_send_init(ide, temp_command, len, alloc_length); - - atapi_command_ready(ide_board, len); - break; - - case GPCMD_READ_DISC_INFORMATION: - idebufferb[1] = 32; - idebufferb[2] = 0xe; /* last session complete, disc finalized */ - idebufferb[3] = 1; /* first track on disc */ - idebufferb[4] = 1; /* # of sessions */ - idebufferb[5] = 1; /* first track of last session */ - idebufferb[6] = 1; /* last track of last session */ - idebufferb[7] = 0x20; /* unrestricted use */ - idebufferb[8] = 0x00; /* CD-ROM */ - - len=34; - ide->packetstatus = ATAPI_STATUS_DATA; - ide->cylinder=len; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=60*IDE_TIME; - ide->packlen=len; - break; - - case GPCMD_PLAY_AUDIO_10: - case GPCMD_PLAY_AUDIO_12: - case GPCMD_PLAY_AUDIO_MSF: - /*This is apparently deprecated in the ATAPI spec, and apparently - has been since 1995 (!). Hence I'm having to guess most of it*/ - if (idebufferb[0] == GPCMD_PLAY_AUDIO_10) - { - pos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - len=(idebufferb[7]<<8)|idebufferb[8]; - } - else if (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) - { - pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - len=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; - } - else - { - pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; - len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; - } - - - if ((cdrom_drive < 1) || (cd_status <= CD_STATUS_DATA_ONLY) || - !atapi->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; - ide->packetstatus = ATAPI_STATUS_ERROR; - idecallback[ide_board]=50*IDE_TIME; - atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); - break; - } - - atapi->playaudio(pos, len, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_READ_SUBCHANNEL: - temp=idebufferb[2]&0x40; - if (idebufferb[3]!=1) - { -// 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) - ide->error |= MCR_ERR; - // ide->discchanged=1; /* Fixes some bugs with NT 3.1. */ - atapi_sense.asc = ASC_ILLEGAL_OPCODE; - ide->packetstatus = ATAPI_STATUS_ERROR; - idecallback[ide_board]=50*IDE_TIME; - break; -/* pclog("Bad read subchannel!\n"); - pclog("Packet data :\n"); - for (c=0;c<12;c++) - pclog("%02X\n",idebufferb[c]); - dumpregs(); - exit(-1);*/ - } - pos=0; - idebufferb[pos++]=0; - 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); -// pclog("Read subchannel complete - audio status %02X\n",idebufferb[1]); - len=11+5; - if (!temp) len=4; - ide->packetstatus = ATAPI_STATUS_DATA; - ide->cylinder=len; - ide->secount=2; - ide->pos=0; - idecallback[ide_board]=1000*IDE_TIME; - ide->packlen=len; - break; - - case GPCMD_START_STOP_UNIT: - if (idebufferb[4]!=2 && idebufferb[4]!=3 && idebufferb[4]) - { - 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_ILLEGAL_OPCODE; - ide->packetstatus = ATAPI_STATUS_ERROR; - idecallback[ide_board]=50*IDE_TIME; - break; -/* pclog("Bad start/stop unit command\n"); - pclog("Packet data :\n"); - for (c=0;c<12;c++) - pclog("%02X\n",idebufferb[c]); - exit(-1);*/ - } - if (!idebufferb[4]) atapi->stop(); - else if (idebufferb[4]==2) atapi->eject(); - else atapi->load(); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_INQUIRY: - page_code = idebufferb[2]; - max_len = idebufferb[4]; - alloc_length = max_len; - temp_command = idebufferb[0]; - - if (idebufferb[1] & 1) - { - preamble_len = 4; - size_idx = 3; - - idebufferb[idx++] = 05; - idebufferb[idx++] = page_code; - idebufferb[idx++] = 0; - - idx++; - - switch (page_code) - { - case 0x00: - idebufferb[idx++] = 0x00; - idebufferb[idx++] = 0x83; - break; - 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; - return; - } - idebufferb[idx++] = 0x02; - idebufferb[idx++] = 0x00; - idebufferb[idx++] = 0x00; - idebufferb[idx++] = 20; - ide_padstr8(idebufferb + idx, 20, "53R141"); /* Serial */ - idx += 20; - - if (idx + 72 > max_len) - { - goto atapi_out; - } - idebufferb[idx++] = 0x02; - idebufferb[idx++] = 0x01; - idebufferb[idx++] = 0x00; - idebufferb[idx++] = 68; - ide_padstr8(idebufferb + idx, 8, "PCem"); /* Vendor */ - idx += 8; - ide_padstr8(idebufferb + idx, 40, "PCemCD 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; - return; - } - } - else - { - preamble_len = 5; - size_idx = 4; - - idebufferb[0] = 5; /*CD-ROM*/ - idebufferb[1] = 0x80; /*Removable*/ - idebufferb[2] = 0; - idebufferb[3] = 0x21; - idebufferb[4] = 31; - 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, "PCem"); /* Vendor */ - ide_padstr8(idebufferb + 16, 16, "PCemCD"); /* Product */ -#endif - ide_padstr8(idebufferb + 32, 4, "1.0"); /* Revision */ - - idx = 36; - } - -atapi_out: - idebufferb[size_idx] = idx - preamble_len; - len=idx; - - atapi_command_send_init(ide, temp_command, len, alloc_length); - - atapi_command_ready(ide_board, len); - break; - - case GPCMD_PREVENT_REMOVAL: - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_PAUSE_RESUME: - if (idebufferb[8]&1) atapi->resume(); - else atapi->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); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_READ_CDROM_CAPACITY: - atapi_command_send_init(ide, 0, 8, 8); - size = atapi->size(); - idebufferb[0] = (size >> 24) & 0xff; - idebufferb[1] = (size >> 16) & 0xff; - idebufferb[2] = (size >> 8) & 0xff; - idebufferb[3] = size & 0xff; - idebufferb[4] = (2048 >> 24) & 0xff; - idebufferb[5] = (2048 >> 16) & 0xff; - idebufferb[6] = (2048 >> 8) & 0xff; - idebufferb[7] = 2048 & 0xff; - len=8; - atapi_command_ready(ide_board, len); - break; - - case GPCMD_SEND_DVD_STRUCTURE: - default: - 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.sensekey = SENSE_ILLEGAL_REQUEST; - atapi_sense.asc = ASC_ILLEGAL_OPCODE; - ide->packetstatus = ATAPI_STATUS_ERROR; - idecallback[ide_board]=50*IDE_TIME; - break; - - case GPCMD_STOP_PLAY_SCAN: - atapi->stop(); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide_board]=50*IDE_TIME; - break; -/* default: - pclog("Bad ATAPI command %02X\n",idebufferb[0]); - pclog("Packet data :\n"); - for (c=0;c<12;c++) - pclog("%02X\n",idebufferb[c]); - exit(-1);*/ - } -} - -static void callnonreadcd(IDE *ide) /* Callabck for non-Read CD commands */ -{ - ide_irq_lower(ide); - if (ide->pos >= ide->packlen) - { - // pclog("Command finished, setting callback\n"); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide->board]=20*IDE_TIME; - } - else - { - // pclog("Command not finished, keep sending data\n"); - ide->atastat = BUSY_STAT; - ide->packetstatus = ATAPI_STATUS_REQ_SENSE; - ide->cylinder=2; - ide->secount=2; - idecallback[ide->board]=60*IDE_TIME; - } -} - -static void callreadcd(IDE *ide) -{ - ide_irq_lower(ide); - if (ide->cdlen<=0) - { -// pclog("All done - callback set\n"); - ide->packetstatus = ATAPI_STATUS_COMPLETE; - idecallback[ide->board]=20*IDE_TIME; - ide->atastat = BUSY_STAT; - return; - } -// pclog("Continue readcd! %i blocks left\n",ide->cdlen); - ide->atastat = BUSY_STAT; - - if (readcdmode) - atapi->readsector_raw((uint8_t *) ide->buffer, ide->cdpos); - else - atapi->readsector((uint8_t *) ide->buffer, ide->cdpos); -#ifndef RPCEMU_IDE - readflash_set(READFLASH_HDC, ide->drive); -#endif - ide->cdpos++; - ide->cdlen--; - ide->packetstatus = ATAPI_STATUS_READCD; - ide->cylinder=readcdmode ? 2352 : 2048; - ide->secount=2; - ide->pos=0; - idecallback[ide->board]=60*IDE_TIME; - ide->packlen=readcdmode ? 2352 : 2048; -} - void ide_write_pri(uint16_t addr, uint8_t val, void *priv) diff --git a/src/ide.h b/src/ide.h index fc7936b..ea16483 100644 --- a/src/ide.h +++ b/src/ide.h @@ -16,6 +16,7 @@ extern void ide_sec_enable(); extern void ide_pri_disable(); extern void ide_sec_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)); +void ide_irq_raise(struct IDE *ide); #include "ide_atapi.h" @@ -34,4 +35,16 @@ uint32_t atapi_get_cd_volume(int channel); extern device_t ide_device; +/* Bits of 'atastat' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + #endif //__IDE__ diff --git a/src/ide_atapi.c b/src/ide_atapi.c new file mode 100644 index 0000000..1faa977 --- /dev/null +++ b/src/ide_atapi.c @@ -0,0 +1,469 @@ +#include "ibm.h" +#include "ide.h" +#include "ide_atapi.h" +#include "scsi.h" +#include "timer.h" + +#define IDE_TIME (5 * 100 * (1 << TIMER_SHIFT)) + +#define ATAPI_STATE_IDLE 0 +#define ATAPI_STATE_COMMAND 1 +#define ATAPI_STATE_GOT_COMMAND 2 +#define ATAPI_STATE_NEXT_PHASE 3 +#define ATAPI_STATE_READ_STATUS 4 +#define ATAPI_STATE_READ_MESSAGE 5 +#define ATAPI_STATE_END_PHASE 6 +#define ATAPI_STATE_READ_DATA 7 +#define ATAPI_STATE_READ_DATA_WAIT 8 +#define ATAPI_STATE_WRITE_DATA 9 +#define ATAPI_STATE_WRITE_DATA_WAIT 10 + +ATAPI *atapi; + +void atapi_data_write(atapi_device_t *atapi_dev, uint16_t val) +{ + switch (atapi_dev->state) + { + case ATAPI_STATE_COMMAND: + atapi_dev->command[atapi_dev->command_pos++] = val & 0xff; + atapi_dev->command[atapi_dev->command_pos++] = val >> 8; + if (atapi_dev->command_pos >= 12) + { + atapi_dev->state = ATAPI_STATE_GOT_COMMAND; + idecallback[atapi_dev->board] = 6 * IDE_TIME; + } + break; + + case ATAPI_STATE_WRITE_DATA_WAIT: + atapi_dev->data[atapi_dev->data_write_pos++] = val & 0xff; + atapi_dev->data[atapi_dev->data_write_pos++] = val >> 8; +// pclog("Write ATAPI data %i %i %i\n", atapi_dev->data_write_pos, atapi_dev->data_read_pos, idecallback[atapi_dev->board]); + if (atapi_dev->data_write_pos >= atapi_dev->data_read_pos) + { + atapi_dev->bus_state = 0; + atapi_dev->state = ATAPI_STATE_WRITE_DATA; + idecallback[atapi_dev->board] = 6 * IDE_TIME; + } + break; + } +} + +uint16_t atapi_data_read(atapi_device_t *atapi_dev) +{ + uint16_t temp = 0xffff; + + switch (atapi_dev->state) + { + case ATAPI_STATE_READ_DATA_WAIT: + if (atapi_dev->data_read_pos >= atapi_dev->data_write_pos) + { +// pclog("ATAPI_STATE_READ_DATA_WAIT - out of data!\n"); + break; + } + + temp = atapi_dev->data[atapi_dev->data_read_pos++]; + if (atapi_dev->data_read_pos < atapi_dev->data_write_pos) + temp |= (atapi_dev->data[atapi_dev->data_read_pos++] << 8); +// pclog("Read data %04x\n", temp); + if (atapi_dev->data_read_pos >= atapi_dev->data_write_pos) + { + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + idecallback[atapi_dev->board] = 6*IDE_TIME; + } + break; + } + + return temp; +} + +static int wait_for_bus(scsi_bus_t *bus, int state, int req_needed) +{ + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(bus); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) == state && (bus_state & BUS_BSY)) + { + if (!req_needed || (bus_state & BUS_REQ)) + return 1; + } + } + + return 0; +} + +void atapi_command_start(atapi_device_t *atapi) +{ + scsi_bus_t *bus = &atapi->bus; + + scsi_bus_update(bus, BUS_SEL | BUS_SETDATA(1 << 0)); + if (!(scsi_bus_read(bus) & BUS_BSY)) + fatal("STATE_SCSI_SELECT failed to select target\n"); + + scsi_bus_update(bus, 0); + if (!(scsi_bus_read(bus) & BUS_BSY)) + fatal("STATE_SCSI_SELECT failed to select target 2\n"); + + /*Device should now be selected*/ + if (!wait_for_bus(bus, BUS_CD, 1)) + fatal("Device failed to request command\n"); + + atapi->state = ATAPI_STATE_COMMAND; + atapi->command_pos = 0; +} + +uint8_t atapi_read_iir(atapi_device_t *atapi_dev) +{ + uint8_t val = 0; + int bus_status = atapi_dev->bus_state;//scsi_bus_read(&atapi_dev->bus); + + if (bus_status & BUS_CD) + val |= 1; + if (bus_status & BUS_IO) + val |= 2; + +// pclog("Read IIR %02X %02x\n", val, bus_status); + + return val; +} + +uint8_t atapi_read_drq(atapi_device_t *atapi_dev) +{ + return atapi_dev->bus_state & BUS_REQ; +} + +void atapi_process_packet(atapi_device_t *atapi_dev) +{ +// pclog("atapi_process_packet: state=%i\n", atapi_dev->state); + switch (atapi_dev->state) + { + case ATAPI_STATE_COMMAND: + *atapi_dev->atastat = READY_STAT | (*atapi_dev->atastat & ERR_STAT); + atapi_dev->max_transfer_len = *atapi_dev->cylinder; + atapi_dev->bus_state = BUS_CD | BUS_REQ; + break; + + case ATAPI_STATE_GOT_COMMAND: + { + int pos = 0; + int bus_state; + int c; + + for (c = 0; c < 20; c++) + { + bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("SEND_COMMAND - dropped BSY\n"); + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_CD) + fatal("SEND_COMMAND - bus phase incorrect\n"); + if (bus_state & BUS_REQ) + break; + } + if (c == 20) + fatal("SEND_COMMAND timed out\n"); + + while (1) + { + int bus_out; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("SEND_COMMAND - dropped BSY\n"); + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_CD) + break; + if (bus_state & BUS_REQ) + break; + } + if (c == 20) + { +// pclog("SEND_COMMAND timed out %x\n", scsi_bus_read(&atapi_dev->bus)); + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + idecallback[atapi_dev->board] = 6 * IDE_TIME; + break; + } + + bus_state = scsi_bus_read(&atapi_dev->bus); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG | BUS_REQ)) != (BUS_CD | BUS_REQ)) + { +// pclog("SEND_COMMAND - bus state changed %x\n", bus_state); + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + idecallback[atapi_dev->board] = 6 * IDE_TIME; + break; + } + + if (pos >= atapi_dev->command_pos) + bus_out = BUS_SETDATA(0); /*Pad out with zeroes*/ + else + bus_out = BUS_SETDATA(atapi_dev->command[pos++]); + scsi_bus_update(&atapi_dev->bus, bus_out | BUS_ACK); + scsi_bus_update(&atapi_dev->bus, bus_out & ~BUS_ACK); + + if (!(bus_state & BUS_BSY)) + fatal("SEND_COMMAND - dropped BSY\n"); + +// if (pos >= atapi_dev->command_pos) +// fatal("Out of data!\n"); + } + } + break; + + case ATAPI_STATE_NEXT_PHASE: + { + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + +// if (!c) +// pclog("NEXT_PHASE - %x\n", bus_state); + if (!(bus_state & BUS_BSY)) + fatal("NEXT_PHASE - dropped BSY waiting\n"); + + if (bus_state & BUS_REQ) + { + scsi_device_t *scsi_dev = atapi_dev->bus.devices[0]; + void *scsi_data = atapi_dev->bus.device_data[0]; + + switch (bus_state & (BUS_IO | BUS_CD | BUS_MSG)) + { + case 0: + atapi_dev->state = ATAPI_STATE_WRITE_DATA_WAIT; + + atapi_dev->data_read_pos = scsi_dev->get_bytes_required(scsi_data); + if (atapi_dev->data_read_pos > atapi_dev->max_transfer_len) + atapi_dev->data_read_pos = atapi_dev->max_transfer_len; + + atapi_dev->data_write_pos = 0; + *atapi_dev->cylinder = atapi_dev->data_read_pos; + +// pclog("WRITE_DATA: bytes=%i\n", *atapi_dev->cylinder); + *atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT); + atapi_dev->bus_state = BUS_REQ; + ide_irq_raise(atapi_dev->ide); + break; + + case BUS_IO: + atapi_dev->state = ATAPI_STATE_READ_DATA; + atapi_dev->data_read_pos = atapi_dev->data_write_pos = 0; + break; + + case (BUS_IO | BUS_CD): + atapi_dev->state = ATAPI_STATE_READ_STATUS; + break; + + case (BUS_CD | BUS_IO | BUS_MSG): + atapi_dev->state = ATAPI_STATE_READ_MESSAGE; + break; + + default: + fatal("NEXT_PHASE - bus state changed %x\n", bus_state); + } + break; + } + } + idecallback[atapi_dev->board] = 6 * IDE_TIME; + } + break; + + case ATAPI_STATE_READ_STATUS: + { + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_STATUS - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != (BUS_CD | BUS_IO)) + fatal("READ_STATUS - changed phase\n"); + + if (bus_state & BUS_REQ) + { +// uint8_t status = BUS_GETDATA(bus_state); + int bus_out = 0; + +// pclog("Read status %02x\n", status); + + scsi_bus_update(&atapi_dev->bus, bus_out | BUS_ACK); + scsi_bus_update(&atapi_dev->bus, bus_out & ~BUS_ACK); + + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + break; + } + } + idecallback[atapi_dev->board] = 6 * IDE_TIME; + } + break; + + case ATAPI_STATE_READ_MESSAGE: + { + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_MESSAGE - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != (BUS_CD | BUS_IO | BUS_MSG)) + { +// pclog("READ_MESSAGE - changed phase\n"); + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t msg = BUS_GETDATA(bus_state); + int bus_out = 0; + +// pclog("Read message %02x\n", msg); + scsi_bus_update(&atapi_dev->bus, bus_out | BUS_ACK); + scsi_bus_update(&atapi_dev->bus, bus_out & ~BUS_ACK); + + switch (msg) + { + case MSG_COMMAND_COMPLETE: + atapi_dev->state = ATAPI_STATE_END_PHASE; + break; + + default: + fatal("READ_MESSAGE - unknown message %02x\n", msg); + } + break; + } + } + idecallback[atapi_dev->board] = 6 * IDE_TIME; + } + break; + + case ATAPI_STATE_READ_DATA: + { + while (atapi_dev->data_write_pos < atapi_dev->max_transfer_len) + { + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_DATA - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_IO) + { +// pclog("READ_DATA - changed phase\n"); + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t data = BUS_GETDATA(bus_state); + int bus_out = 0; + + atapi_dev->data[atapi_dev->data_write_pos++] = data; + +// pclog("Read data %02x %i\n", data, atapi_dev->data_write_pos); + scsi_bus_update(&atapi_dev->bus, bus_out | BUS_ACK); + scsi_bus_update(&atapi_dev->bus, bus_out & ~BUS_ACK); + break; + } + } + if ((scsi_bus_read(&atapi_dev->bus) & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_IO) + break; + } + atapi_dev->state = ATAPI_STATE_READ_DATA_WAIT; + *atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT); + *atapi_dev->cylinder = atapi_dev->data_write_pos; +// pclog("READ_DATA: bytes=%i\n", *atapi_dev->cylinder); + atapi_dev->bus_state = BUS_IO | BUS_REQ; + ide_irq_raise(atapi_dev->ide); + } + break; + + case ATAPI_STATE_WRITE_DATA: + { + atapi_dev->data_read_pos = 0; +// pclog("ATAPI_STATE_WRITE_DATA - %i\n", atapi_dev->data_write_pos); + while (atapi_dev->data_read_pos < atapi_dev->data_write_pos) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("WRITE_DATA - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != 0) + { +// pclog("WRITE_DATA - changed phase\n"); + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t data = atapi_dev->data[atapi_dev->data_read_pos++]; + int bus_out; + +// pclog("Write data %02x %i\n", data, atapi_dev->data_read_pos-1); + bus_out = BUS_SETDATA(data); + scsi_bus_update(&atapi_dev->bus, bus_out | BUS_ACK); + scsi_bus_update(&atapi_dev->bus, bus_out & ~BUS_ACK); + } + } + + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + idecallback[atapi_dev->board] = 6 * IDE_TIME; + } + break; + + case ATAPI_STATE_END_PHASE: + { + int c; + /*Wait for SCSI command to move to next phase*/ + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + { +// pclog("END_PHASE - dropped BSY waiting\n"); + atapi_dev->state = ATAPI_STATE_IDLE; + break; + } + + if (bus_state & BUS_REQ) + fatal("END_PHASE - unexpected REQ\n"); + } + if (atapi_dev->state == ATAPI_STATE_IDLE) + { + scsi_device_t *scsi_dev = atapi_dev->bus.devices[0]; + void *scsi_data = atapi_dev->bus.device_data[0]; + + *atapi_dev->atastat = READY_STAT; + atapi_dev->bus_state = BUS_IO | BUS_CD; + if (scsi_dev->get_status(scsi_data) != STATUS_GOOD) + { + *atapi_dev->error = (scsi_dev->get_sense_key(scsi_data) << 4) | ABRT_ERR; + if (scsi_dev->get_sense_key(scsi_data) == KEY_UNIT_ATTENTION) + *atapi_dev->error |= MCR_ERR; + *atapi_dev->atastat |= ERR_STAT; + } + ide_irq_raise(atapi_dev->ide); + } + else + idecallback[atapi_dev->board] = 6 * IDE_TIME; + } + break; + } +} diff --git a/src/ide_atapi.h b/src/ide_atapi.h index 5530f1c..43ca829 100644 --- a/src/ide_atapi.h +++ b/src/ide_atapi.h @@ -1,6 +1,8 @@ #ifndef __IDE_ATAPI__ #define __IDE_ATAPI__ +#include "scsi.h" + /*ATAPI stuff*/ typedef struct ATAPI { @@ -28,6 +30,36 @@ typedef struct ATAPI extern ATAPI *atapi; void atapi_discchanged(); -void atapi_insert_cdrom(); + +typedef struct atapi_device_t +{ + scsi_bus_t bus; + + uint8_t command[12]; + int command_pos; + + int state; + + int max_transfer_len; + + uint8_t data[65536]; + int data_read_pos, data_write_pos; + + int bus_state; + + struct IDE *ide; + + int board; + uint8_t *atastat; + uint8_t *error; + int *cylinder; +} atapi_device_t; + +void atapi_data_write(atapi_device_t *atapi_dev, uint16_t val); +uint16_t atapi_data_read(atapi_device_t *atapi_dev); +void atapi_command_start(atapi_device_t *atapi); +uint8_t atapi_read_iir(atapi_device_t *atapi_dev); +uint8_t atapi_read_drq(atapi_device_t *atapi_dev); +void atapi_process_packet(atapi_device_t *atapi_dev); #endif diff --git a/src/scsi.c b/src/scsi.c index b703700..c87456f 100644 --- a/src/scsi.c +++ b/src/scsi.c @@ -101,7 +101,7 @@ int scsi_bus_update(scsi_bus_t *bus, int bus_assert) bus->new_state = bus->bus_out & (BUS_IO | BUS_CD | BUS_MSG); bus->bus_out &= ~BUS_REQ; - if (cmd_len[bus->command[0] >> 5] == bus->command_pos) + if (bus->command_pos == (bus->is_atapi ? 12 : cmd_len[bus->command[0] >> 5])) { int new_state; @@ -322,6 +322,19 @@ void scsi_bus_kick(scsi_bus_t *bus) scsi_bus_update(bus, 0); } +void scsi_bus_atapi_init(scsi_bus_t *bus, scsi_device_t *device, int id) +{ + memset(bus->devices, 0, sizeof(bus->devices)); + memset(bus->device_data, 0, sizeof(bus->device_data)); + + bus->devices[0] = device; + bus->device_data[0] = bus->devices[0]->atapi_init(bus, id); + if (!bus->device_data[0]) + bus->devices[0] = NULL; + + bus->is_atapi = 1; +} + void scsi_bus_init(scsi_bus_t *bus) { int c; @@ -331,21 +344,17 @@ void scsi_bus_init(scsi_bus_t *bus) for (c = 0; c < 4; c++) { - if (cdrom_channel != c) - { - bus->devices[c] = &scsi_hd; - bus->device_data[c] = bus->devices[c]->init(bus, c); - if (!bus->device_data[c]) - bus->devices[c] = NULL; - } - else - { + if (cdrom_channel == c) bus->devices[c] = &scsi_cd; - bus->device_data[c] = bus->devices[c]->init(bus, c); - if (!bus->device_data[c]) - bus->devices[c] = NULL; - } + else + bus->devices[c] = &scsi_hd; + + bus->device_data[c] = bus->devices[c]->init(bus, c); + if (!bus->device_data[c]) + bus->devices[c] = NULL; } + + bus->is_atapi = 0; } void scsi_bus_close(scsi_bus_t *bus) diff --git a/src/scsi.h b/src/scsi.h index 75ade74..e824639 100644 --- a/src/scsi.h +++ b/src/scsi.h @@ -1,14 +1,22 @@ +#ifndef _SCSI_H_ +#define _SCSI_H_ + struct scsi_bus_t; typedef struct scsi_device_t { void *(*init)(struct scsi_bus_t *bus, int id); + void *(*atapi_init)(struct scsi_bus_t *bus, int id); void (*close)(void *p); void (*start_command)(void *p); int (*command)(uint8_t *cdb, void *p); uint8_t (*get_status)(void *p); + uint8_t (*get_sense_key)(void *p); + int (*get_bytes_required)(void *p); + + void (*atapi_identify)(uint16_t *buffer, void *p); uint8_t (*read)(void *p); void (*write)(uint8_t val, void *p); @@ -34,6 +42,8 @@ typedef struct scsi_bus_t int change_state_delay; int new_req_delay; + + int is_atapi; } scsi_bus_t; //int scsi_add_data(uint8_t val); @@ -59,6 +69,7 @@ void scsi_set_irq(uint8_t status); #define SCSI_SEEK_10 0x2b #define SCSI_VERIFY_10 0x2f #define SCSI_READ_BUFFER 0x3c +#define SCSI_MODE_SENSE_10 0x5a #define SCSI_RESERVE 0x16 #define SCSI_RELEASE 0x17 @@ -92,10 +103,25 @@ int scsi_bus_match(scsi_bus_t *bus, int bus_assert); void scsi_bus_kick(scsi_bus_t *bus); void scsi_bus_init(scsi_bus_t *bus); void scsi_bus_close(scsi_bus_t *bus); +void scsi_bus_atapi_init(scsi_bus_t *bus, scsi_device_t *device, int id); -#define KEY_ILLEGAL_REQ 5 +#define KEY_NONE 0 +#define KEY_NOT_READY 2 +#define KEY_ILLEGAL_REQ 5 +#define KEY_UNIT_ATTENTION 6 +#define KEY_DATA_PROTECT 7 + +#define ASC_AUDIO_PLAY_OPERATION 0x00 +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_LBA_OUT_OF_RANGE 0x21 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_INVALID_LUN 0x25 +#define ASC_WRITE_PROTECT 0x27 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_DATA_PHASE_ERROR 0x4b +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 -#define ASC_INVALID_LUN 0x25 #define SCSI_PHASE_DATA_OUT 0 #define SCSI_PHASE_DATA_IN BUS_IO @@ -103,3 +129,8 @@ void scsi_bus_close(scsi_bus_t *bus); #define SCSI_PHASE_STATUS (BUS_CD | BUS_IO) #define SCSI_PHASE_MESSAGE_OUT (BUS_MSG | BUS_CD) #define SCSI_PHASE_MESSAGE_IN (BUS_MSG | BUS_CD | BUS_IO) + +#define START_STOP_START 0x01 +#define START_STOP_LOEJ 0x02 + +#endif /*_SCSI_H_*/ diff --git a/src/scsi_cd.c b/src/scsi_cd.c index fb32c01..3ba4b60 100644 --- a/src/scsi_cd.c +++ b/src/scsi_cd.c @@ -65,16 +65,6 @@ enum #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_LBA_OUT_OF_RANGE 0x21 -#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 -#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 -#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 @@ -202,6 +192,7 @@ typedef struct scsi_cd_data_t uint8_t prefix_len; uint8_t page_current; + int is_atapi; } scsi_cd_data_t; static void scsi_add_data(scsi_cd_data_t *data, uint8_t val) @@ -292,6 +283,15 @@ static void *scsi_cd_init(scsi_bus_t *bus, int id) return data; } +static void *scsi_cd_atapi_init(scsi_bus_t *bus, int id) +{ + scsi_cd_data_t *data = scsi_cd_init(bus, id); + + data->is_atapi = 1; + + return data; +} + static void scsi_cd_close(void *p) { scsi_cd_data_t *data = p; @@ -397,6 +397,15 @@ static uint32_t ide_atapi_mode_sense(scsi_cd_data_t *data, uint32_t pos, uint8_t 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 ? 9 : 7] : 0xFF; +} static int scsi_cd_command(uint8_t *cdb, void *p) { scsi_cd_data_t *data = p; @@ -417,6 +426,7 @@ static int scsi_cd_command(uint8_t *cdb, void *p) int temp_command; int alloc_length; int completed; + int changed; if (!data->received_cdb) memcpy(data->cdb, cdb, CDB_MAX_LEN); @@ -433,11 +443,8 @@ static int scsi_cd_command(uint8_t *cdb, void *p) msf = cdb[1] & 2; is_error = 0; + changed = atapi->medium_changed(); - if (atapi->medium_changed()) - { - atapi_insert_cdrom(); - } /*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. @@ -469,7 +476,13 @@ static int scsi_cd_command(uint8_t *cdb, void *p) atapi_cmd_error(data, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); return SCSI_PHASE_STATUS; } - + if ((atapi_cmd_table[cdb[0]] & CHECK_READY) && changed) + { + pclog("Medium changed\n"); + atapi_cmd_error(data, SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); + return SCSI_PHASE_STATUS; + } + data->prev_status = data->cd_status; data->cd_status = atapi->status(); if (((data->prev_status == CD_STATUS_PLAYING) || (data->prev_status == CD_STATUS_PAUSED)) && ((data->cd_status != CD_STATUS_PLAYING) && (data->cd_status != CD_STATUS_PAUSED))) @@ -526,8 +539,7 @@ static int scsi_cd_command(uint8_t *cdb, void *p) data->data_in[13] = (data->cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; } - //data->data_in[7] = 10; - data->data_in[7] = 0; + data->data_in[7] = 0; /* Clear the sense stuff as per the spec. */ atapi_sense_clear(data, temp_command, 0); @@ -1002,8 +1014,16 @@ static int scsi_cd_command(uint8_t *cdb, void *p) data->data_in[0] = 5; /*CD-ROM*/ data->data_in[1] = 0x80; /*Removable*/ - data->data_in[2] = 2; /*SCSI-2 compliant*/ - data->data_in[3] = 0x21; + if (data->is_atapi) + { + data->data_in[2] = 0; /*Not ANSI compliant*/ + data->data_in[3] = 0x21; /*ATAPI compliant*/ + } + else + { + data->data_in[2] = 2; /*SCSI-2 compliant*/ + data->data_in[3] = 0x02; + } data->data_in[4] = 31; data->data_in[5] = 0; data->data_in[6] = 0; @@ -1125,15 +1145,45 @@ static uint8_t scsi_cd_get_status(void *p) return data->status; } +static uint8_t scsi_cd_get_sense_key(void *p) +{ + scsi_cd_data_t *data = p; + + return data->sense_key; +} + +static int scsi_cd_get_bytes_required(void *p) +{ + scsi_cd_data_t *data = p; + + return data->bytes_required - data->bytes_received; +} + +static void scsi_cd_atapi_identify(uint16_t *buffer, void *p) +{ + memset(buffer, 0, 512); + + buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ + ide_padstr((char *)(buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *)(buffer + 23), "v1.0", 8); /* Firmware */ + ide_padstr((char *)(buffer + 27), "PCemCD", 40); /* Model */ + buffer[49] = 0x200; /* LBA supported */ +} + scsi_device_t scsi_cd = { scsi_cd_init, + scsi_cd_atapi_init, scsi_cd_close, scsi_cd_start_command, scsi_cd_command, scsi_cd_get_status, + scsi_cd_get_sense_key, + scsi_cd_get_bytes_required, + + scsi_cd_atapi_identify, scsi_cd_read, scsi_cd_write, diff --git a/src/scsi_hd.c b/src/scsi_hd.c index c03d87a..9cd60ba 100644 --- a/src/scsi_hd.c +++ b/src/scsi_hd.c @@ -418,6 +418,16 @@ static int scsi_hd_command(uint8_t *cdb, void *p) for (; len >= 0; len--) add_data_len(0); + len = data->data_pos_write; + if (cdb[0] == SCSI_MODE_SENSE_6) + { + data->data_in[0] = len - 1; + } + else + { + data->data_in[0] = (len - 2) >> 8; + data->data_in[1] = (len - 2) & 255; + } // scsi_illegal_field(); data->cmd_pos = CMD_POS_IDLE; bus_state = BUS_IO; @@ -789,15 +799,34 @@ static uint8_t scsi_hd_get_status(void *p) return data->status; } +static uint8_t scsi_hd_get_sense_key(void *p) +{ + scsi_hd_data *data = p; + + return data->sense_key; +} + +static int scsi_hd_get_bytes_required(void *p) +{ + scsi_hd_data *data = p; + + return data->bytes_required - data->bytes_received; +} + scsi_device_t scsi_hd = { scsi_hd_init, + NULL, scsi_hd_close, scsi_hd_start_command, scsi_hd_command, scsi_hd_get_status, + scsi_hd_get_sense_key, + scsi_hd_get_bytes_required, + + NULL, scsi_hd_read, scsi_hd_write, diff --git a/src/wx-sdl2.c b/src/wx-sdl2.c index 8fb2948..2fe4465 100644 --- a/src/wx-sdl2.c +++ b/src/wx-sdl2.c @@ -1087,11 +1087,6 @@ int wx_handle_command(void* hwnd, int wParam, int checked) atapi->exit(); atapi_close(); ioctl_set_drive(0); - if (cdrom_enabled) - { - /* Signal disc change to the emulated machine. */ - atapi_insert_cdrom(); - } old_cdrom_drive = cdrom_drive; cdrom_drive = 0; saveconfig(NULL); @@ -1133,11 +1128,6 @@ int wx_handle_command(void* hwnd, int wParam, int checked) atapi->exit(); atapi_close(); image_open(temp_image_path); - if (cdrom_enabled) - { - /* Signal disc change to the emulated machine. */ - atapi_insert_cdrom(); - } cdrom_drive = CDROM_IMAGE; saveconfig(NULL); if (!cdrom_enabled) @@ -1174,11 +1164,6 @@ int wx_handle_command(void* hwnd, int wParam, int checked) atapi->exit(); atapi_close(); ioctl_set_drive(new_cdrom_drive); - if (cdrom_enabled) - { - /* Signal disc change to the emulated machine. */ - atapi_insert_cdrom(); - } cdrom_drive = new_cdrom_drive; saveconfig(NULL); if (!cdrom_enabled)