diff --git a/src/cdrom-ioctl.c b/src/cdrom-ioctl.c index d49cb1fad..2c303f96c 100644 --- a/src/cdrom-ioctl.c +++ b/src/cdrom-ioctl.c @@ -6,6 +6,7 @@ #include #include #include "ntddcdrm.h" +#include "ntddscsi.h" #include "ibm.h" #include "cdrom.h" #include "cdrom-ioctl.h" @@ -208,7 +209,7 @@ static void ioctl_seek(uint32_t pos) { if (!cdrom_drive) return; // ioctl_cd_state = CD_STOPPED; - pclog("Seek %08X\n", pos); + // pclog("Seek %08X\n", pos); ioctl_cd_pos = pos; ioctl_cd_state = CD_STOPPED; /* pos+=150; @@ -268,7 +269,7 @@ static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, i int lb=0; if (!cdrom_drive) return 0; ioctl_cd_state = CD_STOPPED; - pclog("ioctl_readtoc(): IOCtl state now CD_STOPPED\n"); + // pclog("ioctl_readtoc(): IOCtl state now CD_STOPPED\n"); ioctl_open(0); DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&lbtoc,sizeof(lbtoc),&size,NULL); ioctl_close(); @@ -448,16 +449,29 @@ static int is_track_audio(uint32_t pos) if (!tocvalid) return 0; - for (c = toc.FirstTrack; c < toc.LastTrack; c++) + // for (c = toc.FirstTrack; c <= toc.LastTrack; c++) + for (c = 0; c <= toc.LastTrack; c++) { - uint32_t track_address = toc.TrackData[c].Address[3] + - (toc.TrackData[c].Address[2] * 75) + - (toc.TrackData[c].Address[1] * 75 * 60); + uint32_t track_address = MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); + // pclog("Track address: %i (%02X%02X%02X%02X), Position: %i\n", track_address, toc.TrackData[c].Address[0], toc.TrackData[c].Address[1], toc.TrackData[c].Address[2], toc.TrackData[c].Address[3], pos); + if (track_address <= pos) control = toc.TrackData[c].Control; } - return (control & 4) ? 0 : 1; + // pclog("Control: %i\n", control); + if ((control & 0xd) == 0) + { + return 1; + } + else if ((control & 0xd) == 1) + { + return 1; + } + else + { + return 0; + } } static int ioctl_is_track_audio(uint32_t pos, int ismsf) @@ -469,24 +483,169 @@ static int ioctl_is_track_audio(uint32_t pos, int ismsf) int f = pos & 0xff; pos = MSFtoLBA(m, s, f); } + else + { + pos += 150; + } return is_track_audio(pos); } -static void ioctl_readsector_raw(uint8_t *b, int sector) +/* Direct SCSI read in MSF mode. */ +int SCSIReadMSF(uint8_t *b, int sector) { - LARGE_INTEGER pos; - long size; - uint32_t temp; - if (!cdrom_drive) return; - if (ioctl_cd_state == CD_PLAYING) - return; + HANDLE fh; + DWORD ioctl_bytes; + DWORD out_size; + int ioctl_rv; + const UCHAR cdb_0[] = { 0xB9, 0, 0, ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0xFC, 0, 0 }; + const UCHAR cdb_1[] = { 0xB9, 0, 0, ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0xFC, 1, 0 }; + const UCHAR cdb_2[] = { 0xB9, 0, 0, ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0xFC, 2, 0 }; + const UCHAR cdb_4[] = { 0xB9, 0, 0, ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0xFC, 4, 0 }; + UCHAR buf[2856]; + struct sptd_with_sense + { + SCSI_PASS_THROUGH_DIRECT s; + UCHAR sense[128]; + } sptd; - ioctl_cd_state = CD_STOPPED; - pos.QuadPart=sector*2048; /* Yes, 2048, the API specifies that. */ - ioctl_open(0); - /* This should read the actual raw sectors from the disc. */ - DeviceIoControl( hIOCTL, IOCTL_CDROM_RAW_READ, NULL, 0, b, 1, &size, NULL ); - ioctl_close(); + ioctl_open(0); + + memset(&sptd, 0, sizeof(sptd)); + sptd.s.Length = sizeof(sptd.s); + sptd.s.CdbLength = sizeof(cdb_0); /* All 4 of our CDB's are identically sized, therefore we can take this shortcut. */ + sptd.s.DataIn = SCSI_IOCTL_DATA_IN; + sptd.s.TimeOutValue = 30; + sptd.s.DataBuffer = buf; + sptd.s.DataTransferLength = 2856; + sptd.s.SenseInfoLength = sizeof(sptd.sense); + sptd.s.SenseInfoOffset = offsetof(struct sptd_with_sense, sense); + + /* Fill the buffer with zeroes. */ + memset(b, 0, 2856); + + /* First, read without subchannel data so we at least have *SOMETHING*. */ + memcpy(sptd.s.Cdb, cdb_0, sizeof(cdb_0)); + ioctl_rv = DeviceIoControl(hIOCTL, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); + // pclog("Read (%i) without subchannel data: %s\n", sector, ioctl_rv ? "SUCCESS" : "FAILURE"); + memcpy(b, sptd.s.DataBuffer, 2648); + + /* Next, try to read RAW subchannel data. */ + memcpy(sptd.s.Cdb, cdb_1, sizeof(cdb_1)); + ioctl_rv += DeviceIoControl(hIOCTL, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); + // pclog("Read (%i) with RAW subchannel data: %s\n", sector, ioctl_rv ? "SUCCESS" : "FAILURE"); + memcpy(b + 2648, sptd.s.DataBuffer + 2648, 96); + + /* Next, try to read Q subchannel data. */ + memcpy(sptd.s.Cdb, cdb_2, sizeof(cdb_2)); + ioctl_rv += DeviceIoControl(hIOCTL, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); + // pclog("Read (%i) with Q subchannel data: %s\n", sector, ioctl_rv ? "SUCCESS" : "FAILURE"); + memcpy(b + 2648 + 96, sptd.s.DataBuffer + 2648, 16); + + /* Next, try to read R - W subchannel data. */ + memcpy(sptd.s.Cdb, cdb_4, sizeof(cdb_4)); + ioctl_rv += DeviceIoControl(hIOCTL, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); + // pclog("Read (%i) with R - W subchannel data: %s\n", sector, ioctl_rv ? "SUCCESS" : "FAILURE"); + memcpy(b + 2648 + 96 + 16, sptd.s.DataBuffer + 2648, 96); + + ioctl_close(); + + return ioctl_rv; +} + +/* Direct SCSI read in LBA mode. */ +void SCSIRead(uint8_t *b, int sector) +{ + HANDLE fh; + DWORD ioctl_bytes; + DWORD out_size; + BOOL ioctl_rv; + const UCHAR cdb_0[] = { 0xBE, 0, (sector >> 24), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0, 0, 1, 0xFC, 0, 0 }; + const UCHAR cdb_1[] = { 0xBE, 0, (sector >> 24), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0, 0, 1, 0xFC, 1, 0 }; + const UCHAR cdb_2[] = { 0xBE, 0, (sector >> 24), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0, 0, 1, 0xFC, 2, 0 }; + const UCHAR cdb_4[] = { 0xBE, 0, (sector >> 24), ((sector >> 16) & 0xff), ((sector >> 8) & 0xff), (sector & 0xff), 0, 0, 1, 0xFC, 4, 0 }; + UCHAR buf[2856]; + struct sptd_with_sense + { + SCSI_PASS_THROUGH_DIRECT s; + UCHAR sense[128]; + } sptd; + + ioctl_open(0); + + memset(&sptd, 0, sizeof(sptd)); + sptd.s.Length = sizeof(sptd.s); + sptd.s.CdbLength = sizeof(cdb_0); /* All 4 of our CDB's are identically sized, therefore we can take this shortcut. */ + sptd.s.DataIn = SCSI_IOCTL_DATA_IN; + sptd.s.TimeOutValue = 30; + sptd.s.DataBuffer = buf; + sptd.s.DataTransferLength = 2856; + sptd.s.SenseInfoLength = sizeof(sptd.sense); + sptd.s.SenseInfoOffset = offsetof(struct sptd_with_sense, sense); + + /* Fill the buffer with zeroes. */ + memset(b, 0, 2856); + + /* First, read without subchannel data so we at least have *SOMETHING*. */ + memcpy(sptd.s.Cdb, cdb_0, sizeof(cdb_0)); + ioctl_rv = DeviceIoControl(hIOCTL, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); + // pclog("Read (%i) without subchannel data: %s\n", sector, ioctl_rv ? "SUCCESS" : "FAILURE"); + memcpy(b, sptd.s.DataBuffer, 2648); + + /* Next, try to read RAW subchannel data. */ + memcpy(sptd.s.Cdb, cdb_1, sizeof(cdb_1)); + ioctl_rv = DeviceIoControl(hIOCTL, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); + // pclog("Read (%i) with RAW subchannel data: %s\n", sector, ioctl_rv ? "SUCCESS" : "FAILURE"); + memcpy(b + 2648, sptd.s.DataBuffer + 2648, 96); + + /* Next, try to read Q subchannel data. */ + memcpy(sptd.s.Cdb, cdb_2, sizeof(cdb_2)); + ioctl_rv = DeviceIoControl(hIOCTL, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); + // pclog("Read (%i) with Q subchannel data: %s\n", sector, ioctl_rv ? "SUCCESS" : "FAILURE"); + memcpy(b + 2648 + 96, sptd.s.DataBuffer + 2648, 16); + + /* Next, try to read R - W subchannel data. */ + memcpy(sptd.s.Cdb, cdb_4, sizeof(cdb_4)); + ioctl_rv = DeviceIoControl(hIOCTL, IOCTL_SCSI_PASS_THROUGH_DIRECT, &sptd, sizeof(sptd), &sptd, sizeof(sptd), &ioctl_bytes, NULL); + // pclog("Read (%i) with R - W subchannel data: %s\n", sector, ioctl_rv ? "SUCCESS" : "FAILURE"); + memcpy(b + 2648 + 96 + 16, sptd.s.DataBuffer + 2648, 96); + + ioctl_close(); + + return; +} + +static void ioctl_readsector_raw(uint8_t *b, int sector, int ismsf) +{ + RAW_READ_INFO in; + LARGE_INTEGER pos; + DWORD count = 0; + long size; + uint32_t temp; + if (!cdrom_drive) return; + if (ioctl_cd_state == CD_PLAYING) + return; + + if (ismsf) + { + if (!SCSIReadMSF(b, sector)) + { + int m = (sector >> 16) & 0xff; + int s = (sector >> 8) & 0xff; + int f = sector & 0xff; + sector = (m * 60 * 75) + (s * 75) + f; + if (sector < 150) + { + memset(b, 0, 2856); + return; + } + sector += 150; + SCSIRead(b, sector); + } + } + else + { + SCSIRead(b, sector); + } } static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) @@ -691,11 +850,14 @@ int ioctl_open(char d) if (!ioctl_inited) { sprintf(ioctl_path,"\\\\.\\%c:",d); - pclog("Path is %s\n",ioctl_path); + // pclog("Path is %s\n",ioctl_path); tocvalid=0; } // pclog("Opening %s\n",ioctl_path); - hIOCTL = CreateFile(/*"\\\\.\\g:"*/ioctl_path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); + // hIOCTL = CreateFile(/*"\\\\.\\g:"*/ioctl_path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); + hIOCTL = CreateFile(ioctl_path, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); if (!hIOCTL) { //fatal("IOCTL"); diff --git a/src/cdrom-iso.c b/src/cdrom-iso.c index 8820e4f81..3695b0801 100644 --- a/src/cdrom-iso.c +++ b/src/cdrom-iso.c @@ -28,42 +28,42 @@ void iso_audio_callback(int16_t *output, int len) void iso_audio_stop() { - pclog("iso_audio_stop stub\n"); + // pclog("iso_audio_stop stub\n"); } static int get_track_nr(uint32_t pos) { - pclog("get_track_nr stub\n"); + // pclog("get_track_nr stub\n"); return 0; } static void iso_playaudio(uint32_t pos, uint32_t len, int ismsf) { - pclog("iso_playaudio stub\n"); + // pclog("iso_playaudio stub\n"); return; } static void iso_pause(void) { - pclog("iso_pause stub\n"); + // pclog("iso_pause stub\n"); return; } static void iso_resume(void) { - pclog("iso_resume stub\n"); + // pclog("iso_resume stub\n"); return; } static void iso_stop(void) { - pclog("iso_stop stub\n"); + // pclog("iso_stop stub\n"); return; } static void iso_seek(uint32_t pos) { - pclog("iso_seek stub\n"); + // pclog("iso_seek stub\n"); return; } @@ -112,18 +112,18 @@ static int iso_medium_changed(void) static uint8_t iso_getcurrentsubchannel(uint8_t *b, int msf) { - pclog("iso_getcurrentsubchannel stub\n"); + // pclog("iso_getcurrentsubchannel stub\n"); return 0; } static void iso_eject(void) { - pclog("iso_eject stub\n"); + // pclog("iso_eject stub\n"); } static void iso_load(void) { - pclog("iso_load stub\n"); + // pclog("iso_load stub\n"); } static void iso_readsector(uint8_t *b, int sector) @@ -137,12 +137,18 @@ static void iso_readsector(uint8_t *b, int sector) static void lba_to_msf(uint8_t *buf, int lba) { +#if 0 double dlba = (double) lba + 150; buf[2] = (uint8_t) (((uint32_t) dlba) % 75); dlba /= 75; buf[1] = (uint8_t) (((uint32_t) dlba) % 60); dlba /= 60; buf[0] = (uint8_t) dlba; +#endif + lba += 150; + buf[0] = (lba / 75) / 60; + buf[1] = (lba / 75) % 60; + buf[2] = lba % 75; } #if 0 @@ -155,10 +161,24 @@ static void lba_to_msf(uint8_t *buf, int lba) } #endif -static void iso_readsector_raw(uint8_t *b, int sector) +static void iso_readsector_raw(uint8_t *b, int sector, int ismsf) { uint32_t temp; if (!cdrom_drive) return; + memset(b, 0, 2856); + if (ismsf) + { + int m = (sector >> 16) & 0xff; + int s = (sector >> 8) & 0xff; + int f = sector & 0xff; + sector = (m * 60 * 75) + (s * 75) + f; + if (sector < 150) + { + memset(b, 0, 2856); + return; + } + sector -= 150; + } iso_image = fopen(iso_path, "rb"); fseek(iso_image, sector*2048, SEEK_SET); fread(b+16, 2048, 1, iso_image); @@ -174,6 +194,8 @@ static void iso_readsector_raw(uint8_t *b, int sector) b += 4; b += 2048; memset(b, 0, 288); + b += 288; + memset(b, 0, 392); } static int iso_readtoc(unsigned char *buf, unsigned char start_track, int msf, int maxlen, int single) @@ -343,7 +365,7 @@ int iso_open(char *fn) if (!iso_inited || iso_changed) { sprintf(iso_path, "%s", fn); - pclog("Path is %s\n", iso_path); + // pclog("Path is %s\n", iso_path); } iso_image = fopen(iso_path, "rb"); cdrom = &iso_cdrom; diff --git a/src/cdrom-null.c b/src/cdrom-null.c index a54844633..d865c0c0d 100644 --- a/src/cdrom-null.c +++ b/src/cdrom-null.c @@ -66,7 +66,7 @@ static void null_readsector(uint8_t *b, int sector) { } -static void null_readsector_raw(uint8_t *b, int sector) +static void null_readsector_raw(uint8_t *b, int sector, int ismsf) { } diff --git a/src/cdrom.h b/src/cdrom.h index b9aec4277..716a6e647 100644 --- a/src/cdrom.h +++ b/src/cdrom.h @@ -11,7 +11,7 @@ typedef struct CDROM 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 (*readsector_raw)(uint8_t *b, int sector, int ismsf); void (*playaudio)(uint32_t pos, uint32_t len, int ismsf); void (*seek)(uint32_t pos); void (*load)(void); diff --git a/src/codegen_ops.c b/src/codegen_ops.c index 083c80b7d..a12dc0150 100644 --- a/src/codegen_ops.c +++ b/src/codegen_ops.c @@ -47,7 +47,7 @@ RecompOpFn recomp_opcodes[512] = /*c0*/ ropC0, ropC1_w, ropRET_imm_16, ropRET_16, NULL, NULL, ropMOV_b_imm, ropMOV_w_imm, NULL, ropLEAVE_16, NULL, NULL, NULL, NULL, NULL, NULL, /*d0*/ ropD0, ropD1_w, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*e0*/ NULL, NULL, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r16, ropJMP_r16, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, -/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_w, NULL, NULL, NULL, NULL, ropCLD, ropSTD, NULL, ropFF_16, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_w, NULL, NULL, NULL, NULL, ropCLD, ropSTD, ropFE, ropFF_16, /*32-bit data*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ @@ -69,7 +69,7 @@ RecompOpFn recomp_opcodes[512] = /*c0*/ ropC0, ropC1_l, ropRET_imm_32, ropRET_32, NULL, NULL, ropMOV_b_imm, ropMOV_l_imm, NULL, ropLEAVE_32, NULL, NULL, NULL, NULL, NULL, NULL, /*d0*/ ropD0, ropD1_l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /*e0*/ NULL, NULL, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r32, ropJMP_r32, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, -/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_l, NULL, NULL, NULL, NULL, ropCLD, ropSTD, NULL, ropFF_32 +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_l, NULL, NULL, NULL, NULL, ropCLD, ropSTD, ropFE, ropFF_32 }; RecompOpFn recomp_opcodes_0f[512] = diff --git a/src/codegen_ops_misc.h b/src/codegen_ops_misc.h index d71616c55..3754d7fac 100644 --- a/src/codegen_ops_misc.h +++ b/src/codegen_ops_misc.h @@ -14,28 +14,122 @@ static uint32_t ropSTD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32 return op_pc; } -static uint32_t codegen_temp; -static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { + x86seg *target_seg; int host_reg; - - if ((fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20)// && (fetchdat & 0x38) != 0x30) + + if ((fetchdat & 0x30) != 0x00) return 0; + + CALL_FUNC(flags_rebuild_c); if ((fetchdat & 0xc0) == 0xc0) - { - host_reg = LOAD_REG_W(fetchdat & 7); - } + host_reg = LOAD_REG_B(fetchdat & 7); else { - x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - MEM_LOAD_ADDR_EA_W(target_seg); - host_reg = 0; + + SAVE_EA(); + MEM_CHECK_WRITE(target_seg); + host_reg = MEM_LOAD_ADDR_EA_B_NO_ABRT(target_seg); } switch (fetchdat & 0x38) { + case 0x00: /*INC*/ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_B(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC8); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + break; + case 0x08: /*DEC*/ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_B(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC8); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + break; + } + + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_B_RELEASE(host_reg); + else + { + LOAD_EA(); + MEM_STORE_ADDR_EA_B_NO_ABRT(target_seg, host_reg); + } + codegen_flags_changed = 1; + + return op_pc + 1; +} +static uint32_t codegen_temp; +static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + + if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20)// && (fetchdat & 0x38) != 0x30) + return 0; + + if ((fetchdat & 0x30) == 0x00) + CALL_FUNC(flags_rebuild_c); + + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_W(fetchdat & 7); + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + if ((fetchdat & 0x30) != 0x00) + { + MEM_LOAD_ADDR_EA_W(target_seg); + host_reg = 0; + } + else + { + SAVE_EA(); + MEM_CHECK_WRITE_W(target_seg); + host_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); + } + } + + switch (fetchdat & 0x38) + { + case 0x00: /*INC*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_W_RELEASE(host_reg); + else + { + LOAD_EA(); + MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, host_reg); + } + codegen_flags_changed = 1; + return op_pc + 1; + case 0x08: /*DEC*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_W_RELEASE(host_reg); + else + { + LOAD_EA(); + MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, host_reg); + } + codegen_flags_changed = 1; + return op_pc + 1; + case 0x10: /*CALL*/ STORE_HOST_REG_ADDR_W((uintptr_t)&codegen_temp, host_reg); RELEASE_REG(host_reg); @@ -66,25 +160,68 @@ static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint } static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { + x86seg *target_seg; int host_reg; - if ((fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20)// && (fetchdat & 0x38) != 0x30) + if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20)// && (fetchdat & 0x38) != 0x30) return 0; + + if ((fetchdat & 0x30) == 0x00) + CALL_FUNC(flags_rebuild_c); if ((fetchdat & 0xc0) == 0xc0) - { host_reg = LOAD_REG_L(fetchdat & 7); - } else { - x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - MEM_LOAD_ADDR_EA_L(target_seg); - host_reg = 0; + + if ((fetchdat & 0x30) != 0x00) + { + MEM_LOAD_ADDR_EA_L(target_seg); + host_reg = 0; + } + else + { + SAVE_EA(); + MEM_CHECK_WRITE_L(target_seg); + host_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); + } } switch (fetchdat & 0x38) { + case 0x00: /*INC*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_L_RELEASE(host_reg); + else + { + LOAD_EA(); + MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, host_reg); + } + codegen_flags_changed = 1; + return op_pc + 1; + case 0x08: /*DEC*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_L_RELEASE(host_reg); + else + { + LOAD_EA(); + MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, host_reg); + } + codegen_flags_changed = 1; + return op_pc + 1; + case 0x10: /*CALL*/ STORE_HOST_REG_ADDR((uintptr_t)&codegen_temp, host_reg); RELEASE_REG(host_reg); diff --git a/src/ide.c b/src/ide.c index ffb02a853..3083cb01e 100644 --- a/src/ide.c +++ b/src/ide.c @@ -167,6 +167,49 @@ int ide_ter_enabled = 0; uint8_t getstat(IDE *ide) { return ide->atastat; } +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +typedef struct __attribute__((packed)) +{ + uint8_t user_data[2048]; + uint8_t ecc[288]; +} m1_data_t; + +typedef struct __attribute__((packed)) +{ + uint8_t sub_header[8]; + uint8_t user_data[2328]; +} m2_data_t; + +typedef union __attribute__((packed)) +{ + m1_data_t m1_data; + m2_data_t m2_data; + uint8_t raw_data[2352]; +} sector_data_t; + +typedef struct __attribute__((packed)) +{ + uint8_t sync[12]; + uint8_t header[4]; + sector_data_t data; + uint8_t c2[296]; + uint8_t subchannel_raw[96]; + uint8_t subchannel_q[16]; + uint8_t subchannel_rw[96]; +} cdrom_sector_t; + +typedef union __attribute__((packed)) +{ + cdrom_sector_t cdrom_sector; + uint8_t buffer[2856]; +} sector_buffer_t; + +sector_buffer_t cdrom_sector_buffer; + +int cdrom_sector_type, cdrom_sector_flags; +int cdrom_sector_size, cdrom_sector_ismsf; + int image_is_hdi(const char *s) { int i, len; @@ -381,10 +424,8 @@ static void ide_atapi_identify(IDE *ide) ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ ide_padstr((char *) (ide->buffer + 23), emulator_version, 8); /* Firmware */ ide_padstr((char *) (ide->buffer + 27), "86BoxCD", 40); /* Model */ - 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]; + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[51] = 2 << 8; /*PIO timing mode*/ } /* @@ -551,6 +592,10 @@ int ide_set_features(IDE *ide) case 0xc2: return 1; case 0x03: + if (ide->type == IDE_CDROM) + { + return 0; + } switch(ide->secount >> 3) { case 0: @@ -678,6 +723,8 @@ void resetide(void) // ide_drives[1].type = IDE_CDROM; page_flags[GPMODE_CDROM_AUDIO_PAGE] &= ~PAGE_CHANGED; + + SCSISense.UnitAttention = 0; } int idetimes=0; @@ -1791,6 +1838,282 @@ static void atapi_sense_clear(int command, int ignore_ua) } } +static int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type) +{ + if ((cdrom_sector_flags & 0x06) == 0x02) + { + /* Add error flags. */ + memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.c2, 294); + cdrom_sector_size += 294; + } + else if ((cdrom_sector_flags & 0x06) == 0x04) + { + /* Add error flags. */ + memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.c2, 296); + cdrom_sector_size += 296; + } + else if ((cdrom_sector_flags & 0x06) == 0x06) + { + pclog("Invalid error flags\n"); + return 0; + } + + /* if (real_sector_type == 1) + { */ + if ((cdrom_sector_flags & 0x700) == 0x100) + { + memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.subchannel_raw, 96); + cdrom_sector_size += 96; + } + else if ((cdrom_sector_flags & 0x700) == 0x200) + { + memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.subchannel_q, 16); + cdrom_sector_size += 16; + } + else if ((cdrom_sector_flags & 0x700) == 0x400) + { + memcpy(b + cdrom_sector_size, cdrom_sector_buffer.cdrom_sector.subchannel_rw, 96); + cdrom_sector_size += 96; + } + else if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) + { + pclog("Invalid subchannel data flags\n"); + return 0; + } + // } + + // pclog("CD-ROM sector size after processing: %i (%i, %i) [%04X]\n", cdrom_sector_size, cdrom_sector_type, real_sector_type, cdrom_sector_flags); + + return cdrom_sector_size; +} + +static int cdrom_LBAtoMSF_accurate(IDE *ide) +{ + int temp_pos; + int m, s, f; + + temp_pos = ide->cdpos; + f = temp_pos % 75; + temp_pos -= f; + temp_pos /= 75; + s = temp_pos % 60; + temp_pos -= s; + temp_pos /= 60; + m = temp_pos; + + return ((m << 16) | (s << 8) | f); +} + +static int cdrom_read_data(IDE *ide, uint8_t *buffer) +{ + int real_sector_type; + uint8_t *b; + uint8_t *temp_b; + int is_audio; + int real_pos; + + b = temp_b = buffer; + + if (cdrom_sector_ismsf) + { + real_pos = cdrom_LBAtoMSF_accurate(ide); + } + else + { + real_pos = ide->cdpos; + } + + memset(cdrom_sector_buffer.buffer, 0, 2856); + + cdrom->readsector_raw(cdrom_sector_buffer.buffer, real_pos, cdrom_sector_ismsf); + is_audio = cdrom->is_track_audio(real_pos, cdrom_sector_ismsf); + + if (!(cdrom_sector_flags & 0xf0)) /* 0x00 and 0x08 are illegal modes */ + { + return 0; + } + + if (cdrom->is_track_audio(ide->cdpos, 0)) + { + real_sector_type = 1; + + if (cdrom_sector_type > 1) + { + return 0; + } + else + { + memcpy(b, cdrom_sector_buffer.buffer, 2352); + cdrom_sector_size = 2352; + } + } + else + { + if ((cdrom_sector_flags & 0x18) == 0x08) /* EDC/ECC without user data is an illegal mode */ + { + return 0; + } + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) /* Sync */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.sync, 12); + cdrom_sector_size += 12; + temp_b += 12; + } + if (cdrom_sector_flags & 0x20) /* Header */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.header, 4); + cdrom_sector_size += 4; + temp_b += 4; + } + + switch(cdrom_sector_buffer.cdrom_sector.header[3]) + { + case 1: + real_sector_type = 2; /* Mode 1 */ + break; + case 2: + real_sector_type = 3; /* Mode 2 */ + break; + default: + return 0; + } + + if (real_sector_type == 2) + { + if ((cdrom_sector_type == 0) || (cdrom_sector_type == 2)) + { + /* Mode 1 sector, expected type is 1 type. */ + if (cdrom_sector_flags & 0x40) /* Sub-header */ + { + if (!(cdrom_sector_flags & 0x10)) /* No user data */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.user_data, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + } + if (cdrom_sector_flags & 0x10) /* User data */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.user_data, 2048); + cdrom_sector_size += 2048; + temp_b += 2048; + } + if (cdrom_sector_flags & 0x08) /* EDC/ECC */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m1_data.ecc, 288); + cdrom_sector_size += 288; + temp_b += 288; + } + } + else + { + return 0; + } + } + else if (real_sector_type == 3) + { + if ((cdrom_sector_type == 0) || (cdrom_sector_type == 3)) + { + /* Mode 2 sector, non-XA mode. */ + if (cdrom_sector_flags & 0x40) /* Sub-header */ + { + if (!(cdrom_sector_flags & 0x10)) /* No user data */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + } + if (cdrom_sector_flags & 0x10) /* User data */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 2328); + cdrom_sector_size += 8; + temp_b += 8; + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2328); + cdrom_sector_size += 2328; + temp_b += 2328; + } + } + else if (cdrom_sector_type == 4) + { + /* Mode 2 sector, XA Form 1 mode */ + if ((cdrom_sector_flags & 0xf0) == 0x30) + { + return 0; + } + if (((cdrom_sector_flags & 0xf8) >= 0xa8) || ((cdrom_sector_flags & 0xf8) <= 0xd8)) + { + return 0; + } + if (cdrom_sector_flags & 0x40) /* Sub-header */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + if (cdrom_sector_flags & 0x10) /* User data */ + { + if ((cdrom_sector_flags & 0xf0) == 0x10) + { + /* The data is alone, include sub-header. */ + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2040); + cdrom_sector_size += 2040; + temp_b += 2040; + } + if (cdrom_sector_flags & 0x08) /* EDC/ECC */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data + 2040, 288); + cdrom_sector_size += 288; + temp_b += 288; + } + } + else if (cdrom_sector_type == 5) + { + /* Mode 2 sector, XA Form 2 mode */ + if ((cdrom_sector_flags & 0xf0) == 0x30) + { + return 0; + } + if (((cdrom_sector_flags & 0xf8) >= 0xa8) || ((cdrom_sector_flags & 0xf8) <= 0xd8)) + { + return 0; + } + /* Mode 2 sector, XA Form 1 mode */ + if (cdrom_sector_flags & 0x40) /* Sub-header */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.sub_header, 8); + cdrom_sector_size += 8; + temp_b += 8; + } + if (cdrom_sector_flags & 0x10) /* User data */ + { + memcpy(temp_b, cdrom_sector_buffer.cdrom_sector.data.m2_data.user_data, 2328); + cdrom_sector_size += 2328; + temp_b += 2328; + } + } + else + { + return 0; + } + } + else + { + return 0; + } + } + + // pclog("CD-ROM sector size: %i (%i, %i) [%04X]\n", cdrom_sector_size, cdrom_sector_type, real_sector_type, cdrom_sector_flags); + return cdrom_add_error_and_subchannel(b, real_sector_type); +} + static void atapicommand(int ide_board) { IDE *ide = &ide_drives[cur_ide[ide_board]]; @@ -1802,7 +2125,6 @@ static void atapicommand(int ide_board) int pos=0; unsigned char temp; uint32_t size; - int is_error; uint8_t page_code; int max_len; unsigned idx = 0; @@ -1818,7 +2140,7 @@ static void atapicommand(int ide_board) int ret; #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); + pclog("ATAPI command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, %i, Unit attention: %i\n",idebufferb[0],SCSISense.SenseKey,SCSISense.Asc,SCSISense.Ascq,ins,SCSISense.UnitAttention); int CdbLength; for (CdbLength = 1; CdbLength < 12; CdbLength++) @@ -1828,39 +2150,44 @@ static void atapicommand(int ide_board) msf=idebufferb[1]&2; ide->cdlen=0; - is_error = 0; - if (cdrom->medium_changed()) { 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 (!(SCSICommandTable[idebufferb[0]] & ALLOW_UA) && SCSISense.SenseKey == SENSE_UNIT_ATTENTION) + + if (!cdrom->ready() && SCSISense.UnitAttention) { - atapi_cmd_error(ide, SCSISense.SenseKey, SCSISense.Asc, SCSISense.Ascq); - is_error = 1; + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + SCSISense.UnitAttention = 0; } - /*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 the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (!(SCSICommandTable[idebufferb[0]] & ALLOW_UA) && SCSISense.UnitAttention) + { + // pclog("UNIT ATTENTION: Command not allowed to pass through\n"); + atapi_cmd_error(ide, SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); + return; + } + + if (idebufferb[0] == GPCMD_READ_TOC_PMA_ATIP) + { + SCSISense.UnitAttention = 0; + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (idebufferb[0]!=GPCMD_REQUEST_SENSE) { - /* 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; - } - + /* Next it's time for NOT READY. */ if ((SCSICommandTable[idebufferb[0]] & CHECK_READY) && !cdrom->ready()) { + // pclog("Not ready\n"); atapi_cmd_error(ide, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); SCSISense.SenseKey = SENSE_NOT_READY; SCSISense.Asc = ASC_MEDIUM_NOT_PRESENT; @@ -1868,6 +2195,8 @@ static void atapicommand(int ide_board) return; } + // pclog("Continuing with command\n"); + 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))) @@ -1911,18 +2240,34 @@ static void atapicommand(int ide_board) idebufferb[13]=SCSISense.Ascq; } } - else + else if ((SCSISense.SenseKey == 0) && (cd_status >= CD_STATUS_PLAYING)) { 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; } + else + { + if (SCSISense.UnitAttention) + { + idebufferb[2]=SENSE_UNIT_ATTENTION; + idebufferb[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + idebufferb[13]=0; + } + } idebufferb[7]=10; // pclog("REQUEST SENSE start\n"); atapi_command_ready(ide_board, 18); + if (idebufferb[2] == SENSE_UNIT_ATTENTION) + { + /* If the last remaining sense is unit attention, clear + that condition. */ + SCSISense.UnitAttention = 0; + } + /* Clear the sense stuff as per the spec. */ atapi_sense_clear(temp_command, 0); break; @@ -2005,56 +2350,71 @@ static void atapicommand(int ide_board) 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 (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) - ide->error |= MCR_ERR; - SCSISense.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) - cdrom->readsector(idebufferb,ide->cdpos); - else - cdrom->readsector_raw(idebufferb,ide->cdpos); + case GPCMD_READ_CD_MSF: +// 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]); + if (idebufferb[0] == GPCMD_READ_CD_MSF) + { + ide->cdpos=MSFtoLBA(idebufferb[3],idebufferb[4],idebufferb[5]); + ide->cdlen=MSFtoLBA(idebufferb[6],idebufferb[7],idebufferb[8]); + + ide->cdlen -= ide->cdpos; + ide->cdlen++; + + cdrom_sector_ismsf = 1; + } + else + { + ide->cdlen=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; + ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + + cdrom_sector_ismsf = 0; + } + + cdrom_sector_type = (idebufferb[1] >> 2) & 7; + cdrom_sector_flags = idebufferb[9] || (((uint32_t) idebufferb[10]) << 8); + + ret = cdrom_read_data(ide, idebufferb); + + if (!ret) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (SCSISense.SenseKey == SENSE_UNIT_ATTENTION) + { + ide->error |= MCR_ERR; + } + SCSISense.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); + } + +// pclog("Read at %08X %08X\n",ide.cdpos,ide.cdpos*2048); + #ifndef RPCEMU_IDE - readflash=1; + readflash=1; #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; + + ide->cdpos++; + ide->cdlen--; + if (ide->cdlen >= 0) + ide->packetstatus = ATAPI_STATUS_READCD; + else + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=cdrom_sector_size; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=cdrom_sector_size; + 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; + cdrom_sector_ismsf = 0; if (idebufferb[0] == GPCMD_READ_6) { @@ -2071,7 +2431,8 @@ static void atapicommand(int ide_board) 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) + + if (!ide->cdlen) { // pclog("All done - callback set\n"); ide->packetstatus = ATAPI_STATUS_COMPLETE; @@ -2079,7 +2440,11 @@ static void atapicommand(int ide_board) break; } - cdrom->readsector(idebufferb,ide->cdpos); + cdrom_sector_type = 0; + cdrom_sector_flags = 0x10; + + ret = cdrom_read_data(ide, idebufferb); + #ifndef RPCEMU_IDE readflash=1; #endif @@ -2716,6 +3081,8 @@ static void callnonreadcd(IDE *ide) /* Callabck for non-Read CD commands */ static void callreadcd(IDE *ide) { + int ret; + ide_irq_lower(ide); if (ide->cdlen<=0) { @@ -2726,22 +3093,21 @@ static void callreadcd(IDE *ide) } // pclog("Continue readcd! %i blocks left\n",ide->cdlen); ide->atastat = BUSY_STAT; - - if (readcdmode) - cdrom->readsector_raw((uint8_t *) ide->buffer, ide->cdpos); - else - cdrom->readsector((uint8_t *) ide->buffer, ide->cdpos); + + ret = cdrom_read_data(ide, (uint8_t *) ide->buffer); + #ifndef RPCEMU_IDE readflash=1; #endif + ide->cdpos++; ide->cdlen--; ide->packetstatus = ATAPI_STATUS_READCD; - ide->cylinder=readcdmode ? 2352 : 2048; + ide->cylinder=cdrom_sector_size; ide->secount=2; ide->pos=0; idecallback[ide->board]=60*IDE_TIME; - ide->packlen=readcdmode ? 2352 : 2048; + ide->packlen=cdrom_sector_size; } diff --git a/src/scsi.h b/src/scsi.h index 7d929d713..bdd47ac4f 100644 --- a/src/scsi.h +++ b/src/scsi.h @@ -33,7 +33,9 @@ #define GPCMD_PLAY_AUDIO_12 0xa5 #define GPCMD_READ_12 0xa8 #define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ +#define GPCMD_READ_CD_MSF 0xb9 #define GPCMD_SET_SPEED 0xbb +#define GPCMD_PLAY_CD 0xbc #define GPCMD_MECHANISM_STATUS 0xbd #define GPCMD_READ_CD 0xbe #define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ @@ -166,6 +168,7 @@ extern uint8_t scsi_cdrom_id; struct { + uint8_t UnitAttention; uint8_t SenseKey; uint8_t Asc; uint8_t Ascq; diff --git a/src/scsi_cdrom.c b/src/scsi_cdrom.c index 885c4e832..4aafc59e6 100644 --- a/src/scsi_cdrom.c +++ b/src/scsi_cdrom.c @@ -25,13 +25,17 @@ uint8_t SCSICommandTable[0x100] = [GPCMD_INQUIRY] = ALLOW_UA, [GPCMD_MODE_SELECT_6] = 0, [GPCMD_MODE_SENSE_6] = 0, - [GPCMD_START_STOP_UNIT] = 0, + [GPCMD_START_STOP_UNIT] = CHECK_READY, [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_TOC_PMA_ATIP] = CHECK_READY | ALLOW_UA, /* Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS + NOTE: The ATAPI reference says otherwise, but I think this is a question of + interpreting things right - the UNIT ATTENTION condition we have here + is a tradition from not ready to ready, by definition the drive + eventually becomes ready, make the condition go away. */ [GPCMD_READ_HEADER] = CHECK_READY, [GPCMD_PLAY_AUDIO_10] = CHECK_READY, [GPCMD_GET_CONFIGURATION] = ALLOW_UA, @@ -45,7 +49,9 @@ uint8_t SCSICommandTable[0x100] = [GPCMD_PLAY_AUDIO_12] = CHECK_READY, [GPCMD_READ_12] = CHECK_READY, [GPCMD_READ_DVD_STRUCTURE] = CHECK_READY, + [GPCMD_READ_CD_MSF] = CHECK_READY, [GPCMD_SET_SPEED] = 0, + [GPCMD_PLAY_CD] = CHECK_READY, [GPCMD_MECHANISM_STATUS] = 0, [GPCMD_READ_CD] = CHECK_READY, [GPCMD_SEND_DVD_STRUCTURE] = CHECK_READY @@ -359,9 +365,12 @@ uint32_t SCSICDROMEventStatus(uint8_t *buffer) void SCSICDROM_Insert() { + SCSISense.UnitAttention=1; +#if 0 SCSISense.SenseKey=SENSE_UNIT_ATTENTION; SCSISense.Asc=ASC_MEDIUM_MAY_HAVE_CHANGED; SCSISense.Ascq=0; +#endif } int cd_status = CD_STATUS_EMPTY; @@ -557,7 +566,7 @@ void SCSICDROM_RunCommand(SCSI *Scsi, uint8_t Id, uint8_t *Cdb) if (RCdMode == 0x10) cdrom->readsector(Scsi->SegmentData.Address,Scsi->SectorLba); else - cdrom->readsector_raw(Scsi->SegmentData.Address,Scsi->SectorLba); + cdrom->readsector_raw(Scsi->SegmentData.Address,Scsi->SectorLba, 0); readcdmode = (RCdMode == 0xF8); @@ -1181,7 +1190,7 @@ void SCSICDROM_CallRead(SCSI *Scsi, uint8_t Id) pclog("Continue Read command! %i blocks left\n", Scsi->SectorLen); if (readcdmode) - cdrom->readsector_raw(Scsi->SegmentData.Address, Scsi->SectorLba); + cdrom->readsector_raw(Scsi->SegmentData.Address, Scsi->SectorLba, 0); else cdrom->readsector(Scsi->SegmentData.Address, Scsi->SectorLba);