diff --git a/src/86box.c b/src/86box.c index 147233b21..7beef9333 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1068,6 +1068,10 @@ pc_reset_hard_init(void) /* Reset the Hard Disk Controller module. */ hdc_reset(); + + /* Reset the CD-ROM Controller module. */ + cdrom_interface_reset(); + /* Reset and reconfigure the SCSI layer. */ scsi_card_init(); diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index dd1604801..37795b845 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -23,9 +23,12 @@ #include #define HAVE_STDARG_H #include <86box/86box.h> +#include <86box/device.h> #include <86box/config.h> #include <86box/cdrom.h> #include <86box/cdrom_image.h> +#include <86box/cdrom_interface.h> +#include <86box/cdrom_mitsumi.h> #include <86box/plat.h> #include <86box/scsi.h> #include <86box/scsi_device.h> @@ -43,9 +46,6 @@ #define MIN_SEEK 2000 #define MAX_SEEK 333333 -#define CD_BCD(x) (((x) % 10) | (((x) / 10) << 4)) -#define CD_DCB(x) ((((x) &0xf0) >> 4) * 10 + ((x) &0x0f)) - #pragma pack(push, 1) typedef struct { uint8_t user_data[2048], @@ -94,6 +94,8 @@ static uint8_t extra_buffer[296]; cdrom_t cdrom[CDROM_NUM]; +int cdrom_interface_current; + #ifdef ENABLE_CDROM_LOG int cdrom_do_log = ENABLE_CDROM_LOG; @@ -112,6 +114,145 @@ cdrom_log(const char *fmt, ...) # define cdrom_log(fmt, ...) #endif +static const device_t cdrom_interface_none_device = { + .name = "None", + .internal_name = "none", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + { .available = NULL }, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL +}; + +static const struct { + const device_t *device; +} controllers[] = { + // clang-format off + { &cdrom_interface_none_device }, + { NULL } + // clang-format on +}; + +/* Reset the CD-ROM Interface, whichever one that is. */ +void +cdrom_interface_reset(void) +{ + cdrom_log("CD-ROM Interface: reset(current=%d)\n", + cdrom_interface_current); + + /* If we have a valid controller, add its device. */ + if (!controllers[cdrom_interface_current].device) + return; + + device_add(controllers[cdrom_interface_current].device); +} + +char * +cdrom_interface_get_internal_name(int cdinterface) +{ + return device_get_internal_name(controllers[cdinterface].device); +} + +int +cdrom_interface_get_from_internal_name(char *s) +{ + int c = 0; + + while (controllers[c].device != NULL) { + if (!strcmp((char *) controllers[c].device->internal_name, s)) + return c; + c++; + } + + return 0; +} + +const device_t * +cdrom_interface_get_device(int cdinterface) +{ + return (controllers[cdinterface].device); +} + +int +cdrom_interface_has_config(int cdinterface) +{ + const device_t *dev = cdrom_interface_get_device(cdinterface); + + if (dev == NULL) + return (0); + + if (!device_has_config(dev)) + return (0); + + return (1); +} + +int +cdrom_interface_get_flags(int cdinterface) +{ + return (controllers[cdinterface].device->flags); +} + +int +cdrom_interface_available(int cdinterface) +{ + return (device_available(controllers[cdinterface].device)); +} + +char * +cdrom_getname(int type) +{ + return (char *) cdrom_drive_types[type].name; +} + +char * +cdrom_get_internal_name(int type) +{ + return (char *) cdrom_drive_types[type].internal_name; +} + +int +cdrom_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen(cdrom_drive_types[c].internal_name)) { + if (!strcmp((char *) cdrom_drive_types[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + +void +cdrom_set_type(int model, int type) +{ + cdrom[model].type = type; +} + +int +cdrom_get_type(int model) +{ + return cdrom[model].type; +} + +static __inline int +bin2bcd(int x) +{ + return (x % 10) | ((x / 10) << 4); +} + +static __inline int +bcd2bin(int x) +{ + return (x >> 4) * 10 + (x & 0x0f); +} + int cdrom_lba_to_msf_accurate(int lba) { @@ -258,12 +399,26 @@ cdrom_stop(cdrom_t *dev) } void -cdrom_seek(cdrom_t *dev, uint32_t pos) +cdrom_seek(cdrom_t *dev, uint32_t pos, uint8_t vendor_type) { + int m, s, f; + if (!dev) return; - cdrom_log("CD-ROM %i: Seek to LBA %08X\n", dev->id, pos); + cdrom_log("CD-ROM %i: Seek to LBA %08X, vendor type = %02x.\n", dev->id, pos, vendor_type); + + switch (vendor_type) { + case 0x40: + m = bcd2bin((pos >> 24) & 0xff); + s = bcd2bin((pos >> 16) & 0xff); + f = bcd2bin((pos >> 8) & 0xff); + pos = MSFtoLBA(m, s, f) - 150; + break; + case 0x80: + pos = bcd2bin((pos >> 24) & 0xff); + break; + } dev->seek_pos = pos; cdrom_stop(dev); @@ -323,18 +478,6 @@ cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len) return ret; } -static __inline int -bin2bcd(int x) -{ - return (x % 10) | ((x / 10) << 4); -} - -static __inline int -bcd2bin(int x) -{ - return (x >> 4) * 10 + (x & 0x0f); -} - static void msf_from_bcd(int *m, int *s, int *f) { @@ -365,20 +508,22 @@ cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf) /* Track-relative audio play. */ dev->ops->get_track_info(dev, ismsf & 0xff, 0, &ti); pos += MSFtoLBA(ti.m, ti.s, ti.f) - 150; - } else if (ismsf == 2) { + } else if ((ismsf == 2) || (ismsf == 3)) { dev->ops->get_track_info(dev, pos, 0, &ti); pos = MSFtoLBA(ti.m, ti.s, ti.f) - 150; - /* We have to end at the *end* of the specified track, - not at the beginning. */ - dev->ops->get_track_info(dev, len, 1, &ti); - len = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + if (ismsf == 2) { + /* We have to end at the *end* of the specified track, + not at the beginning. */ + dev->ops->get_track_info(dev, len, 1, &ti); + len = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + } } else if (ismsf == 1) { m = (pos >> 16) & 0xff; s = (pos >> 8) & 0xff; f = pos & 0xff; /* NEC CDR-260 speaks BCD. */ - if ((dev->bus_type == CDROM_BUS_ATAPI) && dev->early) + if (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.01") || (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.00"))) /*NEC*/ msf_from_bcd(&m, &s, &f); if (pos == 0xffffff) { @@ -392,7 +537,7 @@ cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf) f = len & 0xff; /* NEC CDR-260 speaks BCD. */ - if ((dev->bus_type == CDROM_BUS_ATAPI) && dev->early) + if (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.01") || (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.00"))) /*NEC*/ msf_from_bcd(&m, &s, &f); len = MSFtoLBA(m, s, f) - 150; @@ -434,33 +579,41 @@ cdrom_audio_track_search(cdrom_t *dev, uint32_t pos, int type, uint8_t playbit) switch (type) { case 0x00: if (pos == 0xffffffff) { - cdrom_log("CD-ROM %i: Search from current position\n", dev->id); + cdrom_log("CD-ROM %i: (type 0) Search from current position\n", dev->id); pos = dev->seek_pos; } + dev->seek_pos = pos; break; case 0x40: - m = CD_DCB((pos >> 24) & 0xff); - s = CD_DCB((pos >> 16) & 0xff); - f = CD_DCB((pos >> 8) & 0xff); + m = bcd2bin((pos >> 24) & 0xff); + s = bcd2bin((pos >> 16) & 0xff); + f = bcd2bin((pos >> 8) & 0xff); if (pos == 0xffffffff) { - cdrom_log("CD-ROM %i: Search from current position\n", dev->id); + cdrom_log("CD-ROM %i: (type 1) Search from current position\n", dev->id); pos = dev->seek_pos; } else pos = MSFtoLBA(m, s, f) - 150; + + dev->seek_pos = pos; + break; + case 0x80: + if (pos == 0xffffffff) { + cdrom_log("CD-ROM %i: (type 2) Search from current position\n", dev->id); + pos = dev->seek_pos; + } + dev->seek_pos = (pos >> 24) & 0xff; break; } /* Unlike standard commands, if there's a data track on an Audio CD (mixed mode) the playback continues with the audio muted (Toshiba CD-ROM SCSI-2 manual reference). */ - - dev->seek_pos = pos; dev->cd_buflen = 0; dev->cd_status = playbit ? CD_STATUS_PLAYING : CD_STATUS_PAUSED; return 1; } uint8_t -cdrom_toshiba_audio_play(cdrom_t *dev, uint32_t pos, int type) +cdrom_audio_play_toshiba(cdrom_t *dev, uint32_t pos, int type) { int m = 0, s = 0, f = 0; @@ -468,31 +621,85 @@ cdrom_toshiba_audio_play(cdrom_t *dev, uint32_t pos, int type) return 0; /*Preliminary support, revert if too incomplete*/ - cdrom_log("Toshiba Play Audio: MSF = %06x, cdstatus = %02x\n", pos, dev->cd_status); switch (type) { + case 0x00: + dev->cd_end = pos; + break; case 0x40: - m = CD_DCB((pos >> 24) & 0xff); - s = CD_DCB((pos >> 16) & 0xff); - f = CD_DCB((pos >> 8) & 0xff); + m = bcd2bin((pos >> 24) & 0xff); + s = bcd2bin((pos >> 16) & 0xff); + f = bcd2bin((pos >> 8) & 0xff); pos = MSFtoLBA(m, s, f) - 150; + dev->cd_end = pos; + break; + case 0x80: + dev->cd_end = (pos >> 24) & 0xff; break; case 0xc0: if (pos == 0xffffffff) { cdrom_log("CD-ROM %i: Playing from current position\n", dev->id); pos = dev->cd_end; } + dev->cd_end = pos; break; } + cdrom_log("Toshiba/NEC Play Audio: MSF = %06x, type = %02x, cdstatus = %02x\n", pos, type, dev->cd_status); + /* Unlike standard commands, if there's a data track on an Audio CD (mixed mode) the playback continues with the audio muted (Toshiba CD-ROM SCSI-2 manual reference). */ - dev->cd_end = pos; dev->cd_buflen = 0; dev->cd_status = CD_STATUS_PLAYING; return 1; } +uint8_t +cdrom_audio_scan(cdrom_t *dev, uint32_t pos, int type) +{ + int m = 0, s = 0, f = 0; + + if (dev->cd_status == CD_STATUS_DATA_ONLY) + return 0; + + cdrom_log("Audio Scan: MSF = %06x, type = %02x\n", pos, type); + switch (type) { + case 0x00: + if (pos == 0xffffffff) { + cdrom_log("CD-ROM %i: (type 0) Search from current position\n", dev->id); + pos = dev->seek_pos; + } + dev->seek_pos = pos; + break; + case 0x40: + m = bcd2bin((pos >> 24) & 0xff); + s = bcd2bin((pos >> 16) & 0xff); + f = bcd2bin((pos >> 8) & 0xff); + if (pos == 0xffffffff) { + cdrom_log("CD-ROM %i: (type 1) Search from current position\n", dev->id); + pos = dev->seek_pos; + } else + pos = MSFtoLBA(m, s, f) - 150; + + dev->seek_pos = pos; + break; + case 0x80: + dev->seek_pos = (pos >> 24) & 0xff; + break; + } + + /* Do this at this point, since it's at this point that we know the + actual LBA position to start playing from. */ + if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) { + cdrom_log("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos); + cdrom_stop(dev); + return 0; + } + + dev->cd_buflen = 0; + return 1; +} + void cdrom_audio_pause_resume(cdrom_t *dev, uint8_t resume) { @@ -509,7 +716,6 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) uint32_t dat; dev->ops->get_subchannel(dev, dev->seek_pos, &subc); - cdrom_log("CD-ROM %i: Returned subchannel at %02i:%02i.%02i\n", subc.abs_m, subc.abs_s, subc.abs_f); if (dev->cd_status == CD_STATUS_DATA_ONLY) ret = 0x15; @@ -522,8 +728,12 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) ret = 0x13; } - if (b[pos] > 1) + cdrom_log("CD-ROM %i: Returned subchannel at %02i:%02i.%02i, ret = %02x, seek pos = %08x, cd_end = %08x.\n", dev->id, subc.abs_m, subc.abs_s, subc.abs_f, ret, dev->seek_pos, dev->cd_end); + + if (b[pos] > 1) { + cdrom_log("B[%i] = %02x, ret = %02x.\n", pos, b[pos], ret); return ret; + } b[pos++] = subc.attr; b[pos++] = subc.track; @@ -533,7 +743,7 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) b[pos] = 0; /* NEC CDR-260 speaks BCD. */ - if ((dev->bus_type == CDROM_BUS_ATAPI) && dev->early) { + if (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.01") || (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.00"))) /*NEC*/ { m = subc.abs_m; s = subc.abs_s; f = subc.abs_f; @@ -552,7 +762,7 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) b[pos] = 0; /* NEC CDR-260 speaks BCD. */ - if ((dev->bus_type == CDROM_BUS_ATAPI) && dev->early) { + if (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.01") || (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.00"))) /*NEC*/ { m = subc.rel_m; s = subc.rel_s; f = subc.rel_f; @@ -583,6 +793,78 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) return ret; } +void +cdrom_get_current_subchannel_sony(cdrom_t *dev, uint8_t *b, int msf) +{ + subchannel_t subc; + int pos = 0, m, s, f; + uint32_t dat; + + dev->ops->get_subchannel(dev, dev->seek_pos, &subc); + + cdrom_log("CD-ROM %i: Returned subchannel at %02i:%02i.%02i, ret = %02x, seek pos = %08x, cd_end = %08x.\n", dev->id, subc.abs_m, subc.abs_s, subc.abs_f, ret, dev->seek_pos, dev->cd_end); + + b[pos++] = subc.attr; + b[pos++] = subc.track; + b[pos++] = subc.index; + + if (msf) { + b[pos++] = subc.rel_m; + b[pos++] = subc.rel_s; + b[pos++] = subc.rel_f; + b[pos++] = subc.abs_m; + b[pos++] = subc.abs_s; + b[pos++] = subc.abs_f; + } else { + dat = MSFtoLBA(subc.rel_m, subc.rel_s, subc.rel_f); + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + dat = MSFtoLBA(subc.abs_m, subc.abs_s, subc.abs_f) - 150; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + } +} + + +uint8_t +cdrom_get_audio_status_sony(cdrom_t *dev, uint8_t *b, int msf) +{ + uint8_t ret; + subchannel_t subc; + int m, s, f; + uint32_t dat; + + dev->ops->get_subchannel(dev, dev->seek_pos, &subc); + + if (dev->cd_status == CD_STATUS_DATA_ONLY) + ret = 0x05; + else { + if (dev->cd_status == CD_STATUS_PLAYING) + ret = dev->sound_on ? 0x00 : 0x02; + else if (dev->cd_status == CD_STATUS_PAUSED) + ret = 0x01; + else + ret = 0x03; + } + + if (msf) { + b[0] = 0; + b[1] = subc.abs_m; + b[2] = subc.abs_s; + b[3] = subc.abs_f; + } else { + dat = MSFtoLBA(subc.abs_m, subc.abs_s, subc.abs_f) - 150; + b[0] = (dat >> 24) & 0xff; + b[1] = (dat >> 16) & 0xff; + b[2] = (dat >> 8) & 0xff; + b[3] = dat & 0xff; + } + + return ret; +} + uint8_t cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b) { @@ -599,16 +881,14 @@ cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b) ret = (dev->cd_status == CD_STATUS_PLAYING) ? 0x00 : dev->audio_op; b[0] = subc.attr; - b[1] = CD_BCD(subc.track); - b[2] = CD_BCD(subc.index); - b[3] = CD_BCD(subc.rel_m); - b[4] = CD_BCD(subc.rel_s); - b[5] = CD_BCD(subc.rel_f); - b[6] = CD_BCD(subc.abs_m); - b[7] = CD_BCD(subc.abs_s); - b[8] = CD_BCD(subc.abs_f); - cdrom_log("CD-ROM %i: Returned subcode-q at %02i:%02i.%02i, track=%02x\n", dev->id, b[3], b[4], b[5], b[1]); - + b[1] = bin2bcd(subc.track); + b[2] = bin2bcd(subc.index); + b[3] = bin2bcd(subc.rel_m); + b[4] = bin2bcd(subc.rel_s); + b[5] = bin2bcd(subc.rel_f); + b[6] = bin2bcd(subc.abs_m); + b[7] = bin2bcd(subc.abs_s); + b[8] = bin2bcd(subc.abs_f); return ret; } @@ -670,7 +950,7 @@ read_toc_normal(cdrom_t *dev, unsigned char *b, unsigned char start_track, int m b[len++] = 0; /* NEC CDR-260 speaks BCD. */ - if ((dev->bus_type == CDROM_BUS_ATAPI) && dev->early) { + if (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.01") || (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.00"))) { /*NEC*/ m = ti.m; s = ti.s; f = ti.f; @@ -720,7 +1000,7 @@ read_toc_session(cdrom_t *dev, unsigned char *b, int msf) b[len++] = 0; /* NEC CDR-260 speaks BCD. */ - if ((dev->bus_type == CDROM_BUS_ATAPI) && dev->early) { + if (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.01") || (!strcmp(cdrom_drive_types[dev->type].internal_name, "NEC_CD-ROM_DRIVE260_1.00"))) { /*NEC*/ m = ti.m; s = ti.s; f = ti.f; @@ -778,6 +1058,75 @@ read_toc_raw(cdrom_t *dev, unsigned char *b) return len; } +static int +read_toc_sony(cdrom_t *dev, unsigned char *b, unsigned char start_track, int msf) +{ + track_info_t ti; + int i, len = 4; + int m, s, f; + int first_track, last_track; + uint32_t temp; + + cdrom_log("read_toc_sony(%08X, %08X, %02X, %i)\n", dev, b, start_track, msf); + + dev->ops->get_tracks(dev, &first_track, &last_track); + + /* Byte 2 = Number of the first track */ + dev->ops->get_track_info(dev, 1, 0, &ti); + b[2] = ti.number; + cdrom_log(" b[2] = %02X\n", b[2]); + + /* Byte 3 = Number of the last track before the lead-out track */ + dev->ops->get_track_info(dev, last_track, 0, &ti); + b[3] = ti.number; + cdrom_log(" b[3] = %02X\n", b[2]); + + if (start_track == 0x00) + first_track = 0; + else { + first_track = -1; + for (i = 0; i <= last_track; i++) { + dev->ops->get_track_info(dev, i + 1, 0, &ti); + if (ti.number >= start_track) { + first_track = i; + break; + } + } + } + cdrom_log(" first_track = %i, last_track = %i\n", first_track, last_track); + + /* No suitable starting track, return with error. */ + if (first_track == -1) { +#ifdef ENABLE_CDROM_LOG + cdrom_log(" [ERROR] No suitable track found\n"); +#endif + return -1; + } + + for (i = first_track; i <= last_track; i++) { + cdrom_log(" tracks(%i) = %02X, %02X, %i:%02i.%02i\n", i, ti.attr, ti.number, ti.m, ti.s, ti.f); + dev->ops->get_track_info(dev, i + 1, 0, &ti); + + b[len++] = ti.attr; + b[len++] = ti.number; /* track number */ + + if (msf) { + b[len++] = 0; + b[len++] = ti.m; + b[len++] = ti.s; + b[len++] = ti.f; + } else { + temp = MSFtoLBA(ti.m, ti.s, ti.f) - 150; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + } + + return len; +} + int cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_track, int msf, int max_len) { @@ -806,6 +1155,21 @@ cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_tra return len; } +int +cdrom_read_toc_sony(cdrom_t *dev, unsigned char *b, unsigned char start_track, int msf, int max_len) +{ + int len; + + len = read_toc_sony(dev, b, start_track, msf); + + len = MIN(len, max_len); + + b[0] = (uint8_t) (((len - 2) >> 8) & 0xff); + b[1] = (uint8_t) ((len - 2) & 0xff); + + return len; +} + /* New API calls for Mitsumi CD-ROM. */ void cdrom_get_track_buffer(cdrom_t *dev, uint8_t *buf) @@ -841,7 +1205,7 @@ cdrom_get_q(cdrom_t *dev, uint8_t *buf, int *curtoctrk, uint8_t mode) dev->ops->get_track_info(dev, *curtoctrk, 0, &ti); buf[0] = (ti.attr << 4) & 0xf0; buf[1] = ti.number; - buf[2] = CD_BCD(*curtoctrk + 1); + buf[2] = bin2bcd(*curtoctrk + 1); buf[3] = ti.m; buf[4] = ti.s; buf[5] = ti.f; @@ -888,36 +1252,50 @@ cdrom_mitsumi_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len) return 1; } -void +uint8_t cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, int type) { track_info_t ti; int first_track, last_track; + int m = 0, s = 0, f = 0; dev->ops->get_tracks(dev, &first_track, &last_track); - cdrom_log("Read DISC Info TOC Type = %d.\n", type); + cdrom_log("Read DISC Info TOC Type = %d, track = %d, first_track = %d, last_track = %d.\n", type, track, first_track, last_track); switch (type) { case 0: - b[0] = CD_BCD(first_track); - b[1] = CD_BCD(last_track); + b[0] = bin2bcd(first_track); + b[1] = bin2bcd(last_track); b[2] = 0; b[3] = 0; + cdrom_log("CD-ROM %i: Returned Toshiba/NEC disc information (type 0) at %02i:%02i\n", dev->id, b[0], b[1]); break; case 1: - dev->ops->get_track_info(dev, 0xAA, 0, &ti); - b[0] = CD_BCD(ti.m); - b[1] = CD_BCD(ti.s); - b[2] = CD_BCD(ti.f); + dev->ops->get_track_info(dev, 0xaa, 0, &ti); + m = ti.m; + s = ti.s; + f = ti.f; + msf_to_bcd(&m, &s, &f); + b[0] = m; + b[1] = s; + b[2] = f; b[3] = 0; + cdrom_log("CD-ROM %i: Returned Toshiba/NEC disc information (type 1) at %02i:%02i.%02i, track=%d\n", dev->id, b[0], b[1], b[2], bcd2bin(track)); break; case 2: - dev->ops->get_track_info(dev, CD_DCB(track), 0, &ti); - b[0] = CD_BCD(ti.m); - b[1] = CD_BCD(ti.s); - b[2] = CD_BCD(ti.f); + if (track > bin2bcd(last_track)) + return 0; + + dev->ops->get_track_info(dev, bcd2bin(track), 0, &ti); + m = ti.m; + s = ti.s; + f = ti.f; + msf_to_bcd(&m, &s, &f); + b[0] = m; + b[1] = s; + b[2] = f; b[3] = ti.attr; - cdrom_log("CD-ROM %i: Returned Toshiba disc information at %02i:%02i.%02i, track=%d\n", dev->id, b[0], b[1], b[2], CD_DCB(track)); + cdrom_log("CD-ROM %i: Returned Toshiba/NEC disc information (type 2) at %02i:%02i.%02i, track=%d, m=%02i,s=%02i,f=%02i, tno=%02x.\n", dev->id, b[0], b[1], b[2], bcd2bin(track), m, s, f, ti.attr); break; case 3: b[0] = 0x00; /*TODO: correct it further, mark it as CD-Audio/CD-ROM disc for now*/ @@ -926,6 +1304,8 @@ cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, in b[3] = 0; break; } + + return 1; } static int @@ -1203,7 +1583,7 @@ read_mode2_xa_form2(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t int cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, - int cdrom_sector_flags, int *len) + int cdrom_sector_flags, int *len, uint8_t vendor_type) { uint8_t *b, *temp_b; uint32_t msf, lba; @@ -1224,8 +1604,23 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int c lba = MSFtoLBA(m, s, f) - 150; msf = sector; } else { - lba = sector; - msf = cdrom_lba_to_msf_accurate(sector); + switch (vendor_type) { + case 0x00: + lba = sector; + msf = cdrom_lba_to_msf_accurate(sector); + break; + case 0x40: + m = bcd2bin((sector >> 24) & 0xff); + s = bcd2bin((sector >> 16) & 0xff); + f = bcd2bin((sector >> 8) & 0xff); + lba = MSFtoLBA(m, s, f) - 150; + msf = sector; + break; + case 0x80: + lba = bcd2bin((sector >> 24) & 0xff); + msf = sector; + break; + } } if (dev->ops->track_type) diff --git a/src/config.c b/src/config.c index 8e2b5c292..a552408c0 100644 --- a/src/config.c +++ b/src/config.c @@ -61,6 +61,7 @@ #include <86box/scsi.h> #include <86box/scsi_device.h> #include <86box/cdrom.h> +#include <86box/cdrom_interface.h> #include <86box/zip.h> #include <86box/mo.h> #include <86box/sound.h> @@ -904,6 +905,15 @@ load_storage_controllers(void) p = NULL; } + p = ini_section_get_string(cat, "cdrom_interface", NULL); + if (p != NULL) + cdrom_interface_current = cdrom_interface_get_from_internal_name(p); + + if (free_p) { + free(p); + p = NULL; + } + ide_ter_enabled = !!ini_section_get_int(cat, "ide_ter", 0); ide_qua_enabled = !!ini_section_get_int(cat, "ide_qua", 0); @@ -1321,8 +1331,13 @@ load_floppy_and_cdrom_drives(void) sprintf(temp, "cdrom_%02i_speed", c + 1); cdrom[c].speed = ini_section_get_int(cat, temp, 8); - sprintf(temp, "cdrom_%02i_early", c + 1); - cdrom[c].early = ini_section_get_int(cat, temp, 0); + + sprintf(temp, "cdrom_%02i_type", c + 1); + p = ini_section_get_string(cat, temp, (c == 1) ? "86BOX_CD-ROM_1.00" : "none"); + cdrom_set_type(c, cdrom_get_from_internal_name(p)); + if (cdrom_get_type(c) > KNOWN_CDROM_DRIVE_TYPES) + cdrom_set_type(c, KNOWN_CDROM_DRIVE_TYPES); + ini_section_delete_var(cat, temp); /* Default values, needed for proper operation of the Settings dialog. */ cdrom[c].ide_channel = cdrom[c].scsi_device_id = c + 2; @@ -2470,6 +2485,12 @@ save_storage_controllers(void) ini_section_set_string(cat, "hdc", hdc_get_internal_name(hdc_current)); + if (cdrom_interface_current == 0) + ini_section_delete_var(cat, "cdrom_interface"); + else + ini_section_set_string(cat, "cdrom_interface", + cdrom_interface_get_internal_name(cdrom_interface_current)); + if (ide_ter_enabled == 0) ini_section_delete_var(cat, "ide_ter"); else @@ -2717,17 +2738,25 @@ save_floppy_and_cdrom_drives(void) ini_section_set_int(cat, temp, cdrom[c].speed); } - sprintf(temp, "cdrom_%02i_early", c + 1); - if ((cdrom[c].bus_type == 0) || (cdrom[c].early == 0)) { + sprintf(temp, "cdrom_%02i_type", c + 1); + if ((cdrom[c].bus_type == 0) || (cdrom[c].bus_type == CDROM_BUS_MITSUMI)) { ini_section_delete_var(cat, temp); } else { - ini_section_set_int(cat, temp, cdrom[c].early); + ini_section_set_string(cat, temp, + cdrom_get_internal_name(cdrom_get_type(c))); } sprintf(temp, "cdrom_%02i_parameters", c + 1); if (cdrom[c].bus_type == 0) { ini_section_delete_var(cat, temp); - } else { + } else { /*In case one wants an ATAPI drive on SCSI and vice-versa.*/ + if (cdrom[c].bus_type == CDROM_BUS_ATAPI) { + if (cdrom_drive_types[cdrom_get_type(c)].bus_type == BUS_TYPE_SCSI) + cdrom[c].bus_type = CDROM_BUS_SCSI; + } else if (cdrom[c].bus_type == CDROM_BUS_SCSI) { + if (cdrom_drive_types[cdrom_get_type(c)].bus_type == BUS_TYPE_IDE) + cdrom[c].bus_type = CDROM_BUS_ATAPI; + } sprintf(tmp2, "%u, %s", cdrom[c].sound_on, hdd_bus_to_string(cdrom[c].bus_type, 1)); ini_section_set_string(cat, temp, tmp2); diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index f5bfc9026..ca7bcb2a1 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -60,6 +60,54 @@ enum { CDROM_BUS_USB }; +#define KNOWN_CDROM_DRIVE_TYPES 30 +#define BUS_TYPE_ALL 0 +#define BUS_TYPE_IDE 1 +#define BUS_TYPE_SCSI 2 + +static const struct +{ + const char vendor[9]; + const char model[17]; + const char revision[5]; + const char *name; + const char *internal_name; + const int bus_type; +} cdrom_drive_types[] = +{ + { "86BOX", "CD-ROM", "1.00", "(ATAPI/SCSI) 86BOX CD-ROM 1.00", "86BOX_CD-ROM_1.00", BUS_TYPE_ALL}, + { "AZT", "CDA46802I", "1.15", "(ATAPI) AZT CDA46802I 1.15", "AZT_CDA46802I_1.15", BUS_TYPE_IDE}, + { "BTC", "CD-ROM BCD36XH", "U1.0", "(ATAPI) BTC CD-ROM BCD36XH U1.0", "BTC_CD-ROM_BCD36XH_U1.0", BUS_TYPE_IDE}, + { "GOLDSTAR", "CRD-8160B", "3.14", "(ATAPI) GOLDSTAR CRD-8160B 3.14", "GOLDSTAR_CRD-8160B_3.14", BUS_TYPE_IDE}, + { "HITACHI", "CDR-8130", "0020", "(ATAPI) HITACHI CDR-8130 0020", "HITACHI_CDR-8130_0020", BUS_TYPE_IDE}, + { "KENWOOD", "CD-ROM UCR-421", "208E", "(ATAPI) KENWOOD CD-ROM UCR-421 208E", "KENWOOD_CD-ROM_UCR-421_208E", BUS_TYPE_IDE}, + { "MATSHITA", "CD-ROM CR-587", "7S13", "(ATAPI) MATSHITA CD-ROM CR-587 7S13", "MATSHITA_CD-ROM_CR-587_7S13", BUS_TYPE_IDE}, + { "MATSHITA", "CD-ROM CR-588", "LS15", "(ATAPI) MATSHITA CD-ROM CR-588 LS15", "MATSHITA_CD-ROM_CR-588_LS15", BUS_TYPE_IDE}, + { "MITSUMI", "CRMC-FX4820T", "D02A", "(ATAPI) MITSUMI CRMC-FX4820T D02A", "MITSUMI_CRMC-FX4820T_D02A", BUS_TYPE_IDE}, + { "NEC", "CD-ROM DRIVE:260", "1.00", "(ATAPI) NEC CD-ROM DRIVE:260 1.00", "NEC_CD-ROM_DRIVE260_1.00", BUS_TYPE_IDE}, + { "NEC", "CD-ROM DRIVE:260", "1.01", "(ATAPI) NEC CD-ROM DRIVE:260 1.01", "NEC_CD-ROM_DRIVE260_1.01", BUS_TYPE_IDE}, + { "NEC", "CDR-1300A", "1.05", "(ATAPI) NEC CDR-1300A 1.05", "NEC_CDR-1300A_1.05", BUS_TYPE_IDE}, + { "PHILIPS", "CD-ROM PCA403CD", "U31P", "(ATAPI) PHILIPS CD-ROM PCA403CD U31P", "PHILIPS_CD-ROM_PCA403CD_U31P", BUS_TYPE_IDE}, + { "SONY", "CD-ROM CDU76", "1.0i", "(ATAPI) SONY CD-ROM CDU76 1.0i", "SONY_CD-ROM_CDU76_1.0i", BUS_TYPE_IDE}, + { "SONY", "CD-ROM CDU311", "3.0h", "(ATAPI) SONY CD-ROM CDU311 3.0h", "SONY_CD-ROM_CDU311_3.0h", BUS_TYPE_IDE}, + { "TOSHIBA", "CD-ROM XM-5702B", "TA70", "(ATAPI) TOSHIBA CD-ROM XM-5702B TA70", "TOSHIBA_CD-ROM_XM-5702B_TA70", BUS_TYPE_IDE}, + { "CHINON", "CD-ROM CDS-431", "H42 ", "(SCSI) CHINON CD-ROM CDS-431 H42", "CHINON_CD-ROM_CDS-431_H42", BUS_TYPE_SCSI}, + { "DEC", "RRD45 (C) DEC", "0436", "(SCSI) DEC RRD45 0436", "DEC_RRD45_0436", BUS_TYPE_SCSI}, + { "MATSHITA", "CD-ROM CR-501", "1.0b", "(SCSI) MATSHITA CD-ROM CR-501 1.0b", "MATSHITA_CD-ROM_CR-501_1.0b", BUS_TYPE_SCSI}, + { "NEC", "CD-ROM DRIVE:74", "1.00", "(SCSI) NEC CD-ROM DRIVE:74 1.00", "NEC_CD-ROM_DRIVE74_1.00", BUS_TYPE_SCSI}, + { "NEC", "CD-ROM DRIVE:464", "1.05", "(SCSI) NEC CD-ROM DRIVE:464 1.05", "NEC_CD-ROM_DRIVE464_1.05", BUS_TYPE_SCSI}, + { "SONY", "CD-ROM CDU-541", "1.0i", "(SCSI) SONY CD-ROM CDU-541 1.0i", "SONY_CD-ROM_CDU-541_1.0i", BUS_TYPE_SCSI}, + { "SONY", "CD-ROM CDU-76S", "1.00", "(SCSI) SONY CD-ROM CDU-76S 1.00", "SONY_CD-ROM_CDU-76S_1.00", BUS_TYPE_SCSI}, + { "PHILIPS", "CDD2600", "1.07", "(SCSI) PHILIPS CDD2600 1.07", "PHILIPS_CDD2600_1.07", BUS_TYPE_SCSI}, + { "PIONEER", "CD-ROM DRM-604X", "2403", "(SCSI) PIONEER CD-ROM DRM-604X 2403", "PIONEER_CD-ROM_DRM-604X_2403", BUS_TYPE_SCSI}, + { "PLEXTOR", "CD-ROM PX-32TS", "1.03", "(SCSI) PLEXTOR CD-ROM PX-32TS 1.03", "PLEXTOR_CD-ROM_PX-32TS_1.03", BUS_TYPE_SCSI}, + { "TEAC", "CD-R55S", "1.0R", "(SCSI) TEAC CD-R55S 1.0R", "TEAC_CD-R55S_1.0R", BUS_TYPE_SCSI}, + { "TOSHIBA", "CD-ROM DRIVE:XM", "3433", "(SCSI) TOSHIBA CD-ROM DRIVE:XM 3433", "TOSHIBA_CD-ROM_DRIVEXM_3433", BUS_TYPE_SCSI}, + { "TOSHIBA", "CD-ROM XM-3301TA", "0272", "(SCSI) TOSHIBA CD-ROM XM-3301TA 0272", "TOSHIBA_CD-ROM_XM-3301TA_0272", BUS_TYPE_SCSI}, + { "TOSHIBA", "CD-ROM XM-5701TA", "3136", "(SCSI) TOSHIBA CD-ROM XM-5701TA 3136", "TOSHIBA_CD-ROM_XM-5701TA_3136", BUS_TYPE_SCSI}, + { "", "", "", "", "", -1}, +}; + /* To shut up the GCC compilers. */ struct cdrom; @@ -113,7 +161,7 @@ typedef struct cdrom { uint32_t sound_on, cdrom_capacity, early, seek_pos, - seek_diff, cd_end; + seek_diff, cd_end, type; int host_drive, prev_host_drive, cd_buflen, audio_op; @@ -132,6 +180,13 @@ typedef struct cdrom { extern cdrom_t cdrom[CDROM_NUM]; +extern char *cdrom_getname(int type); + +extern char *cdrom_get_internal_name(int type); +extern int cdrom_get_from_internal_name(char *s); +extern void cdrom_set_type(int model, int type); +extern int cdrom_get_type(int model); + extern int cdrom_lba_to_msf_accurate(int lba); extern double cdrom_seek_time(cdrom_t *dev); extern void cdrom_stop(cdrom_t *dev); @@ -139,20 +194,24 @@ extern int cdrom_is_pre(cdrom_t *dev, uint32_t lba); extern int cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len); extern uint8_t cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf); extern uint8_t cdrom_audio_track_search(cdrom_t *dev, uint32_t pos, int type, uint8_t playbit); -extern uint8_t cdrom_toshiba_audio_play(cdrom_t *dev, uint32_t pos, int type); +extern uint8_t cdrom_audio_play_toshiba(cdrom_t *dev, uint32_t pos, int type); extern void cdrom_audio_pause_resume(cdrom_t *dev, uint8_t resume); +extern uint8_t cdrom_audio_scan(cdrom_t *dev, uint32_t pos, int type); +extern uint8_t cdrom_get_audio_status_sony(cdrom_t *dev, uint8_t *b, int msf); extern uint8_t cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf); +extern void cdrom_get_current_subchannel_sony(cdrom_t *dev, uint8_t *b, int msf); extern uint8_t cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b); extern int cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_track, int msf, int max_len); +extern int cdrom_read_toc_sony(cdrom_t *dev, unsigned char *b, unsigned char start_track, int msf, int max_len); extern void cdrom_get_track_buffer(cdrom_t *dev, uint8_t *buf); extern void cdrom_get_q(cdrom_t *dev, uint8_t *buf, int *curtoctrk, uint8_t mode); extern uint8_t cdrom_mitsumi_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len); extern int cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, - int cdrom_sector_type, int cdrom_sector_flags, int *len); -extern void cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, int type); + int cdrom_sector_type, int cdrom_sector_flags, int *len, uint8_t vendor_type); +extern uint8_t cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, int type); -extern void cdrom_seek(cdrom_t *dev, uint32_t pos); +extern void cdrom_seek(cdrom_t *dev, uint32_t pos, uint8_t vendor_type); extern void cdrom_close_handler(uint8_t id); extern void cdrom_insert(uint8_t id); diff --git a/src/include/86box/cdrom_interface.h b/src/include/86box/cdrom_interface.h new file mode 100644 index 000000000..860a436e0 --- /dev/null +++ b/src/include/86box/cdrom_interface.h @@ -0,0 +1,31 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * Definitions for the common CD-ROM interface controller handler. + * + * + * + * Authors: TheCollector1995 + * + * Copyright 2022 TheCollector1995. + */ +#ifndef EMU_CDROM_INTERFACE_H +#define EMU_CDROM_INTERFACE_H + +extern int cdrom_interface_current; + +extern void cdrom_interface_reset(void); + +extern char *cdrom_interface_get_internal_name(int cdinterface); +extern int cdrom_interface_get_from_internal_name(char *s); +extern int cdrom_interface_has_config(int cdinterface); +extern const device_t *cdrom_interface_get_device(int cdinterface); +extern int cdrom_interface_get_flags(int cdinterface); +extern int cdrom_interface_available(int cdinterface); + +#endif /*EMU_CDROM_INTERFACE_H*/ diff --git a/src/include/86box/scsi_cdrom.h b/src/include/86box/scsi_cdrom.h index e991ccc36..42d4412d1 100644 --- a/src/include/86box/scsi_cdrom.h +++ b/src/include/86box/scsi_cdrom.h @@ -49,6 +49,10 @@ typedef struct { packet_len, pos; double callback; + + mode_sense_pages_t ms_pages_saved_sony; + mode_sense_pages_t ms_drive_status_pages_saved; + int sony_vendor; } scsi_cdrom_t; #endif diff --git a/src/include/86box/scsi_device.h b/src/include/86box/scsi_device.h index 650215cb5..8cb2f3877 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -53,6 +53,8 @@ #define GPCMD_SEEK_6 0x0b #define GPCMD_IOMEGA_SET_PROTECTION_MODE 0x0c #define GPCMD_IOMEGA_EJECT 0x0d /* ATAPI only? */ +#define GPCMD_NO_OPERATION_TOSHIBA 0x0d /* Toshiba Vendor Unique command */ +#define GPCMD_NO_OPERATION_NEC 0x0d /* NEC Vendor Unique command */ #define GPCMD_INQUIRY 0x12 #define GPCMD_VERIFY_6 0x13 #define GPCMD_MODE_SELECT_6 0x15 @@ -64,7 +66,7 @@ #define GPCMD_PREVENT_REMOVAL 0x1e #define GPCMD_READ_FORMAT_CAPACITIES 0x23 #define GPCMD_READ_CDROM_CAPACITY 0x25 -#define GPCMD_CHINON_UNKNOWN 0x26 +#define GPCMD_UNKNOWN_CHINON 0x26 /*Chinon Vendor Unique command*/ #define GPCMD_READ_10 0x28 #define GPCMD_READ_GENERATION 0x29 #define GPCMD_WRITE_10 0x2a @@ -100,23 +102,51 @@ #define GPCMD_PLAY_CD_OLD 0xb4 #define GPCMD_READ_CD_OLD 0xb8 #define GPCMD_READ_CD_MSF 0xb9 -#define GPCMD_SCAN 0xba +#define GPCMD_AUDIO_SCAN 0xba #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 86Box. */ -#define GPCMD_CHINON_EJECT 0xc0 /* Chinon Vendor Unique command */ -#define GPCMD_AUDIO_TRACK_SEARCH 0xc0 /* Toshiba Vendor Unique command */ -#define GPCMD_TOSHIBA_PLAY_AUDIO 0xc1 /* Toshiba Vendor Unique command */ +#define GPCMD_EJECT_CHINON 0xc0 /* Chinon Vendor Unique command */ +#define GPCMD_AUDIO_TRACK_SEARCH_TOSHIBA 0xc0 /* Toshiba Vendor Unique command */ +#define GPCMD_UNKNOWN_SONY 0xc0 /* Sony Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_TOSHIBA 0xc1 /* Toshiba Vendor Unique command */ +#define GPCMD_READ_TOC_SONY 0xc1 /* Sony Vendor Unique command */ #define GPCMD_PAUSE_RESUME_ALT 0xc2 -#define GPCMD_STILL 0xc2 /* Toshiba Vendor Unique command */ -#define GPCMD_CADDY_EJECT 0xc4 /* Toshiba Vendor Unique command */ -#define GPCMD_CHINON_STOP 0xc6 /* Chinon Vendor Unique command */ -#define GPCMD_READ_SUBCODEQ_PLAYING_STATUS 0xc6 /* Toshiba Vendor Unique command */ +#define GPCMD_READ_SUBCHANNEL_MATSUSHITA 0xc2 /* Matsushita Vendor Unique command */ +#define GPCMD_READ_SUBCHANNEL_SONY 0xc2 /* Sony Vendor Unique command */ +#define GPCMD_STILL_TOSHIBA 0xc2 /* Toshiba Vendor Unique command */ +#define GPCMD_READ_TOC_MATSUSHITA 0xc3 /* Matsushita Vendor Unique command */ +#define GPCMD_READ_HEADER_SONY 0xc3 /* Sony Vendor Unique command */ +#define GPCMD_SET_STOP_TIME_TOSHIBA 0xc3 /* Toshiba Vendor Unique command */ +#define GPCMD_READ_HEADER_MATSUSHITA 0xc4 /* Matsushita Vendor Unique command */ +#define GPCMD_PLAYBACK_STATUS_TOSHIBA 0xc4 /* Sony Vendor Unique command */ +#define GPCMD_CADDY_EJECT_TOSHIBA 0xc4 /* Toshiba Vendor Unique command */ +#define GPCMD_PAUSE_SONY 0xc5 /* Sony Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_MATSUSHITA 0xc5 /* Matsushita Vendor Unique command */ +#define GPCMD_STOP_CHINON 0xc6 /* Chinon Vendor Unique command */ +#define GPCMD_PLAT_TRACK_SONY 0xc6 /* Sony Vendor Unique command */ +#define GPCMD_READ_SUBCODEQ_PLAYING_STATUS_TOSHIBA 0xc6 /* Toshiba Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_MSF_MATSUSHITA 0xc7 /* Matsushita Vendor Unique command*/ +#define GPCMD_PLAY_MSF_SONY 0xc7 /* Sony Vendor Unique command*/ #define GPCMD_READ_DISC_INFORMATION_TOSHIBA 0xc7 /* Toshiba Vendor Unique command */ -#define GPCMD_SCAN_ALT 0xcd /* Should be equivalent to 0xba */ +#define GPCMD_PLAY_AUDIO_TRACK_INDEX_MATSUSHITA 0xc8 /* Matsushita Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_SONY 0xc8 /* Sony Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10_MATSUSHITA 0xc9 /*Matsushita Vendor Unique command */ +#define GPCMD_PLAYBACK_CONTROL_SONY 0xc9 /* Sony Vendor Unique command */ +#define GPCMD_PAUSE_RESUME_MATSUSHITA 0xcb /* Matsushita Vendor Unique command */ +#define GPCMD_SCAN_PIONEER 0xcd /* Should be equivalent to 0xba */ +#define GPCMD_AUDIO_TRACK_SEARCH_NEC 0xd8 /* NEC Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_NEC 0xd9 /* NEC Vendor Unique command */ +#define GPCMD_STILL_NEC 0xda /* NEC Vendor Unique command */ #define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */ +#define GPCMD_SET_STOP_TIME_NEC 0xdb /* NEC Vendor Unique command */ +#define GPCMD_CADDY_EJECT_NEC 0xdc /* NEC Vendor Unique command */ +#define GPCMD_READ_SUBCODEQ_PLAYING_STATUS_NEC 0xdd /* NEC Vendor Unique command */ +#define GPCMD_READ_DISC_INFORMATION_NEC 0xde /* NEC Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_12_MATSUSHITA 0xe5 /* Matsushita Vendor Unique command */ +#define GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12_MATSUSHITA 0xe9 /* Matsushita Vendor Unique command */ /* Mode page codes for mode sense/set */ #define GPMODE_R_W_ERROR_PAGE 0x01 @@ -125,6 +155,8 @@ #define GPMODE_RIGID_DISK_PAGE 0x04 /* Rigid disk geometry page */ #define GPMODE_FLEXIBLE_DISK_PAGE 0x05 #define GPMODE_CACHING_PAGE 0x08 +#define GPMODE_CDROM_PAGE_SONY 0x08 +#define GPMODE_CDROM_AUDIO_PAGE_SONY 0x09 #define GPMODE_CDROM_PAGE 0x0d #define GPMODE_CDROM_AUDIO_PAGE 0x0e #define GPMODE_CAPABILITIES_PAGE 0x2a @@ -139,6 +171,8 @@ #define GPMODEP_RIGID_DISK_PAGE 0x0000000000000010LL #define GPMODEP_FLEXIBLE_DISK_PAGE 0x0000000000000020LL #define GPMODEP_CACHING_PAGE 0x0000000000000100LL +#define GPMODEP_CDROM_PAGE_SONY 0x0000000000000200LL +#define GPMODEP_CDROM_AUDIO_PAGE_SONY 0x0000000000000400LL #define GPMODEP_CDROM_PAGE 0x0000000000002000LL #define GPMODEP_CDROM_AUDIO_PAGE 0x0000000000004000LL #define GPMODEP_CAPABILITIES_PAGE 0x0000040000000000LL diff --git a/src/qt/qt_harddrive_common.cpp b/src/qt/qt_harddrive_common.cpp index 7d3beaa2b..2b415f6f4 100644 --- a/src/qt/qt_harddrive_common.cpp +++ b/src/qt/qt_harddrive_common.cpp @@ -20,6 +20,7 @@ extern "C" { #include <86box/hdd.h> +#include <86box/cdrom.h> } #include @@ -48,14 +49,16 @@ void Harddrives::populateRemovableBuses(QAbstractItemModel *model) { model->removeRows(0, model->rowCount()); - model->insertRows(0, 3); + model->insertRows(0, 4); model->setData(model->index(0, 0), QObject::tr("Disabled")); model->setData(model->index(1, 0), QObject::tr("ATAPI")); model->setData(model->index(2, 0), QObject::tr("SCSI")); + model->setData(model->index(3, 0), QObject::tr("Mitsumi")); model->setData(model->index(0, 0), HDD_BUS_DISABLED, Qt::UserRole); model->setData(model->index(1, 0), HDD_BUS_ATAPI, Qt::UserRole); model->setData(model->index(2, 0), HDD_BUS_SCSI, Qt::UserRole); + model->setData(model->index(3, 0), CDROM_BUS_MITSUMI, Qt::UserRole); } void @@ -143,6 +146,9 @@ Harddrives::BusChannelName(uint8_t bus, uint8_t channel) case HDD_BUS_SCSI: busName = QString("SCSI (%1:%2)").arg(channel >> 4).arg(channel & 15, 2, 10, QChar('0')); break; + case CDROM_BUS_MITSUMI: + busName = QString("Mitsumi"); + break; } return busName; diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index 23df27150..d095eadb7 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -29,6 +29,7 @@ extern uint64_t tsc; #include <86box/cartridge.h> #include <86box/cassette.h> #include <86box/cdrom.h> +#include <86box/cdrom_interface.h> #include <86box/fdd.h> #include <86box/hdc.h> #include <86box/scsi.h> @@ -300,6 +301,8 @@ MachineStatus::iterateCDROM(const std::function &cb) continue; if ((cdrom[i].bus_type == CDROM_BUS_SCSI) && !hasSCSI() && (scsi_card_current[0] == 0) && (scsi_card_current[1] == 0) && (scsi_card_current[2] == 0) && (scsi_card_current[3] == 0)) continue; + if ((cdrom[i].bus_type == CDROM_BUS_MITSUMI) && (cdrom_interface_current == 0)) + continue; if (cdrom[i].bus_type != 0) { cb(i); } diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index e0c145981..f6f091bdc 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -593,6 +593,9 @@ MediaMenu::cdromUpdateMenu(int i) case CDROM_BUS_SCSI: busName = "SCSI"; break; + case CDROM_BUS_MITSUMI: + busName = "Mitsumi"; + break; } // menu->setTitle(tr("CD-ROM %1 (%2): %3").arg(QString::number(i+1), busName, name.isEmpty() ? tr("(empty)") : name)); diff --git a/src/qt/qt_settingsfloppycdrom.cpp b/src/qt/qt_settingsfloppycdrom.cpp index 2eabe80ab..751bb829a 100644 --- a/src/qt/qt_settingsfloppycdrom.cpp +++ b/src/qt/qt_settingsfloppycdrom.cpp @@ -20,6 +20,15 @@ #include "ui_qt_settingsfloppycdrom.h" extern "C" { +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include <86box/86box.h> #include <86box/timer.h> #include <86box/fdd.h> #include <86box/cdrom.h> @@ -59,6 +68,7 @@ setCDROMBus(QAbstractItemModel *model, const QModelIndex &idx, uint8_t bus, uint break; case CDROM_BUS_ATAPI: case CDROM_BUS_SCSI: + case CDROM_BUS_MITSUMI: icon = ProgSettings::loadIcon("/cdrom.ico"); break; } @@ -88,6 +98,18 @@ setCDROMEarly(QAbstractItemModel *model, const QModelIndex &idx, bool early) model->setData(i, early, Qt::UserRole); } +static void +setCDROMType(QAbstractItemModel *model, const QModelIndex &idx, int type) +{ + auto i = idx.siblingAtColumn(2); + if (idx.siblingAtColumn(0).data(Qt::UserRole).toUInt() == CDROM_BUS_DISABLED) { + model->setData(i, QCoreApplication::translate("", "None")); + } else if (idx.siblingAtColumn(0).data(Qt::UserRole).toUInt() != CDROM_BUS_MITSUMI) { + model->setData(i, QObject::tr(cdrom_getname(type))); + } + model->setData(i, type, Qt::UserRole); +} + SettingsFloppyCDROM::SettingsFloppyCDROM(QWidget *parent) : QWidget(parent) , ui(new Ui::SettingsFloppyCDROM) @@ -134,18 +156,36 @@ SettingsFloppyCDROM::SettingsFloppyCDROM(QWidget *parent) Models::AddEntry(model, QString("%1x").arg(i + 1), i + 1); } + model = ui->comboBoxCDROMType->model(); + i = 0; + while (true) { + QString name = tr(cdrom_getname(i)); + if (name.isEmpty()) { + break; + } + + Models::AddEntry(model, name, i); + ++i; + } + model = new QStandardItemModel(0, 3, this); ui->tableViewCDROM->setModel(model); model->setHeaderData(0, Qt::Horizontal, tr("Bus")); model->setHeaderData(1, Qt::Horizontal, tr("Speed")); - model->setHeaderData(2, Qt::Horizontal, tr("Earlier drive")); + model->setHeaderData(2, Qt::Horizontal, tr("Type")); model->insertRows(0, CDROM_NUM); for (int i = 0; i < CDROM_NUM; i++) { auto idx = model->index(i, 0); + int type = cdrom_get_type(i); setCDROMBus(model, idx, cdrom[i].bus_type, cdrom[i].res); setCDROMSpeed(model, idx.siblingAtColumn(1), cdrom[i].speed); - setCDROMEarly(model, idx.siblingAtColumn(2), cdrom[i].early); - Harddrives::busTrackClass->device_track(1, DEV_CDROM, cdrom[i].bus_type, cdrom[i].bus_type == CDROM_BUS_ATAPI ? cdrom[i].ide_channel : cdrom[i].scsi_device_id); + setCDROMType(model, idx.siblingAtColumn(2), type); + if (cdrom[i].bus_type == CDROM_BUS_ATAPI) + Harddrives::busTrackClass->device_track(1, DEV_CDROM, cdrom[i].bus_type, cdrom[i].ide_channel); + else if (cdrom[i].bus_type == CDROM_BUS_SCSI) + Harddrives::busTrackClass->device_track(1, DEV_CDROM, cdrom[i].bus_type, cdrom[i].scsi_device_id); + else if (cdrom[i].bus_type == CDROM_BUS_MITSUMI) + Harddrives::busTrackClass->device_track(1, DEV_CDROM, cdrom[i].bus_type, 0); } ui->tableViewCDROM->resizeColumnsToContents(); ui->tableViewCDROM->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); @@ -172,18 +212,18 @@ SettingsFloppyCDROM::save() /* Removable devices category */ model = ui->tableViewCDROM->model(); for (int i = 0; i < CDROM_NUM; i++) { - cdrom[i].is_dir = 0; - cdrom[i].priv = NULL; - cdrom[i].ops = NULL; - cdrom[i].image = NULL; - cdrom[i].insert = NULL; - cdrom[i].close = NULL; - cdrom[i].get_volume = NULL; + cdrom[i].is_dir = 0; + cdrom[i].priv = NULL; + cdrom[i].ops = NULL; + cdrom[i].image = NULL; + cdrom[i].insert = NULL; + cdrom[i].close = NULL; + cdrom[i].get_volume = NULL; cdrom[i].get_channel = NULL; - cdrom[i].bus_type = model->index(i, 0).data(Qt::UserRole).toUInt(); - cdrom[i].res = model->index(i, 0).data(Qt::UserRole + 1).toUInt(); - cdrom[i].speed = model->index(i, 1).data(Qt::UserRole).toUInt(); - cdrom[i].early = model->index(i, 2).data(Qt::UserRole).toUInt(); + cdrom[i].bus_type = model->index(i, 0).data(Qt::UserRole).toUInt(); + cdrom[i].res = model->index(i, 0).data(Qt::UserRole + 1).toUInt(); + cdrom[i].speed = model->index(i, 1).data(Qt::UserRole).toUInt(); + cdrom_set_type(i, model->index(i, 2).data(Qt::UserRole).toInt()); } } @@ -202,12 +242,12 @@ SettingsFloppyCDROM::onCDROMRowChanged(const QModelIndex ¤t) uint8_t bus = current.siblingAtColumn(0).data(Qt::UserRole).toUInt(); uint8_t channel = current.siblingAtColumn(0).data(Qt::UserRole + 1).toUInt(); uint8_t speed = current.siblingAtColumn(1).data(Qt::UserRole).toUInt(); - bool early = current.siblingAtColumn(2).data(Qt::UserRole).toBool(); + int type = current.siblingAtColumn(2).data(Qt::UserRole).toInt(); ui->comboBoxBus->setCurrentIndex(-1); - auto *model = ui->comboBoxBus->model(); - auto match = model->match(model->index(0, 0), Qt::UserRole, bus); - if (!match.isEmpty()) { + auto* model = ui->comboBoxBus->model(); + auto match = model->match(model->index(0, 0), Qt::UserRole, bus); + if (! match.isEmpty()) { ui->comboBoxBus->setCurrentIndex(match.first().row()); } @@ -218,7 +258,7 @@ SettingsFloppyCDROM::onCDROMRowChanged(const QModelIndex ¤t) } ui->comboBoxSpeed->setCurrentIndex(speed == 0 ? 7 : speed - 1); - ui->checkBoxEarlierDrive->setChecked(early); + ui->comboBoxCDROMType->setCurrentIndex(type); } void @@ -250,9 +290,10 @@ SettingsFloppyCDROM::on_comboBoxBus_currentIndexChanged(int index) int bus = ui->comboBoxBus->currentData().toInt(); bool enabled = (bus != CDROM_BUS_DISABLED); - ui->comboBoxChannel->setEnabled(enabled); - ui->comboBoxSpeed->setEnabled(enabled); - ui->checkBoxEarlierDrive->setEnabled(enabled); + ui->comboBoxChannel->setEnabled((bus == CDROM_BUS_MITSUMI) ? 0 : enabled); + ui->comboBoxSpeed->setEnabled((bus == CDROM_BUS_MITSUMI) ? 0 : enabled); + ui->comboBoxCDROMType->setEnabled((bus == CDROM_BUS_MITSUMI) ? 0 : enabled); + Harddrives::populateBusChannels(ui->comboBoxChannel->model(), bus); } @@ -266,14 +307,26 @@ SettingsFloppyCDROM::on_comboBoxSpeed_activated(int index) void SettingsFloppyCDROM::on_comboBoxBus_activated(int) { - auto i = ui->tableViewCDROM->selectionModel()->currentIndex().siblingAtColumn(0); + auto i = ui->tableViewCDROM->selectionModel()->currentIndex().siblingAtColumn(0); + uint8_t bus_type = ui->comboBoxBus->currentData().toUInt(); + Harddrives::busTrackClass->device_track(0, DEV_CDROM, ui->tableViewCDROM->model()->data(i, Qt::UserRole).toInt(), ui->tableViewCDROM->model()->data(i, Qt::UserRole + 1).toInt()); - ui->comboBoxChannel->setCurrentIndex(ui->comboBoxBus->currentData().toUInt() == CDROM_BUS_ATAPI ? Harddrives::busTrackClass->next_free_ide_channel() : Harddrives::busTrackClass->next_free_scsi_id()); + if (bus_type == CDROM_BUS_ATAPI) + ui->comboBoxChannel->setCurrentIndex(Harddrives::busTrackClass->next_free_ide_channel()); + else if (bus_type == CDROM_BUS_SCSI) + ui->comboBoxChannel->setCurrentIndex(Harddrives::busTrackClass->next_free_scsi_id()); + else if (bus_type == CDROM_BUS_MITSUMI) + ui->comboBoxChannel->setCurrentIndex(0); + setCDROMBus( ui->tableViewCDROM->model(), ui->tableViewCDROM->selectionModel()->currentIndex(), - ui->comboBoxBus->currentData().toUInt(), + bus_type, ui->comboBoxChannel->currentData().toUInt()); + setCDROMType( + ui->tableViewCDROM->model(), + ui->tableViewCDROM->selectionModel()->currentIndex(), + ui->comboBoxCDROMType->currentData().toUInt()); Harddrives::busTrackClass->device_track(1, DEV_CDROM, ui->tableViewCDROM->model()->data(i, Qt::UserRole).toInt(), ui->tableViewCDROM->model()->data(i, Qt::UserRole + 1).toInt()); } @@ -291,8 +344,12 @@ SettingsFloppyCDROM::on_comboBoxChannel_activated(int) } void -SettingsFloppyCDROM::on_checkBoxEarlierDrive_stateChanged(int arg1) +SettingsFloppyCDROM::on_comboBoxCDROMType_activated(int) { - auto idx = ui->tableViewCDROM->selectionModel()->currentIndex(); - setCDROMEarly(ui->tableViewCDROM->model(), idx.siblingAtColumn(2), (arg1 == Qt::Checked) ? true : false); + setCDROMType( + ui->tableViewCDROM->model(), + ui->tableViewCDROM->selectionModel()->currentIndex(), + ui->comboBoxCDROMType->currentData().toUInt()); + ui->tableViewCDROM->resizeColumnsToContents(); + ui->tableViewCDROM->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); } diff --git a/src/qt/qt_settingsfloppycdrom.hpp b/src/qt/qt_settingsfloppycdrom.hpp index 5c2920199..3d6dd0e45 100644 --- a/src/qt/qt_settingsfloppycdrom.hpp +++ b/src/qt/qt_settingsfloppycdrom.hpp @@ -17,6 +17,7 @@ public: void save(); private slots: + void on_comboBoxCDROMType_activated(int index); void on_comboBoxChannel_activated(int index); void on_comboBoxBus_activated(int index); void on_comboBoxSpeed_activated(int index); @@ -27,8 +28,6 @@ private slots: void onFloppyRowChanged(const QModelIndex ¤t); void onCDROMRowChanged(const QModelIndex ¤t); - void on_checkBoxEarlierDrive_stateChanged(int arg1); - private: Ui::SettingsFloppyCDROM *ui; }; diff --git a/src/qt/qt_settingsfloppycdrom.ui b/src/qt/qt_settingsfloppycdrom.ui index 6233e9e7b..30be29153 100644 --- a/src/qt/qt_settingsfloppycdrom.ui +++ b/src/qt/qt_settingsfloppycdrom.ui @@ -115,16 +115,20 @@ + + + + Bus: + + + - + Channel: - - - @@ -132,25 +136,24 @@ - - + + - Bus: + Type: + + + - - - - Earlier drive - - + + diff --git a/src/qt/qt_settingsstoragecontrollers.cpp b/src/qt/qt_settingsstoragecontrollers.cpp index 2aecab568..ac406853c 100644 --- a/src/qt/qt_settingsstoragecontrollers.cpp +++ b/src/qt/qt_settingsstoragecontrollers.cpp @@ -25,6 +25,7 @@ extern "C" { #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/fdc_ext.h> +#include <86box/cdrom_interface.h> #include <86box/scsi.h> #include <86box/scsi_device.h> #include <86box/cassette.h> @@ -57,11 +58,12 @@ SettingsStorageControllers::save() auto *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); scsi_card_current[i] = cbox->currentData().toInt(); } - hdc_current = ui->comboBoxHD->currentData().toInt(); - fdc_type = ui->comboBoxFD->currentData().toInt(); - ide_ter_enabled = ui->checkBoxTertiaryIDE->isChecked() ? 1 : 0; - ide_qua_enabled = ui->checkBoxQuaternaryIDE->isChecked() ? 1 : 0; - cassette_enable = ui->checkBoxCassette->isChecked() ? 1 : 0; + hdc_current = ui->comboBoxHD->currentData().toInt(); + fdc_type = ui->comboBoxFD->currentData().toInt(); + cdrom_interface_current = ui->comboBoxCDInterface->currentData().toInt(); + ide_ter_enabled = ui->checkBoxTertiaryIDE->isChecked() ? 1 : 0; + ide_qua_enabled = ui->checkBoxQuaternaryIDE->isChecked() ? 1 : 0; + cassette_enable = ui->checkBoxCassette->isChecked() ? 1 : 0; } void @@ -131,6 +133,35 @@ SettingsStorageControllers::onCurrentMachineChanged(int machineId) ui->comboBoxFD->setCurrentIndex(-1); ui->comboBoxFD->setCurrentIndex(selectedRow); + /*CD interface controller config*/ + model = ui->comboBoxCDInterface->model(); + removeRows = model->rowCount(); + c = 0; + selectedRow = 0; + while (true) { + /* Skip "internal" if machine doesn't have it. */ + QString name = DeviceConfig::DeviceName(cdrom_interface_get_device(c), cdrom_interface_get_internal_name(c), 1); + if (name.isEmpty()) { + break; + } + + if (cdrom_interface_available(c)) { + auto *cdrom_interface_dev = cdrom_interface_get_device(c); + + if (device_is_valid(cdrom_interface_dev, machineId)) { + int row = Models::AddEntry(model, name, c); + if (c == cdrom_interface_current) { + selectedRow = row - removeRows; + } + } + } + c++; + } + model->removeRows(0, removeRows); + ui->comboBoxCDInterface->setEnabled(model->rowCount() > 0); + ui->comboBoxCDInterface->setCurrentIndex(-1); + ui->comboBoxCDInterface->setCurrentIndex(selectedRow); + for (int i = 0; i < SCSI_BUS_MAX; ++i) { auto *cbox = findChild(QString("comboBoxSCSI%1").arg(i + 1)); model = cbox->model(); @@ -187,6 +218,14 @@ SettingsStorageControllers::on_comboBoxFD_currentIndexChanged(int index) ui->pushButtonFD->setEnabled(hdc_has_config(ui->comboBoxFD->currentData().toInt()) > 0); } +void SettingsStorageControllers::on_comboBoxCDInterface_currentIndexChanged(int index) +{ + if (index < 0) { + return; + } + ui->pushButtonCDInterface->setEnabled(cdrom_interface_has_config(ui->comboBoxCDInterface->currentData().toInt()) > 0); +} + void SettingsStorageControllers::on_checkBoxTertiaryIDE_stateChanged(int arg1) { diff --git a/src/qt/qt_settingsstoragecontrollers.hpp b/src/qt/qt_settingsstoragecontrollers.hpp index 7e9cd9d6c..5641889e4 100644 --- a/src/qt/qt_settingsstoragecontrollers.hpp +++ b/src/qt/qt_settingsstoragecontrollers.hpp @@ -32,10 +32,12 @@ private slots: void on_pushButtonTertiaryIDE_clicked(); void on_pushButtonFD_clicked(); void on_pushButtonHD_clicked(); + void on_pushButtonCDInterface_clicked(); void on_checkBoxQuaternaryIDE_stateChanged(int arg1); void on_checkBoxTertiaryIDE_stateChanged(int arg1); void on_comboBoxFD_currentIndexChanged(int index); void on_comboBoxHD_currentIndexChanged(int index); + void on_comboBoxCDInterface_currentIndexChanged(int index); private: Ui::SettingsStorageControllers *ui; diff --git a/src/qt/qt_settingsstoragecontrollers.ui b/src/qt/qt_settingsstoragecontrollers.ui index 30a59f982..558d4c441 100644 --- a/src/qt/qt_settingsstoragecontrollers.ui +++ b/src/qt/qt_settingsstoragecontrollers.ui @@ -49,6 +49,23 @@ + + + + CD-ROM Controller: + + + + + + + + + + Configure + + + @@ -69,21 +86,21 @@ - + Tertiary IDE Controller - + Quaternary IDE Controller - + false @@ -93,7 +110,7 @@ - + false diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index e736b879d..d2cf4c4e5 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -62,7 +62,7 @@ typedef struct #pragma pack(pop) /* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ -const uint8_t scsi_cdrom_command_flags[0x100] = { +uint8_t scsi_cdrom_command_flags[0x100] = { IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ 0, /* 0x02 */ @@ -71,7 +71,9 @@ const uint8_t scsi_cdrom_command_flags[0x100] = { IMPLEMENTED | CHECK_READY, /* 0x08 */ 0, 0, /* 0x09-0x0A */ IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ - 0, 0, 0, 0, 0, 0, /* 0x0C-0x11 */ + 0, /* 0x0C */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0x0D */ + 0, 0, 0, 0, /* 0x0E-0x11 */ IMPLEMENTED | ALLOW_UA, /* 0x12 */ IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ 0, /* 0x14 */ @@ -81,9 +83,11 @@ const uint8_t scsi_cdrom_command_flags[0x100] = { IMPLEMENTED | CHECK_READY, /* 0x1B */ 0, 0, /* 0x1C-0x1D */ IMPLEMENTED | CHECK_READY, /* 0x1E */ - 0, 0, 0, 0, 0, 0, /* 0x1F-0x24 */ + 0, 0, 0, /* 0x1F-0x21*/ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0x22*/ + 0, 0, /* 0x23-0x24 */ IMPLEMENTED | CHECK_READY, /* 0x25 */ - IMPLEMENTED | CHECK_READY | SCSI_ONLY | EARLY_ONLY, /* 0x26 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0x26 */ 0, /* 0x27 */ IMPLEMENTED | CHECK_READY, /* 0x28 */ 0, 0, /* 0x29-0x2A */ @@ -143,21 +147,94 @@ const uint8_t scsi_cdrom_command_flags[0x100] = { IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC0 */ IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC1 */ IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC2 */ - 0, /* 0xC3 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC3 */ IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC4 */ - 0, /* 0xC5 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC5 */ IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC6 */ IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC7 */ - 0, 0, 0, 0, 0, /* 0xC8-0xCC */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC8 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC9 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCA */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCB */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCC */ IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCD */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCE-0xD9 */ - IMPLEMENTED | SCSI_ONLY, /* 0xDA */ - 0, 0, 0, 0, 0, /* 0xDB-0xDF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0-0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCE-0xD7 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xD8 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xD9 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xDA */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xDB */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xDC */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xDD */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xDE */ + 0, /* 0xDF */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE0 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE1 */ + 0, /* 0xE2 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE3 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE4 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE5 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE6 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE7 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE8 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xE9 */ + 0, /* 0xEA */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xEB */ + 0, /* 0xEC */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xED */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xEE */ + 0, /* 0xEF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xF0-0xFF */ }; static uint64_t scsi_cdrom_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_DISCONNECT_PAGE | GPMODEP_CDROM_PAGE | GPMODEP_CDROM_AUDIO_PAGE | (1ULL << 0x0fULL) | GPMODEP_CAPABILITIES_PAGE | GPMODEP_ALL_PAGES); +static uint64_t scsi_cdrom_mode_sense_page_flags_sony = (GPMODEP_R_W_ERROR_PAGE | GPMODEP_DISCONNECT_PAGE | GPMODEP_CDROM_PAGE_SONY | GPMODEP_CDROM_AUDIO_PAGE_SONY | (1ULL << 0x0fULL) | GPMODEP_CAPABILITIES_PAGE | GPMODEP_ALL_PAGES); +static uint64_t scsi_cdrom_drive_status_page_flags = ((1ULL << 0x01ULL) | (1ULL << 0x02ULL) | (1ULL << 0x0fULL) | GPMODEP_ALL_PAGES); + +static const mode_sense_pages_t scsi_cdrom_drive_status_pages = { + {{ 0, 0 }, + { 0x01, 0, 2, 0x0f, 0xbf }, /*Drive Status Data Format*/ + { 0x02, 0, 1, 0}, /*Audio Play Status Format*/ + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }} +}; static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default = { {{ 0, 0 }, @@ -174,7 +251,7 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default = { { 0, 0 }, { 0, 0 }, { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0xE, 4, 0, 0, 0, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -220,7 +297,53 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default_scsi = { { 0, 0 }, { 0, 0 }, { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, - { 0x8E, 0xE, 5, 4, 0, 128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0xE, 5, 4, 0, 128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 }} +}; + +static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_default_sony_scsi = { + {{ 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { GPMODE_DISCONNECT_PAGE, 0x0e, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE_SONY, 2, 1, 0 }, + { GPMODE_CDROM_AUDIO_PAGE_SONY | 0x80, 0xE, 5, 0, 0, 0, 0, 0, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0xE, 5, 4, 0, 128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -266,7 +389,53 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_changeable = { { 0, 0 }, { 0, 0 }, { GPMODE_CDROM_PAGE, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0x8E, 0xE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0xE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }} +}; + +static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_changeable_sony = { + {{ 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0xFF, 0xFF, 0, 0, 0, 0 }, + { GPMODE_DISCONNECT_PAGE, 0x0E, 0xFF, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE_SONY, 2, 0xFF, 0xFF }, + { GPMODE_CDROM_AUDIO_PAGE_SONY | 0x80, 0xE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { GPMODE_CDROM_AUDIO_PAGE | 0x80, 0xE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, { 0x0F, 0x14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -303,6 +472,7 @@ static gesn_event_header_t *gesn_event_header; static void scsi_cdrom_command_complete(scsi_cdrom_t *dev); static void scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev); +static void scsi_cdrom_drive_status_load(scsi_cdrom_t *dev); static void scsi_cdrom_init(scsi_cdrom_t *dev); @@ -352,7 +522,7 @@ scsi_cdrom_init(scsi_cdrom_t *dev) dev->sense[0] = 0xf0; dev->sense[7] = 10; - if (dev->early) + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE260_1.01") || !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE260_1.00")) /*NEC only*/ dev->status = READY_STAT | DSC_STAT; else dev->status = 0; @@ -361,6 +531,8 @@ scsi_cdrom_init(scsi_cdrom_t *dev) scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; dev->drv->cur_speed = dev->drv->speed; scsi_cdrom_mode_sense_load(dev); + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403")) + scsi_cdrom_drive_status_load(dev); } /* Returns: 0 for none, 1 for PIO, 2 for DMA. */ @@ -411,7 +583,11 @@ scsi_cdrom_get_channel(void *p, int channel) if (!dev) return channel + 1; - return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) + return dev->ms_pages_saved_sony.pages[dev->sony_vendor ? GPMODE_CDROM_AUDIO_PAGE_SONY : GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; + else + return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; } static uint32_t @@ -421,7 +597,11 @@ scsi_cdrom_get_volume(void *p, int channel) if (!dev) return 255; - return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) + return dev->ms_pages_saved_sony.pages[dev->sony_vendor ? GPMODE_CDROM_AUDIO_PAGE_SONY : GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; + else + return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; } static void @@ -430,22 +610,37 @@ scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) FILE *f; char file_name[512]; - memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); - if (dev->drv->bus_type == CDROM_BUS_SCSI) - memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default_scsi, sizeof(mode_sense_pages_t)); - else - memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default, sizeof(mode_sense_pages_t)); + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { + memset(&dev->ms_pages_saved_sony, 0, sizeof(mode_sense_pages_t)); + memcpy(&dev->ms_pages_saved_sony, &scsi_cdrom_mode_sense_pages_default_sony_scsi, sizeof(mode_sense_pages_t)); - memset(file_name, 0, 512); - if (dev->drv->bus_type == CDROM_BUS_SCSI) - sprintf(file_name, "scsi_cdrom_%02i_mode_sense_bin", dev->id); - else - sprintf(file_name, "cdrom_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), "rb"); - if (f) { - if (fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f) != 0x10) - fatal("scsi_cdrom_mode_sense_load(): Error reading data\n"); - fclose(f); + memset(file_name, 0, 512); + sprintf(file_name, "scsi_cdrom_%02i_mode_sense_sony_bin", dev->id); + f = plat_fopen(nvr_path(file_name), "rb"); + if (f) { + if (fread(dev->ms_pages_saved_sony.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, 0x10, f) != 0x10) + fatal("scsi_cdrom_mode_sense_load(): Error reading data\n"); + fclose(f); + } + } else { + memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); + if (dev->drv->bus_type == CDROM_BUS_SCSI) + memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default_scsi, sizeof(mode_sense_pages_t)); + else + memcpy(&dev->ms_pages_saved, &scsi_cdrom_mode_sense_pages_default, sizeof(mode_sense_pages_t)); + + memset(file_name, 0, 512); + if (dev->drv->bus_type == CDROM_BUS_SCSI) + sprintf(file_name, "scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + sprintf(file_name, "cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), "rb"); + if (f) { + if (fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f) != 0x10) + fatal("scsi_cdrom_mode_sense_load(): Error reading data\n"); + fclose(f); + } } } @@ -456,35 +651,116 @@ scsi_cdrom_mode_sense_save(scsi_cdrom_t *dev) char file_name[512]; memset(file_name, 0, 512); - if (dev->drv->bus_type == CDROM_BUS_SCSI) - sprintf(file_name, "scsi_cdrom_%02i_mode_sense_bin", dev->id); - else - sprintf(file_name, "cdrom_%02i_mode_sense_bin", dev->id); - f = plat_fopen(nvr_path(file_name), "wb"); - if (f) { - fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); - fclose(f); + + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { + sprintf(file_name, "scsi_cdrom_%02i_mode_sense_sony_bin", dev->id); + f = plat_fopen(nvr_path(file_name), "wb"); + if (f) { + fwrite(dev->ms_pages_saved_sony.pages[GPMODE_CDROM_AUDIO_PAGE_SONY], 1, 0x10, f); + fclose(f); + } + } else { + if (dev->drv->bus_type == CDROM_BUS_SCSI) + sprintf(file_name, "scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + sprintf(file_name, "cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), "wb"); + if (f) { + fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); + fclose(f); + } } } +/*SCSI Drive Status (Pioneer only)*/ +static void +scsi_cdrom_drive_status_load(scsi_cdrom_t *dev) +{ + memset(&dev->ms_drive_status_pages_saved, 0, sizeof(mode_sense_pages_t)); + memcpy(&dev->ms_drive_status_pages_saved, &scsi_cdrom_drive_status_pages, sizeof(mode_sense_pages_t)); +} + +static uint8_t +scsi_cdrom_drive_status_read(scsi_cdrom_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) +{ + return dev->ms_drive_status_pages_saved.pages[page][pos]; +} + +static uint32_t +scsi_cdrom_drive_status(scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t page) +{ + uint8_t page_control = (page >> 6) & 3; + int i = 0, j = 0; + + uint16_t msplen; + + page &= 0x3f; + + for (i = 0; i < 0x40; i++) { + if (page == i) { + if (scsi_cdrom_drive_status_page_flags & (1LL << ((uint64_t) (page & 0x3f)))) { + buf[pos++] = scsi_cdrom_drive_status_read(dev, page_control, i, 0); + msplen = (scsi_cdrom_drive_status_read(dev, page_control, i, 1) << 8); + msplen |= scsi_cdrom_drive_status_read(dev, page_control, i, 2); + buf[pos++] = (msplen >> 8) & 0xff; + buf[pos++] = msplen & 0xff; + scsi_cdrom_log("CD-ROM %i: DRIVE STATUS: Page [%02X] length %i\n", dev->id, i, msplen); + for (j = 0; j < msplen; j++) { + if (i == 0x01) { + buf[pos++] = scsi_cdrom_drive_status_read(dev, page_control, i, 3 + j); + if (!(j & 1)) { /*MSB of Drive Status*/ + if (dev->drv->ops) /*Bit 11 of Drive Status, */ + buf[pos] &= ~0x08; /*Disc is present*/ + else + buf[pos] |= 0x08; /*Disc not present*/ + } + } else if ((i == 0x02) && (j == 0)) { + buf[pos++] = ((dev->drv->cd_status == CD_STATUS_PLAYING) ? 0x01 : 0x00); + } else + buf[pos++] = scsi_cdrom_drive_status_read(dev, page_control, i, 3 + j); + } + } + } + } + + return pos; +} + /*SCSI Mode Sense 6/10*/ static uint8_t scsi_cdrom_mode_sense_read(scsi_cdrom_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) { - switch (page_control) { - case 0: - case 3: - return dev->ms_pages_saved.pages[page][pos]; - break; - case 1: - return scsi_cdrom_mode_sense_pages_changeable.pages[page][pos]; - break; - case 2: - if (dev->drv->bus_type == CDROM_BUS_SCSI) - return scsi_cdrom_mode_sense_pages_default_scsi.pages[page][pos]; - else - return scsi_cdrom_mode_sense_pages_default.pages[page][pos]; - break; + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { + switch (page_control) { + case 0: + case 3: + return dev->ms_pages_saved_sony.pages[page][pos]; + break; + case 1: + return scsi_cdrom_mode_sense_pages_changeable_sony.pages[page][pos]; + break; + case 2: + return scsi_cdrom_mode_sense_pages_default_sony_scsi.pages[page][pos]; + break; + } + } else { + switch (page_control) { + case 0: + case 3: + return dev->ms_pages_saved.pages[page][pos]; + break; + case 1: + return scsi_cdrom_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + if (dev->drv->bus_type == CDROM_BUS_SCSI) + return scsi_cdrom_mode_sense_pages_default_scsi.pages[page][pos]; + else + return scsi_cdrom_mode_sense_pages_default.pages[page][pos]; + break; + } } return 0; @@ -526,14 +802,25 @@ scsi_cdrom_mode_sense(scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t pag else { if ((i == GPMODE_CAPABILITIES_PAGE) && (j == 4)) { buf[pos] = scsi_cdrom_mode_sense_read(dev, page_control, i, 2 + j) & 0x1f; - /* The early CD-ROM drives we emulate (NEC CDR-260 for ATAPI and Toshiba CDS-431) are + /* The early CD-ROM drives we emulate (NEC CDR-260 for ATAPI and early vendor SCSI CD-ROM models) are caddy drives, the later ones are tray drives. */ - buf[pos++] |= (dev->early ? 0x00 : 0x20); + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + buf[pos++] |= ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "86BOX_CD-ROM_1.00")) ? 0x20 : 0x00); + } else { + buf[pos++] |= ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE260_1.01") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE260_1.00")) ? 0x00 : 0x20); + } } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 6) && (j <= 7)) { if (j & 1) buf[pos++] = ((dev->drv->speed * 176) & 0xff); else buf[pos++] = ((dev->drv->speed * 176) >> 8); + } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 8) && (j <= 9) && + (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403"))) { + if (j & 1) + buf[pos++] = ((dev->drv->speed * 176) & 0xff); + else + buf[pos++] = ((dev->drv->speed * 176) >> 8); } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 12) && (j <= 13)) { if (j & 1) buf[pos++] = ((dev->drv->cur_speed * 176) & 0xff); @@ -684,14 +971,44 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) case 0xb8: case 0xb9: case 0xbe: - case 0xc6: - case 0xc7: if (dev->current_cdb[0] == 0x42) dev->callback += 40.0; /* Account for seek time. */ bytes_per_second = 176.0 * 1024.0; bytes_per_second *= (double) dev->drv->cur_speed; break; + case 0xc6: + case 0xc7: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_DRIVEXM_3433"))) { + bytes_per_second = 176.0 * 1024.0; + bytes_per_second *= (double) dev->drv->cur_speed; + } + break; + case 0xc1: + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403")) { + bytes_per_second = 176.0 * 1024.0; + bytes_per_second *= (double) dev->drv->cur_speed; + } + break; + case 0xc2: + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403")) { + dev->callback += 40.0; + bytes_per_second = 176.0 * 1024.0; + bytes_per_second *= (double) dev->drv->cur_speed; + } + break; + case 0xc3: + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { + bytes_per_second = 176.0 * 1024.0; + bytes_per_second *= (double) dev->drv->cur_speed; + } + break; + default: bytes_per_second = scsi_cdrom_bus_speed(dev); if (bytes_per_second == 0.0) { @@ -846,9 +1163,9 @@ scsi_cdrom_unit_attention(scsi_cdrom_t *dev) static void scsi_cdrom_buf_alloc(scsi_cdrom_t *dev, uint32_t len) { - scsi_cdrom_log("CD-ROM %i: Allocated buffer length: %i\n", dev->id, len); if (!dev->buffer) dev->buffer = (uint8_t *) malloc(len); + scsi_cdrom_log("CD-ROM %i: Allocated buffer length: %i, buffer = %p\n", dev->id, len, dev->buffer); } static void @@ -955,7 +1272,7 @@ scsi_cdrom_data_phase_error(scsi_cdrom_t *dev) } static int -scsi_cdrom_read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *len) +scsi_cdrom_read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *len, int vendor_type) { int ret = 0, data_pos = 0; int i = 0, temp_len = 0; @@ -992,7 +1309,7 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *l for (i = 0; i < dev->requested_blocks; i++) { ret = cdrom_readsector_raw(dev->drv, dev->buffer + data_pos, - dev->sector_pos + i, msf, type, flags, &temp_len); + dev->sector_pos + i, msf, type, flags, &temp_len, vendor_type); data_pos += temp_len; dev->old_len += temp_len; @@ -1009,7 +1326,7 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *l } static int -scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch) +scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch, int vendor_type) { int ret = 0, msf = 0; int type = 0, flags = 0; @@ -1032,7 +1349,7 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch) scsi_cdrom_log("Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); - ret = scsi_cdrom_read_data(dev, msf, type, flags, len); + ret = scsi_cdrom_read_data(dev, msf, type, flags, len, vendor_type); scsi_cdrom_log("Read %i bytes of blocks...\n", *len); @@ -1201,12 +1518,6 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) return 0; } - if (!dev->early && (scsi_cdrom_command_flags[cdb[0]] & EARLY_ONLY)) { - scsi_cdrom_log("CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); - scsi_cdrom_illegal_opcode(dev); - return 0; - } - if ((dev->drv->bus_type < CDROM_BUS_SCSI) && (scsi_cdrom_command_flags[cdb[0]] & SCSI_ONLY)) { scsi_cdrom_log("CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); scsi_cdrom_illegal_opcode(dev); @@ -1281,7 +1592,7 @@ static void scsi_cdrom_rezero(scsi_cdrom_t *dev) { dev->sector_pos = dev->sector_len = 0; - cdrom_seek(dev->drv, 0); + cdrom_seek(dev->drv, 0, 0); } void @@ -1392,10 +1703,8 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) int toc_format, block_desc = 0; int ret, format = 0; int real_pos, track = 0; -#ifdef USE_86BOX_CD - char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; - char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; -#endif + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; int32_t blen = 0, *BufLen; uint8_t *b; uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; @@ -1413,16 +1722,15 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->packet_len = 0; dev->request_pos = 0; -#ifdef USE_86BOX_CD device_identify[7] = dev->id + 0x30; device_identify_ex[7] = dev->id + 0x30; device_identify_ex[10] = EMU_VERSION_EX[0]; device_identify_ex[12] = EMU_VERSION_EX[2]; device_identify_ex[13] = EMU_VERSION_EX[3]; -#endif memcpy(dev->current_cdb, cdb, 12); + dev->sony_vendor = 0; if (cdb[0] != 0) { scsi_cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", @@ -1443,6 +1751,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (scsi_cdrom_pre_execution_check(dev, cdb) == 0) return; +begin: switch (cdb[0]) { case GPCMD_TEST_UNIT_READY: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); @@ -1453,7 +1762,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_stop(sc); dev->sector_pos = dev->sector_len = 0; dev->drv->seek_diff = dev->drv->seek_pos; - cdrom_seek(dev->drv, 0); + cdrom_seek(dev->drv, 0, 0); scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); break; @@ -1477,8 +1786,16 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_data_command_finish(dev, 18, 18, cdb[4], 0); break; + case 0xDA: /*GPCMD_SPEED_ALT*/ + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE74_1.00") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE464_1.05")) { /*GPCMD_STILL_NEC*/ + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + cdrom_audio_pause_resume(dev->drv, 0x00); + dev->drv->audio_op = 0x01; + scsi_cdrom_command_complete(dev); + break; + } case GPCMD_SET_SPEED: - case GPCMD_SET_SPEED_ALT: dev->drv->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; if (dev->drv->cur_speed < 1) dev->drv->cur_speed = 1; @@ -1488,6 +1805,24 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_command_complete(dev); break; + case 0xCD: + case GPCMD_AUDIO_SCAN: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + if ((dev->drv->host_drive < 1) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) { + scsi_cdrom_illegal_mode(dev); + break; + } + + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + ret = cdrom_audio_scan(dev->drv, pos, 0); + + if (ret) + scsi_cdrom_command_complete(dev); + else + scsi_cdrom_illegal_mode(dev); + break; + case GPCMD_MECHANISM_STATUS: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; @@ -1538,34 +1873,47 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); - /* scsi_cdrom_log("CD-ROM %i: READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", dev->id, - toc_format, ide->cylinder, dev->buffer[1]); */ return; - case GPCMD_READ_DISC_INFORMATION_TOSHIBA: + case 0xC7: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-501_1.0b"))) { /*GPCMD_PLAY_AUDIO_MSF_MATSUSHITA*/ + cdb[0] = GPCMD_PLAY_AUDIO_MSF; + dev->current_cdb[0] = cdb[0]; + goto begin; + break; + } else if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { /*GPCMD_PLAY_MSF_SONY*/ + cdb[0] = GPCMD_PLAY_AUDIO_MSF; + dev->current_cdb[0] = cdb[0]; + dev->sony_vendor = 1; + goto begin; + break; + } /*GPCMD_READ_DISC_INFORMATION_TOSHIBA*/ + case 0xDE: /*GPCMD_READ_DISC_INFORMATION_NEC*/ scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + scsi_cdrom_buf_alloc(dev, 4); - scsi_cdrom_buf_alloc(dev, 65536); - - if ((!dev->drv->ops) && ((cdb[1] & 3) == 2)) { + if (!dev->drv->ops) { scsi_cdrom_not_ready(dev); return; } - memset(dev->buffer, 0, 4); - - cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); - + ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); len = 4; - scsi_cdrom_set_buf_len(dev, BufLen, &len); + if (!ret) { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); return; case GPCMD_READ_CD_OLD: /* IMPORTANT: Convert the command to new read CD for pass through purposes. */ - dev->current_cdb[0] = 0xbe; + dev->current_cdb[0] = GPCMD_READ_CD; /*FALLTHROUGH*/ case GPCMD_READ_6: @@ -1665,7 +2013,18 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->drv->seek_diff = ABS((int) (pos - dev->sector_pos)); - ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1); + if ((cdb[0] == GPCMD_READ_10) || (cdb[0] == GPCMD_READ_12)) { + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE74_1.00") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE464_1.05") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_DRIVEXM_3433") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_XM-3301TA_0272") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_XM-5701TA_3136")) + ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1, cdb[9] & 0xc0); + else + ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1, 0); + } else + ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1, 0); + if (ret <= 0) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->packet_status = PHASE_COMPLETE; @@ -1733,10 +2092,19 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_buf_alloc(dev, 65536); } - if (!(scsi_cdrom_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) { - scsi_cdrom_invalid_field(dev); - scsi_cdrom_buf_free(dev); - return; + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { + if (!(scsi_cdrom_mode_sense_page_flags_sony & (1LL << (uint64_t) (cdb[2] & 0x3f)))) { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + } else { + if (!(scsi_cdrom_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } } memset(dev->buffer, 0, len); @@ -2031,9 +2399,16 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); break; - /* GPCMD_CHINON_EJECT on Chinon */ - case GPCMD_AUDIO_TRACK_SEARCH: - if (dev->early) { + case 0xC0: /*GPCMD_UNKNOWN_SONY*/ + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + dev->sony_vendor = 1; + break; + } /*GPCMD_AUDIO_TRACK_SEARCH_TOSHIBA and GPCMD_EJECT_CHINON*/ + case 0xD8: /*GPCMD_AUDIO_TRACK_SEARCH_NEC*/ + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "CHINON_CD-ROM_CDS-431_H42"))) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); cdrom_eject(dev->id); @@ -2055,14 +2430,51 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } break; - case GPCMD_TOSHIBA_PLAY_AUDIO: + case 0xC1: /*GPCMD_READ_TOC_SONY*/ + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403")) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + if (strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403")) { + dev->sony_vendor = 0; + } else { + msf = dev->ms_pages_saved_sony.pages[GPMODE_CDROM_PAGE_SONY][2] & 0x01; + dev->sony_vendor = 1; + } + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + scsi_cdrom_buf_alloc(dev, 65536); + + if (!dev->drv->ops) { + scsi_cdrom_not_ready(dev); + return; + } + + len = cdrom_read_toc_sony(dev->drv, dev->buffer, cdb[5], msf, max_len); + if (len == -1) { + /* If the returned length is -1, this means cdrom_read_toc_sony() has encountered an error. */ + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + return; + } /*GPCMD_PLAY_AUDIO_TOSHIBA*/ + case 0xD9: /*GPCMD_PLAY_AUDIO_NEC*/ scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); if ((dev->drv->host_drive < 1) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) { scsi_cdrom_illegal_mode(dev); break; } pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - ret = cdrom_toshiba_audio_play(dev->drv, pos, cdb[9] & 0xc0); + ret = cdrom_audio_play_toshiba(dev->drv, pos, cdb[9] & 0xc0); if (ret) scsi_cdrom_command_complete(dev); @@ -2134,6 +2546,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) case GPCMD_READ_SUBCHANNEL: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->sony_vendor = 0; max_len = cdb[7]; max_len <<= 8; @@ -2191,13 +2604,13 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->buffer[1] = 0x11; break; case CD_STATUS_PAUSED: - dev->buffer[1] = ((dev->drv->bus_type == CDROM_BUS_SCSI) && dev->early) ? 0x15 : 0x12; + dev->buffer[1] = ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "CHINON_CD-ROM_CDS-431_H42"))) ? 0x15 : 0x12; break; case CD_STATUS_DATA_ONLY: - dev->buffer[1] = ((dev->drv->bus_type == CDROM_BUS_SCSI) && dev->early) ? 0x00 : 0x15; + dev->buffer[1] = ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "CHINON_CD-ROM_CDS-431_H42"))) ? 0x00 : 0x15; break; default: - dev->buffer[1] = ((dev->drv->bus_type == CDROM_BUS_SCSI) && dev->early) ? 0x00 : 0x13; + dev->buffer[1] = ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "CHINON_CD-ROM_CDS-431_H42"))) ? 0x00 : 0x13; break; } @@ -2210,9 +2623,34 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_data_command_finish(dev, len, len, len, 0); break; - /* GPCMD_CHINON_STOP on Chinon */ - case GPCMD_READ_SUBCODEQ_PLAYING_STATUS: - if (dev->early) { + case 0xC6: + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->sony_vendor = 1; + + msf = 3; + if ((cdb[5] != 1) || (cdb[8] != 1)) { + scsi_cdrom_illegal_mode(dev); + break; + } + pos = cdb[4]; + + if ((dev->drv->host_drive < 1) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) { + scsi_cdrom_illegal_mode(dev); + break; + } + + ret = cdrom_audio_play(dev->drv, pos, len, msf); + + if (ret) + scsi_cdrom_command_complete(dev); + else + scsi_cdrom_illegal_mode(dev); + break; + } /*GPCMD_READ_SUBCODEQ_PLAYING_STATUS_TOSHIBA and GPCMD_STOP_CHINON*/ + case 0xDD: /*GPCMD_READ_SUBCODEQ_PLAYING_STATUS_NEC*/ + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "CHINON_CD-ROM_CDS-431_H42"))) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); scsi_cdrom_command_complete(dev); @@ -2220,8 +2658,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); alloc_length = cdb[1] & 0x1f; - - scsi_cdrom_buf_alloc(dev, alloc_length); + len = 10; if (!dev->drv->ops) { scsi_cdrom_not_ready(dev); @@ -2230,14 +2667,15 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (!alloc_length) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_log("CD-ROM %i: All done - callback set\n", dev->id); + scsi_cdrom_log("CD-ROM %i: Subcode Q All done - callback set\n", dev->id); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); break; } - len = alloc_length; + scsi_cdrom_buf_alloc(dev, len); + len = MIN(len, alloc_length); memset(dev->buffer, 0, len); dev->buffer[0] = cdrom_get_current_subcodeq_playstatus(dev->drv, &dev->buffer[1]); @@ -2284,7 +2722,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) } break; - case GPCMD_CHINON_UNKNOWN: + case 0x26: /*GPCMD_UNKNOWN_CHINON*/ scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); scsi_cdrom_command_complete(dev); @@ -2313,7 +2751,43 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) scsi_cdrom_command_complete(dev); break; - case GPCMD_CADDY_EJECT: + case 0xC4: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-501_1.0b"))) { /*GPCMD_READ_HEADER_MATSUSHITA*/ + cdb[0] = GPCMD_READ_HEADER; + dev->current_cdb[0] = cdb[0]; + goto begin; + break; + } else if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { /*GPCMD_PLAYBACK_STATUS_SONY*/ + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->sony_vendor = 1; + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + msf = dev->ms_pages_saved_sony.pages[GPMODE_CDROM_PAGE_SONY][2] & 0x01; + + scsi_cdrom_buf_alloc(dev, 18); + + len = max_len; + + memset(dev->buffer, 0, 10); + dev->buffer[0] = 0x00; /*Reserved*/ + dev->buffer[1] = 0x00; /*Reserved*/ + dev->buffer[2] = cdb[7]; /*Audio Status data length*/ + dev->buffer[3] = cdb[8]; /*Audio Status data length*/ + dev->buffer[4] = cdrom_get_audio_status_sony(dev->drv, &dev->buffer[6], msf); /*Audio status*/ + dev->buffer[5] = 0x00; + + scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[4]); + + len = MIN(len, max_len); + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + break; + } /*GPCMD_CADDY_EJECT_TOSHIBA and GPCMD_CADDY_EJECT_NEC*/ + case 0xDC: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_stop(sc); cdrom_eject(dev->id); @@ -2333,7 +2807,7 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) preamble_len = 4; size_idx = 3; - dev->buffer[idx++] = 05; + dev->buffer[idx++] = 5; dev->buffer[idx++] = cdb[2]; dev->buffer[idx++] = 0; @@ -2364,41 +2838,20 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->buffer[idx++] = 0x01; dev->buffer[idx++] = 0x00; dev->buffer[idx++] = 68; -#ifdef USE_86BOX_CD - ide_padstr8(dev->buffer + idx, 8, EMU_NAME); /* Vendor */ -#else - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - if (dev->early) - ide_padstr8(dev->buffer + idx, 8, "CHINON"); /* Vendor */ - else - ide_padstr8(dev->buffer + idx, 8, "TOSHIBA"); /* Vendor */ - } else { - if (dev->early) - ide_padstr8(dev->buffer + idx, 8, "NEC"); /* Vendor */ - else if (machine_is_sony()) - ide_padstr8(dev->buffer + idx, 8, "SONY"); /* Vendor */ - else - ide_padstr8(dev->buffer + idx, 8, "HITACHI"); /* Vendor */ - } -#endif + + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "86BOX_CD-ROM_1.00"))) + ide_padstr8(dev->buffer + idx, 8, EMU_NAME); /* Vendor */ + else + ide_padstr8(dev->buffer + idx, 8, cdrom_drive_types[dev->drv->type].vendor); /* Vendor */ + idx += 8; -#ifdef USE_86BOX_CD - ide_padstr8(dev->buffer + idx, 40, device_identify_ex); /* Product */ -#else - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - if (dev->early) - ide_padstr8(dev->buffer + idx, 40, "CD-ROM CDS-431"); /* Product */ - else - ide_padstr8(dev->buffer + idx, 40, "CD-ROM DRIVE:XM"); /* Product */ - } else { - if (dev->early) - ide_padstr8(dev->buffer + idx, 40, "CD-ROM DRIVE:260"); /* Product */ - else if (machine_is_sony()) - ide_padstr8(dev->buffer + idx, 40, "CD-ROM CDU76"); /* Product */ - else - ide_padstr8(dev->buffer + idx, 40, "CDR-8130"); /* Product */ - } -#endif + + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "86BOX_CD-ROM_1.00"))) + ide_padstr8(dev->buffer + idx, 40, device_identify_ex); /* Product */ + else + ide_padstr8(dev->buffer + idx, 40, cdrom_drive_types[dev->drv->type].model); /* Product */ + + idx += 40; ide_padstr8(dev->buffer + idx, 20, "53R141"); /* Serial */ idx += 20; @@ -2419,8 +2872,37 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->buffer[1] = 0x80; /*Removable*/ if (dev->drv->bus_type == CDROM_BUS_SCSI) { - dev->buffer[2] = 0x02; dev->buffer[3] = 0x02; + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "86BOX_CD-ROM_1.00"))) { + dev->buffer[2] = 0x05; + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_DRIVEXM_3433"))) { + dev->buffer[2] = 0x02; + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_XM-3301TA_0272"))) { + dev->buffer[2] = 0x02; + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_XM-5701TA_3136"))) { + dev->buffer[2] = 0x02; + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "CHINON_CD-ROM_CDS-431_H42"))) { + dev->buffer[3] = 0x01; + dev->buffer[2] = 0x02; + } else if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i")) { + dev->buffer[3] = 0x01; + dev->buffer[2] = 0x02; + } else if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { + dev->buffer[3] = 0x01; + dev->buffer[2] = 0x02; + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-501_1.0b"))) { + dev->buffer[3] = 0x01; + dev->buffer[2] = 0x02; + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE74_1.00"))) { + dev->buffer[3] = 0x01; + dev->buffer[2] = 0x02; + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "DEC_RRD45_0436"))) { + dev->buffer[2] = 0x02; + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE464_1.05"))) { + dev->buffer[2] = 0x02; + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403"))) { + dev->buffer[2] = 0x02; + } } else { dev->buffer[2] = 0x00; dev->buffer[3] = 0x21; @@ -2428,47 +2910,57 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) dev->buffer[4] = 31; if (dev->drv->bus_type == CDROM_BUS_SCSI) { - dev->buffer[6] = 1; /* 16-bit transfers supported */ - dev->buffer[7] = 0x20; /* Wide bus supported */ + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "86BOX_CD-ROM_1.00"))) { + dev->buffer[6] = 0x01; /* 16-bit transfers supported */ + dev->buffer[7] = 0x20; /* Wide bus supported */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PLEXTOR_CD-ROM_PX-32TS_1.03"))) { + dev->buffer[6] = 0x01; /* 16-bit transfers supported */ + dev->buffer[7] = 0x20; /* Wide bus supported */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TEAC_CD-R55S_1.0R"))) { + dev->buffer[6] = 0x01; /* 16-bit transfers supported */ + dev->buffer[7] = 0x20; /* Wide bus supported */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "DEC_RRD45_0436"))) { + dev->buffer[7] = 0x98; /* Linked Command and Relative Addressing supported */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_DRIVEXM_3433"))) { + dev->buffer[4] = 91; /* Always 91 on Toshiba SCSI-2 CD-ROM drives from 1990*/ + dev->buffer[7] = 0x88; /* Linked Command and Relative Addressing supported */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_XM-3301TA_0272"))) { + dev->buffer[4] = 91; /* Always 91 on Toshiba SCSI-2 CD-ROM drives from 1990*/ + dev->buffer[7] = 0x88; /* Linked Command and Relative Addressing supported */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_XM-5701TA_3136"))) { + dev->buffer[4] = 91; /* Always 91 on Toshiba SCSI-2 CD-ROM drives from 1990*/ + dev->buffer[7] = 0x88; /* Linked Command and Relative Addressing supported */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403"))) { + dev->buffer[4] = 42; + } } -#ifdef USE_86BOX_CD - ide_padstr8(dev->buffer + 8, 8, EMU_NAME); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, device_identify); /* Product */ - ide_padstr8(dev->buffer + 32, 4, EMU_VERSION_EX); /* Revision */ -#else - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - if (dev->early) { - ide_padstr8(dev->buffer + 8, 8, "CHINON"); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, "CD-ROM CDS-431"); /* Product */ - ide_padstr8(dev->buffer + 32, 4, "H42"); /* Revision */ - } else { - ide_padstr8(dev->buffer + 8, 8, "TOSHIBA"); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, "CD-ROM DRIVE:XM"); /* Product */ - ide_padstr8(dev->buffer + 32, 4, "3433"); /* Revision */ - } + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "86BOX_CD-ROM_1.00"))) { + ide_padstr8(dev->buffer + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(dev->buffer + 16, 16, device_identify); /* Product */ + ide_padstr8(dev->buffer + 32, 4, EMU_VERSION_EX); /* Revision */ } else { - if (dev->early) { - ide_padstr8(dev->buffer + 8, 8, "NEC"); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, "CD-ROM DRIVE:260"); /* Product */ - ide_padstr8(dev->buffer + 32, 4, "1.01"); /* Revision */ - } else if (machine_is_sony()) { - ide_padstr8(dev->buffer + 8, 8, "SONY"); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, "CD-ROM CDU76"); /* Product */ - ide_padstr8(dev->buffer + 32, 4, "1.0i"); /* Revision */ - } else { - ide_padstr8(dev->buffer + 8, 8, "HITACHI"); /* Vendor */ - ide_padstr8(dev->buffer + 16, 16, "CDR-8130"); /* Product */ - ide_padstr8(dev->buffer + 32, 4, "0020"); /* Revision */ + ide_padstr8(dev->buffer + 8, 8, cdrom_drive_types[dev->drv->type].vendor); /* Vendor */ + ide_padstr8(dev->buffer + 16, 16, cdrom_drive_types[dev->drv->type].model); /* Product */ + ide_padstr8(dev->buffer + 32, 4, cdrom_drive_types[dev->drv->type].revision); /* Revision */ + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403"))) { + dev->buffer[36] = 0x20; + ide_padstr8(dev->buffer + 37, 10, "1993/01/01"); /* Date */ } } -#endif idx = 36; - - if (max_len == 96) { - dev->buffer[4] = 91; - idx = 96; + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_DRIVEXM_3433") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_XM-3301TA_0272") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_XM-5701TA_3136")) /*Toshiba only*/ + idx = 96; + else if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403")) /*Pioneer only*/ + idx = 47; + else { + if (max_len == 96) { + dev->buffer[4] = 91; + idx = 96; + } } } @@ -2477,19 +2969,23 @@ atapi_out: len = idx; len = MIN(len, max_len); + scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_log("Inquiry = %d, max = %d, BufLen = %d.\n", len, max_len, *BufLen); scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); break; + case 0x0D: /*GPCMD_NO_OPERATION_TOSHIBA and GPCMD_NO_OPERATION_NEC*/ + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + break; + case GPCMD_PREVENT_REMOVAL: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_command_complete(dev); break; -#if 0 - case GPCMD_PAUSE_RESUME_ALT: -#endif case GPCMD_PAUSE_RESUME: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); cdrom_audio_pause_resume(dev->drv, cdb[8] & 0x01); @@ -2497,7 +2993,81 @@ atapi_out: scsi_cdrom_command_complete(dev); break; - case GPCMD_STILL: + case 0xC3: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-501_1.0b"))) { /*GPCMD_READ_TOC_MATSUSHITA*/ + cdb[0] = GPCMD_READ_TOC_PMA_ATIP; + dev->current_cdb[0] = cdb[0]; + goto begin; + break; + } else if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { /*GPCMD_READ_HEADER_SONY*/ + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + dev->sony_vendor = 1; + + alloc_length = ((cdb[7] << 8) | cdb[8]); + scsi_cdrom_buf_alloc(dev, 4); + + dev->sector_len = 1; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + real_pos = cdrom_lba_to_msf_accurate(dev->sector_pos); + dev->buffer[0] = ((real_pos >> 16) & 0xff); + dev->buffer[1] = ((real_pos >> 8) & 0xff); + dev->buffer[2] = real_pos & 0xff; + dev->buffer[3] = 1; /*2048 bytes user data*/ + + len = 4; + len = MIN(len, alloc_length); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + return; + } /*GPCMD_SET_STOP_TIME_TOSHIBA and GPCMD_SET_STOP_TIME_NEC*/ + case 0xDB: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + break; + + case 0xC2: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-501_1.0b"))) { /*GPCMD_READ_SUBCHANNEL_MATSUSHITA*/ + cdb[0] = GPCMD_READ_SUBCHANNEL; + dev->current_cdb[0] = cdb[0]; + goto begin; + break; + } else if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403")) { /*GPCMD_READ_SUBCHANNEL_SONY*/ + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + dev->sony_vendor = !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403") ? 0 : 1; + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + if (strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403")) + msf = dev->ms_pages_saved_sony.pages[GPMODE_CDROM_PAGE_SONY][2] & 0x01; + + scsi_cdrom_buf_alloc(dev, 32); + + scsi_cdrom_log("CD-ROM %i: Getting sub-channel type (%s)\n", dev->id, msf ? "MSF" : "LBA"); + + if (!(cdb[2] & 0x40)) + alloc_length = 4; + else + alloc_length = 24; + + len = alloc_length; + + memset(dev->buffer, 0, 24); + cdrom_get_current_subchannel_sony(dev->drv, dev->buffer, msf); + + len = MIN(len, max_len); + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + break; + } + /*GPCMD_STILL_TOSHIBA*/ scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); cdrom_audio_pause_resume(dev->drv, 0x00); dev->drv->audio_op = 0x01; @@ -2517,7 +3087,18 @@ atapi_out: break; } dev->drv->seek_diff = ABS((int) (pos - dev->drv->seek_pos)); - cdrom_seek(dev->drv, pos); + if (cdb[0] == GPCMD_SEEK_10) { + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE74_1.00") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE464_1.05") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_DRIVEXM_3433") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_XM-3301TA_0272") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_XM-5701TA_3136")) + cdrom_seek(dev->drv, pos, cdb[9] & 0xc0); + else + cdrom_seek(dev->drv, pos, 0); + } else + cdrom_seek(dev->drv, pos, 0); + scsi_cdrom_command_complete(dev); break; @@ -2552,6 +3133,143 @@ atapi_out: scsi_cdrom_command_complete(dev); break; + case 0xC5: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-501_1.0b"))) { /*GPCMD_PLAY_AUDIO_MATSUSHITA*/ + cdb[0] = GPCMD_PLAY_AUDIO_10; + dev->current_cdb[0] = cdb[0]; + goto begin; + break; + } else if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { /*GPCMD_PAUSE_SONY*/ + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->sony_vendor = 1; + cdrom_audio_pause_resume(dev->drv, !(cdb[1] & 0x10)); + scsi_cdrom_command_complete(dev); + break; + } + case 0xC8: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-501_1.0b"))) { /*GPCMD_PLAY_AUDIO_TRACK_INDEX_MATSUSHITA*/ + cdb[0] = GPCMD_PLAY_AUDIO_TRACK_INDEX; + dev->current_cdb[0] = cdb[0]; + goto begin; + break; + } else if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { /*GPCMD_PLAY_AUDIO_SONY*/ + cdb[0] = GPCMD_PLAY_AUDIO_10; + dev->current_cdb[0] = cdb[0]; + dev->sony_vendor = 1; + goto begin; + break; + } + case 0xC9: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-501_1.0b"))) { /*GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10_MATSUSHITA*/ + cdb[0] = GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10; + dev->current_cdb[0] = cdb[0]; + goto begin; + break; + } else if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { /*GPCMD_PLAYBACK_CONTROL_SONY*/ + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); + dev->sony_vendor = 1; + + len = (cdb[7] << 8) | cdb[8]; + scsi_cdrom_buf_alloc(dev, 65536); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_data_command_finish(dev, len, len, len, 1); + break; + } + case 0xCA: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403"))) { /*GPCMD_PAUSE_PIONEER*/ + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + cdrom_audio_pause_resume(dev->drv, !(cdb[1] & 0x10)); + scsi_cdrom_command_complete(dev); + break; + } + case 0xCB: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-501_1.0b"))) { /*GPCMD_PAUSE_RESUME_MATSUSHITA*/ + cdb[0] = GPCMD_PAUSE_RESUME; + dev->current_cdb[0] = cdb[0]; + goto begin; + break; + } + case 0xCC: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403"))) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + scsi_cdrom_buf_alloc(dev, 18); + + len = max_len; + + memset(dev->buffer, 0, 10); + dev->buffer[0] = 0x00; /*Reserved*/ + dev->buffer[1] = 0x00; /*Reserved*/ + dev->buffer[2] = cdb[7]; /*Audio Status data length*/ + dev->buffer[3] = cdb[8]; /*Audio Status data length*/ + dev->buffer[4] = cdrom_get_audio_status_sony(dev->drv, &dev->buffer[6], msf); /*Audio status*/ + dev->buffer[5] = 0x00; + + scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[4]); + + len = MIN(len, max_len); + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + break; + } + case 0xE0: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PIONEER_CD-ROM_DRM-604X_2403"))) { /*GPCMD_DRIVE_STATUS_PIONEER*/ + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + len = (cdb[9] | (cdb[8] << 8)); + scsi_cdrom_buf_alloc(dev, 65536); + + if (!(scsi_cdrom_drive_status_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; + } + + if (!len) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_log("CD-ROM %i: Drive Status All done - callback set\n", dev->id); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + break; + } + + memset(dev->buffer, 0, len); + alloc_length = len; + + len = scsi_cdrom_drive_status(dev, dev->buffer, 0, cdb[2]); + len = MIN(len, alloc_length); + + scsi_cdrom_set_buf_len(dev, BufLen, &len); + + scsi_cdrom_log("CD-ROM %i: Reading drive status page: %02X...\n", dev->id, cdb[2]); + + scsi_cdrom_data_command_finish(dev, len, len, alloc_length, 0); + return; + } + case 0xE5: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-501_1.0b"))) { /*GPCMD_PLAY_AUDIO_12_MATSUSHITA*/ + cdb[0] = GPCMD_PLAY_AUDIO_12; + dev->current_cdb[0] = cdb[0]; + goto begin; + break; + } + case 0xE9: + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-501_1.0b"))) { /*GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12_MATSUSHITA*/ + cdb[0] = GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12; + dev->current_cdb[0] = cdb[0]; + goto begin; + break; + } default: scsi_cdrom_illegal_opcode(dev); break; @@ -2623,20 +3341,42 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) pos += 2; - if (!(scsi_cdrom_mode_sense_page_flags & (1LL << ((uint64_t) page)))) { - scsi_cdrom_log("CD-ROM %i: Unimplemented page %02X\n", dev->id, page); - error |= 1; + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { + if (!(scsi_cdrom_mode_sense_page_flags_sony & (1LL << ((uint64_t) page)))) { + scsi_cdrom_log("CD-ROM %i: Unimplemented page %02X\n", dev->id, page); + error |= 1; + } else { + for (i = 0; i < page_len; i++) { + ch = scsi_cdrom_mode_sense_pages_changeable_sony.pages[page][i + 2]; + val = dev->buffer[pos + i]; + old_val = dev->ms_pages_saved_sony.pages[page][i + 2]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved_sony.pages[page][i + 2] = val; + else { + scsi_cdrom_log("CD-ROM %i: Unchangeable value on position %02X on page %02X\n", dev->id, i + 2, page); + error |= 1; + } + } + } + } } else { - for (i = 0; i < page_len; i++) { - ch = scsi_cdrom_mode_sense_pages_changeable.pages[page][i + 2]; - val = dev->buffer[pos + i]; - old_val = dev->ms_pages_saved.pages[page][i + 2]; - if (val != old_val) { - if (ch) - dev->ms_pages_saved.pages[page][i + 2] = val; - else { - scsi_cdrom_log("CD-ROM %i: Unchangeable value on position %02X on page %02X\n", dev->id, i + 2, page); - error |= 1; + if (!(scsi_cdrom_mode_sense_page_flags & (1LL << ((uint64_t) page)))) { + scsi_cdrom_log("CD-ROM %i: Unimplemented page %02X\n", dev->id, page); + error |= 1; + } else { + for (i = 0; i < page_len; i++) { + ch = scsi_cdrom_mode_sense_pages_changeable.pages[page][i + 2]; + val = dev->buffer[pos + i]; + old_val = dev->ms_pages_saved.pages[page][i + 2]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved.pages[page][i + 2] = val; + else { + scsi_cdrom_log("CD-ROM %i: Unchangeable value on position %02X on page %02X\n", dev->id, i + 2, page); + error |= 1; + } } } } @@ -2644,7 +3384,10 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) pos += page_len; - if (dev->drv->bus_type == CDROM_BUS_SCSI) + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) + val = scsi_cdrom_mode_sense_pages_default_sony_scsi.pages[page][0] & 0x80; + else if (dev->drv->bus_type == CDROM_BUS_SCSI) val = scsi_cdrom_mode_sense_pages_default_scsi.pages[page][0] & 0x80; else val = scsi_cdrom_mode_sense_pages_default.pages[page][0] & 0x80; @@ -2662,6 +3405,14 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) return 0; } break; + case 0xC9: + if (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-541_1.0i") || + !strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU-76S_1.00")) { + for (i = 0; i < 18; i++) { + dev->ms_pages_saved_sony.pages[GPMODE_CDROM_AUDIO_PAGE_SONY][i] = dev->buffer[i]; + } + } + break; } scsi_cdrom_command_stop((scsi_common_t *) dev); @@ -2732,43 +3483,72 @@ scsi_cdrom_get_timings(int ide_has_dma, int type) static void scsi_cdrom_identify(ide_t *ide, int ide_has_dma) { -#ifdef USE_86BOX_CD scsi_cdrom_t *dev; - char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; dev = (scsi_cdrom_t *) ide->sc; device_identify[7] = dev->id + 0x30; scsi_cdrom_log("ATAPI Identify: %s\n", device_identify); -#else - scsi_cdrom_t *dev = (scsi_cdrom_t *) ide->sc; -#endif - if (dev->early) + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE260_1.01")) || (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE260_1.00"))) /*NEC only*/ ide->buffer[0] = 0x8000 | (5 << 8) | 0x80 | (1 << 5); /* ATAPI device, CD-ROM drive, removable media, interrupt DRQ */ else 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 */ -#ifdef USE_86BOX_CD - ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ -#else - if (dev->early) { -# ifdef WRONG - ide_padstr((char *) (ide->buffer + 23), "1.01 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:260 ", 40); /* Model */ -# else - ide_padstr((char *) (ide->buffer + 23), ".110 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "EN C DCR-MOD IREV2:06 ", 40); /* Model */ -# endif - } else if (machine_is_sony()) { - ide_padstr((char *) (ide->buffer + 23), "1.0i ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "CD-ROM CDU76 ", 40); /* Model */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "86BOX_CD-ROM_1.00"))) { + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION_EX, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ } else { - ide_padstr((char *) (ide->buffer + 23), "0020 ", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "HITACHI CDR-8130 ", 40); /* Model */ + if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE260_1.01"))) { + ide_padstr((char *) (ide->buffer + 23), ".110 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "EN C DCR-MOD IREV2:06 ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE260_1.00"))) { + ide_padstr((char *) (ide->buffer + 23), ".100 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "EN C DCR-MOD IREV2:06 ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "AZT_CDA46802I_1.15"))) { + ide_padstr((char *) (ide->buffer + 23), "1.15 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "AZT CDA46802I ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "HITACHI_CDR-8130_0020"))) { + ide_padstr((char *) (ide->buffer + 23), "0020 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "HITACHI CDR-8130 ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU76_1.0i"))) { + ide_padstr((char *) (ide->buffer + 23), "1.0i ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "SONY CD-ROM CDU76 ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "SONY_CD-ROM_CDU311_3.0h"))) { + ide_padstr((char *) (ide->buffer + 23), "3.0h ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "SONY CD-ROM CDU311 ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CDR-1300A_1.05"))) { + ide_padstr((char *) (ide->buffer + 23), "1.05 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "NEC CDR-1300A ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "TOSHIBA_CD-ROM_XM-5702B_TA70"))) { + ide_padstr((char *) (ide->buffer + 23), "TA70 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "TOSHIBA CD-ROM XM-5702B ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "GOLDSTAR_CRD-8160B_3.14"))) { + ide_padstr((char *) (ide->buffer + 23), "3.14 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "GOLDSTAR CRD-8160B ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-587_7S13"))) { + ide_padstr((char *) (ide->buffer + 23), "7S13 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "MATSHITA CD-ROM CR-587 ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MATSHITA_CD-ROM_CR-588_LS15"))) { + ide_padstr((char *) (ide->buffer + 23), "LS15 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "MATSHITA CD-ROM CR-588 ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "MITSUMI_CRMC-FX4820T_D02A"))) { + ide_padstr((char *) (ide->buffer + 23), "D02A ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "MITSUMI CRMC-FX4820T ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "PHILIPS_CD-ROM_PCA403CD_U31P"))) { + ide_padstr((char *) (ide->buffer + 23), "U31P ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "PHILIPS CD-ROM PCA403CD ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "BTC_CD-ROM_BCD36XH_U1.0"))) { + ide_padstr((char *) (ide->buffer + 23), "U1.0 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "BTC CD-ROM BCD36XH ", 40); /* Model */ + } else if ((!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "KENWOOD_CD-ROM_UCR-421_208E"))) { + ide_padstr((char *) (ide->buffer + 23), "208E ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "KENWOOD CD-ROM UCR-421 ", 40); /* Model */ + } } -#endif + ide->buffer[49] = 0x200; /* LBA supported */ ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ @@ -2815,7 +3595,6 @@ scsi_cdrom_drive_reset(int c) dev->drv = drv; dev->cur_lun = SCSI_LUN_USE_CDB; - dev->early = dev->drv->early; drv->insert = scsi_cdrom_insert; drv->get_volume = scsi_cdrom_get_volume; @@ -2854,7 +3633,8 @@ scsi_cdrom_drive_reset(int c) id->phase_data_out = scsi_cdrom_phase_data_out; id->command_stop = scsi_cdrom_command_stop; id->bus_master_error = scsi_cdrom_bus_master_error; - id->interrupt_drq = dev->early; + id->interrupt_drq = (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE260_1.01") || + (!strcmp(cdrom_drive_types[dev->drv->type].internal_name, "NEC_CD-ROM_DRIVE260_1.00"))); ide_atapi_attach(id); } diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 668f9ea9f..54875963d 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -1,23 +1,23 @@ /* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the 86Box distribution. + * This file is part of the 86Box distribution. * - * Implementation of the NCR 5380 series of SCSI Host Adapters - * made by NCR. These controllers were designed for the ISA bus. + * Implementation of the NCR 5380 series of SCSI Host Adapters + * made by NCR. These controllers were designed for the ISA bus. * * * - * Authors: Sarah Walker, - * TheCollector1995, - * Fred N. van Kempen, + * Authors: Sarah Walker, + * TheCollector1995, + * Fred N. van Kempen, * - * Copyright 2017-2019 Sarah Walker. - * Copyright 2017-2019 TheCollector1995. - * Copyright 2017-2019 Fred N. van Kempen. + * Copyright 2017-2019 Sarah Walker. + * Copyright 2017-2019 TheCollector1995. + * Copyright 2017-2019 Fred N. van Kempen. */ #include #include @@ -598,7 +598,7 @@ ncr_write(uint16_t port, uint8_t val, void *priv) break; case 2: /* Mode register */ - ncr_log("Write: Mode register, val=%02x\n", val & MODE_DMA); + ncr_log("Write: Mode register, val=%02x.\n", val); if ((val & MODE_ARBITRATE) && !(ncr->mode & MODE_ARBITRATE)) { ncr->icr &= ~ICR_ARB_LOST; ncr->icr |= ICR_ARB_IN_PROGRESS; @@ -741,12 +741,7 @@ ncr_read(uint16_t port, void *priv) break; case 2: /* Mode register */ - if (((ncr->mode & 0x30) == 0x30) && ((ncr_dev->type == 1) && (ncr_dev->bios_ver == 1))) - ncr->mode = 0; - if (((ncr->mode & 0x20) == 0x20) && (ncr_dev->type == 0)) - ncr->mode = 0; - - ncr_log("Read: Mode register\n"); + ncr_log("Read: Mode register = %02x.\n", ncr->mode); ret = ncr->mode; break; @@ -761,10 +756,10 @@ ncr_read(uint16_t port, void *priv) ncr_bus_read(ncr_dev); ncr_log("NCR cur bus stat=%02x\n", ncr->cur_bus & 0xff); ret |= (ncr->cur_bus & 0xff); - if ((ncr->icr & ICR_SEL) && ((ncr_dev->type == 1) && (ncr_dev->bios_ver == 1))) - ret |= 0x02; - if ((ncr->icr & ICR_BSY) && ((ncr_dev->type == 1) && (ncr_dev->bios_ver == 1))) - ret |= 0x40; + if (ncr->icr & ICR_SEL) + ret |= BUS_SEL; + if (ncr->icr & ICR_BSY) + ret |= BUS_BSY; break; case 5: /* Bus and Status register */ @@ -783,9 +778,9 @@ ncr_read(uint16_t port, void *priv) ncr_bus_read(ncr_dev); bus = ncr->cur_bus; - if ((bus & BUS_ACK) || ((ncr->icr & ICR_ACK) && ((ncr_dev->type == 1) && (ncr_dev->bios_ver == 1)))) + if ((bus & BUS_ACK) || (ncr->icr & ICR_ACK)) ret |= STATUS_ACK; - if ((bus & BUS_ATN) || ((ncr->icr & ICR_ATN) && ((ncr_dev->type == 1) && (ncr_dev->bios_ver == 1)))) + if ((bus & BUS_ATN) || (ncr->icr & ICR_ATN)) ret |= 0x02; if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) { @@ -885,6 +880,13 @@ memio_read(uint32_t addr, void *priv) ncr_log("NCR status ctrl read=%02x\n", ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY); if (!ncr_dev->ncr_busy) ret |= STATUS_53C80_ACCESSIBLE; + if (ncr->mode & 0x30) { /*Parity bits*/ + if (!(ncr->mode & MODE_DMA)) { /*This is to avoid RTBios 8.10R BIOS problems with the hard disk and detection.*/ + ret |= 0x01; /*If the parity bits are set, bit 0 of the 53c400 status port should be set as well.*/ + ncr->mode = 0; /*Required by RTASPI10.SYS otherwise it won't initialize.*/ + } + } + ncr_log("NCR 53c400 status = %02x.\n", ret); break; case 0x3981: /* block counter register*/ @@ -948,6 +950,7 @@ memio_write(uint32_t addr, uint8_t val, void *priv) case 0x3980: switch (addr) { case 0x3980: /* Control */ + ncr_log("NCR 53c400 control = %02x, mode = %02x.\n", val, ncr->mode); if ((val & CTRL_DATA_DIR) && !(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { ncr_dev->buffer_host_pos = MIN(128, dev->buffer_length); ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; diff --git a/src/scsi/scsi_spock.c b/src/scsi/scsi_spock.c index ab970f17a..af37d63a4 100644 --- a/src/scsi/scsi_spock.c +++ b/src/scsi/scsi_spock.c @@ -1,21 +1,21 @@ /* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. * - * This file is part of the 86Box distribution. + * This file is part of the 86Box distribution. * - * Implementation of the IBM PS/2 SCSI controller with - * cache for MCA only. + * Implementation of the IBM PS/2 SCSI controller with + * cache for MCA only. * * * - * Authors: Sarah Walker, - * TheCollector1995, + * Authors: Sarah Walker, + * TheCollector1995, * - * Copyright 2020 Sarah Walker. - * Copyright 2020 TheCollector1995. + * Copyright 2020 Sarah Walker. + * Copyright 2020 TheCollector1995. */ #include #include @@ -126,9 +126,10 @@ typedef struct { get_pos_info_t get_pos_info; scb_t scb; - int adapter_reset; int scb_id; int adapter_id; + int assign; + int present[8]; int cmd_status; int cir_status; @@ -380,7 +381,7 @@ spock_read(uint16_t port, void *p) break; } - spock_log("spock_read: port=%04x val=%02x %04x(%05x):%04x %02x\n", port, temp, CS, cs, cpu_state.pc, BH); + spock_log("spock_read: port=%04x val=%02x %04x(%05x):%04x.\n", port, temp, CS, cs, cpu_state.pc); return temp; } @@ -436,11 +437,14 @@ spock_get_len(spock_t *scsi, scb_t *scb) static void spock_process_imm_cmd(spock_t *scsi) { - int i; + int i, j = 0; int adapter_id, phys_id, lun_id; + scsi->assign = 0; + switch (scsi->command & CMD_MASK) { case CMD_ASSIGN: + scsi->assign = 1; adapter_id = (scsi->command >> 16) & 15; phys_id = (scsi->command >> 20) & 7; lun_id = (scsi->command >> 24) & 7; @@ -458,10 +462,10 @@ spock_process_imm_cmd(spock_t *scsi) if (phys_id != scsi->adapter_id) { scsi->dev_id[adapter_id].phys_id = phys_id; scsi->dev_id[adapter_id].lun_id = lun_id; - spock_log("Assign: adapter dev=%x scsi ID=%i LUN=%i\n", adapter_id, scsi->dev_id[adapter_id].phys_id, scsi->dev_id[adapter_id].lun_id); + spock_log("Assign: adapter dev=%x scsi ID=%i LUN=%i.\n", adapter_id, scsi->dev_id[adapter_id].phys_id, scsi->dev_id[adapter_id].lun_id); spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); } else { /*Can not assign adapter*/ - spock_log("Assign: PUN=%d, cannot assign adapter\n", phys_id); + spock_log("Assign: PUN=%d, cannot assign adapter.\n", phys_id); spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_COMMAND_FAIL); } } @@ -481,18 +485,25 @@ spock_process_imm_cmd(spock_t *scsi) spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); break; case CMD_RESET: - spock_log("Reset Command\n"); + spock_log("Reset Command, attention = %d.\n", scsi->attention & 0x0f); if ((scsi->attention & 0x0f) == 0x0f) { /*Adapter reset*/ - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { scsi_device_reset(&scsi_devices[scsi->bus][i]); - spock_log("Adapter Reset\n"); + } - if (!scsi->adapter_reset) /*The early 1990 bios must have its boot drive - set to ID 6 according https://www.ardent-tool.com/IBM_SCSI/SCSI-A.html */ - scsi->adapter_reset = 1; + for (i = 6; i > -1; i--) { + if (scsi_device_present(&scsi_devices[scsi->bus][i])) { + spock_log("Adapter Reset, SCSI reset present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); + scsi->present[j] = i; + j++; + } else { + spock_log("Adapter Reset, SCSI reset not present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[i].phys_id, scsi_devices[scsi->bus][i].type); + } + } scsi->scb_state = 0; } + spock_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); break; @@ -505,7 +516,7 @@ spock_process_imm_cmd(spock_t *scsi) static void spock_execute_cmd(spock_t *scsi, scb_t *scb) { - int c; + int c, j; int old_scb_state; if (scsi->in_reset) { @@ -519,9 +530,9 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) if (scsi->in_reset == 1) { scsi->basic_ctrl |= CTRL_IRQ_ENA; - spock_set_irq(scsi, 0x0f, IRQ_TYPE_RESET_COMPLETE); - } else - spock_set_irq(scsi, 0x0f, IRQ_TYPE_RESET_COMPLETE); + } + + spock_set_irq(scsi, 0x0f, IRQ_TYPE_RESET_COMPLETE); /*Reset device mappings*/ for (c = 0; c < 7; c++) { @@ -532,6 +543,16 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) scsi->dev_id[c].phys_id = -1; scsi->in_reset = 0; + + for (c = 6; c > -1; c--) { + if (scsi_device_present(&scsi_devices[scsi->bus][c])) { + spock_log("Reset, SCSI reset present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[c].phys_id, scsi_devices[scsi->bus][c].type); + scsi->present[j] = c; + j++; + } else { + spock_log("Reset, SCSI reset not present devices=%d, phys ID=%d, type=%04x.\n", j, scsi->dev_id[c].phys_id, scsi_devices[scsi->bus][c].type); + } + } return; } @@ -584,11 +605,11 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) " SCB chain address = %08x\n" " Block count = %04x\n" " Block length = %04x\n" - " SCB id = %d, Phys id = %d\n", + " SCB id = %d, Phys id = %d, Spock CMD = %08x, CMD Mask = %02x.\n", scb->command, scb->enable, scb->lba_addr, scb->sge.sys_buf_addr, scb->sge.sys_buf_byte_count, scb->term_status_block_addr, scb->scb_chain_addr, - scb->block_count, scb->block_length, scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id); + scb->block_count, scb->block_length, scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id, scsi->command, scb->command & 0xc0); switch (scb->command & CMD_MASK) { case CMD_GET_COMPLETE_STATUS: @@ -662,10 +683,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) break; case CMD_DEVICE_INQUIRY: - if (scb->command != CMD_DEVICE_INQUIRY) - scsi->cdb_id = scsi->scb_id; - else - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + scsi->cdb_id = scsi->assign ? scsi->dev_id[scsi->scb_id].phys_id : scsi->present[scsi->scb_id]; spock_log("Device Inquiry, ID=%d\n", scsi->cdb_id); scsi->cdb[0] = GPCMD_INQUIRY; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ @@ -681,12 +699,9 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_SEND_OTHER_SCSI: - if (scb->command != CMD_SEND_OTHER_SCSI) - scsi->cdb_id = scsi->scb_id; - else - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; - spock_log("Send Other SCSI, SCB ID=%d, PHYS ID=%d, reset=%d\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id, scsi->adapter_reset); + scsi->cdb_id = scsi->assign ? scsi->dev_id[scsi->scb_id].phys_id : scsi->present[scsi->scb_id]; dma_bm_read(scsi->scb_addr + 0x18, scsi->cdb, 12, 2); + spock_log("Send Other SCSI, SCB ID=%d, PHYS ID=%d\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id); scsi->cdb[1] = (scsi->cdb[1] & 0x1f) | (scsi->dev_id[scsi->scb_id].lun_id << 5); /*Patch correct LUN into command*/ scsi->cdb_len = (scb->lba_addr & 0xff) ? (scb->lba_addr & 0xff) : 6; scsi->scsi_state = SCSI_STATE_SELECT; @@ -694,11 +709,8 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_READ_DEVICE_CAPACITY: - if (scb->command != CMD_READ_DEVICE_CAPACITY) - scsi->cdb_id = scsi->scb_id; - else - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; - spock_log("Device Capacity, SCB ID=%d, PHYS ID=%d, reset=%d\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id, scsi->adapter_reset); + scsi->cdb_id = scsi->assign ? scsi->dev_id[scsi->scb_id].phys_id : scsi->present[scsi->scb_id]; + spock_log("Device Capacity, SCB ID=%d, PHYS ID=%d\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id); scsi->cdb[0] = GPCMD_READ_CDROM_CAPACITY; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ scsi->cdb[2] = 0; /*LBA*/ @@ -715,11 +727,8 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_READ_DATA: - if (scb->command != CMD_READ_DATA) - scsi->cdb_id = scsi->scb_id; - else - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; - spock_log("Device Read Data, SCB ID=%d, PHYS ID=%d, reset=%d\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id, scsi->adapter_reset); + scsi->cdb_id = scsi->assign ? scsi->dev_id[scsi->scb_id].phys_id : scsi->present[scsi->scb_id]; + spock_log("Device Read Data, SCB ID=%d, PHYS ID=%d\n", scsi->scb_id, scsi->dev_id[scsi->scb_id].phys_id); scsi->cdb[0] = GPCMD_READ_10; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ scsi->cdb[2] = (scb->lba_addr >> 24) & 0xff; /*LBA*/ @@ -736,10 +745,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_WRITE_DATA: - if (scb->command != CMD_WRITE_DATA) - scsi->cdb_id = scsi->scb_id; - else - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + scsi->cdb_id = scsi->assign ? scsi->dev_id[scsi->scb_id].phys_id : scsi->present[scsi->scb_id]; spock_log("Device Write Data\n"); scsi->cdb[0] = GPCMD_WRITE_10; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ @@ -757,10 +763,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_VERIFY: - if (scb->command != CMD_VERIFY) - scsi->cdb_id = scsi->scb_id; - else - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + scsi->cdb_id = scsi->assign ? scsi->dev_id[scsi->scb_id].phys_id : scsi->present[scsi->scb_id]; spock_log("Device Verify\n"); scsi->cdb[0] = GPCMD_VERIFY_10; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ @@ -779,10 +782,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) return; case CMD_REQUEST_SENSE: - if (scb->command != CMD_REQUEST_SENSE) - scsi->cdb_id = scsi->scb_id; - else - scsi->cdb_id = scsi->dev_id[scsi->scb_id].phys_id; + scsi->cdb_id = scsi->assign ? scsi->dev_id[scsi->scb_id].phys_id : scsi->present[scsi->scb_id]; spock_log("Device Request Sense, ID=%d\n", scsi->cdb_id); scsi->cdb[0] = GPCMD_REQUEST_SENSE; scsi->cdb[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ @@ -802,7 +802,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) if (scsi_device_present(&scsi_devices[scsi->bus][scsi->cdb_id])) { if (scsi->last_status == SCSI_STATUS_OK) { scsi->scb_state = 3; - spock_log("Status is Good on device ID %d, reset = %d\n", scsi->scb_id, scsi->adapter_reset); + spock_log("Status is Good on device ID %d, cdb id = %d.\n", scsi->scb_id, scsi->cdb_id); } else if (scsi->last_status == SCSI_STATUS_CHECK_CONDITION) { uint16_t term_stat_block_addr7 = (0xc << 8) | 2; uint16_t term_stat_block_addr8 = 0x20; @@ -811,7 +811,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) spock_set_irq(scsi, scsi->scb_id, IRQ_TYPE_COMMAND_FAIL); scsi->scb_state = 0; - spock_log("Status Check Condition on device ID %d, reset = %d\n", scsi->scb_id, scsi->adapter_reset); + spock_log("Status Check Condition on device ID %d, cdb id = %d.\n", scsi->attention & 0x0f, scsi->cdb_id); dma_bm_write(scb->term_status_block_addr + 0x7 * 2, (uint8_t *) &term_stat_block_addr7, 2, 2); dma_bm_write(scb->term_status_block_addr + 0x8 * 2, (uint8_t *) &term_stat_block_addr8, 2, 2); dma_bm_write(scb->term_status_block_addr + 0xb * 2, (uint8_t *) &term_stat_block_addrb, 2, 2); @@ -822,7 +822,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) uint16_t term_stat_block_addr8 = 0x10; spock_set_irq(scsi, scsi->scb_id, IRQ_TYPE_COMMAND_FAIL); scsi->scb_state = 0; - spock_log("Status Check Condition on device ID %d on no device, reset = %d\n", scsi->scb_id, scsi->adapter_reset); + spock_log("Status Check Condition on device ID %d on no device\n", scsi->scb_id); dma_bm_write(scb->term_status_block_addr + 0x7 * 2, (uint8_t *) &term_stat_block_addr7, 2, 2); dma_bm_write(scb->term_status_block_addr + 0x8 * 2, (uint8_t *) &term_stat_block_addr8, 2, 2); } @@ -837,7 +837,7 @@ spock_execute_cmd(spock_t *scsi, scb_t *scb) } else { spock_set_irq(scsi, scsi->scb_id, IRQ_TYPE_SCB_COMPLETE); scsi->scb_state = 0; - spock_log("Complete SCB\n"); + spock_log("Complete SCB ID = %d.\n", scsi->attention & 0x0f); } break; } @@ -856,12 +856,12 @@ spock_process_scsi(spock_t *scsi, scb_t *scb) break; case SCSI_STATE_SELECT: - spock_log("Selecting ID %d\n", scsi->cdb_id); + spock_log("Selecting ID %d, SCB ID %d, LUN %d, adapter id = %d.\n", scsi->cdb_id, scsi->scb_id, scsi->dev_id[scsi->scb_id].lun_id, scsi->attention); if ((scsi->cdb_id != (uint8_t) -1) && scsi_device_present(&scsi_devices[scsi->bus][scsi->cdb_id])) { scsi->scsi_state = SCSI_STATE_SEND_COMMAND; - spock_log("Device selected at ID %i\n", scsi->cdb_id); + spock_log("Device selected at ID %i.\n", scsi->cdb_id); } else { - spock_log("Device selection failed at ID %i\n", scsi->cdb_id); + spock_log("Device selection failed at ID %i.\n", scsi->cdb_id); scsi->scsi_state = SCSI_STATE_IDLE; if (!scsi->cmd_timer) { spock_log("Callback to reset\n"); @@ -985,6 +985,7 @@ spock_callback(void *priv) scsi->cir[3] = scsi->cir_pending[3]; scsi->cir_status = 0; + spock_log("SCSI attention = %02x.\n", scsi->attention_pending); switch (scsi->attention >> 4) { case 1: /*Immediate command*/ scsi->cmd_status = 0x0a; @@ -1007,7 +1008,7 @@ spock_callback(void *priv) scsi->scb_addr = scsi->cir[0] | (scsi->cir[1] << 8) | (scsi->cir[2] << 16) | (scsi->cir[3] << 24); scsi->scb_id = scsi->attention & 0x0f; scsi->cmd_timer = SPOCK_TIME * 2; - spock_log("Start SCB at ID = %d\n", scsi->scb_id); + spock_log("Start SCB at ID = %d, attention = %02x\n", scsi->scb_id, scsi->attention >> 4); scsi->scb_state = 1; break; @@ -1019,7 +1020,7 @@ spock_callback(void *priv) case 0x0e: /*EOI*/ scsi->irq_status = 0; - spock_clear_irq(scsi, scsi->attention & 0xf); + spock_clear_irq(scsi, scsi->attention & 0x0f); break; } } @@ -1049,10 +1050,9 @@ spock_mca_write(int port, uint8_t val, void *priv) if (scsi->pos_regs[2] & 1) { io_sethandler((((scsi->pos_regs[2] >> 1) & 7) * 8) + 0x3540, 0x0008, spock_read, spock_readw, NULL, spock_write, spock_writew, NULL, scsi); - if ((scsi->pos_regs[2] >> 4) == 0x0f) - mem_mapping_disable(&scsi->bios_rom.mapping); - else { + if ((scsi->pos_regs[2] & 0xf0) != 0xf0) { mem_mapping_set_addr(&scsi->bios_rom.mapping, ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000, 0x8000); + mem_mapping_enable(&scsi->bios_rom.mapping); } } } @@ -1089,10 +1089,10 @@ spock_mca_reset(void *priv) scsi->basic_ctrl = 0; /* Reset all devices on controller reset. */ - for (i = 0; i < 8; i++) + for (i = 0; i < 8; i++) { scsi_device_reset(&scsi_devices[scsi->bus][i]); - - scsi->adapter_reset = 0; + scsi->present[i] = 0; + } } static void * @@ -1175,7 +1175,7 @@ static const device_config_t spock_rom_config[] = { }, }, { .name = "", .description = "", .type = CONFIG_END } - // clang-format on +// clang-format on }; const device_t spock_device = {