diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 0bdcb5fb8..784b84a39 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -443,7 +443,7 @@ cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len) int ret = 1; if (!dev->sound_on || (dev->cd_status != CD_STATUS_PLAYING) || dev->audio_muted_soft) { - cdrom_log("CD-ROM %i: Audio callback while not playing\n", dev->id); + // cdrom_log("CD-ROM %i: Audio callback while not playing\n", dev->id); if (dev->cd_status == CD_STATUS_PLAYING) dev->seek_pos += (len >> 11); memset(output, 0, len * 2); @@ -452,25 +452,25 @@ cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len) while (dev->cd_buflen < len) { if (dev->seek_pos < dev->cd_end) { - if (dev->ops->read_sector(dev, CD_READ_AUDIO, (uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), - dev->seek_pos)) { + if (dev->ops->read_sector(dev, (uint8_t *) &(dev->cd_buffer[dev->cd_buflen]), dev->seek_pos)) { cdrom_log("CD-ROM %i: Read LBA %08X successful\n", dev->id, dev->seek_pos); + memcpy(dev->subch_buffer, ((uint8_t *) &(dev->cd_buffer[dev->cd_buflen])) + 2352, 96); dev->seek_pos++; dev->cd_buflen += (RAW_SECTOR_SIZE / 2); ret = 1; } else { cdrom_log("CD-ROM %i: Read LBA %08X failed\n", dev->id, dev->seek_pos); memset(&(dev->cd_buffer[dev->cd_buflen]), 0x00, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_status = CD_STATUS_STOPPED; - dev->cd_buflen = len; - ret = 0; + dev->cd_status = CD_STATUS_STOPPED; + dev->cd_buflen = len; + ret = 0; } } else { cdrom_log("CD-ROM %i: Playing completed\n", dev->id); memset(&dev->cd_buffer[dev->cd_buflen], 0x00, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_status = CD_STATUS_PLAYING_COMPLETED; - dev->cd_buflen = len; - ret = 0; + dev->cd_status = CD_STATUS_PLAYING_COMPLETED; + dev->cd_buflen = len; + ret = 0; } } @@ -792,18 +792,60 @@ cdrom_audio_pause_resume(cdrom_t *dev, uint8_t resume) dev->cd_status = (dev->cd_status & 0xfe) | (resume & 0x01); } +static void +cdrom_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc, int cooked) +{ + uint8_t *scb = dev->subch_buffer; + uint8_t q[16] = { 0 }; + + if ((lba == dev->seek_pos) && (dev->cd_status == CD_STATUS_PLAYING)) { + for (int i = 0; i < 12; i++) + for (int j = 0; j < 8; j++) + q[i] |= ((scb[(i << 3) + j] >> 6) & 0x01) << (7 - j); + + if (cooked) { + uint8_t temp = (q[0] >> 4) | ((q[0] & 0xf) << 4); + q[0] = temp; + + for (int i = 1; i < 10; i++) { + temp = bcd2bin(q[i]); + q[i] = temp; + } + } + + subc->attr = q[0]; + subc->track = q[1]; + subc->index = q[2]; + subc->rel_m = q[3]; + subc->rel_s = q[4]; + subc->rel_f = q[5]; + subc->abs_m = q[7]; + subc->abs_s = q[8]; + subc->abs_f = q[9]; + } else if ((dev->ops != NULL) && (dev->ops->get_subchannel != NULL)) { + dev->ops->get_subchannel(dev, lba, subc); + + if (!cooked) { + uint8_t temp = (q[0] >> 4) | ((q[0] & 0xf) << 4); + q[0] = temp; + + subc->attr = (subc->attr >> 4) | ((subc->attr & 0xf) << 4); + subc->track = bin2bcd(subc->track); + subc->index = bin2bcd(subc->index); + subc->rel_m = bin2bcd(subc->rel_m); + subc->rel_s = bin2bcd(subc->rel_s); + subc->rel_f = bin2bcd(subc->rel_f); + subc->abs_m = bin2bcd(subc->abs_m); + subc->abs_s = bin2bcd(subc->abs_s); + subc->abs_f = bin2bcd(subc->abs_f); + } + } +} + uint8_t -cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) +cdrom_get_current_status(cdrom_t *dev) { uint8_t ret; - subchannel_t subc; - int pos = 1; - int m; - int s; - int f; - uint32_t dat; - - dev->ops->get_subchannel(dev, dev->seek_pos, &subc); if (dev->cd_status == CD_STATUS_DATA_ONLY) ret = 0x15; @@ -816,78 +858,103 @@ cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) ret = 0x13; } - cdrom_log("CD-ROM %i: Returned subchannel absolute at %02i:%02i.%02i, relative at %02i:%02i.%02i, ret = %02x, seek pos = %08x, cd_end = %08x.\n", dev->id, subc.abs_m, subc.abs_s, subc.abs_f, subc.rel_m, subc.rel_s, subc.rel_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; - b[pos++] = subc.index; - - if (msf) { - b[pos] = 0; - - /* NEC CDR-260 speaks BCD. */ - if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) { /*NEC*/ - m = subc.abs_m; - s = subc.abs_s; - f = subc.abs_f; - msf_to_bcd(&m, &s, &f); - b[pos + 1] = m; - b[pos + 2] = s; - b[pos + 3] = f; - } else { - b[pos + 1] = subc.abs_m; - b[pos + 2] = subc.abs_s; - b[pos + 3] = subc.abs_f; - } - - pos += 4; - - b[pos] = 0; - - /* NEC CDR-260 speaks BCD. */ - if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) { /*NEC*/ - m = subc.rel_m; - s = subc.rel_s; - f = subc.rel_f; - msf_to_bcd(&m, &s, &f); - b[pos + 1] = m; - b[pos + 2] = s; - b[pos + 3] = f; - } else { - b[pos + 1] = subc.rel_m; - b[pos + 2] = subc.rel_s; - b[pos + 3] = subc.rel_f; - } - - pos += 4; - } else { - dat = MSFtoLBA(subc.abs_m, subc.abs_s, subc.abs_f) - 150; - b[pos++] = (dat >> 24) & 0xff; - b[pos++] = (dat >> 16) & 0xff; - b[pos++] = (dat >> 8) & 0xff; - b[pos++] = dat & 0xff; - dat = MSFtoLBA(subc.rel_m, subc.rel_s, subc.rel_f); - b[pos++] = (dat >> 24) & 0xff; - b[pos++] = (dat >> 16) & 0xff; - b[pos++] = (dat >> 8) & 0xff; - b[pos++] = dat & 0xff; - } - return ret; } +void +cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf) +{ + subchannel_t subc; + uint32_t dat; + + cdrom_get_subchannel(dev, dev->seek_pos, &subc, 1); + + cdrom_log("CD-ROM %i: Returned subchannel absolute at %02i:%02i.%02i, " + "relative at %02i:%02i.%02i, seek pos = %08x, cd_end = %08x.\n", + dev->id, subc.abs_m, subc.abs_s, subc.abs_f, subc.rel_m, subc.rel_s, subc.rel_f, + dev->seek_pos, dev->cd_end); + + /* Format code. */ + switch (b[0]) { + /* Mode 0 = Q subchannel mode, first 16 bytes are indentical to mode 1 (current position), + the rest are stuff like ISRC etc., which can be all zeroes. */ + case 0x01: + /* Current position. */ + b[1] = subc.attr; + b[2] = subc.track; + b[3] = subc.index; + + if (msf) { + b[4] = b[8] = 0x00; + + /* NEC CDR-260 speaks BCD. */ + if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) { + /* NEC */ + b[5] = bin2bcd(subc.abs_m); + b[6] = bin2bcd(subc.abs_s); + b[7] = bin2bcd(subc.abs_f); + + b[9] = bin2bcd(subc.rel_m); + b[10] = bin2bcd(subc.rel_s); + b[11] = bin2bcd(subc.rel_f); + } else { + b[5] = subc.abs_m; + b[6] = subc.abs_s; + b[7] = subc.abs_f; + + b[9] = subc.rel_m; + b[10] = subc.rel_s; + b[11] = subc.rel_f; + } + } else { + dat = MSFtoLBA(subc.abs_m, subc.abs_s, subc.abs_f) - 150; + b[4] = (dat >> 24) & 0xff; + b[5] = (dat >> 16) & 0xff; + b[6] = (dat >> 8) & 0xff; + b[7] = dat & 0xff; + + dat = MSFtoLBA(subc.rel_m, subc.rel_s, subc.rel_f); + b[8] = (dat >> 24) & 0xff; + b[9] = (dat >> 16) & 0xff; + b[10] = (dat >> 8) & 0xff; + b[11] = dat & 0xff; + } + break; + case 0x02: + /* UPC - TODO: Finding and reporting the actual UPC data. */ + memset(&(b[1]), 0x00, 19); + memset(&(b[5]), 0x30, 13); + /* NEC CDR-260 speaks BCD. */ + if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) + /* NEC */ + b[19] = bin2bcd(subc.abs_f); + else + b[19] = subc.abs_f; + break; + case 0x03: + /* ISRC - TODO: Finding and reporting the actual ISRC data. */ + memset(&(b[1]), 0x00, 19); + memset(&(b[5]), 0x30, 12); + /* NEC CDR-260 speaks BCD. */ + if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) + /* NEC */ + b[18] = bin2bcd(subc.abs_f); + else + b[18] = subc.abs_f; + break; + default: + cdrom_log("b[0] = %02X\n", b[0]); + break; + } +} + void cdrom_get_current_subchannel_sony(cdrom_t *dev, uint8_t *b, int msf) { subchannel_t subc; uint32_t dat; - dev->ops->get_subchannel(dev, dev->seek_pos, &subc); + cdrom_get_subchannel(dev, dev->seek_pos, &subc, 1); cdrom_log("CD-ROM %i: Returned subchannel at %02i:%02i.%02i, seek pos = %08x, cd_end = %08x, msf = %x.\n", dev->id, subc.abs_m, subc.abs_s, subc.abs_f, dev->seek_pos, dev->cd_end, msf); @@ -920,7 +987,7 @@ cdrom_get_audio_status_pioneer(cdrom_t *dev, uint8_t *b) uint8_t ret; subchannel_t subc; - dev->ops->get_subchannel(dev, dev->seek_pos, &subc); + cdrom_get_subchannel(dev, dev->seek_pos, &subc, 0); if (dev->cd_status == CD_STATUS_DATA_ONLY) ret = 0x05; @@ -934,9 +1001,9 @@ cdrom_get_audio_status_pioneer(cdrom_t *dev, uint8_t *b) } b[0] = 0; - b[1] = bin2bcd(subc.abs_m); - b[2] = bin2bcd(subc.abs_s); - b[3] = bin2bcd(subc.abs_f); + b[1] = subc.abs_m; + b[2] = subc.abs_s; + b[3] = subc.abs_f; return ret; } @@ -948,7 +1015,7 @@ cdrom_get_audio_status_sony(cdrom_t *dev, uint8_t *b, int msf) subchannel_t subc; uint32_t dat; - dev->ops->get_subchannel(dev, dev->seek_pos, &subc); + cdrom_get_subchannel(dev, dev->seek_pos, &subc, 1); if (dev->cd_status == CD_STATUS_DATA_ONLY) ret = 0x05; @@ -982,26 +1049,25 @@ cdrom_get_current_subcodeq(cdrom_t *dev, uint8_t *b) { subchannel_t subc; - dev->ops->get_subchannel(dev, dev->seek_pos, &subc); + cdrom_get_subchannel(dev, dev->seek_pos, &subc, 0); b[0] = subc.attr; - 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); + b[1] = subc.track; + b[2] = subc.index; + b[3] = subc.rel_m; + b[4] = subc.rel_s; + b[5] = subc.rel_f; + b[6] = subc.abs_m; + b[7] = subc.abs_s; + b[8] = subc.abs_f; } uint8_t cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b) { uint8_t ret; - subchannel_t subc; - dev->ops->get_subchannel(dev, dev->seek_pos, &subc); + cdrom_get_current_subcodeq(dev, b); if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->cd_status == CD_STATUS_PLAYING_COMPLETED) || @@ -1014,100 +1080,166 @@ cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b) if (dev->ops->track_type(dev, dev->seek_pos) & CD_TRACK_AUDIO) dev->audio_muted_soft = 0; - cdrom_log("SubCodeQ: Play Status: Seek LBA=%08x, CDEND=%08x, mute=%d.\n", dev->seek_pos, dev->cd_end, dev->audio_muted_soft); - b[0] = subc.attr; - 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); + cdrom_log("SubCodeQ: Play Status: Seek LBA=%08x, CDEND=%08x, mute=%d.\n", + dev->seek_pos, dev->cd_end, dev->audio_muted_soft); + return ret; +} + +static void +read_toc_identify_sessions(raw_track_info_t *rti, int num, unsigned char *b) +{ + /* Bytes 2 and 3 = Number of first and last sessions */ + b[2] = 0xff; + b[3] = 0x00; + + for (int i = (num - 1); i >= 0; i--) { + if (rti[i].session < b[2]) + b[2] = rti[i].session; + } + + for (int i = 0; i < num; i++) { + if (rti[i].session > b[3]) + b[3] = rti[i].session; + } +} + +static int +find_track(raw_track_info_t *trti, int num, int first) +{ + int ret = -1; + + if (first) { + for (int i = 0; i < num; i++) + if ((trti[i].point >= 1) && (trti[i].point <= 99)) { + ret = i; + break; + } + } else { + for (int i = (num - 1); i >= 0; i--) + if ((trti[i].point >= 1) && (trti[i].point <= 99)) { + ret = i; + break; + } + } + return ret; } static int -read_toc_normal(cdrom_t *dev, unsigned char *b, unsigned char start_track, int msf) +find_last_lead_out(raw_track_info_t *trti, int num) { - track_info_t ti; - int i; - int len = 4; - int m; - int s; - int f; - int first_track; - int last_track; - uint32_t temp; + int ret = -1; - cdrom_log("read_toc_normal(%08X, %08X, %02X, %i)\n", dev, b, start_track, msf); + for (int i = (num - 1); i >= 0; i--) + if (trti[i].point == 0xa2) { + ret = i; + break; + } - dev->ops->get_tracks(dev, &first_track, &last_track); + return ret; +} - /* 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]); +static int +find_specific_track(raw_track_info_t *trti, int num, int track) +{ + int ret = -1; - /* 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 ((track >= 1) && (track <= 99)) { + for (int i = (num - 1); i >= 0; i--) + if (trti[i].point == track) { + ret = i; + break; + } + } - 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; + return ret; +} + +static int +read_toc_normal(cdrom_t *dev, unsigned char *b, unsigned char start_track, int msf, int sony) +{ + uint8_t rti[65536] = { 0 }; + uint8_t prti[65536] = { 0 }; + raw_track_info_t *trti = (raw_track_info_t *) rti; + raw_track_info_t *tprti = (raw_track_info_t *) prti; + int num = 0; + int len = 4; + int s = -1; + + cdrom_log("read_toc_normal(%016" PRIXPTR ", %016" PRIXPTR ", %02X, %i)\n", + (uintptr_t) dev, (uintptr_t) b, start_track, msf, sony); + + dev->ops->get_raw_track_info(dev, &num, (raw_track_info_t *) rti); + + if (num > 0) { + int j = 0; + for (int i = 0; i < num; i++) { + if ((trti[i].point >= 0x01) && (trti[i].point <= 0x63)) { + tprti[j] = trti[i]; + if ((s == -1) && (tprti[j].point >= start_track)) + s = j; + cdrom_log("Sorted %03i = Unsorted %03i (s = %03i)\n", j, i, s); + j++; + } + } + + /* Bytes 2 and 3 = Number of first and last tracks found before lead out */ + b[2] = tprti[0].point; + b[3] = tprti[j - 1].point; + + for (int i = (num - 1); i >= 0; i--) { + if (trti[i].point == 0xa2) { + tprti[j] = trti[i]; + tprti[j].point = 0xaa; + if ((s == -1) && (tprti[j].point >= start_track)) + s = j; + cdrom_log("Sorted %03i = Unsorted %03i (s = %03i)\n", j, i, s); + j++; 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) { - cdrom_log(" [ERROR] No suitable track found\n"); - return -1; - } + if (s != -1) for (int i = s; i < j; i++) { + uint8_t *c = &(b[len]); - 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); + if (!sony) + b[len++] = 0; /* Reserved */ + b[len++] = tprti[i].adr_ctl; /* ADR/CTL */ + b[len++] = tprti[i].point; /* Track number */ + if (!sony) + b[len++] = 0; /* Reserved */ - b[len++] = 0; /* reserved */ - b[len++] = ti.attr; - b[len++] = ti.number; /* track number */ - b[len++] = 0; /* reserved */ + if (msf) { + b[len++] = 0; - if (msf) { - b[len++] = 0; - - /* NEC CDR-260 speaks BCD. */ - if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) { /*NEC*/ - m = ti.m; - s = ti.s; - f = ti.f; - msf_to_bcd(&m, &s, &f); - b[len++] = m; - b[len++] = s; - b[len++] = f; + /* NEC CDR-260 speaks BCD. */ + if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) { + int m = tprti[i].pm; + int s = tprti[i].ps; + int f = tprti[i].pf; + msf_to_bcd(&m, &s, &f); + b[len++] = m; + b[len++] = s; + b[len++] = f; + } else { + b[len++] = tprti[i].pm; + b[len++] = tprti[i].ps; + b[len++] = tprti[i].pf; + } } else { - b[len++] = ti.m; - b[len++] = ti.s; - b[len++] = ti.f; + uint32_t temp = MSFtoLBA(tprti[i].pm, tprti[i].ps, tprti[i].pf) - 150; + + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; } - } 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; + + cdrom_log("Track %02X: %02X %02X %02X %02X %02X %02X %02X %02X\n", + i, c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]); } - } + } else + b[2] = b[3] = 0; return len; } @@ -1115,229 +1247,89 @@ read_toc_normal(cdrom_t *dev, unsigned char *b, unsigned char start_track, int m static int read_toc_session(cdrom_t *dev, unsigned char *b, int msf) { - track_info_t ti; - int len = 4; - int m; - int s; - int f; - uint32_t temp; + uint8_t rti[65536] = { 0 }; + raw_track_info_t *t = (raw_track_info_t *) rti; + raw_track_info_t *first = NULL; + int num = 0; + int len = 4; - cdrom_log("read_toc_session(%08X, %08X, %i)\n", dev, b, msf); + dev->ops->get_raw_track_info(dev, &num, (raw_track_info_t *) rti); /* Bytes 2 and 3 = Number of first and last sessions */ - b[2] = b[3] = 1; + read_toc_identify_sessions((raw_track_info_t *) rti, num, b); - dev->ops->get_track_info(dev, 1, 0, &ti); + cdrom_log("read_toc_session(%016" PRIXPTR ", %016" PRIXPTR ", %i)\n", + (uintptr_t) dev, (uintptr_t) b, msf); - cdrom_log(" tracks(0) = %02X, %02X, %i:%02i.%02i\n", ti.attr, ti.number, ti.m, ti.s, ti.f); - - b[len++] = 0; /* reserved */ - b[len++] = ti.attr; - b[len++] = ti.number; /* track number */ - b[len++] = 0; /* reserved */ - - if (msf) { - b[len++] = 0; - - /* NEC CDR-260 speaks BCD. */ - if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) { /*NEC*/ - m = ti.m; - s = ti.s; - f = ti.f; - msf_to_bcd(&m, &s, &f); - b[len++] = m; - b[len++] = s; - b[len++] = f; - } else { - b[len++] = ti.m; - b[len++] = ti.s; - b[len++] = ti.f; + if (num != 0) { + for (int i = 0; i < num; i++) if ((t[i].session == b[3]) && (t[i].point >= 0x01) && (t[i].point <= 0x63)) { + first = &(t[i]); + break; } - } 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; - } + if (first != NULL) { + b[len++] = 0x00; + b[len++] = first->adr_ctl; + b[len++] = first->point; + b[len++] = 0x00; - return len; -} + if (msf) { + b[len++] = 0x00; -static int -read_toc_raw(cdrom_t *dev, unsigned char *b) -{ - track_info_t ti; - raw_track_info_t rti[256] = { 0 }; - int num = 0; - int len = 4; - int first_track; - int last_track; + /* NEC CDR-260 speaks BCD. */ + if ((dev->type == CDROM_TYPE_NEC_260_100) || (dev->type == CDROM_TYPE_NEC_260_101)) { /*NEC*/ + int m = first->pm; + int s = first->ps; + int f = first->pf; - /* Bytes 2 and 3 = Number of first and last sessions */ - b[2] = b[3] = 1; + msf_to_bcd(&m, &s, &f); - if (dev->ops->get_raw_track_info != NULL) { - cdrom_log("read_toc_raw(%08X, %08X): Raw tracks\n", dev, b); - pclog("read_toc_raw(%016" PRIXPTR ", %016" PRIXPTR "): Raw tracks\n", - (uintptr_t) dev, (uintptr_t) b); + b[len++] = m; + b[len++] = s; + b[len++] = f; + } else { + b[len++] = first->pm; + b[len++] = first->ps; + b[len++] = first->pf; + } + } else { + uint32_t temp = MSFtoLBA(first->pm, first->ps, first->pf) - 150; - dev->ops->get_raw_track_info(dev, &num, (raw_track_info_t *) rti); - - if (num != 0) for (int i = 0; i < num; i++) { - b[len++] = rti[i].session; - b[len++] = rti[i].adr_ctl; - b[len++] = rti[i].tno; - b[len++] = rti[i].point; - b[len++] = rti[i].m; - b[len++] = rti[i].s; - b[len++] = rti[i].f; - b[len++] = rti[i].zero; - b[len++] = rti[i].pm; - b[len++] = rti[i].ps; - b[len++] = rti[i].pf; - } - } else { - cdrom_log("read_toc_raw(%08X, %08X): Cooked tracks\n", dev, b); - pclog("read_toc_raw(%016" PRIXPTR ", %016" PRIXPTR "): Cooked tracks\n", - (uintptr_t) dev, (uintptr_t) b); - - dev->ops->get_tracks(dev, &first_track, &last_track); - - dev->ops->get_track_info(dev, 1, 0, &ti); - - b[len++] = 1; /* Session number */ - b[len++] = ti.attr; /* Track ADR and Control */ - b[len++] = 0; /* TNO (always 0) */ - b[len++] = 0xA0; /* Point (for track points - track number) */ - /* Yes, this is correct - MSF followed by PMSF, the actual position is in PMSF. */ - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = ti.number; /* First track number */ - b[len++] = 0; - b[len++] = 0; - - dev->ops->get_track_info(dev, last_track, 0, &ti); - - b[len++] = 1; /* Session number */ - b[len++] = ti.attr; /* Track ADR and Control */ - b[len++] = 0; /* TNO (always 0) */ - b[len++] = 0xA1; /* Point (for track points - track number) */ - /* Yes, this is correct - MSF followed by PMSF, the actual position is in PMSF. */ - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = ti.number; /* First track number */ - b[len++] = 0; - b[len++] = 0; - - dev->ops->get_track_info(dev, last_track + 1, 0, &ti); - - cdrom_log(" tracks(%i) = %02X, %02X, %i:%02i.%02i\n", i, ti.attr, ti.number, ti.m, ti.s, ti.f); - - b[len++] = 1; /* Session number */ - b[len++] = ti.attr; /* Track ADR and Control */ - b[len++] = 0; /* TNO (always 0) */ - b[len++] = 0xA2; /* Point (for track points - track number) */ - /* Yes, this is correct - MSF followed by PMSF, the actual position is in PMSF. */ - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = ti.m; /* PM */ - b[len++] = ti.s; /* PS */ - b[len++] = ti.f; /* PF */ - - for (int i = 0; i < last_track; i++) { - dev->ops->get_track_info(dev, i + 1, 0, &ti); - - cdrom_log(" tracks(%i) = %02X, %02X, %i:%02i.%02i\n", i, ti.attr, ti.number, ti.m, ti.s, ti.f); - - b[len++] = 1; /* Session number */ - b[len++] = ti.attr; /* Track ADR and Control */ - b[len++] = 0; /* TNO (always 0) */ - b[len++] = ti.number; /* Point (for track points - track number) */ - /* Yes, this is correct - MSF followed by PMSF, the actual position is in PMSF. */ - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = 0; - b[len++] = ti.m; /* PM */ - b[len++] = ti.s; /* PS */ - b[len++] = ti.f; /* PF */ - } - } - - 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; - int len = 4; - int first_track; - int 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; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; } } } - cdrom_log(" first_track = %i, last_track = %i\n", first_track, last_track); - /* No suitable starting track, return with error. */ - if (first_track == -1) { - cdrom_log(" [ERROR] No suitable track found\n"); - return -1; - } + if (len == 4) + memset(&(b[len += 8]), 0x00, 8); - 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); + return len; +} - b[len++] = ti.number; /* track number */ - b[len++] = ti.attr; +static int +read_toc_raw(cdrom_t *dev, unsigned char *b, unsigned char start_track) +{ + uint8_t rti[65536] = { 0 }; + raw_track_info_t *t = (raw_track_info_t *) rti; + int num = 0; + int len = 4; - 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; + /* Bytes 2 and 3 = Number of first and last sessions */ + read_toc_identify_sessions((raw_track_info_t *) rti, num, b); + + cdrom_log("read_toc_raw(%016" PRIXPTR ", %016" PRIXPTR ", %02X)\n", + (uintptr_t) dev, (uintptr_t) b, start_track); + + dev->ops->get_raw_track_info(dev, &num, (raw_track_info_t *) rti); + + if (num != 0) for (int i = 0; i < num; i++) + if (t[i].session >= start_track) { + memcpy(&(b[len]), &(t[i]), 11); + len += 11; } - } + return len; } @@ -1348,13 +1340,13 @@ cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_tra switch (type) { case CD_TOC_NORMAL: - len = read_toc_normal(dev, b, start_track, msf); + len = read_toc_normal(dev, b, start_track, msf, 0); break; case CD_TOC_SESSION: len = read_toc_session(dev, b, msf); break; case CD_TOC_RAW: - len = read_toc_raw(dev, b); + len = read_toc_raw(dev, b, start_track); break; default: cdrom_log("CD-ROM %i: Unknown TOC read type: %i\n", dev->id, type); @@ -1374,7 +1366,7 @@ cdrom_read_toc_sony(cdrom_t *dev, unsigned char *b, unsigned char start_track, i { int len; - len = read_toc_sony(dev, b, start_track, msf); + len = read_toc_normal(dev, b, start_track, msf, 1); len = MIN(len, max_len); @@ -1384,29 +1376,50 @@ cdrom_read_toc_sony(cdrom_t *dev, unsigned char *b, unsigned char start_track, i return len; } +#ifdef USE_CDROM_MITSUMI /* New API calls for Mitsumi CD-ROM. */ void cdrom_get_track_buffer(cdrom_t *dev, uint8_t *buf) { - track_info_t ti; - int first_track; - int last_track; + uint8_t rti[65536] = { 0 }; + raw_track_info_t *trti = (raw_track_info_t *) rti; + int num = 0; + int first = -1; + int last = -1; - if (dev != NULL) { - dev->ops->get_tracks(dev, &first_track, &last_track); - buf[0] = 1; - buf[1] = last_track + 1; - dev->ops->get_track_info(dev, 1, 0, &ti); - buf[2] = ti.m; - buf[3] = ti.s; - buf[4] = ti.f; - dev->ops->get_track_info(dev, last_track + 1, 0, &ti); - buf[5] = ti.m; - buf[6] = ti.s; - buf[7] = ti.f; - buf[8] = 0x00; - } else - memset(buf, 0x00, 9); + if (dev != NULL) + dev->ops->get_raw_track_info(dev, &num, (raw_track_info_t *) rti); + + if (num > 0) { + first = find_track(trti, num, 1); + last = find_track(trti, num, 0); + } + + if (first != -1) { + buf[0] = trti[first].point; + buf[2] = trti[first].pm; + buf[3] = trti[first].ps; + buf[4] = trti[first].pf; + } else { + buf[0] = 0x01; + buf[2] = 0x00; + buf[3] = 0x02; + buf[4] = 0x00; + } + + if (last != -1) { + buf[1] = trti[last].point; + buf[5] = trti[first].pm; + buf[6] = trti[first].ps; + buf[7] = trti[first].pf; + } else { + buf[1] = 0x01; + buf[5] = 0x00; + buf[6] = 0x02; + buf[7] = 0x00; + } + + buf[8] = 0x00; } void @@ -1467,55 +1480,75 @@ cdrom_mitsumi_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len) return 1; } +#endif 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; - int last_track; - int m = 0; - int s = 0; - int f = 0; - uint32_t temp; + uint8_t rti[65536] = { 0 }; + raw_track_info_t *trti = (raw_track_info_t *) rti; + int num = 0; + int first = -1; + int last = -1; + int t = -1; + uint32_t temp; + uint8_t ret = 1; - dev->ops->get_tracks(dev, &first_track, &last_track); + if (dev != NULL) + dev->ops->get_raw_track_info(dev, &num, (raw_track_info_t *) rti); + + cdrom_log("Read DISC Info TOC Type = %d, track = %d\n", type, track); - 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] = 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]); + if (num > 0) { + first = find_track(trti, num, 1); + last = find_track(trti, num, 0); + } + + if ((first == -1) || (last == -1)) + ret = 0; + else { + b[0] = bin2bcd(first); + b[1] = bin2bcd(last); + b[2] = 0x00; + b[3] = 0x00; + + 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); - 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)); + if (num > 0) + t = find_last_lead_out(trti, num); + + if (t == -1) + ret = 0; + else { + b[0] = bin2bcd(trti[t].pm); + b[1] = bin2bcd(trti[t].ps); + b[2] = bin2bcd(trti[t].pf); + b[3] = 0x00; + + cdrom_log("CD-ROM %i: Returned Toshiba/NEC disc information (type 1) at %02i:%02i.%02i\n", + dev->id, b[0], b[1], b[2]); + } break; case 2: - if (track > bin2bcd(last_track)) - return 0; + if (num > 0) + t = find_specific_track(trti, num, bcd2bin(track)); - 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/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); + if (t == -1) + ret = 0; + else { + b[0] = bin2bcd(trti[t].pm); + b[1] = bin2bcd(trti[t].ps); + b[2] = bin2bcd(trti[t].pf); + b[3] = trti[t].adr_ctl; + + cdrom_log("CD-ROM %i: Returned Toshiba/NEC disc information (type 2) at " + "%02i:%02i.%02i, track=%d, attr=%02x.\n", dev->id, b[0], b[1], b[2], bcd2bin(track), b[3]); + } break; case 3: /* Undocumented on NEC CD-ROM's, from information based on sr_vendor.c from the Linux kernel */ switch (dev->type) { @@ -1525,22 +1558,36 @@ cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, in case CDROM_TYPE_NEC_77_106: case CDROM_TYPE_NEC_211_100: case CDROM_TYPE_NEC_464_105: - dev->ops->get_track_info(dev, 1, 0, &ti); - b[0x0e] = 0; - temp = MSFtoLBA(ti.m, ti.s, ti.f) - 150; - b[0x0f] = temp >> 24; - b[0x10] = temp >> 16; - b[0x11] = temp >> 8; - b[0x12] = temp; + b[0x0e] = 0x00; + + if (num > 0) + first = find_track(trti, num, 1); + + if (first == -1) + ret = 0; + else { + temp = MSFtoLBA(trti[first].pm, trti[first].ps, trti[first].pf) - 150; + b[0x0f] = temp >> 24; + b[0x10] = temp >> 16; + b[0x11] = temp >> 8; + b[0x12] = temp; + } break; default: - dev->ops->get_track_info(dev, 1, 0, &ti); - b[0] = 0; - temp = MSFtoLBA(ti.m, ti.s, ti.f) - 150; - b[1] = temp >> 24; - b[2] = temp >> 16; - b[3] = temp >> 8; + b[0] = 0x00; /* Audio or CDROM disc. */ + + if (num > 0) + first = find_track(trti, num, 1); + + if (first == -1) + ret = 0; + else { + temp = MSFtoLBA(trti[first].pm, trti[first].ps, trti[first].pf) - 150; + b[0x1] = temp >> 24; + b[0x2] = temp >> 16; + b[0x3] = temp >> 8; + } break; } break; @@ -1548,7 +1595,7 @@ cdrom_read_disc_info_toc(cdrom_t *dev, unsigned char *b, unsigned char track, in break; } - return 1; + return ret; } static int @@ -1595,40 +1642,10 @@ track_type_is_valid(UNUSED(uint8_t id), int type, int flags, int audio, int mode return 1; } -static int -read_sector_to_buffer(cdrom_t *dev, uint8_t *rbuf, uint32_t msf, uint32_t lba, int mode2, int len) -{ - uint8_t *bb = rbuf; - const int offset = (!!(mode2 & 0x03)) ? 24 : 16; - - int ret = dev->ops->read_sector(dev, CD_READ_DATA, rbuf + offset, lba); - - /* Sync bytes */ - bb[0] = 0; - memset(bb + 1, 0xff, 10); - bb[11] = 0; - bb += 12; - - /* Sector header */ - bb[0] = (msf >> 16) & 0xff; - bb[1] = (msf >> 8) & 0xff; - bb[2] = msf & 0xff; - - bb[3] = 1; /* mode 1 data */ - bb += mode2 ? 12 : 4; - bb += len; - if (mode2 && ((mode2 & 0x03) == 1)) - memset(bb, 0, 280); - else if (!mode2) - memset(bb, 0, 288); - - return ret; -} - static int read_audio(cdrom_t *dev, uint32_t lba, uint8_t *b) { - int ret = dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); + int ret = dev->ops->read_sector(dev, raw_buffer, lba); memcpy(b, raw_buffer, 2352); @@ -1637,15 +1654,9 @@ read_audio(cdrom_t *dev, uint32_t lba, uint8_t *b) return ret; } -static int -read_mode1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +static void +process_mode1(cdrom_t *dev, int cdrom_sector_flags, uint8_t *b) { - int ret; - if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2048)) - ret = read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048); - else - ret = dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); - cdrom_sector_size = 0; if (cdrom_sector_flags & 0x80) { @@ -1690,18 +1701,28 @@ read_mode1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int cdrom_sector_size += 288; b += 288; } +} + +static int +read_data(cdrom_t *dev, uint32_t lba) +{ + return dev->ops->read_sector(dev, raw_buffer, lba); +} + +static int +read_mode1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint8_t *b) +{ + int ret = read_data(dev, lba); + + process_mode1(dev, cdrom_sector_flags, b); return ret; } static int -read_mode2_non_xa(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +read_mode2_non_xa(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint8_t *b) { - int ret; - if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2336)) - ret = read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2336); - else - ret = dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); + int ret = dev->ops->read_sector(dev, raw_buffer, lba); cdrom_sector_size = 0; @@ -1741,15 +1762,9 @@ read_mode2_non_xa(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t m return ret; } -static int -read_mode2_xa_form1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +static void +process_mode2_xa_form1(cdrom_t *dev, int cdrom_sector_flags, uint8_t *b) { - int ret; - if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2048)) - ret = read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048); - else - ret = dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); - cdrom_sector_size = 0; if (cdrom_sector_flags & 0x80) { @@ -1791,18 +1806,22 @@ read_mode2_xa_form1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t cdrom_sector_size += 280; b += 280; } +} + +static int +read_mode2_xa_form1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint8_t *b) +{ + int ret = read_data(dev, lba); + + process_mode2_xa_form1(dev, cdrom_sector_flags, b); return ret; } static int -read_mode2_xa_form2(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +read_mode2_xa_form2(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint8_t *b) { - int ret; - if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2324)) - ret = read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2324); - else - ret = dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba); + int ret = dev->ops->read_sector(dev, raw_buffer, lba); cdrom_sector_size = 0; @@ -1847,14 +1866,11 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int c { uint8_t *b; uint8_t *temp_b; - uint32_t msf; uint32_t lba; - int audio = 0; - int mode2 = 0; - int m; - int s; - int f; - int ret = 0; + int audio = 0; + int mode2 = 0; + int unk = 0; + int ret = 0; if (dev->cd_status == CD_STATUS_EMPTY) return 0; @@ -1864,38 +1880,37 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int c *len = 0; if (ismsf) { - m = (sector >> 16) & 0xff; - s = (sector >> 8) & 0xff; - f = sector & 0xff; + int m = (sector >> 16) & 0xff; + int s = (sector >> 8) & 0xff; + int f = sector & 0xff; + lba = MSFtoLBA(m, s, f) - 150; - msf = sector; } else { 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); + int m = bcd2bin((sector >> 24) & 0xff); + int s = bcd2bin((sector >> 16) & 0xff); + int f = bcd2bin((sector >> 8) & 0xff); + lba = MSFtoLBA(m, s, f) - 150; - msf = sector; break; case 0x80: lba = bcd2bin((sector >> 24) & 0xff); - msf = sector; break; /* Never used values but the compiler complains. */ default: - lba = msf = 0; + lba = 0; } } if (dev->ops->track_type) audio = dev->ops->track_type(dev, lba); - mode2 = audio & ~CD_TRACK_AUDIO; + mode2 = audio & CD_TRACK_MODE2; + unk = audio & CD_TRACK_UNK_DATA; audio &= CD_TRACK_AUDIO; memset(raw_buffer, 0, 2448); @@ -1926,55 +1941,67 @@ cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int c return 0; } - ret = read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + ret = read_mode1(dev, cdrom_sector_flags, lba, temp_b); } else if (cdrom_sector_type == 3) { if (audio || !mode2 || (mode2 & 0x03)) { cdrom_log("CD-ROM %i: [Mode 2 Formless] Attempting to read a sector of another type\n", dev->id); return 0; } - ret = read_mode2_non_xa(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + ret = read_mode2_non_xa(dev, cdrom_sector_flags, lba, temp_b); } else if (cdrom_sector_type == 4) { if (audio || !mode2 || ((mode2 & 0x03) != 1)) { cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Attempting to read a sector of another type\n", dev->id); return 0; } - read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + read_mode2_xa_form1(dev, cdrom_sector_flags, lba, temp_b); } else if (cdrom_sector_type == 5) { if (audio || !mode2 || ((mode2 & 0x03) != 2)) { cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Attempting to read a sector of another type\n", dev->id); return 0; } - ret = read_mode2_xa_form2(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + ret = read_mode2_xa_form2(dev, cdrom_sector_flags, lba, temp_b); } else if (cdrom_sector_type == 8) { if (audio) { cdrom_log("CD-ROM %i: [Any Data] Attempting to read a data sector from an audio track\n", dev->id); return 0; } - if (mode2 && ((mode2 & 0x03) == 1)) - ret = read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + if (unk) { + /* This is needed to correctly read Mode 2 XA Form 1 sectors over IOCTL. */ + ret = read_data(dev, lba); + + if (raw_buffer[0x000f] == 0x02) { + cdrom_log("CD-ROM %i: [Any Data] Unknown data type determined to be XA Mode 2 Form 1\n", dev->id); + process_mode2_xa_form1(dev, cdrom_sector_flags, temp_b); + } else { + cdrom_log("CD-ROM %i: [Any Data] Unknown data type determined to be Mode 1\n", dev->id); + process_mode1(dev, cdrom_sector_flags, temp_b); + } + } else if (mode2 && ((mode2 & 0x03) == 1)) + ret = read_mode2_xa_form1(dev, cdrom_sector_flags, lba, temp_b); else if (!mode2) - ret = read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + ret = read_mode1(dev, cdrom_sector_flags, lba, temp_b); else { - cdrom_log("CD-ROM %i: [Any Data] Attempting to read a data sector whose cooked size is not 2048 bytes\n", dev->id); + cdrom_log("CD-ROM %i: [Any Data] Attempting to read a data sector whose cooked size " + "is not 2048 bytes\n", dev->id); return 0; } } else { if (mode2) { if ((mode2 & 0x03) == 0x01) - ret = read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + ret = read_mode2_xa_form1(dev, cdrom_sector_flags, lba, temp_b); else if ((mode2 & 0x03) == 0x02) - ret = read_mode2_xa_form2(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + ret = read_mode2_xa_form2(dev, cdrom_sector_flags, lba, temp_b); else - ret = read_mode2_non_xa(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + ret = read_mode2_non_xa(dev, cdrom_sector_flags, lba, temp_b); } else { if (audio) ret = read_audio(dev, lba, temp_b); else - ret = read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b); + ret = read_mode1(dev, cdrom_sector_flags, lba, temp_b); } } @@ -2027,7 +2054,6 @@ cdrom_drive_reset(cdrom_t *dev) dev->get_channel = NULL; } -/* Will be removed later. */ #ifdef ENABLE_CDROM_LOG static void cdrom_toc_dump(cdrom_t *dev) @@ -2040,6 +2066,24 @@ cdrom_toc_dump(cdrom_t *dev) fflush(f); fclose(f); pclog("Written TOC of %i bytes to %s\n", len, fn2); + + memset(b, 0x00, 65536); + len = cdrom_read_toc(dev, b, CD_TOC_NORMAL, 0, 0, 65536); + fn2 = "d:\\86boxnew\\toc_cue_cooked.dmp"; + f = fopen(fn2, "wb"); + fwrite(b, 1, len, f); + fflush(f); + fclose(f); + pclog("Written cooked TOC of %i bytes to %s\n", len, fn2); + + memset(b, 0x00, 65536); + len = cdrom_read_toc(dev, b, CD_TOC_SESSION, 0, 0, 65536); + fn2 = "d:\\86boxnew\\toc_cue_session.dmp"; + f = fopen(fn2, "wb"); + fwrite(b, 1, len, f); + fflush(f); + fclose(f); + pclog("Written session TOC of %i bytes to %s\n", len, fn2); } #endif @@ -2084,8 +2128,12 @@ cdrom_hard_reset(void) else cdrom_image_open(dev, dev->image_path); + cdrom_insert(i); + cdrom_insert(i); + #ifdef ENABLE_CDROM_LOG - cdrom_toc_dump(dev); + if (i == 0) + cdrom_toc_dump(dev); #endif } } @@ -2144,9 +2192,24 @@ cdrom_exit(uint8_t id) memset(dev->image_path, 0, sizeof(dev->image_path)); + pclog("cdrom_exit(%i): cdrom_insert(%i)\n", id, id); cdrom_insert(id); } +int +cdrom_is_empty(uint8_t id) +{ + cdrom_t *dev = &cdrom[id]; + int ret = 0; + + /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ + if (strlen(dev->image_path) == 0) + /* Switch from empty to empty. Do nothing. */ + ret = 1; + + return ret; +} + /* The mechanics of ejecting a CD-ROM from a drive. */ void cdrom_eject(uint8_t id) @@ -2154,10 +2217,9 @@ cdrom_eject(uint8_t id) cdrom_t *dev = &cdrom[id]; /* This entire block should be in cdrom.c/cdrom_eject(dev*) ... */ - if (strlen(dev->image_path) == 0) { + if (strlen(dev->image_path) == 0) /* Switch from empty to empty. Do nothing. */ return; - } cdrom_exit(id); @@ -2170,7 +2232,8 @@ cdrom_eject(uint8_t id) void cdrom_reload(uint8_t id) { - cdrom_t *dev = &cdrom[id]; + cdrom_t *dev = &cdrom[id]; + int was_empty = cdrom_is_empty(id); if ((strcmp(dev->image_path, dev->prev_image_path) == 0) || (strlen(dev->prev_image_path) == 0) || (strlen(dev->image_path) > 0)) { /* Switch from empty to empty. Do nothing. */ @@ -2206,7 +2269,13 @@ cdrom_reload(uint8_t id) cdrom_toc_dump(dev); #endif + /* Signal media change to the emulated machine. */ + pclog("cdrom_reload(%i): cdrom_insert(%i)\n", id, id); cdrom_insert(id); + + /* The drive was previously empty, transition directly to UNIT ATTENTION. */ + if (was_empty) + cdrom_insert(id); } plat_cdrom_ui_update(id, 1); diff --git a/src/cdrom/cdrom_image.c b/src/cdrom/cdrom_image.c index 0ff914795..6e06676f8 100644 --- a/src/cdrom/cdrom_image.c +++ b/src/cdrom/cdrom_image.c @@ -80,6 +80,12 @@ image_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti) ti->f = tmsf.fr; } +static void +image_get_raw_track_info(cdrom_t *dev, int *num, raw_track_info_t *rti) +{ + cdi_get_raw_track_info((cd_img_t *) dev->local, num, (uint8_t *) rti); +} + static void image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) { @@ -99,7 +105,8 @@ image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) subc->rel_f = rel_pos.fr; cdrom_image_log("image_get_subchannel(): %02X, %02X, %02i, %02i:%02i:%02i, %02i:%02i:%02i\n", - subc->attr, subc->track, subc->index, subc->abs_m, subc->abs_s, subc->abs_f, subc->rel_m, subc->rel_s, subc->rel_f); + subc->attr, subc->track, subc->index, subc->abs_m, subc->abs_s, subc->abs_f, + subc->rel_m, subc->rel_s, subc->rel_f); } static int @@ -183,24 +190,14 @@ image_sector_size(struct cdrom *dev, uint32_t lba) } static int -image_read_sector(struct cdrom *dev, int type, uint8_t *b, uint32_t lba) +image_read_sector(struct cdrom *dev, uint8_t *b, uint32_t lba) { cd_img_t *img = (cd_img_t *) dev->local; - switch (type) { - case CD_READ_DATA: - return cdi_read_sector(img, b, 0, lba); - case CD_READ_AUDIO: - return cdi_read_sector(img, b, 1, lba); - case CD_READ_RAW: - if (cdi_get_sector_size(img, lba) == 2352) - return cdi_read_sector(img, b, 1, lba); - else - return cdi_read_sector_sub(img, b, lba); - default: - cdrom_image_log("CD-ROM %i: Unknown CD read type\n", dev->id); - return 0; - } + if (cdi_get_sector_size(img, lba) <= 2352) + return cdi_read_sector(img, b, 1, lba); + else + return cdi_read_sector_sub(img, b, lba); } static int @@ -211,10 +208,8 @@ image_track_type(cdrom_t *dev, uint32_t lba) if (img) { if (image_is_track_audio(dev, lba, 0)) return CD_TRACK_AUDIO; - else { - if (cdi_is_mode2(img, lba)) - return CD_TRACK_MODE2 | cdi_get_mode2_form(img, lba); - } + else if (cdi_is_mode2(img, lba)) + return CD_TRACK_MODE2 | cdi_get_mode2_form(img, lba); } return 0; @@ -245,7 +240,7 @@ image_exit(cdrom_t *dev) static const cdrom_ops_t cdrom_image_ops = { image_get_tracks, image_get_track_info, - NULL, + image_get_raw_track_info, image_get_subchannel, image_is_track_pre, image_sector_size, @@ -303,8 +298,8 @@ cdrom_image_open(cdrom_t *dev, const char *fn) cf = dev->cdrom_capacity % 75; cs = (dev->cdrom_capacity / 75) % 60; cm = (dev->cdrom_capacity / 75) / 60; - pclog("CD-ROM capacity: %i sectors (%" PRIi64 " bytes) (time: %02i:%02i:%02i)\n", - dev->cdrom_capacity, ((uint64_t) dev->cdrom_capacity - 150ULL) * 2352ULL, cm, cs, cf); + cdrom_image_log("CD-ROM capacity: %i sectors (%" PRIi64 " bytes) (time: %02i:%02i:%02i)\n", + dev->cdrom_capacity, ((uint64_t) dev->cdrom_capacity - 150ULL) * 2352ULL, cm, cs, cf); /* Attach this handler to the drive. */ dev->ops = &cdrom_image_ops; diff --git a/src/cdrom/cdrom_image_backend.c b/src/cdrom/cdrom_image_backend.c index 2578e9e33..3e0fa017a 100644 --- a/src/cdrom/cdrom_image_backend.c +++ b/src/cdrom/cdrom_image_backend.c @@ -269,9 +269,8 @@ bin_init(const char *filename, int *error) if ((tf->fp != NULL) && ((stats.st_mode & S_IFMT) == S_IFDIR)) { /* tf is freed by bin_close */ bin_close(tf); - } else { + } else free(tf); - } tf = NULL; } @@ -384,7 +383,8 @@ int cdi_get_audio_track_info(cd_img_t *cdi, UNUSED(int end), int track, int *track_num, TMSF *start, uint8_t *attr) { const track_t *trk = &cdi->tracks[track - 1]; - const int pos = trk->start + 150; + // const int pos = trk->start + 150; + const int pos = trk->indexes[1].start; if ((track < 1) || (track > cdi->tracks_num)) return 0; @@ -406,6 +406,7 @@ cdi_get_audio_track_info_lba(cd_img_t *cdi, UNUSED(int end), int track, int *tra return 0; *start = (uint32_t) trk->start; + // *start = (uint32_t) trk->indexes[1].start - 150ULL; *track_num = trk->track_number; *attr = trk->attr; @@ -413,6 +414,86 @@ cdi_get_audio_track_info_lba(cd_img_t *cdi, UNUSED(int end), int track, int *tra return 1; } +void +cdi_get_raw_track_info(cd_img_t *cdi, int *num, uint8_t *buffer) +{ + TMSF tmsf; + int track_num = 0; + uint8_t attr = 0; + int len = 0; + int first_track; + int last_track; + + cdi_get_audio_tracks(cdi, &first_track, &last_track, &tmsf); + + *num = last_track + 3; + + cdi_get_audio_track_info(cdi, 0, 1, &track_num, &tmsf, &attr); + + buffer[len++] = 1; /* Session number */ + buffer[len++] = attr; /* Track ADR and Control */ + buffer[len++] = 0; /* TNO (always 0) */ + buffer[len++] = 0xA0; /* Point (for track points - track number) */ + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = track_num; /* First track number */ + buffer[len++] = 0; + buffer[len++] = 0; + + cdi_get_audio_track_info(cdi, 0, last_track, &track_num, &tmsf, &attr); + + buffer[len++] = 1; /* Session number */ + buffer[len++] = attr; /* Track ADR and Control */ + buffer[len++] = 0; /* TNO (always 0) */ + buffer[len++] = 0xA1; /* Point (for track points - track number) */ + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = track_num; /* Last track number */ + buffer[len++] = 0; + buffer[len++] = 0; + + cdi_get_audio_track_info(cdi, 0, last_track + 1, &track_num, &tmsf, &attr); + + cdrom_image_backend_log(" tracks(%i) = %02X, %02X, %02i:%02i.%02i\n", last_track, attr, + track_num, tmsf.min, tmsf.sec, tmsf.fr); + + buffer[len++] = 1; /* Session number */ + buffer[len++] = attr; /* Track ADR and Control */ + buffer[len++] = 0; /* TNO (always 0) */ + buffer[len++] = 0xA2; /* Point (for track points - track number) */ + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = tmsf.min; /* PM */ + buffer[len++] = tmsf.sec; /* PS */ + buffer[len++] = tmsf.fr; /* PF */ + + for (int i = 0; i < last_track; i++) { + cdi_get_audio_track_info(cdi, 0, i + 1, &track_num, &tmsf, &attr); + + cdrom_image_backend_log(" tracks(%i) = %02X, %02X, %02i:%02i.%02i\n", i, attr, + track_num, tmsf.min, tmsf.sec, tmsf.fr); + + buffer[len++] = 1; /* Session number */ + buffer[len++] = attr; /* Track ADR and Control */ + buffer[len++] = 0; /* TNO (always 0) */ + buffer[len++] = track_num; /* Point (for track points - track number) */ + /* Yes, this is correct - MSF followed by PMSF, the actual position is in PMSF. */ + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = 0; + buffer[len++] = tmsf.min; /* PM */ + buffer[len++] = tmsf.sec; /* PS */ + buffer[len++] = tmsf.fr; /* PF */ + } +} + int cdi_get_track(cd_img_t *cdi, uint32_t sector) { @@ -427,10 +508,12 @@ cdi_get_track(cd_img_t *cdi, uint32_t sector) const track_t *next = &cdi->tracks[i + 1]; /* Take into account cue sheets that do not start on sector 0. */ - if ((i == 0) && (sector < cur->start)) + // if ((i == 0) && (sector < cur->start)) + if ((i == 0) && (sector < cur->indexes[0].start)) return cur->number; - if ((cur->start <= sector) && (sector < next->start)) + // if ((cur->start <= sector) && (sector < next->start)) + if ((cur->indexes[0].start <= sector) && (sector < next->indexes[0].start)) return cur->number; } @@ -454,11 +537,32 @@ cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, FRAMES_TO_MSF(sector + 150, &abs_pos->min, &abs_pos->sec, &abs_pos->fr); /* Absolute position should be adjusted by 150, not the relative ones. */ - FRAMES_TO_MSF(sector - trk->start, &rel_pos->min, &rel_pos->sec, &rel_pos->fr); + // FRAMES_TO_MSF(sector - trk->start, &rel_pos->min, &rel_pos->sec, &rel_pos->fr); + /* Relative position is relative Index 1 start - pre-gap values will be negative. */ + FRAMES_TO_MSF((int32_t) (sector + 150 - trk->indexes[1].start), &rel_pos->min, &rel_pos->sec, &rel_pos->fr); return 1; } +static int +cdi_get_sector_index(const track_t *trk, const uint32_t sector) +{ + int ret = 1; + + if ((sector + 150) < trk->indexes[1].start) + ret = 0; + else if ((sector + 150) >= trk->indexes[2].start) + ret = 2; + + return ret; +} + +static __inline int +bin2bcd(int x) +{ + return (x % 10) | ((x / 10) << 4); +} + int cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) { @@ -467,9 +571,11 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) int raw_size; int cooked_size; uint64_t offset; - int m = 0; - int s = 0; - int f = 0; + int m = 0; + int s = 0; + int f = 0; + int ret = 0; + uint8_t q[16] = { 0x00 }; if (track < 0) return 0; @@ -478,6 +584,9 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) const int track_is_raw = ((trk->sector_size == RAW_SECTOR_SIZE) || (trk->sector_size == 2448)); const uint64_t seek = trk->skip + ((sect - trk->start) * trk->sector_size); + const int index = cdi_get_sector_index(trk, sector); + cdrom_image_backend_log("cdrom_read_sector(%08X): track %02X, index %02X, %016" PRIX64 ", %016" PRIX64 ", %i\n", + sector, track, index, trk->skip, trk->start, trk->sector_size); if (track_is_raw) raw_size = trk->sector_size; @@ -499,26 +608,67 @@ cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector) else offset = 16ULL; - if (raw && !track_is_raw) { + if (!trk->indexes[index].in_file) { memset(buffer, 0x00, 2448); - const int ret = trk->file->read(trk->file, buffer + offset, seek, length); - if (ret <= 0) - return ret; - /* Construct the rest of the raw sector. */ - memset(buffer + 1, 0xff, 10); - buffer += 12; - FRAMES_TO_MSF(sector + 150, &m, &s, &f); - /* These have to be BCD. */ - buffer[0] = CDROM_BCD(m & 0xff); - buffer[1] = CDROM_BCD(s & 0xff); - buffer[2] = CDROM_BCD(f & 0xff); - /* Data, should reflect the actual sector type. */ - buffer[3] = trk->mode2 ? 2 : 1; - return 1; + if (trk->attr & 0x04) { + /* Construct the rest of the raw sector. */ + memset(buffer + 1, 0xff, 10); + buffer += 12; + FRAMES_TO_MSF(sector + 150, &m, &s, &f); + /* These have to be BCD. */ + buffer[0] = CDROM_BCD(m & 0xff); + buffer[1] = CDROM_BCD(s & 0xff); + buffer[2] = CDROM_BCD(f & 0xff); + /* Data, should reflect the actual sector type. */ + buffer[3] = trk->mode2 ? 2 : 1; + ret = 1; + } + } else if (raw && !track_is_raw) { + memset(buffer, 0x00, 2448); + const int temp = trk->file->read(trk->file, buffer + offset, seek, length); + if (temp <= 0) + return temp; + if (trk->attr & 0x04) { + /* Construct the rest of the raw sector. */ + memset(buffer + 1, 0xff, 10); + buffer += 12; + FRAMES_TO_MSF(sector + 150, &m, &s, &f); + /* These have to be BCD. */ + buffer[0] = CDROM_BCD(m & 0xff); + buffer[1] = CDROM_BCD(s & 0xff); + buffer[2] = CDROM_BCD(f & 0xff); + /* Data, should reflect the actual sector type. */ + buffer[3] = trk->mode2 ? 2 : 1; + ret = 1; + } } else if (!raw && track_is_raw) return trk->file->read(trk->file, buffer, seek + offset, length); - else - return trk->file->read(trk->file, buffer, seek, length); + else { + ret = trk->file->read(trk->file, buffer, seek, length); + if (raw && (raw_size == 2448)) + return ret; + } + + /* Construct Q. */ + q[0] = (trk->attr >> 4) | ((trk->attr & 0xf) << 4); + q[1] = bin2bcd(trk->track_number); + q[2] = 1; /* TODO: Index number. */ + // FRAMES_TO_MSF(sector - trk->start, &m, &s, &f); + FRAMES_TO_MSF((int32_t) (sector + 150 - trk->indexes[1].start), &m, &s, &f); + q[3] = bin2bcd(m); + q[4] = bin2bcd(s); + q[5] = bin2bcd(f); + FRAMES_TO_MSF(sector + 150, &m, &s, &f); + q[7] = bin2bcd(m); + q[8] = bin2bcd(s); + q[9] = bin2bcd(f); + + /* Construct raw subchannel data from Q only. */ + for (int i = 0; i < 12; i++) + for (int j = 0; j < 8; j++) + buffer[2352 + (i << 3) + j] = ((q[i] >> (7 - j)) & 0x01) << 6; + + return ret; } int @@ -700,6 +850,17 @@ cdi_get_iso_track(cd_img_t *cdi, track_t *trk, const char *filename) } trk->length = trk->file->get_length(trk->file) / trk->sector_size; + + trk->indexes[0].in_file = 0; + trk->indexes[0].start = 0; + trk->indexes[0].length = 150; + trk->indexes[1].in_file = 1; + trk->indexes[1].start = 150; + trk->indexes[1].length = trk->length; + trk->indexes[2].in_file = 0; + trk->indexes[2].start = trk->length + 150; + trk->indexes[2].length = 0; + cdrom_image_backend_log("ISO: Data track: length = %" PRIu64 ", sector_size = %i\n", trk->length, trk->sector_size); return ret; } @@ -721,10 +882,18 @@ cdi_load_iso(cd_img_t *cdi, const char *filename) /* Lead out track. */ trk.number = 2; trk.track_number = 0xAA; - trk.attr = 0x16; /* Was originally 0x00, but I believe 0x16 is appropriate. */ + // trk.attr = 0x16; /* Was originally 0x00, but I believe 0x16 is appropriate. */ trk.start = trk.length; - trk.length = 0; trk.file = NULL; + + for (int i = 0; i < 3; i++) { + trk.indexes[i].in_file = 0; + trk.indexes[i].start = trk.length + 150; + trk.indexes[i].length = 0; + } + + trk.length = 0; + cdi_track_push_back(cdi, &trk); } @@ -856,6 +1025,8 @@ cdi_cue_get_flags(track_t *cur, char **line) return 1; } +uint64_t total_pregap = 0ULL; + static int cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, uint64_t cur_pregap) { @@ -888,6 +1059,23 @@ cdi_add_track(cd_img_t *cdi, track_t *cur, uint64_t *shift, uint64_t prestart, u return 1; } + if (prev->indexes[2].length != 0) { + prev->indexes[2].start = cur->indexes[0].start - prev->indexes[2].length; + prev->indexes[1].length = prev->indexes[2].start - prev->indexes[1].start; + cdrom_image_backend_log("Index 2 (%i): %02i:%02i:%02i\n", prev->indexes[2].in_file, + (int) ((prev->indexes[2].start / 75) / 60), (int) ((prev->indexes[2].start / 75) % 60), + (int) (prev->indexes[2].start % 75)); + } else if (prev->indexes[2].in_file) + prev->indexes[2].length = cur->indexes[0].start - prev->indexes[2].start; + else { + prev->indexes[1].length = cur->indexes[0].start - prev->indexes[1].start; + prev->indexes[2].start = prev->indexes[1].start + prev->indexes[1].length; + prev->indexes[2].length = 0; + cdrom_image_backend_log("Index 2 (%i): %02i:%02i:%02i\n", prev->indexes[2].in_file, + (int) ((prev->indexes[2].start / 75) / 60), (int) ((prev->indexes[2].start / 75) % 60), + (int) (prev->indexes[2].start % 75)); + } + /* Current track consumes data from the same file as the previous. */ if (prev->file == cur->file) { cur->start += *shift; @@ -926,10 +1114,10 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) { track_t trk; char pathname[MAX_FILENAME_LENGTH]; - uint64_t shift = 0ULL; - uint64_t prestart = 0ULL; - uint64_t cur_pregap = 0ULL; - uint64_t frame = 0ULL; + uint64_t shift = 0ULL; + uint64_t prestart = 0ULL; + uint64_t cur_pregap = 0ULL; + uint64_t frame = 0ULL; uint64_t index; int iso_file_used = 0; int success; @@ -976,6 +1164,7 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) /* nuke trailing newline */ } } + cdrom_image_backend_log("line = %s\n", line); (void) cdi_cue_get_keyword(&command, &line); @@ -987,35 +1176,34 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) if (!success) break; + cur_pregap = 0; + prestart = 0; + trk.number = cdi_cue_get_number(&line); + trk.track_number = trk.number; + cdrom_image_backend_log("cdi_load_cue(): Track %02X\n", trk.number); + success = cdi_cue_get_keyword(&type, &line); + + memset(trk.indexes, 0x00, sizeof(trk.indexes)); + + if (!success) + break; + if (iso_file_used) { - /* We don't alter anything of the detected track type with the one specified in the CUE file, except its numbers. */ - cur_pregap = 0; - prestart = 0; + /* + We don't alter anything of the detected track type with + the one specified in the CUE file, except its numbers. + */ + can_add_track = 1; - trk.number = cdi_cue_get_number(&line); - trk.track_number = trk.number; - success = cdi_cue_get_keyword(&type, &line); - if (!success) - break; - can_add_track = 1; - - iso_file_used = 0; + iso_file_used = 0; } else { - trk.start = 0; - trk.skip = 0; - cur_pregap = 0; - prestart = 0; + trk.start = 0; + trk.skip = 0; - trk.number = cdi_cue_get_number(&line); - trk.track_number = trk.number; - success = cdi_cue_get_keyword(&type, &line); - if (!success) - break; + trk.form = 0; + trk.mode2 = 0; - trk.form = 0; - trk.mode2 = 0; - - trk.pre = 0; + trk.pre = 0; if (!strcmp(type, "AUDIO")) { trk.sector_size = RAW_SECTOR_SIZE; @@ -1076,6 +1264,9 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) } else success = 0; + cdrom_image_backend_log("cdi_load_cue(): Format: %i bytes per sector, %02X, %i, %i\n", + trk.sector_size, trk.attr, trk.mode2, trk.form); + can_add_track = 1; } } else if (!strcmp(command, "INDEX")) { @@ -1084,11 +1275,55 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) switch (index) { case 0: - prestart = frame; + prestart = frame; + trk.indexes[0].in_file = 1; + trk.indexes[0].start = prestart + total_pregap; break; case 1: - trk.start = frame; + if (trk.indexes[0].in_file) + trk.indexes[0].length = frame - prestart; + else if (cur_pregap > 0) { + trk.indexes[0].start = frame + total_pregap; + trk.indexes[0].length = cur_pregap; + total_pregap += trk.indexes[0].length; + } else if (trk.number == 1) { + trk.indexes[0].start = 0; + trk.indexes[0].length = 150; + total_pregap += trk.indexes[0].length; + } else { + trk.indexes[0].start = frame + total_pregap; + trk.indexes[0].length = 0; + } + cdrom_image_backend_log("Index 0 (%i): %02i:%02i:%02i\n", trk.indexes[0].in_file, + (int) ((trk.indexes[0].start / 75) / 60), + (int) ((trk.indexes[0].start / 75) % 60), + (int) (trk.indexes[0].start % 75)); + + if (cur_pregap > 0) + trk.start = frame + cur_pregap; + else + trk.start = frame; + trk.indexes[1].start = trk.indexes[0].start + trk.indexes[0].length; + trk.indexes[1].in_file = 1; + cdrom_image_backend_log("Index 1 (%i): %02i:%02i:%02i\n", trk.indexes[1].in_file, + (int) ((trk.indexes[1].start / 75) / 60), + (int) ((trk.indexes[1].start / 75) % 60), + (int) (trk.indexes[1].start % 75)); + break; + + case 2: + trk.indexes[2].in_file = 1; + if (cur_pregap > 0) + trk.indexes[2].start = frame + cur_pregap; + else + trk.indexes[2].start = frame; + trk.indexes[1].length = trk.indexes[2].start - trk.indexes[1].start; + trk.indexes[2].length = 0; + cdrom_image_backend_log("Index 2 (%i): %02i:%02i:%02i\n", trk.indexes[2].in_file, + (int) ((trk.indexes[2].start / 75) / 60), + (int) ((trk.indexes[2].start / 75) % 60), + (int) (trk.indexes[2].start % 75)); break; default: @@ -1163,7 +1398,10 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) } } else if (!strcmp(command, "PREGAP")) success = cdi_cue_get_frame(&cur_pregap, &line); - else if (!strcmp(command, "FLAGS")) + else if (!strcmp(command, "POSTGAP")) { + success = cdi_cue_get_frame(&trk.indexes[2].length, &line); + trk.indexes[2].in_file = 0; + } else if (!strcmp(command, "FLAGS")) success = cdi_cue_get_flags(&trk, &line); else if (!strcmp(command, "CATALOG") || !strcmp(command, "CDTEXTFILE") || !strcmp(command, "ISRC") || !strcmp(command, "PERFORMER") || !strcmp(command, "POSTGAP") || !strcmp(command, "REM") || !strcmp(command, "SONGWRITER") || !strcmp(command, "TITLE") || !strcmp(command, "")) { /* Ignored commands. */ @@ -1183,18 +1421,58 @@ cdi_load_cue(cd_img_t *cdi, const char *cuefile) return 0; /* Add last track. */ + cdrom_image_backend_log("LEAD OUT\n"); if (!cdi_add_track(cdi, &trk, &shift, prestart, cur_pregap)) return 0; /* Add lead out track. */ + cdrom_image_backend_log("END OF CUE\n"); trk.number++; + memset(trk.indexes, 0x00, sizeof(trk.indexes)); trk.track_number = 0xAA; + // trk.attr = 0x16; trk.start = 0; trk.length = 0; trk.file = NULL; if (!cdi_add_track(cdi, &trk, &shift, 0, 0)) return 0; + track_t *cur = &cdi->tracks[cdi->tracks_num - 1]; + track_t *prev = &cdi->tracks[cdi->tracks_num - 2]; + + for (int i = 0; i < 3; i++) { + cur->indexes[i].in_file = 0; + cur->indexes[i].start = prev->indexes[1].start + prev->length - 150; + cur->indexes[i].length = 0; + } + + if (prev->indexes[2].length != 0) { + prev->indexes[2].start = cur->indexes[0].start - prev->indexes[2].length; + prev->indexes[1].length = prev->indexes[2].start - prev->indexes[1].start; + } else if (prev->indexes[2].in_file) + prev->indexes[2].length = cur->indexes[0].start - prev->indexes[2].start; + else { + prev->indexes[1].length = cur->indexes[0].start - prev->indexes[1].start; + prev->indexes[2].start = prev->indexes[1].start + prev->indexes[1].length; + prev->indexes[2].length = 0; + } + + for (int i = 0; i < cdi->tracks_num; i++) { + track_t *t = &(cdi->tracks[i]); + for (int j = 0; j < 3; j++) { + track_index_t *ti = &(t->indexes[j]); + cdrom_image_backend_log("Track %02X.%01X (%i): %02i:%02i:%02i-%02i:%02i:%02i\n", + t->track_number, j, + ti->in_file, + (int) ((ti->start / 75) / 60), + (int) ((ti->start / 75) % 60), + (int) (ti->start % 75), + (int) (((ti->start + ti->length - 1) / 75) / 60), + (int) (((ti->start + ti->length - 1) / 75) % 60), + (int) ((ti->start + ti->length - 1) % 75)); + } + } + return 1; } diff --git a/src/cdrom/cdrom_ioctl.c b/src/cdrom/cdrom_ioctl.c index f25988bb9..eccb75fef 100644 --- a/src/cdrom/cdrom_ioctl.c +++ b/src/cdrom/cdrom_ioctl.c @@ -109,7 +109,8 @@ ioctl_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) subc->rel_f = rel_pos.fr; cdrom_ioctl_log("ioctl_get_subchannel(): %02X, %02X, %02i, %02i:%02i:%02i, %02i:%02i:%02i\n", - subc->attr, subc->track, subc->index, subc->abs_m, subc->abs_s, subc->abs_f, subc->rel_m, subc->rel_s, subc->rel_f); + subc->attr, subc->track, subc->index, subc->abs_m, subc->abs_s, subc->abs_f, + subc->rel_m, subc->rel_s, subc->rel_f); } static int @@ -157,29 +158,16 @@ ioctl_sector_size(cdrom_t *dev, uint32_t lba) } static int -ioctl_read_sector(cdrom_t *dev, int type, uint8_t *b, uint32_t lba) +ioctl_read_sector(cdrom_t *dev, uint8_t *b, uint32_t lba) { - switch (type) { - case CD_READ_DATA: - cdrom_ioctl_log("cdrom_ioctl_read_sector(): Data.\n"); - return plat_cdrom_read_sector(dev->local, b, 0, lba); - case CD_READ_AUDIO: - cdrom_ioctl_log("cdrom_ioctl_read_sector(): Audio.\n"); - return plat_cdrom_read_sector(dev->local, b, 1, lba); - case CD_READ_RAW: - cdrom_ioctl_log("cdrom_ioctl_read_sector(): Raw.\n"); - return plat_cdrom_read_sector(dev->local, b, 1, lba); - default: - cdrom_ioctl_log("cdrom_ioctl_read_sector(): Unknown CD read type.\n"); - break; - } - return 0; + cdrom_ioctl_log("cdrom_ioctl_read_sector(): Raw.\n"); + return plat_cdrom_read_sector(dev->local, b, lba); } static int ioctl_track_type(cdrom_t *dev, uint32_t lba) { - int ret = 0; + int ret = CD_TRACK_UNK_DATA; if (ioctl_is_track_audio(dev, lba, 0)) ret = CD_TRACK_AUDIO; diff --git a/src/include/86box/cdrom.h b/src/include/86box/cdrom.h index 0a28e630d..8fb0bc742 100644 --- a/src/include/86box/cdrom.h +++ b/src/include/86box/cdrom.h @@ -28,6 +28,7 @@ #define CD_STATUS_TRANSITION 0x40 #define CD_STATUS_MEDIUM_CHANGED 0x80 +#define CD_TRACK_UNK_DATA 0x10 #define CD_TRACK_AUDIO 0x08 #define CD_TRACK_MODE2 0x04 @@ -85,6 +86,7 @@ enum CDROM_TYPE_TOSHIBA_5302TA_0305, CDROM_TYPE_TOSHIBA_5702B_TA70, CDROM_TYPE_CHINON_CDS431_H42, + CDROM_TYPE_CHINON_CDX435_M62, CDROM_TYPE_DEC_RRD45_0436, CDROM_TYPE_MATSHITA_501_10b, CDROM_TYPE_NEC_25_10a, @@ -93,6 +95,7 @@ enum CDROM_TYPE_NEC_77_106, CDROM_TYPE_NEC_211_100, CDROM_TYPE_NEC_464_105, + CDROM_TYPE_ShinaKen_DM3x1S_104, CDROM_TYPE_SONY_CDU541_10i, CDROM_TYPE_SONY_CDU561_18k, CDROM_TYPE_SONY_CDU76S_100, @@ -101,7 +104,8 @@ enum CDROM_TYPE_PLEXTOR_PX32TS_103, CDROM_TYPE_TEAC_CD50_100, CDROM_TYPE_TEAC_R55S_10R, - CDROM_TYPE_TEXEL_DMXX24_100, + CDROM_TYPE_TEXEL_DM3024_100, + CDROM_TYPE_TEXEL_DM3028_106, CDROM_TYPE_TOSHIBA_XM_3433, CDROM_TYPE_TOSHIBA_XM3201B_3232, CDROM_TYPE_TOSHIBA_XM3301TA_0272, @@ -146,30 +150,33 @@ static const struct { "SONY", "CD-ROM CDU311", "3.0h", "SONY CD-ROM CDU311 3.0h", "SONY_CD-ROM_CDU311_3.0h", BUS_TYPE_IDE }, { "TOSHIBA", "CD-ROM XM-5302TA", "0305", "TOSHIBA CD-ROM XM-5302TA 0305", "TOSHIBA_CD-ROM_XM-5302TA_0305", BUS_TYPE_IDE }, { "TOSHIBA", "CD-ROM XM-5702B", "TA70", "TOSHIBA CD-ROM XM-5702B TA70", "TOSHIBA_CD-ROM_XM-5702B_TA70", BUS_TYPE_IDE }, - { "CHINON", "CD-ROM CDS-431", "H42 ", "CHINON CD-ROM CDS-431 H42", "CHINON_CD-ROM_CDS-431_H42", BUS_TYPE_SCSI }, - { "DEC", "RRD45 (C) DEC", "0436", "DEC RRD45 0436", "DEC_RRD45_0436", BUS_TYPE_SCSI }, - { "MATSHITA", "CD-ROM CR-501", "1.0b", "MATSHITA CD-ROM CR-501 1.0b", "MATSHITA_CD-ROM_CR-501_1.0b", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:25", "1.0a", "NEC CD-ROM DRIVE:25 1.0a", "NEC_CD-ROM_DRIVE25_1.0a", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:38", "1.00", "NEC CD-ROM DRIVE:38 1.00", "NEC_CD-ROM_DRIVE38_1.00", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:75", "1.03", "NEC CD-ROM DRIVE:75 1.03", "NEC_CD-ROM_DRIVE75_1.03", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:77", "1.06", "NEC CD-ROM DRIVE:77 1.06", "NEC_CD-ROM_DRIVE77_1.06", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:211", "1.00", "NEC CD-ROM DRIVE:211 1.00", "NEC_CD-ROM_DRIVE211_1.00", BUS_TYPE_SCSI }, - { "NEC", "CD-ROM DRIVE:464", "1.05", "NEC CD-ROM DRIVE:464 1.05", "NEC_CD-ROM_DRIVE464_1.05", BUS_TYPE_SCSI }, - { "SONY", "CD-ROM CDU-541", "1.0i", "SONY CD-ROM CDU-541 1.0i", "SONY_CD-ROM_CDU-541_1.0i", BUS_TYPE_SCSI }, - { "SONY", "CD-ROM CDU-561", "1.8k", "SONY CD-ROM CDU-561 1.8k", "SONY_CD-ROM_CDU-561_1.8k", BUS_TYPE_SCSI }, - { "SONY", "CD-ROM CDU-76S", "1.00", "SONY CD-ROM CDU-76S 1.00", "SONY_CD-ROM_CDU-76S_1.00", BUS_TYPE_SCSI }, - { "PHILIPS", "CDD2600", "1.07", "PHILIPS CDD2600 1.07", "PHILIPS_CDD2600_1.07", BUS_TYPE_SCSI }, - { "PIONEER", "CD-ROM DRM-604X", "2403", "PIONEER CD-ROM DRM-604X 2403", "PIONEER_CD-ROM_DRM-604X_2403", BUS_TYPE_SCSI }, - { "PLEXTOR", "CD-ROM PX-32TS", "1.03", "PLEXTOR CD-ROM PX-32TS 1.03", "PLEXTOR_CD-ROM_PX-32TS_1.03", BUS_TYPE_SCSI }, - { "TEAC", "CD 50", "1.00", "TEAC CD 50 1.00", "TEAC_CD_50_1.00", BUS_TYPE_SCSI }, - { "TEAC", "CD-ROM R55S", "1.0R", "TEAC CD-ROM R55S 1.0R", "TEAC_CD-ROM_R55S_1.0R", BUS_TYPE_SCSI }, - { "TEXEL", "CD-ROM DM-XX24", "1.00", "TEXEL CD-ROM DM-XX24 1.00", "TEXEL_CD-ROM_DM-XX24_1.00", BUS_TYPE_SCSI }, - { "TOSHIBA", "CD-ROM DRIVE:XM", "3433", "TOSHIBA CD-ROM DRIVE:XM 3433", "TOSHIBA_CD-ROM_DRIVEXM_3433", BUS_TYPE_SCSI }, - { "TOSHIBA", "CD-ROM XM-3201B", "3232", "TOSHIBA CD-ROM XM-3201B 3232", "TOSHIBA_CD-ROM_XM-3201B_3232", BUS_TYPE_SCSI }, - { "TOSHIBA", "CD-ROM XM-3301TA", "0272", "TOSHIBA CD-ROM XM-3301TA 0272", "TOSHIBA_CD-ROM_XM-3301TA_0272", BUS_TYPE_SCSI }, - { "TOSHIBA", "CD-ROM XM-5701TA", "3136", "TOSHIBA CD-ROM XM-5701TA 3136", "TOSHIBA_CD-ROM_XM-5701TA_3136", BUS_TYPE_SCSI }, - { "TOSHIBA", "DVD-ROM SD-M1401", "1008", "TOSHIBA DVD-ROM SD-M1401 1008", "TOSHIBA_DVD-ROM_SD-M1401_1008", BUS_TYPE_SCSI }, - { "", "", "", "", "", BUS_TYPE_NONE }, + { "CHINON", "CD-ROM CDS-431", "H42 ", "[SCSI-1] CHINON CD-ROM CDS-431 H42", "CHINON_CD-ROM_CDS-431_H42", BUS_TYPE_SCSI }, + { "CHINON", "CD-ROM CDX-435", "M62 ", "[SCSI-1] CHINON CD-ROM CDX-435 M62", "CHINON_CD-ROM_CDX-435_M62", BUS_TYPE_SCSI }, + { "DEC", "RRD45 (C) DEC", "0436", "[SCSI-1] DEC RRD45 0436", "DEC_RRD45_0436", BUS_TYPE_SCSI }, + { "MATSHITA", "CD-ROM CR-501", "1.0b", "[SCSI-1] MATSHITA CD-ROM CR-501 1.0b", "MATSHITA_CD-ROM_CR-501_1.0b", BUS_TYPE_SCSI }, + { "NEC", "CD-ROM DRIVE:25", "1.0a", "[SCSI-1] NEC CD-ROM DRIVE:25 1.0a", "NEC_CD-ROM_DRIVE25_1.0a", BUS_TYPE_SCSI }, + { "NEC", "CD-ROM DRIVE:38", "1.00", "[SCSI-2] NEC CD-ROM DRIVE:38 1.00", "NEC_CD-ROM_DRIVE38_1.00", BUS_TYPE_SCSI }, + { "NEC", "CD-ROM DRIVE:75", "1.03", "[SCSI-1] NEC CD-ROM DRIVE:75 1.03", "NEC_CD-ROM_DRIVE75_1.03", BUS_TYPE_SCSI }, + { "NEC", "CD-ROM DRIVE:77", "1.06", "[SCSI-1] NEC CD-ROM DRIVE:77 1.06", "NEC_CD-ROM_DRIVE77_1.06", BUS_TYPE_SCSI }, + { "NEC", "CD-ROM DRIVE:211", "1.00", "[SCSI-2] NEC CD-ROM DRIVE:211 1.00", "NEC_CD-ROM_DRIVE211_1.00", BUS_TYPE_SCSI }, + { "NEC", "CD-ROM DRIVE:464", "1.05", "[SCSI-2] NEC CD-ROM DRIVE:464 1.05", "NEC_CD-ROM_DRIVE464_1.05", BUS_TYPE_SCSI }, + { "ShinaKen", "CD-ROM DM-3x1S", "1.04", "[SCSI-1] ShinaKen CD-ROM DM-3x1S 1.04", "ShinaKen_CD-ROM_DM-3x1S_1.04", BUS_TYPE_SCSI }, + { "SONY", "CD-ROM CDU-541", "1.0i", "[SCSI-1] SONY CD-ROM CDU-541 1.0i", "SONY_CD-ROM_CDU-541_1.0i", BUS_TYPE_SCSI }, + { "SONY", "CD-ROM CDU-561", "1.8k", "[SCSI-2] SONY CD-ROM CDU-561 1.8k", "SONY_CD-ROM_CDU-561_1.8k", BUS_TYPE_SCSI }, + { "SONY", "CD-ROM CDU-76S", "1.00", "[SCSI-2] SONY CD-ROM CDU-76S 1.00", "SONY_CD-ROM_CDU-76S_1.00", BUS_TYPE_SCSI }, + { "PHILIPS", "CDD2600", "1.07", "[SCSI-2] PHILIPS CDD2600 1.07", "PHILIPS_CDD2600_1.07", BUS_TYPE_SCSI }, + { "PIONEER", "CD-ROM DRM-604X", "2403", "[SCSI-2] PIONEER CD-ROM DRM-604X 2403", "PIONEER_CD-ROM_DRM-604X_2403", BUS_TYPE_SCSI }, + { "PLEXTOR", "CD-ROM PX-32TS", "1.03", "[SCSI-2] PLEXTOR CD-ROM PX-32TS 1.03", "PLEXTOR_CD-ROM_PX-32TS_1.03", BUS_TYPE_SCSI }, + { "TEAC", "CD 50", "1.00", "[SCSI-2] TEAC CD 50 1.00", "TEAC_CD_50_1.00", BUS_TYPE_SCSI }, + { "TEAC", "CD-ROM R55S", "1.0R", "[SCSI-2] TEAC CD-ROM R55S 1.0R", "TEAC_CD-ROM_R55S_1.0R", BUS_TYPE_SCSI }, + { "TEXEL", "CD-ROM DM-3024", "1.00", "[SCSI-1] TEXEL CD-ROM DM-3024 1.00", "TEXEL_CD-ROM_DM-3024_1.00", BUS_TYPE_SCSI }, + { "TEXEL", "CD-ROM DM-3028", "1.06", "[SCSI-2] TEXEL CD-ROM DM-3028 1.06", "TEXEL_CD-ROM_DM-3028_1.06", BUS_TYPE_SCSI }, + { "TOSHIBA", "CD-ROM DRIVE:XM", "3433", "[SCSI-2] TOSHIBA CD-ROM DRIVE:XM 3433", "TOSHIBA_CD-ROM_DRIVEXM_3433", BUS_TYPE_SCSI }, + { "TOSHIBA", "CD-ROM XM-3201B", "3232", "[SCSI-1] TOSHIBA CD-ROM XM-3201B 3232", "TOSHIBA_CD-ROM_XM-3201B_3232", BUS_TYPE_SCSI }, + { "TOSHIBA", "CD-ROM XM-3301TA", "0272", "[SCSI-2] TOSHIBA CD-ROM XM-3301TA 0272", "TOSHIBA_CD-ROM_XM-3301TA_0272", BUS_TYPE_SCSI }, + { "TOSHIBA", "CD-ROM XM-5701TA", "3136", "[SCSI-2] TOSHIBA CD-ROM XM-5701TA 3136", "TOSHIBA_CD-ROM_XM-5701TA_3136", BUS_TYPE_SCSI }, + { "TOSHIBA", "DVD-ROM SD-M1401", "1008", "[SCSI-2] TOSHIBA DVD-ROM SD-M1401 1008", "TOSHIBA_DVD-ROM_SD-M1401_1008", BUS_TYPE_SCSI }, + { "", "", "", "", "", BUS_TYPE_NONE }, }; /* To shut up the GCC compilers. */ @@ -217,7 +224,7 @@ typedef struct cdrom_ops_t { void (*get_subchannel)(struct cdrom *dev, uint32_t lba, subchannel_t *subc); int (*is_track_pre)(struct cdrom *dev, uint32_t lba); int (*sector_size)(struct cdrom *dev, uint32_t lba); - int (*read_sector)(struct cdrom *dev, int type, uint8_t *b, uint32_t lba); + int (*read_sector)(struct cdrom *dev, uint8_t *b, uint32_t lba); int (*track_type)(struct cdrom *dev, uint32_t lba); int (*ext_medium_changed)(struct cdrom *dev); void (*exit)(struct cdrom *dev); @@ -255,6 +262,7 @@ typedef struct cdrom { uint32_t seek_diff; uint32_t cd_end; uint32_t type; + uint32_t sector_size; int cd_buflen; int audio_op; @@ -270,7 +278,9 @@ typedef struct cdrom { uint32_t (*get_volume)(void *p, int channel); uint32_t (*get_channel)(void *p, int channel); - int16_t cd_buffer[BUF_SIZE]; + int16_t cd_buffer[BUF_SIZE]; + + uint8_t subch_buffer[96]; } cdrom_t; extern cdrom_t cdrom[CDROM_NUM]; @@ -296,7 +306,8 @@ 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_pioneer(cdrom_t *dev, uint8_t *b); 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 uint8_t cdrom_get_current_status(cdrom_t *dev); +extern void 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 void cdrom_get_current_subcodeq(cdrom_t *dev, uint8_t *b); extern uint8_t cdrom_get_current_subcodeq_playstatus(cdrom_t *dev, uint8_t *b); @@ -315,6 +326,7 @@ 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); extern void cdrom_exit(uint8_t id); +extern int cdrom_is_empty(uint8_t id); extern void cdrom_eject(uint8_t id); extern void cdrom_reload(uint8_t id); diff --git a/src/include/86box/cdrom_image_backend.h b/src/include/86box/cdrom_image_backend.h index c6b2d9fc7..2e3aa85b9 100644 --- a/src/include/86box/cdrom_image_backend.h +++ b/src/include/86box/cdrom_image_backend.h @@ -63,19 +63,16 @@ typedef struct track_file_t { #define BLOCK_NONE ((uint64_t) -1LL) -typedef struct track_block_t { +typedef struct track_index_t { /* Is the current block in the file? If not, return all 0x00's. */ - int type; + int in_file; /* The amount of bytes to skip at the beginning of each sector. */ int skip; /* Starting and ending sector LBA - negative in order to accomodate LBA -150 to -1 to read the pregap of track 1. */ - int64_t start_sector; - int64_t end_sector; - /* Starting and ending offset in the file. */ - uint64_t start_offs; - uint64_t end_offs; -} track_block_t; + uint64_t start; + uint64_t length; +} track_index_t; typedef struct track_t { int pregap_len; /* Pre-gap - not in file. */ @@ -93,7 +90,7 @@ typedef struct track_t { uint64_t start; uint64_t length; uint64_t skip; - track_block_t blocks[256]; + track_index_t indexes[3]; track_file_t *file; } track_t; @@ -108,10 +105,14 @@ extern int cdi_set_device(cd_img_t *cdi, const char *path); extern void cdi_get_audio_tracks(cd_img_t *cdi, int *st_track, int *end, TMSF *lead_out); extern void cdi_get_audio_tracks_lba(cd_img_t *cdi, int *st_track, int *end, uint32_t *lead_out); extern int cdi_get_audio_track_pre(cd_img_t *cdi, int track); -extern int cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, TMSF *start, uint8_t *attr); -extern int cdi_get_audio_track_info_lba(cd_img_t *cdi, int end, int track, int *track_num, uint32_t *start, uint8_t *attr); +extern int cdi_get_audio_track_info(cd_img_t *cdi, int end, int track, int *track_num, + TMSF *start, uint8_t *attr); +extern int cdi_get_audio_track_info_lba(cd_img_t *cdi, int end, int track, int *track_num, + uint32_t *start, uint8_t *attr); +extern void cdi_get_raw_track_info(cd_img_t *cdi, int *num, uint8_t *buffer); extern int cdi_get_track(cd_img_t *cdi, uint32_t sector); -extern int cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos); +extern int cdi_get_audio_sub(cd_img_t *cdi, uint32_t sector, uint8_t *attr, uint8_t *track, + uint8_t *index, TMSF *rel_pos, TMSF *abs_pos); extern int cdi_read_sector(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector); extern int cdi_read_sectors(cd_img_t *cdi, uint8_t *buffer, int raw, uint32_t sector, uint32_t num); extern int cdi_read_sector_sub(cd_img_t *cdi, uint8_t *buffer, uint32_t sector); diff --git a/src/include/86box/mo.h b/src/include/86box/mo.h index 5d4b723f3..4ab567aca 100644 --- a/src/include/86box/mo.h +++ b/src/include/86box/mo.h @@ -121,7 +121,6 @@ typedef struct mo_drive_t { uint32_t medium_size; uint32_t base; uint16_t sector_size; - } mo_drive_t; typedef struct mo_t { @@ -139,17 +138,6 @@ typedef struct mo_t { uint8_t current_cdb[16]; uint8_t sense[256]; -#ifdef ANCIENT_CODE - /* Task file. */ - uint8_t features; - uint8_t phase; - uint16_t request_length; - uint8_t status; - uint8_t error; - uint16_t pad; - uint32_t pos; -#endif - uint8_t id; uint8_t cur_lun; uint8_t pad0; @@ -172,6 +160,8 @@ typedef struct mo_t { uint32_t packet_len; double callback; + + uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); } mo_t; extern mo_t *mo[MO_NUM]; diff --git a/src/include/86box/plat_cdrom.h b/src/include/86box/plat_cdrom.h index 06439a652..1e70e014b 100644 --- a/src/include/86box/plat_cdrom.h +++ b/src/include/86box/plat_cdrom.h @@ -59,7 +59,7 @@ extern int plat_cdrom_get_audio_track_info(void *local, int end, int track, extern int plat_cdrom_get_audio_sub(void *local, uint32_t sector, uint8_t *attr, uint8_t *track, uint8_t *index, TMSF *rel_pos, TMSF *abs_pos); extern int plat_cdrom_get_sector_size(void *local, uint32_t sector); -extern int plat_cdrom_read_sector(void *local, uint8_t *buffer, int raw, uint32_t sector); +extern int plat_cdrom_read_sector(void *local, uint8_t *buffer, uint32_t sector); extern void plat_cdrom_eject(void *local); extern void plat_cdrom_close(void *local); extern int plat_cdrom_set_drive(void *local, const char *drv); diff --git a/src/include/86box/scsi_cdrom.h b/src/include/86box/scsi_cdrom.h index dec537429..684a9d589 100644 --- a/src/include/86box/scsi_cdrom.h +++ b/src/include/86box/scsi_cdrom.h @@ -38,17 +38,6 @@ typedef struct scsi_cdrom_t { uint8_t current_cdb[16]; uint8_t sense[256]; -#ifdef ANCIENT_CODE - /* Task file. */ - uint8_t features; - uint8_t phase; - uint16_t request_length; - uint8_t status; - uint8_t error; - uint16_t pad; - uint32_t pos; -#endif - uint8_t id; uint8_t cur_lun; uint8_t early; @@ -72,9 +61,12 @@ typedef struct scsi_cdrom_t { double callback; + uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); + + int sony_vendor; + 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 e69d3cc93..3f9f3791b 100644 --- a/src/include/86box/scsi_device.h +++ b/src/include/86box/scsi_device.h @@ -100,43 +100,53 @@ #define GPCMD_WRITE_AND_VERIFY_12 0xae #define GPCMD_VERIFY_12 0xaf #define GPCMD_PLAY_CD_OLD 0xb4 -#define GPCMD_READ_CD_OLD 0xb8 +#define GPCMD_READ_CD_OLD 0xb8 /* Should be equivalent to 0xbe */ #define GPCMD_READ_CD_MSF 0xb9 #define GPCMD_AUDIO_SCAN 0xba #define GPCMD_SET_SPEED 0xbb -#define GPCMD_PLAY_CD 0xbc +#define GPCMD_PLAY_CD 0xbc /* At some point, this was READ CD, according to the + ATAPI specification */ #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_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_SET_ADDRESS_FORMAT_SONY 0xc0 /* Sony Vendor Unique command */ +#define GPCMD_MAGAZINE_EJECT_PIONEER 0xc0 /* Pioneer 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_READ_TOC_PIONEER 0xc1 /* Pioneer Vendor Unique command */ #define GPCMD_PAUSE_RESUME_ALT 0xc2 #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_SUBCODEQ_PIONEER 0xc2 /* Pioneer 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_PLAYBACK_STATUS_SONY 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_PLAY_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_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_AUDIO_TRACK_SEARCH_PIONEER 0xc8 /* Pioneer 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_PLAY_AUDIO_PIONEER 0xc9 /* Pioneer Vendor Unique command */ +#define GPCMD_PAUSE_PIONEER 0xca /* Pioneer Vendor Unique command */ #define GPCMD_PAUSE_RESUME_MATSUSHITA 0xcb /* Matsushita Vendor Unique command */ +#define GPCMD_STOP_PIONEER 0xcb /* Pioneer Vendor Unique command */ +#define GPCMD_PLAYBACK_STATUS_PIONEER 0xcc /* Pioneer Vendor Unique command */ #define GPCMD_SCAN_PIONEER 0xcd /* Should be equivalent to 0xba */ +#define GPCMD_READ_CD_MSF_OLD 0xd5 /* Should be equivalent to 0xb9 */ #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 */ @@ -145,6 +155,7 @@ #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_DRIVE_STATUS_PIONEER 0xe0 /* Pioneer 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 */ @@ -366,17 +377,6 @@ typedef struct scsi_common_s { uint8_t current_cdb[16]; uint8_t sense[256]; -#ifdef ANCIENT_CODE - /* Task file. */ - uint8_t features; - uint8_t phase; - uint16_t request_length; - uint8_t status; - uint8_t error; - uint16_t pad; - uint32_t pos; -#endif - uint8_t id; uint8_t cur_lun; uint8_t pad0; @@ -399,6 +399,8 @@ typedef struct scsi_common_s { uint32_t packet_len; double callback; + + uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); } scsi_common_t; typedef struct scsi_device_t { diff --git a/src/include/86box/scsi_disk.h b/src/include/86box/scsi_disk.h index eb4dc69a4..8c7e045fb 100644 --- a/src/include/86box/scsi_disk.h +++ b/src/include/86box/scsi_disk.h @@ -31,17 +31,6 @@ typedef struct scsi_disk_t { uint8_t current_cdb[16]; uint8_t sense[256]; -#ifdef ANCIENT_CODE - /* Task file. */ - uint8_t features; - uint8_t phase; - uint16_t request_length; - uint8_t status; - uint8_t error; - uint16_t pad; - uint32_t pos; -#endif - uint8_t id; uint8_t cur_lun; uint8_t pad0; @@ -64,6 +53,8 @@ typedef struct scsi_disk_t { uint32_t packet_len; double callback; + + uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); } scsi_disk_t; extern scsi_disk_t *scsi_disk[HDD_NUM]; diff --git a/src/include/86box/zip.h b/src/include/86box/zip.h index a4a4c341f..739ba388b 100644 --- a/src/include/86box/zip.h +++ b/src/include/86box/zip.h @@ -85,17 +85,6 @@ typedef struct zip_t { uint8_t current_cdb[16]; uint8_t sense[256]; -#ifdef ANCIENT_CODE - /* Task file. */ - uint8_t features; - uint8_t phase; - uint16_t request_length; - uint8_t status; - uint8_t error; - uint16_t pad; - uint32_t pos; -#endif - uint8_t id; uint8_t cur_lun; uint8_t pad0; @@ -118,6 +107,8 @@ typedef struct zip_t { uint32_t packet_len; double callback; + + uint8_t (*ven_cmd)(void *sc, uint8_t *cdb, int32_t *BufLen); } zip_t; extern zip_t *zip[ZIP_NUM]; diff --git a/src/qt/dummy_cdrom_ioctl.c b/src/qt/dummy_cdrom_ioctl.c index bf656177b..8555642e6 100644 --- a/src/qt/dummy_cdrom_ioctl.c +++ b/src/qt/dummy_cdrom_ioctl.c @@ -218,18 +218,14 @@ plat_cdrom_get_sector_size(UNUSED(void *local), UNUSED(uint32_t sector)) } int -plat_cdrom_read_sector(void *local, uint8_t *buffer, int raw, uint32_t sector) +plat_cdrom_read_sector(void *local, uint8_t *buffer, uint32_t sector) { dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; plat_cdrom_open(ioctl); - if (raw) - /* Raw */ - dummy_cdrom_ioctl_log("Raw\n"); - else - /* Cooked */ - dummy_cdrom_ioctl_log("Cooked\n"); + /* Raw */ + dummy_cdrom_ioctl_log("Raw\n"); plat_cdrom_close(ioctl); diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 103ce3161..fc8f93e51 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -193,8 +193,8 @@ static uint64_t scsi_cdrom_drive_status_page_flags = ((1ULL << 0x01ULL) | (1U 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 }, + { 0x02, 0, 1, 0 }, /*Audio Play Status Format*/ + { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, @@ -564,11 +564,11 @@ scsi_cdrom_get_channel(void *priv, int channel) switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: - ret = dev->ms_pages_saved_sony.pages[dev->sony_vendor ? GPMODE_CDROM_AUDIO_PAGE_SONY : GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: + ret = dev->ms_pages_saved_sony.pages[dev->sony_vendor ? + GPMODE_CDROM_AUDIO_PAGE_SONY : GPMODE_CDROM_AUDIO_PAGE] + [channel ? 10 : 8]; break; default: ret = dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; @@ -589,10 +589,8 @@ scsi_cdrom_get_volume(void *priv, int channel) switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: ret = dev->ms_pages_saved_sony.pages[dev->sony_vendor ? GPMODE_CDROM_AUDIO_PAGE_SONY : GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; break; @@ -612,10 +610,8 @@ scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev) switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: 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)); @@ -664,10 +660,8 @@ scsi_cdrom_mode_sense_save(scsi_cdrom_t *dev) switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: sprintf(file_name, "scsi_cdrom_%02i_mode_sense_sony_bin", dev->id); fp = plat_fopen(nvr_path(file_name), "wb"); if (fp) { @@ -747,10 +741,8 @@ scsi_cdrom_mode_sense_read(scsi_cdrom_t *dev, uint8_t page_control, uint8_t page { switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: switch (page_control) { case 0: case 3: @@ -795,14 +787,14 @@ scsi_cdrom_mode_sense(scsi_cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t pag page &= 0x3f; if (block_descriptor_len) { - buf[pos++] = 1; /* Density code. */ - buf[pos++] = 0; /* Number of blocks (0 = all). */ - buf[pos++] = 0; - buf[pos++] = 0; - buf[pos++] = 0; /* Reserved. */ - buf[pos++] = 0; /* Block length (0x800 = 2048 bytes). */ - buf[pos++] = 8; - buf[pos++] = 0; + buf[pos++] = 0x01; /* Density code. */ + buf[pos++] = 0x00; /* Number of blocks (0 = all). */ + buf[pos++] = 0x00; + buf[pos++] = 0x00; + buf[pos++] = 0x00; /* Reserved. */ + buf[pos++] = dev->drv->sector_size >> 16; /* Block length (default: 0x800 = 2048 bytes). */ + buf[pos++] = dev->drv->sector_size >> 8; + buf[pos++] = dev->drv->sector_size; } for (uint8_t i = 0; i < 0x40; i++) { @@ -979,6 +971,10 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) period = cdrom_seek_time(dev->drv); scsi_cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", dev->id, (uint64_t) period); + scsi_cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us, speed: %" PRIu64 " bytes per second, " + "should be: %" PRIu64 " bytes per second\n", + dev->id, (uint64_t) period, (uint64_t) (1000000.0 / period), + (uint64_t) (176400.0 * (double) dev->drv->cur_speed)); dev->callback += period; fallthrough; case 0x25: @@ -996,11 +992,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) break; case 0xc6 ... 0xc7: switch (dev->drv->type) { - case CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: - case CDROM_TYPE_TOSHIBA_SDM1401_1008: + case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_SDM1401_1008: bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; break; @@ -1008,10 +1000,8 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) case 0xc0: switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; @@ -1020,11 +1010,9 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) case 0xc1: switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: case CDROM_TYPE_PIONEER_DRM604X_2403: - case CDROM_TYPE_TEXEL_DMXX24_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; @@ -1033,11 +1021,9 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) case 0xc2 ... 0xc3: switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: case CDROM_TYPE_PIONEER_DRM604X_2403: - case CDROM_TYPE_TEXEL_DMXX24_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: if (dev->current_cdb[0] == 0xc2) dev->callback += 40.0; /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ @@ -1047,12 +1033,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) } case 0xdd ... 0xde: switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: + case CDROM_TYPE_NEC_25_10a ... CDROM_TYPE_NEC_464_105: /* 44100 * 16 bits * 2 channels = 176400 bytes per second */ bytes_per_second = 176400.0; bytes_per_second *= (double) dev->drv->cur_speed; @@ -1230,6 +1211,7 @@ scsi_cdrom_bus_master_error(scsi_common_t *sc) { scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + scsi_cdrom_log("CD-ROM %i: Bus master error\n", dev->id); scsi_cdrom_buf_free(dev); scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = 0; scsi_cdrom_cmd_error(dev); @@ -1238,6 +1220,7 @@ scsi_cdrom_bus_master_error(scsi_common_t *sc) static void scsi_cdrom_not_ready(scsi_cdrom_t *dev) { + scsi_cdrom_log("CD-ROM %i: Medium not present\n", dev->id); scsi_cdrom_sense_key = SENSE_NOT_READY; scsi_cdrom_asc = ASC_MEDIUM_NOT_PRESENT; scsi_cdrom_ascq = 0; @@ -1247,6 +1230,7 @@ scsi_cdrom_not_ready(scsi_cdrom_t *dev) static void scsi_cdrom_circ_error(scsi_cdrom_t *dev) { + scsi_cdrom_log("CD-ROM %i: CIRC unrecovered error\n", dev->id); scsi_cdrom_sense_key = SENSE_MEDIUM_ERROR; scsi_cdrom_asc = ASC_UNRECOVERED_READ_ERROR; scsi_cdrom_ascq = ASCQ_CIRC_UNRECOVERED_ERROR; @@ -1256,6 +1240,7 @@ scsi_cdrom_circ_error(scsi_cdrom_t *dev) static void scsi_cdrom_invalid_lun(scsi_cdrom_t *dev) { + scsi_cdrom_log("CD-ROM %i: Invalid LUN\n", dev->id); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_INV_LUN; scsi_cdrom_ascq = 0; @@ -1265,6 +1250,7 @@ scsi_cdrom_invalid_lun(scsi_cdrom_t *dev) static void scsi_cdrom_illegal_opcode(scsi_cdrom_t *dev) { + scsi_cdrom_log("CD-ROM %i: Illegal opcode\n", dev->id); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_ILLEGAL_OPCODE; scsi_cdrom_ascq = 0; @@ -1274,6 +1260,7 @@ scsi_cdrom_illegal_opcode(scsi_cdrom_t *dev) static void scsi_cdrom_lba_out_of_range(scsi_cdrom_t *dev) { + scsi_cdrom_log("CD-ROM %i: LBA out of range\n", dev->id); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_LBA_OUT_OF_RANGE; scsi_cdrom_ascq = 0; @@ -1283,6 +1270,7 @@ scsi_cdrom_lba_out_of_range(scsi_cdrom_t *dev) static void scsi_cdrom_invalid_field(scsi_cdrom_t *dev) { + scsi_cdrom_log("CD-ROM %i: Invalid field in command packet\n", dev->id); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET; scsi_cdrom_ascq = 0; @@ -1293,6 +1281,7 @@ scsi_cdrom_invalid_field(scsi_cdrom_t *dev) static void scsi_cdrom_invalid_field_pl(scsi_cdrom_t *dev) { + scsi_cdrom_log("CD-ROM %i: Invalid field in parameter list\n", dev->id); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; scsi_cdrom_ascq = 0; @@ -1303,6 +1292,7 @@ scsi_cdrom_invalid_field_pl(scsi_cdrom_t *dev) static void scsi_cdrom_illegal_mode(scsi_cdrom_t *dev) { + scsi_cdrom_log("CD-ROM %i: Illegal mode for this track\n", dev->id); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; scsi_cdrom_ascq = 0; @@ -1312,6 +1302,7 @@ scsi_cdrom_illegal_mode(scsi_cdrom_t *dev) static void scsi_cdrom_incompatible_format(scsi_cdrom_t *dev) { + scsi_cdrom_log("CD-ROM %i: Incompatible format\n", dev->id); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_INCOMPATIBLE_FORMAT; scsi_cdrom_ascq = 2; @@ -1321,6 +1312,7 @@ scsi_cdrom_incompatible_format(scsi_cdrom_t *dev) static void scsi_cdrom_data_phase_error(scsi_cdrom_t *dev) { + scsi_cdrom_log("CD-ROM %i: Data phase error\n", dev->id); scsi_cdrom_sense_key = SENSE_ILLEGAL_REQUEST; scsi_cdrom_asc = ASC_DATA_PHASE_ERROR; scsi_cdrom_ascq = 0; @@ -1393,15 +1385,20 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch, int ven int type = 0; int flags = 0; - if (dev->current_cdb[0] == GPCMD_READ_CD_MSF) - msf = 1; - - if ((dev->current_cdb[0] == GPCMD_READ_CD_MSF) || (dev->current_cdb[0] == GPCMD_READ_CD)) { - type = (dev->current_cdb[1] >> 2) & 7; - flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); - } else { - type = 8; /* Internal type code indicating both Mode 1 and Mode 2 Form 1 are allowed. */ - flags = 0x10; + switch (dev->current_cdb[0]) { + case GPCMD_READ_CD_MSF_OLD: + case GPCMD_READ_CD_MSF: + msf = 1; + fallthrough; + case GPCMD_READ_CD_OLD: + case GPCMD_READ_CD: + type = (dev->current_cdb[1] >> 2) & 7; + flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); + break; + default: + type = 8; /* Internal type code indicating both Mode 1 and Mode 2 Form 1 are allowed. */ + flags = (dev->drv->sector_size == 2340) ? 0x78 : 0x10; + break; } if (!dev->sector_len) { @@ -1561,7 +1558,7 @@ scsi_cdrom_insert(void *priv) } else if (dev->drv->cd_status & CD_STATUS_TRANSITION) { dev->unit_attention = 1; /* Turn off the medium changed status. */ - dev->drv->cd_status &= ~(CD_STATUS_TRANSITION | CD_STATUS_MEDIUM_CHANGED); + dev->drv->cd_status &= ~CD_STATUS_TRANSITION; scsi_cdrom_log("CD-ROM %i: Media insert\n", dev->id); } else { dev->unit_attention = 0; @@ -1570,6 +1567,25 @@ scsi_cdrom_insert(void *priv) } } +static void +scsi_cdrom_ext_insert(void *priv, int ext_medium_changed) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) priv; + + if ((dev == NULL) || (dev->drv == NULL)) + return; + + if ((dev->drv->ops == NULL) || (ext_medium_changed == -1)) { + dev->unit_attention = 0; + dev->drv->cd_status = CD_STATUS_EMPTY; + scsi_cdrom_log("CD-ROM %i: External media removal\n", dev->id); + } else if (ext_medium_changed == 1) { + dev->unit_attention = 0; + dev->drv->cd_status |= CD_STATUS_TRANSITION; + scsi_cdrom_log("CD-ROM %i: External media transition\n", dev->id); + } +} + static int scsi_command_check_ready(scsi_cdrom_t *dev, uint8_t *cdb) { @@ -1583,11 +1599,9 @@ scsi_command_check_ready(scsi_cdrom_t *dev, uint8_t *cdb) ret = 1; break; case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: - if (cdb[0] == 0xC0) + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: + if (cdb[0] == 0xc0) break; ret = 1; break; @@ -1601,7 +1615,7 @@ scsi_command_check_ready(scsi_cdrom_t *dev, uint8_t *cdb) static int scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) { - int ready = 0; + int ready = 0; int ext_medium_changed = 0; if (dev->drv && dev->drv->ops && dev->drv->ops->ext_medium_changed) @@ -1634,6 +1648,9 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) return 0; } + if (ext_medium_changed != 0) + scsi_cdrom_ext_insert((void *) dev, ext_medium_changed); + if ((dev->drv->cd_status == CD_STATUS_PLAYING) || (dev->drv->cd_status == CD_STATUS_PAUSED)) { ready = 1; goto skip_ready_check; @@ -1643,16 +1660,15 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) if ((cdb[0] == GPCMD_TEST_UNIT_READY) || (cdb[0] == GPCMD_REQUEST_SENSE)) ready = 0; else { - scsi_cdrom_insert((void *) dev); + if ((ext_medium_changed != 0) || !(scsi_cdrom_command_flags[cdb[0]] & ALLOW_UA)) { + scsi_cdrom_log("(ext_medium_changed != 0): scsi_cdrom_insert()\n"); + scsi_cdrom_insert((void *) dev); + } ready = (dev->drv->cd_status != CD_STATUS_EMPTY) || (ext_medium_changed == -1); } - } else { - if ((dev->drv->cd_status & CD_STATUS_MEDIUM_CHANGED) || (ext_medium_changed == 1)) - scsi_cdrom_insert((void *) dev); - - ready = (dev->drv->cd_status != CD_STATUS_EMPTY) || (ext_medium_changed == -1); - } + } else + ready = (dev->drv->cd_status != CD_STATUS_EMPTY); skip_ready_check: /* If the drive is not ready, there is no reason to keep the @@ -1666,7 +1682,7 @@ skip_ready_check: if (dev->unit_attention == 1) { /* Only increment the unit attention phase if the command can not pass through it. */ if (!(scsi_cdrom_command_flags[cdb[0]] & ALLOW_UA)) { - /* scsi_cdrom_log("CD-ROM %i: Unit attention now 2\n", dev->id); */ + scsi_cdrom_log("CD-ROM %i: Unit attention now 2\n", dev->id); dev->unit_attention++; scsi_cdrom_log("CD-ROM %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", dev->id, cdb[0]); @@ -1675,12 +1691,12 @@ skip_ready_check: } } else if (dev->unit_attention == 2) { if (cdb[0] != GPCMD_REQUEST_SENSE) { - /* scsi_cdrom_log("CD-ROM %i: Unit attention now 0\n", dev->id); */ + scsi_cdrom_log("CD-ROM %i: Unit attention now 0\n", dev->id); dev->unit_attention = 0; } } - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* clear the UNIT ATTENTION condition if it's set. */ if (cdb[0] != GPCMD_REQUEST_SENSE) scsi_cdrom_sense_clear(dev, cdb[0]); @@ -1760,17 +1776,23 @@ scsi_cdrom_request_sense(scsi_cdrom_t *dev, uint8_t *buffer, uint8_t alloc_lengt dev->unit_attention = 0; } - if (dev->drv->cd_status & CD_STATUS_TRANSITION) + if (dev->drv->cd_status & CD_STATUS_TRANSITION) { + scsi_cdrom_log("CD_STATUS_TRANSITION: scsi_cdrom_insert()\n"); scsi_cdrom_insert((void *) dev); + } } void scsi_cdrom_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) { - scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + int ext_medium_changed = 0; - if (dev->drv->cd_status & CD_STATUS_MEDIUM_CHANGED) - scsi_cdrom_insert((void *) dev); + if (dev->drv && dev->drv->ops && dev->drv->ops->ext_medium_changed) + ext_medium_changed = dev->drv->ops->ext_medium_changed(dev->drv); + + if (ext_medium_changed != 0) + scsi_cdrom_ext_insert((void *) dev, ext_medium_changed); if ((dev->drv->cd_status == CD_STATUS_EMPTY) && dev->unit_attention) { /* If the drive is not ready, there is no reason to keep the @@ -1805,34 +1827,779 @@ scsi_cdrom_stop(scsi_common_t *sc) cdrom_stop(dev->drv); } +static void +scsi_cdrom_set_speed(scsi_cdrom_t *dev, uint8_t *cdb) +{ + dev->drv->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; + if (dev->drv->cur_speed < 1) + dev->drv->cur_speed = 1; + else if (dev->drv->cur_speed > dev->drv->speed) + dev->drv->cur_speed = dev->drv->speed; + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); +} + +static uint8_t +scsi_cdrom_command_chinon(void *sc, uint8_t *cdb, int32_t *BufLen) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + uint8_t cmd_stat = 0x00; + + switch (cdb[0]) { + case GPCMD_UNKNOWN_CHINON: + if (dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_stop(sc); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + } + break; + + case GPCMD_EJECT_CHINON: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_stop(sc); + cdrom_eject(dev->id); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + break; + + case GPCMD_STOP_CHINON: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_stop(sc); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + break; + } + + return cmd_stat; +} + +static uint8_t +scsi_cdrom_command_dec_sony_texel(void *sc, uint8_t *cdb, int32_t *BufLen) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + int msf = 0; + int pos = dev->drv->seek_pos; + int ret = 1; + uint8_t cmd_stat = 0x00; + int len; + int max_len; + int alloc_length; + int real_pos; + + switch (cdb[0]) { + case GPCMD_SET_ADDRESS_FORMAT_SONY: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->sony_vendor = 1; + dev->drv->sony_msf = cdb[8] & 1; + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + break; + + case GPCMD_READ_TOC_SONY: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + msf = dev->drv->sony_msf; + 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); + else { + 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); + else { + scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + } + } + cmd_stat = 0x01; + break; + + case GPCMD_READ_SUBCHANNEL_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->drv->sony_msf; + + scsi_cdrom_log("CD-ROM %i: Getting sub-channel type (%s), code-q = %02x\n", + dev->id, msf ? "MSF" : "LBA", cdb[2] & 0x40); + + if (cdb[2] & 0x40) { + scsi_cdrom_buf_alloc(dev, 9); + memset(dev->buffer, 0, 9); + len = 9; + 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); + } else { + 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); + } + cmd_stat = 0x01; + break; + + case 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); + cmd_stat = 0x01; + break; + + case 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->drv->sony_msf; + + scsi_cdrom_buf_alloc(dev, 18); + + len = 18; + + memset(dev->buffer, 0, 18); + dev->buffer[0] = 0x00; /* Reserved */ + dev->buffer[1] = 0x00; /* Reserved */ + dev->buffer[2] = 0x00; /* Audio Status data length */ + dev->buffer[3] = 0x00; /* Audio Status data length */ + dev->buffer[4] = cdrom_get_audio_status_sony(dev->drv, /* Audio status */ + &dev->buffer[6], msf); + 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); + cmd_stat = 0x01; + break; + + case 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); + cmd_stat = 0x01; + break; + + case GPCMD_PLAY_TRACK_SONY: + 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); + else { + pos = cdb[4]; + + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + scsi_cdrom_illegal_mode(dev); + else { + /* In this case, len is unused so just pass a fixed value of 1 intead. */ + ret = cdrom_audio_play(dev->drv, pos, 1 /*len*/, msf); + + if (ret) + scsi_cdrom_command_complete(dev); + else + scsi_cdrom_illegal_mode(dev); + } + } + cmd_stat = 0x01; + break; + + case GPCMD_PLAY_MSF_SONY: + cdb[0] = GPCMD_PLAY_AUDIO_MSF; + dev->current_cdb[0] = cdb[0]; + dev->sony_vendor = 1; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_MSF. */ + break; + + case GPCMD_PLAY_AUDIO_SONY: + cdb[0] = GPCMD_PLAY_AUDIO_10; + dev->current_cdb[0] = cdb[0]; + dev->sony_vendor = 1; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_10. */ + break; + + case GPCMD_PLAYBACK_CONTROL_SONY: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); + dev->sony_vendor = 1; + + len = (cdb[7] << 8) | cdb[8]; + if (len == 0) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_log("CD-ROM %i: PlayBack Control Sony All done - callback set\n", dev->id); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + } else { + 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; + } + + return cmd_stat; +} + +static uint8_t +scsi_cdrom_command_matsushita(void *sc, uint8_t *cdb, int32_t *BufLen) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + uint8_t cmd_stat = 0x00; + + switch (cdb[0]) { + case GPCMD_READ_SUBCHANNEL_MATSUSHITA: + cdb[0] = GPCMD_READ_SUBCHANNEL; + dev->current_cdb[0] = cdb[0]; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_READ_SUBCHANNEL. */ + break; + + case GPCMD_READ_TOC_MATSUSHITA: + cdb[0] = GPCMD_READ_TOC_PMA_ATIP; + dev->current_cdb[0] = cdb[0]; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_READ_TOC_PMA_ATIP. */ + break; + + case GPCMD_READ_HEADER_MATSUSHITA: + cdb[0] = GPCMD_READ_HEADER; + dev->current_cdb[0] = cdb[0]; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_READ_HEADER. */ + break; + + case GPCMD_PLAY_AUDIO_MATSUSHITA: + cdb[0] = GPCMD_PLAY_AUDIO_10; + dev->current_cdb[0] = cdb[0]; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_10. */ + break; + + case GPCMD_PLAY_AUDIO_MSF_MATSUSHITA: + cdb[0] = GPCMD_PLAY_AUDIO_MSF; + dev->current_cdb[0] = cdb[0]; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_MSF. */ + break; + + case GPCMD_PLAY_AUDIO_TRACK_INDEX_MATSUSHITA: + cdb[0] = GPCMD_PLAY_AUDIO_TRACK_INDEX; + dev->current_cdb[0] = cdb[0]; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_TRACK_INDEX. */ + break; + + case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10_MATSUSHITA: + cdb[0] = GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10; + dev->current_cdb[0] = cdb[0]; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10. */ + break; + + case GPCMD_PAUSE_RESUME_MATSUSHITA: + cdb[0] = GPCMD_PAUSE_RESUME; + dev->current_cdb[0] = cdb[0]; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PAUSE_RESUME. */ + break; + + case GPCMD_PLAY_AUDIO_12_MATSUSHITA: + cdb[0] = GPCMD_PLAY_AUDIO_12; + dev->current_cdb[0] = cdb[0]; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_12. */ + break; + + case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12_MATSUSHITA: + cdb[0] = GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12; + dev->current_cdb[0] = cdb[0]; + /* Keep cmd_stat at 0x00, therefore, it's going to process it as GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12. */ + break; + } + + return cmd_stat; +} + +static uint8_t +scsi_cdrom_command_nec(void *sc, uint8_t *cdb, int32_t *BufLen) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + int pos = dev->drv->seek_pos; + int ret = 1; + uint8_t cmd_stat = 0x00; + int len; + int alloc_length; + + switch (cdb[0]) { + case GPCMD_NO_OPERATION_NEC: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + break; + + case GPCMD_AUDIO_TRACK_SEARCH_NEC: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + scsi_cdrom_illegal_mode(dev); + else { + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + ret = cdrom_audio_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); + dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; + + if (ret) + scsi_cdrom_command_complete(dev); + else + scsi_cdrom_illegal_mode(dev); + } + cmd_stat = 0x01; + break; + + case GPCMD_PLAY_AUDIO_NEC: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + ret = 0; + else { + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + ret = cdrom_audio_play_toshiba(dev->drv, pos, cdb[9] & 0xc0); + } + + if (ret) + scsi_cdrom_command_complete(dev); + else + scsi_cdrom_illegal_mode(dev); + + cmd_stat = 0x01; + break; + + case 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); + cmd_stat = 0x01; + break; + + case GPCMD_SET_STOP_TIME_NEC: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + break; + + case GPCMD_CADDY_EJECT_NEC: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_stop(sc); + cdrom_eject(dev->id); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + break; + + case GPCMD_READ_SUBCODEQ_PLAYING_STATUS_NEC: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + alloc_length = cdb[1] & 0x1f; + len = 10; + + if (!dev->drv->ops) + scsi_cdrom_not_ready(dev); + else if (alloc_length <= 0) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + 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); + } else { + 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]); + scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[0]); + + scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + } + cmd_stat = 0x01; + break; + + case GPCMD_READ_DISC_INFORMATION_NEC: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + /* + NEC manual claims 4 bytes but the Linux kernel + (namely sr_vendor.c) actually states otherwise. + */ + scsi_cdrom_buf_alloc(dev, 22); + + if (!dev->drv->ops) + scsi_cdrom_not_ready(dev); + else { + ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); + len = 22; + if (ret) { + scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + } else + scsi_cdrom_invalid_field(dev); + } + cmd_stat = 0x01; + break; + } + + return cmd_stat; +} + +static uint8_t +scsi_cdrom_command_pioneer(void *sc, uint8_t *cdb, int32_t *BufLen) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + int pos = dev->drv->seek_pos; + int ret = 1; + uint8_t cmd_stat = 0x00; + int len; + int max_len; + int alloc_length; + + switch (cdb[0]) { + case GPCMD_MAGAZINE_EJECT_PIONEER: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_stop(sc); + cdrom_eject(dev->id); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + break; + + case GPCMD_READ_TOC_PIONEER: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + scsi_cdrom_buf_alloc(dev, 4); + + if (!dev->drv->ops) + scsi_cdrom_not_ready(dev); + else { + ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); + len = 4; + + if (ret) { + scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + } else + scsi_cdrom_invalid_field(dev); + } + cmd_stat = 0x01; + break; + + case GPCMD_READ_SUBCODEQ_PIONEER: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + alloc_length = cdb[1] & 0x1f; + len = 9; + + if (!dev->drv->ops) + scsi_cdrom_not_ready(dev); + else if (!alloc_length) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + 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); + } else { + scsi_cdrom_buf_alloc(dev, len); + len = MIN(len, alloc_length); + + memset(dev->buffer, 0, len); + cdrom_get_current_subcodeq(dev->drv, &dev->buffer[1]); + scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[0]); + + scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + } + cmd_stat = 0x01; + break; + + case GPCMD_AUDIO_TRACK_SEARCH_PIONEER: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + ret = 0; + else { + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + ret = cdrom_audio_track_search_pioneer(dev->drv, pos, cdb[1] & 1); + + dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; + } + + if (ret) + scsi_cdrom_command_complete(dev); + else + scsi_cdrom_illegal_mode(dev); + + cmd_stat = 0x01; + break; + + case GPCMD_PLAY_AUDIO_PIONEER: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + ret = 0; + else { + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + ret = cdrom_audio_play_pioneer(dev->drv, pos); + } + + if (ret) + scsi_cdrom_command_complete(dev); + else + scsi_cdrom_illegal_mode(dev); + cmd_stat = 0x01; + break; + + case 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); + cmd_stat = 0x01; + break; + + case GPCMD_STOP_PIONEER: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_stop(sc); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + break; + + case GPCMD_PLAYBACK_STATUS_PIONEER: + 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, 6); + + len = 6; + + memset(dev->buffer, 0, 6); + dev->buffer[0] = cdrom_get_audio_status_pioneer(dev->drv, &dev->buffer[1]); /*Audio status*/ + + 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); + cmd_stat = 0x01; + break; + + case 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); + else if (len <= 0) { + 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); + } else { + 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); + } + cmd_stat = 0x01; + break; + } + + return cmd_stat; +} + +static uint8_t +scsi_cdrom_command_toshiba(void *sc, uint8_t *cdb, int32_t *BufLen) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + int pos = dev->drv->seek_pos; + int ret = 1; + uint8_t cmd_stat = 0x00; + int len; + int alloc_length; + + switch (cdb[0]) { + case GPCMD_NO_OPERATION_TOSHIBA: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + break; + + case GPCMD_AUDIO_TRACK_SEARCH_TOSHIBA: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + if ((dev->drv->image_path[0] == 0x00) || (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_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); + dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; + + if (ret) + scsi_cdrom_command_complete(dev); + else + scsi_cdrom_illegal_mode(dev); + cmd_stat = 0x01; + break; + + case GPCMD_PLAY_AUDIO_TOSHIBA: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + if ((dev->drv->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) + scsi_cdrom_illegal_mode(dev); + else { + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + ret = cdrom_audio_play_toshiba(dev->drv, pos, cdb[9] & 0xc0); + + if (ret) + scsi_cdrom_command_complete(dev); + else + scsi_cdrom_illegal_mode(dev); + } + cmd_stat = 0x01; + break; + + case GPCMD_STILL_TOSHIBA: + 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); + cmd_stat = 0x01; + break; + + case GPCMD_SET_STOP_TIME_TOSHIBA: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + break; + + case GPCMD_CADDY_EJECT_TOSHIBA: + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + scsi_cdrom_stop(sc); + cdrom_eject(dev->id); + scsi_cdrom_command_complete(dev); + cmd_stat = 0x01; + break; + + case GPCMD_READ_SUBCODEQ_PLAYING_STATUS_TOSHIBA: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + alloc_length = cdb[1] & 0x1f; + len = 10; + + if (!dev->drv->ops) + scsi_cdrom_not_ready(dev); + else if (alloc_length <= 0) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + 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); + } else { + 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]); + scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[0]); + + scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + } + cmd_stat = 0x01; + break; + + case GPCMD_READ_DISC_INFORMATION_TOSHIBA: + scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + scsi_cdrom_buf_alloc(dev, 4); + + if (!dev->drv->ops) + scsi_cdrom_not_ready(dev); + else { + ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); + len = 4; + if (ret) { + scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_data_command_finish(dev, len, len, len, 0); + } else + scsi_cdrom_invalid_field(dev); + } + cmd_stat = 0x01; + break; + } + + return cmd_stat; +} + void scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) { - scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - int len; - int max_len; - int used_len; - int alloc_length; - int msf; - int pos = dev->drv->seek_pos; - int size_idx; - int idx = 0; - uint32_t feature; - unsigned preamble_len; - int toc_format; - int block_desc = 0; - int ret; + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + int msf = 0; + int pos = dev->drv->seek_pos; + int idx = 0; + int block_desc = 0; + int ret = 1; int format = 0; - int real_pos; int track = 0; char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; int32_t blen = 0; + uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; + uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; + uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; + int len; + int max_len; + int used_len; + int alloc_length; + int size_idx; + uint32_t feature; + unsigned preamble_len; + int toc_format; + int real_pos; int32_t *BufLen; uint8_t *b; - uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; - uint8_t scsi_bus = (dev->drv->scsi_device_id >> 4) & 0x0f; - uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f; if (dev->drv->bus_type == CDROM_BUS_SCSI) { BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length; @@ -1875,12 +2642,12 @@ scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) if (scsi_cdrom_pre_execution_check(dev, cdb) == 0) return; -begin: if (cdb[0] != GPCMD_REQUEST_SENSE) { /* Clear the sense stuff as per the spec. */ scsi_cdrom_sense_clear(dev, cdb[0]); } - switch (cdb[0]) { + + if ((dev->ven_cmd == NULL) || (dev->ven_cmd(sc, cdb, BufLen) == 0x00)) switch (cdb[0]) { case GPCMD_TEST_UNIT_READY: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); scsi_cdrom_command_complete(dev); @@ -1914,34 +2681,11 @@ begin: scsi_cdrom_data_command_finish(dev, 18, 18, cdb[4], 0); break; - case 0xDA: /*GPCMD_SPEED_ALT*/ - switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: /*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); - if ((dev->packet_status == PHASE_COMPLETE) || (dev->packet_status == PHASE_ERROR)) - scsi_cdrom_buf_free(dev); - return; - } - fallthrough; case GPCMD_SET_SPEED: - dev->drv->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; - if (dev->drv->cur_speed < 1) - dev->drv->cur_speed = 1; - else if (dev->drv->cur_speed > dev->drv->speed) - dev->drv->cur_speed = dev->drv->speed; - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_command_complete(dev); + scsi_cdrom_set_speed(dev, cdb); break; - case 0xCD: + case GPCMD_SCAN_PIONEER: case GPCMD_AUDIO_SCAN: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); @@ -1994,110 +2738,22 @@ begin: if (toc_format < 3) { len = cdrom_read_toc(dev->drv, dev->buffer, toc_format, cdb[6], msf, max_len); - if (len == -1) { - /* If the returned length is -1, this means cdrom_read_toc() has encountered an error. */ + /* If the returned length is -1, this means cdrom_read_toc() has encountered an error. */ + if (len == -1) scsi_cdrom_invalid_field(dev); - scsi_cdrom_buf_free(dev); - return; + else { + scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_data_command_finish(dev, len, len, len, 0); } - } else { + } else 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 0xC7: - switch (dev->drv->type) { - case CDROM_TYPE_MATSHITA_501_10b: /*GPCMD_PLAY_AUDIO_MSF_MATSUSHITA*/ - cdb[0] = GPCMD_PLAY_AUDIO_MSF; - dev->current_cdb[0] = cdb[0]; - goto begin; - break; - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: /*GPCMD_PLAY_MSF_SONY*/ - cdb[0] = GPCMD_PLAY_AUDIO_MSF; - dev->current_cdb[0] = cdb[0]; - dev->sony_vendor = 1; - goto begin; - break; - case CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: - case CDROM_TYPE_TOSHIBA_SDM1401_1008: /*GPCMD_READ_DISC_INFORMATION_TOSHIBA*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - scsi_cdrom_buf_alloc(dev, 4); - - if (!dev->drv->ops) { - scsi_cdrom_not_ready(dev); - return; - } - - ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); - len = 4; - 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; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } break; - case 0xDE: - switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: /*GPCMD_READ_DISC_INFORMATION_NEC*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - scsi_cdrom_buf_alloc(dev, 22); /* NEC manual claims 4 bytes, but the Linux kernel (namely sr_vendor.c) actually states otherwise. */ - - if (!dev->drv->ops) { - scsi_cdrom_not_ready(dev); - return; - } - - ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); - len = 22; - 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; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - case GPCMD_READ_CD_OLD: - /* IMPORTANT: Convert the command to new read CD - for pass through purposes. */ - dev->current_cdb[0] = GPCMD_READ_CD; - fallthrough; - case GPCMD_READ_6: case GPCMD_READ_10: case GPCMD_READ_12: + case GPCMD_READ_CD_OLD: + case GPCMD_READ_CD_MSF_OLD: case GPCMD_READ_CD: case GPCMD_READ_CD_MSF: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); @@ -2106,139 +2762,117 @@ begin: switch (cdb[0]) { case GPCMD_READ_6: dev->sector_len = cdb[4]; + /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sectors. */ if (dev->sector_len == 0) - dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */ - dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - msf = 0; + dev->sector_len = 256; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | + ((uint32_t) cdb[3]); + scsi_cdrom_log("CD-ROM %i: READ (6): Length: %i, LBA: %i\n", dev->id, dev->sector_len, + dev->sector_pos); break; case GPCMD_READ_10: dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - scsi_cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, + scsi_cdrom_log("CD-ROM %i: READ (10): Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); - msf = 0; break; case GPCMD_READ_12: - dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - scsi_cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | + (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | + (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + scsi_cdrom_log("CD-ROM %i: READ (12): Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); - msf = 0; break; + case GPCMD_READ_CD_MSF_OLD: case GPCMD_READ_CD_MSF: - alloc_length = 2856; - dev->sector_len = MSFtoLBA(cdb[6], cdb[7], cdb[8]); - dev->sector_pos = MSFtoLBA(cdb[3], cdb[4], cdb[5]); - - dev->sector_len -= dev->sector_pos; - dev->sector_len++; - msf = 1; - - if ((cdb[9] & 0xf8) == 0x08) { - /* 0x08 is an illegal mode */ - scsi_cdrom_invalid_field(dev); - return; - } - - /* If all the flag bits are cleared, then treat it as a non-data command. */ - if ((cdb[9] == 0x00) && ((cdb[10] & 0x07) == 0x00)) - dev->sector_len = 0; - else if ((cdb[9] == 0x00) && ((cdb[10] & 0x07) != 0x00)) { - scsi_cdrom_invalid_field(dev); - return; - } - break; + fallthrough; case GPCMD_READ_CD_OLD: case GPCMD_READ_CD: alloc_length = 2856; - dev->sector_len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; - dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - msf = 0; + if (msf) { + dev->sector_len = MSFtoLBA(cdb[6], cdb[7], cdb[8]); + dev->sector_pos = MSFtoLBA(cdb[3], cdb[4], cdb[5]); - if ((cdb[9] & 0xf8) == 0x08) { - /* 0x08 is an illegal mode */ - scsi_cdrom_invalid_field(dev); - return; + dev->sector_len -= dev->sector_pos; + dev->sector_len++; + } else { + dev->sector_len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; } - /* If all the flag bits are cleared, then treat it as a non-data command. */ - if ((cdb[9] == 0x00) && ((cdb[10] & 0x07) == 0x00)) + if (((cdb[9] & 0xf8) == 0x08) || ((cdb[9] == 0x00) && ((cdb[10] & 0x07) != 0x00))) { + /* Illegal mode */ + scsi_cdrom_invalid_field(dev); + ret = 0; + } else if ((cdb[9] == 0x00) && ((cdb[10] & 0x07) == 0x00)) + /* If all the flag bits are cleared, then treat it as a non-data command. */ dev->sector_len = 0; - else if ((cdb[9] == 0x00) && ((cdb[10] & 0x07) != 0x00)) { - scsi_cdrom_invalid_field(dev); - return; - } break; default: break; } - if (!dev->sector_len) { - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - /* scsi_cdrom_log("CD-ROM %i: All done - callback set\n", dev->id); */ - dev->packet_status = PHASE_COMPLETE; - dev->callback = 20.0 * CDROM_TIME; - scsi_cdrom_set_callback(dev); - break; - } + if (ret) { + if (dev->sector_len > 0) { + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* + If we're reading all blocks in one go for DMA, + why not also for PIO, it should NOT matter + anyway, this step should be identical and only + the way the read dat is transferred to the host + should be different. + */ - max_len = dev->sector_len; - dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ + dev->packet_len = max_len * alloc_length; + scsi_cdrom_buf_alloc(dev, dev->packet_len); - dev->packet_len = max_len * alloc_length; - scsi_cdrom_buf_alloc(dev, dev->packet_len); + dev->drv->seek_diff = ABS((int) (pos - dev->sector_pos)); - dev->drv->seek_diff = ABS((int) (pos - dev->sector_pos)); - - if ((cdb[0] == GPCMD_READ_10) || (cdb[0] == GPCMD_READ_12)) { - switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: - case CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: - case CDROM_TYPE_TOSHIBA_SDM1401_1008: - ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1, cdb[9] & 0xc0); - break; - default: + if ((cdb[0] == GPCMD_READ_10) || (cdb[0] == GPCMD_READ_12)) { + switch (dev->drv->type) { + case CDROM_TYPE_NEC_25_10a ... CDROM_TYPE_NEC_464_105: + case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_SDM1401_1008: + ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1, cdb[9] & 0xc0); + break; + default: + ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1, 0); + break; + } + } else ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1, 0); - break; + + if (ret > 0) { + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + scsi_cdrom_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, + alloc_length, 0); + + if (dev->packet_status != PHASE_COMPLETE) + ui_sb_update_icon(SB_CDROM | dev->id, 1); + else + ui_sb_update_icon(SB_CDROM | dev->id, 0); + } else { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + } + } else { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + /* scsi_cdrom_log("CD-ROM %i: All done - callback set\n", dev->id); */ + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); } - } 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 = (ret < 0) ? PHASE_ERROR : PHASE_COMPLETE; - dev->callback = 20.0 * CDROM_TIME; - scsi_cdrom_set_callback(dev); - scsi_cdrom_buf_free(dev); - return; } - - dev->requested_blocks = max_len; - dev->packet_len = alloc_length; - - scsi_cdrom_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - - scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, - alloc_length, 0); - - if (dev->packet_status != PHASE_COMPLETE) - ui_sb_update_icon(SB_CDROM | dev->id, 1); - else - ui_sb_update_icon(SB_CDROM | dev->id, 0); - return; + break; case GPCMD_READ_HEADER: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); @@ -2265,7 +2899,7 @@ begin: scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); - return; + break; case GPCMD_MODE_SENSE_6: case GPCMD_MODE_SENSE_10: @@ -2286,67 +2920,63 @@ begin: switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: - 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; - } + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: + if (!(scsi_cdrom_mode_sense_page_flags_sony & (1LL << (uint64_t) (cdb[2] & 0x3f)))) + ret = 0; break; default: - 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 (!(scsi_cdrom_mode_sense_page_flags & (1LL << (uint64_t) (cdb[2] & 0x3f)))) + ret = 0; break; } - memset(dev->buffer, 0, len); - alloc_length = len; - /* This determines the media type ID to return - this is - a SCSI/ATAPI-specific thing, so it makes the most sense - to keep this here. - Also, the max_len variable is reused as this command - does otherwise not use it, to avoid having to declare - another variable. */ - if (dev->drv->cd_status == CD_STATUS_EMPTY) - max_len = 70; /* No media inserted. */ - else if (dev->drv->cdrom_capacity > CD_MAX_SECTORS) - max_len = 65; /* DVD. */ - else if (dev->drv->cd_status == CD_STATUS_DATA_ONLY) - max_len = 1; /* Data CD. */ - else - max_len = 3; /* Audio or mixed-mode CD. */ + if (ret == 1) { + memset(dev->buffer, 0, len); + alloc_length = len; - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = scsi_cdrom_mode_sense(dev, dev->buffer, 4, cdb[2], block_desc); - len = MIN(len, alloc_length); - dev->buffer[0] = len - 1; - dev->buffer[1] = max_len; - if (block_desc) - dev->buffer[3] = 8; - } else { - len = scsi_cdrom_mode_sense(dev, dev->buffer, 8, cdb[2], block_desc); - len = MIN(len, alloc_length); - dev->buffer[0] = (len - 2) >> 8; - dev->buffer[1] = (len - 2) & 255; - dev->buffer[2] = max_len; - if (block_desc) { - dev->buffer[6] = 0; - dev->buffer[7] = 8; + /* This determines the media type ID to return - this is + a SCSI/ATAPI-specific thing, so it makes the most sense + to keep this here. + Also, the max_len variable is reused as this command + does otherwise not use it, to avoid having to declare + another variable. */ + if (dev->drv->cd_status == CD_STATUS_EMPTY) + max_len = 70; /* No media inserted. */ + else if (dev->drv->cdrom_capacity > CD_MAX_SECTORS) + max_len = 65; /* DVD. */ + else if (dev->drv->cd_status == CD_STATUS_DATA_ONLY) + max_len = 1; /* Data CD. */ + else + max_len = 3; /* Audio or mixed-mode CD. */ + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = scsi_cdrom_mode_sense(dev, dev->buffer, 4, cdb[2], block_desc); + len = MIN(len, alloc_length); + dev->buffer[0] = len - 1; + dev->buffer[1] = max_len; + if (block_desc) + dev->buffer[3] = 8; + } else { + len = scsi_cdrom_mode_sense(dev, dev->buffer, 8, cdb[2], block_desc); + len = MIN(len, alloc_length); + dev->buffer[0] = (len - 2) >> 8; + dev->buffer[1] = (len - 2) & 255; + dev->buffer[2] = max_len; + if (block_desc) { + dev->buffer[6] = 0; + dev->buffer[7] = 8; + } } - } - scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); - scsi_cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", dev->id, cdb[2]); + scsi_cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", dev->id, cdb[2]); - scsi_cdrom_data_command_finish(dev, len, len, alloc_length, 0); - return; + scsi_cdrom_data_command_finish(dev, len, len, alloc_length, 0); + } else + scsi_cdrom_invalid_field(dev); + break; case GPCMD_MODE_SELECT_6: case GPCMD_MODE_SELECT_10: @@ -2366,171 +2996,166 @@ begin: dev->do_page_save = cdb[1] & 1; scsi_cdrom_data_command_finish(dev, len, len, len, 1); - return; + break; case GPCMD_GET_CONFIGURATION: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - /* XXX: could result in alignment problems in some architectures */ + /* XXX: Could result in alignment problems in some architectures */ feature = (cdb[2] << 8) | cdb[3]; max_len = (cdb[7] << 8) | cdb[8]; - /* only feature 0 is supported */ - if ((feature > 3) && (feature != 0x010) && - (feature != 0x1d) && (feature != 0x01e) && - (feature != 0x01f) && (feature != 0x103)) { + /* Only feature 0 is supported */ + if ((feature > 3) && (feature != 0x010) && (feature != 0x1d) && (feature != 0x01e) && + (feature != 0x01f) && (feature != 0x103)) scsi_cdrom_invalid_field(dev); - scsi_cdrom_buf_free(dev); - return; - } + else { + scsi_cdrom_buf_alloc(dev, 65536); + memset(dev->buffer, 0, max_len); - scsi_cdrom_buf_alloc(dev, 65536); - memset(dev->buffer, 0, max_len); + alloc_length = 0; + b = dev->buffer; - alloc_length = 0; - b = dev->buffer; + /* + The number of sectors from the media tells us which profile + to use as current. 0 means there is no media. + */ + if (dev->drv->cd_status != CD_STATUS_EMPTY) { + len = dev->drv->cdrom_capacity; + if (len > CD_MAX_SECTORS) { + b[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; + b[7] = MMC_PROFILE_DVD_ROM & 0xff; + ret = 1; + } else { + b[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; + b[7] = MMC_PROFILE_CD_ROM & 0xff; + ret = 0; + } + } else + ret = 2; - /* - * the number of sectors from the media tells us which profile - * to use as current. 0 means there is no media - */ - if (dev->drv->cd_status != CD_STATUS_EMPTY) { - len = dev->drv->cdrom_capacity; - if (len > CD_MAX_SECTORS) { - b[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; - b[7] = MMC_PROFILE_DVD_ROM & 0xff; - ret = 1; - } else { - b[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; - b[7] = MMC_PROFILE_CD_ROM & 0xff; - ret = 0; + alloc_length = 8; + b += 8; + + if ((feature == 0) || ((cdb[1] & 3) < 2)) { + b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 8; + + alloc_length += 4; + b += 4; + + for (uint8_t i = 0; i < 2; i++) { + b[0] = (profiles[i] >> 8) & 0xff; + b[1] = profiles[i] & 0xff; + + if (ret == i) + b[2] |= 1; + + alloc_length += 4; + b += 4; + } } - } else - ret = 2; + if ((feature == 1) || ((cdb[1] & 3) < 2)) { + b[1] = 1; + b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 8; - alloc_length = 8; - b += 8; + if (dev->drv->bus_type == CDROM_BUS_SCSI) + b[7] = 1; + else + b[7] = 2; + b[8] = 1; - if ((feature == 0) || ((cdb[1] & 3) < 2)) { - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 8; + alloc_length += 12; + b += 12; + } + if ((feature == 2) || ((cdb[1] & 3) < 2)) { + b[1] = 2; + b[2] = (1 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 4; + b[4] = 2; - alloc_length += 4; - b += 4; + alloc_length += 8; + b += 8; + } + if ((feature == 3) || ((cdb[1] & 3) < 2)) { + b[1] = 2; + b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 4; + b[4] = 0x0d; - for (uint8_t i = 0; i < 2; i++) { - b[0] = (profiles[i] >> 8) & 0xff; - b[1] = profiles[i] & 0xff; + /* 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. */ + if (dev->drv->bus_type == CDROM_BUS_SCSI) + b[4] |= ((dev->drv->type == CDROM_TYPE_86BOX_100) ? 0x20 : 0x00); + else + b[4] |= ((dev->drv->type == CDROM_TYPE_NEC_260_100) || + ((dev->drv->type == CDROM_TYPE_NEC_260_101)) ? 0x00 : 0x20); - if (ret == i) - b[2] |= 1; + alloc_length += 8; + b += 8; + } + if ((feature == 0x10) || ((cdb[1] & 3) < 2)) { + b[1] = 0x10; + b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 8; + + b[6] = 8; + b[9] = 0x10; + + alloc_length += 12; + b += 12; + } + if ((feature == 0x1d) || ((cdb[1] & 3) < 2)) { + b[1] = 0x1d; + b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 0; alloc_length += 4; b += 4; } + if ((feature == 0x1e) || ((cdb[1] & 3) < 2)) { + b[1] = 0x1e; + b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 4; + b[4] = 0; + + alloc_length += 8; + b += 8; + } + if ((feature == 0x1f) || ((cdb[1] & 3) < 2)) { + b[1] = 0x1f; + b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 0; + + alloc_length += 4; + b += 4; + } + if ((feature == 0x103) || ((cdb[1] & 3) < 2)) { + b[0] = 1; + b[1] = 3; + b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 0; + b[4] = 7; + + b[6] = 1; + + alloc_length += 8; + b += 8; + } + + dev->buffer[0] = ((alloc_length - 4) >> 24) & 0xff; + dev->buffer[1] = ((alloc_length - 4) >> 16) & 0xff; + dev->buffer[2] = ((alloc_length - 4) >> 8) & 0xff; + dev->buffer[3] = (alloc_length - 4) & 0xff; + + alloc_length = MIN(alloc_length, max_len); + + scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); + + scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); } - if ((feature == 1) || ((cdb[1] & 3) < 2)) { - b[1] = 1; - b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 8; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - b[7] = 1; - else - b[7] = 2; - b[8] = 1; - - alloc_length += 12; - b += 12; - } - if ((feature == 2) || ((cdb[1] & 3) < 2)) { - b[1] = 2; - b[2] = (1 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 4; - - b[4] = 2; - - alloc_length += 8; - b += 8; - } - if ((feature == 3) || ((cdb[1] & 3) < 2)) { - b[1] = 2; - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 4; - - b[4] = 0x0d; - /* 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. */ - if (dev->drv->bus_type == CDROM_BUS_SCSI) - b[4] |= ((dev->drv->type == CDROM_TYPE_86BOX_100) ? 0x20 : 0x00); - else - b[4] |= ((dev->drv->type == CDROM_TYPE_NEC_260_100) || - ((dev->drv->type == CDROM_TYPE_NEC_260_101)) ? 0x00 : 0x20); - - alloc_length += 8; - b += 8; - } - if ((feature == 0x10) || ((cdb[1] & 3) < 2)) { - b[1] = 0x10; - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 8; - - b[6] = 8; - b[9] = 0x10; - - alloc_length += 12; - b += 12; - } - if ((feature == 0x1d) || ((cdb[1] & 3) < 2)) { - b[1] = 0x1d; - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 0; - - alloc_length += 4; - b += 4; - } - if ((feature == 0x1e) || ((cdb[1] & 3) < 2)) { - b[1] = 0x1e; - b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 4; - - b[4] = 0; - - alloc_length += 8; - b += 8; - } - if ((feature == 0x1f) || ((cdb[1] & 3) < 2)) { - b[1] = 0x1f; - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 0; - - alloc_length += 4; - b += 4; - } - if ((feature == 0x103) || ((cdb[1] & 3) < 2)) { - b[0] = 1; - b[1] = 3; - b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ - b[3] = 0; - - b[4] = 7; - b[6] = 1; - - alloc_length += 8; - b += 8; - } - - dev->buffer[0] = ((alloc_length - 4) >> 24) & 0xff; - dev->buffer[1] = ((alloc_length - 4) >> 16) & 0xff; - dev->buffer[2] = ((alloc_length - 4) >> 8) & 0xff; - dev->buffer[3] = (alloc_length - 4) & 0xff; - - alloc_length = MIN(alloc_length, max_len); - - scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); - - scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); break; case GPCMD_GET_EVENT_STATUS_NOTIFICATION: @@ -2541,56 +3166,56 @@ begin: gesn_cdb = (void *) cdb; gesn_event_header = (void *) dev->buffer; - /* It is fine by the MMC spec to not support async mode operations. */ - if (!(gesn_cdb->polled & 0x01)) { - /* asynchronous mode */ - /* Only polling is supported, asynchronous mode is not. */ + if (gesn_cdb->polled & 0x01) { + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + * Notification class requests and supported event classes are bitmasks, + * but they are built from the same values as the "notification class" + * field. + */ + gesn_event_header->supported_events = 1 << GESN_MEDIA; + + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & (1 << GESN_MEDIA)) { + gesn_event_header->notification_class |= GESN_MEDIA; + + dev->buffer[4] = dev->media_status; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */ + dev->buffer[5] = 1; /* Power Status (1 = Active) */ + dev->buffer[6] = 0; + dev->buffer[7] = 0; + used_len = 8; + } else { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + gesn_event_header->len = used_len - sizeof(*gesn_event_header); + + memmove(dev->buffer, gesn_event_header, 4); + + scsi_cdrom_set_buf_len(dev, BufLen, &used_len); + + scsi_cdrom_data_command_finish(dev, used_len, used_len, used_len, 0); + } else { + /* + Only polling is supported, asynchronous mode is not. + It is fine by the MMC spec to not support async mode operations. + */ scsi_cdrom_invalid_field(dev); scsi_cdrom_buf_free(dev); - return; } - - /* - * These are the supported events. - * - * We currently only support requests of the 'media' type. - * Notification class requests and supported event classes are bitmasks, - * but they are built from the same values as the "notification class" - * field. - */ - gesn_event_header->supported_events = 1 << GESN_MEDIA; - - /* - * We use |= below to set the class field; other bits in this byte - * are reserved now but this is useful to do if we have to use the - * reserved fields later. - */ - gesn_event_header->notification_class = 0; - - /* - * Responses to requests are to be based on request priority. The - * notification_class_request_type enum above specifies the - * priority: upper elements are higher prio than lower ones. - */ - if (gesn_cdb->class & (1 << GESN_MEDIA)) { - gesn_event_header->notification_class |= GESN_MEDIA; - - dev->buffer[4] = dev->media_status; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */ - dev->buffer[5] = 1; /* Power Status (1 = Active) */ - dev->buffer[6] = 0; - dev->buffer[7] = 0; - used_len = 8; - } else { - gesn_event_header->notification_class = 0x80; /* No event available */ - used_len = sizeof(*gesn_event_header); - } - gesn_event_header->len = used_len - sizeof(*gesn_event_header); - - memmove(dev->buffer, gesn_event_header, 4); - - scsi_cdrom_set_buf_len(dev, BufLen, &used_len); - - scsi_cdrom_data_command_finish(dev, used_len, used_len, used_len, 0); break; case GPCMD_READ_DISC_INFORMATION: @@ -2632,213 +3257,36 @@ begin: track |= ((uint32_t) cdb[4]) << 8; track |= (uint32_t) cdb[5]; - if (((cdb[1] & 0x03) != 1) || (track != 1)) { + if (((cdb[1] & 0x03) != 1) || (track != 1)) scsi_cdrom_invalid_field(dev); - scsi_cdrom_buf_free(dev); - return; - } + else { + len = 36; - len = 36; + memset(dev->buffer, 0, 36); + dev->buffer[0] = 0; + dev->buffer[1] = 34; + dev->buffer[2] = 1; /* track number (LSB) */ + dev->buffer[3] = 1; /* session number (LSB) */ + dev->buffer[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ + dev->buffer[6] = (0 << 7) | (0 << 6) | (0 << 5) | /* not reserved track, not blank, */ + (0 << 6) | (1 << 0); /* not packet writing, not fixed packet, */ + /* data mode 1 */ + dev->buffer[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, */ + /* next recordable address not valid */ - memset(dev->buffer, 0, 36); - dev->buffer[0] = 0; - dev->buffer[1] = 34; - dev->buffer[2] = 1; /* track number (LSB) */ - dev->buffer[3] = 1; /* session number (LSB) */ - dev->buffer[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ - dev->buffer[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ - dev->buffer[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ + dev->buffer[24] = ((dev->drv->cdrom_capacity - 1) >> 24) & 0xff; /* track size */ + dev->buffer[25] = ((dev->drv->cdrom_capacity - 1) >> 16) & 0xff; /* track size */ + dev->buffer[26] = ((dev->drv->cdrom_capacity - 1) >> 8) & 0xff; /* track size */ + dev->buffer[27] = (dev->drv->cdrom_capacity - 1) & 0xff; /* track size */ - dev->buffer[24] = ((dev->drv->cdrom_capacity - 1) >> 24) & 0xff; /* track size */ - dev->buffer[25] = ((dev->drv->cdrom_capacity - 1) >> 16) & 0xff; /* track size */ - dev->buffer[26] = ((dev->drv->cdrom_capacity - 1) >> 8) & 0xff; /* track size */ - dev->buffer[27] = (dev->drv->cdrom_capacity - 1) & 0xff; /* track size */ + if (len > max_len) { + len = max_len; + dev->buffer[0] = ((max_len - 2) >> 8) & 0xff; + dev->buffer[1] = (max_len - 2) & 0xff; + } - if (len > max_len) { - len = max_len; - dev->buffer[0] = ((max_len - 2) >> 8) & 0xff; - dev->buffer[1] = (max_len - 2) & 0xff; - } - - scsi_cdrom_set_buf_len(dev, BufLen, &len); - - scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); - break; - - case 0xC0: - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: /*GPCMD_SET_ADDRESS_FORMAT_SONY*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - dev->sony_vendor = 1; - dev->drv->sony_msf = cdb[8] & 1; - scsi_cdrom_command_complete(dev); - break; - case CDROM_TYPE_PIONEER_DRM604X_2403: /*GPCMD_MAGAZINE_EJECT_PIONEER*/ - case CDROM_TYPE_CHINON_CDS431_H42: /*GPCMD_EJECT_CHINON*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_stop(sc); - cdrom_eject(dev->id); - scsi_cdrom_command_complete(dev); - break; - case CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: - case CDROM_TYPE_TOSHIBA_SDM1401_1008: /*GPCMD_AUDIO_TRACK_SEARCH_TOSHIBA*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (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_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); - dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; - - if (ret) - scsi_cdrom_command_complete(dev); - else - scsi_cdrom_illegal_mode(dev); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - - case 0xD8: - switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: /*GPCMD_AUDIO_TRACK_SEARCH_NEC*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (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_track_search(dev->drv, pos, cdb[9] & 0xc0, cdb[1] & 1); - dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; - - if (ret) - scsi_cdrom_command_complete(dev); - else - scsi_cdrom_illegal_mode(dev); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - - case 0xC1: - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: /*GPCMD_READ_TOC_SONY*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - 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 || dev->drv->sony_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; - case CDROM_TYPE_PIONEER_DRM604X_2403: /*GPCMD_READ_TOC_PIONEER*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - scsi_cdrom_buf_alloc(dev, 4); - - if (!dev->drv->ops) { - scsi_cdrom_not_ready(dev); - return; - } - - ret = cdrom_read_disc_info_toc(dev->drv, dev->buffer, cdb[2], cdb[1] & 3); - len = 4; - 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 CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: - case CDROM_TYPE_TOSHIBA_SDM1401_1008: /*GPCMD_PLAY_AUDIO_TOSHIBA*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (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_play_toshiba(dev->drv, pos, cdb[9] & 0xc0); - - if (ret) - scsi_cdrom_command_complete(dev); - else - scsi_cdrom_illegal_mode(dev); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - - case 0xD9: - switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: /*GPCMD_PLAY_AUDIO_NEC*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (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_play_toshiba(dev->drv, pos, cdb[9] & 0xc0); - - if (ret) - scsi_cdrom_command_complete(dev); - else - scsi_cdrom_illegal_mode(dev); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; + scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_data_command_finish(dev, len, len, max_len, 0); } break; @@ -2848,10 +3296,10 @@ begin: case GPCMD_PLAY_AUDIO_TRACK_INDEX: case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12: - len = 0; - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + len = 0; + switch (cdb[0]) { case GPCMD_PLAY_AUDIO_10: msf = 0; @@ -2870,12 +3318,11 @@ begin: break; case GPCMD_PLAY_AUDIO_TRACK_INDEX: msf = 2; - if ((cdb[5] != 1) || (cdb[8] != 1)) { - scsi_cdrom_illegal_mode(dev); - break; - } - pos = cdb[4]; - len = cdb[7]; + if ((cdb[5] == 1) && (cdb[8] == 1)) { + pos = cdb[4]; + len = cdb[7]; + } else + ret = 0; break; case GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10: msf = 0x100 | cdb[6]; @@ -2892,12 +3339,10 @@ begin: break; } - if ((dev->drv->image_path[0] == 0x00) || (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 && (dev->drv->image_path[0] != 0x00) && (dev->drv->cd_status > CD_STATUS_DATA_ONLY)) + ret = cdrom_audio_play(dev->drv, pos, len, msf); + else + ret = 0; if (ret) scsi_cdrom_command_complete(dev); @@ -2921,23 +3366,15 @@ begin: /* scsi_cdrom_log("CD-ROM %i: Read subchannel check condition %02X\n", dev->id, cdb[3]); */ scsi_cdrom_invalid_field(dev); - scsi_cdrom_buf_free(dev); - return; - } - - if (max_len <= 0) { + } else if (max_len <= 0) { scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); dev->packet_status = PHASE_COMPLETE; dev->callback = 20.0 * CDROM_TIME; scsi_cdrom_set_callback(dev); - scsi_cdrom_buf_free(dev); - return; - } - - if (!(cdb[2] & 0x40)) - alloc_length = 4; - else - switch (cdb[3]) { + } else { + if (!(cdb[2] & 0x40)) + alloc_length = 4; + else switch (cdb[3]) { case 0: /* SCSI-2: Q-type subchannel, ATAPI: reserved */ alloc_length = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 48 : 4; @@ -2950,21 +3387,21 @@ begin: break; } - len = alloc_length; + len = alloc_length; - memset(dev->buffer, 0, 24); - pos = 0; - dev->buffer[pos++] = 0; - dev->buffer[pos++] = 0; /*Audio status*/ - dev->buffer[pos++] = 0; - dev->buffer[pos++] = 0; /*Subchannel length*/ - /* Mode 0 = Q subchannel mode, first 16 bytes are indentical to mode 1 (current position), - the rest are stuff like ISRC etc., which can be all zeroes. */ - if (cdb[3] <= 3) { - dev->buffer[pos++] = cdb[3]; /*Format code*/ + memset(dev->buffer, 0, 24); + pos = 0x00; + dev->buffer[pos++] = 0x00; + dev->buffer[pos++] = 0x00; /* Audio status */ + dev->buffer[pos++] = 0x00; + dev->buffer[pos++] = 0x00; /* Subchannel length */ + dev->buffer[pos++] = cdb[3]; /* Format code */ if (alloc_length != 4) { - dev->buffer[1] = cdrom_get_current_subchannel(dev->drv, &dev->buffer[4], msf); + dev->buffer[1] = cdrom_get_current_status(dev->drv); + + cdrom_get_current_subchannel(dev->drv, &dev->buffer[4], msf); + dev->buffer[2] = alloc_length - 4; } @@ -2973,140 +3410,25 @@ begin: dev->buffer[1] = 0x11; break; case CD_STATUS_PAUSED: - dev->buffer[1] = (dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) ? 0x15 : 0x12; + dev->buffer[1] = ((dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) || + (dev->drv->type == CDROM_TYPE_CHINON_CDX435_M62)) ? 0x15 : 0x12; break; case CD_STATUS_DATA_ONLY: - dev->buffer[1] = (dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) ? 0x00 : 0x15; + dev->buffer[1] = ((dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) || + (dev->drv->type == CDROM_TYPE_CHINON_CDX435_M62)) ? 0x00 : 0x15; break; default: - dev->buffer[1] = (dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) ? 0x00 : 0x13; + dev->buffer[1] = ((dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) || + (dev->drv->type == CDROM_TYPE_CHINON_CDX435_M62)) ? 0x00 : 0x13; break; } scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[1]); - } - len = MIN(len, max_len); - scsi_cdrom_set_buf_len(dev, BufLen, &len); + 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 0xC6: - switch (dev->drv->type) { - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: /*GPCMD_PLAY_TRACK_SONY*/ - 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->image_path[0] == 0x00) || (dev->drv->cd_status <= CD_STATUS_DATA_ONLY)) { - scsi_cdrom_illegal_mode(dev); - break; - } - - /* In this case, len is unused so just pass a fixed value of 1 intead. */ - ret = cdrom_audio_play(dev->drv, pos, 1 /*len*/, msf); - - if (ret) - scsi_cdrom_command_complete(dev); - else - scsi_cdrom_illegal_mode(dev); - break; - case CDROM_TYPE_CHINON_CDS431_H42: /*GPCMD_STOP_CHINON*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_stop(sc); - scsi_cdrom_command_complete(dev); - break; - case CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: - case CDROM_TYPE_TOSHIBA_SDM1401_1008: /*GPCMD_READ_SUBCODEQ_PLAYING_STATUS_TOSHIBA*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - alloc_length = cdb[1] & 0x1f; - len = 10; - - if (!dev->drv->ops) { - scsi_cdrom_not_ready(dev); - return; - } - - if (!alloc_length) { - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - 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; - } - - 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]); - scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[0]); - - scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); - scsi_cdrom_data_command_finish(dev, len, len, len, 0); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - - case 0xDD: - switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: /*GPCMD_READ_SUBCODEQ_PLAYING_STATUS_NEC*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - alloc_length = cdb[1] & 0x1f; - len = 10; - - if (!dev->drv->ops) { - scsi_cdrom_not_ready(dev); - return; - } - - if (!alloc_length) { - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - 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; - } - - 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]); - scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[0]); - - scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); - scsi_cdrom_data_command_finish(dev, len, len, len, 0); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; + scsi_cdrom_data_command_finish(dev, len, len, len, 0); } break; @@ -3117,43 +3439,31 @@ begin: scsi_cdrom_buf_alloc(dev, alloc_length); - if ((cdb[7] < 0xc0) && (dev->drv->cdrom_capacity <= CD_MAX_SECTORS)) { + if ((cdb[7] < 0xc0) && (dev->drv->cdrom_capacity <= CD_MAX_SECTORS)) scsi_cdrom_incompatible_format(dev); - scsi_cdrom_buf_free(dev); - return; - } + else { + memset(dev->buffer, 0, alloc_length); - memset(dev->buffer, 0, alloc_length); - - if ((cdb[7] <= 0x7f) || (cdb[7] == 0xff)) { - if (cdb[1] == 0) { - format = cdb[7]; - ret = scsi_cdrom_read_dvd_structure(dev, format, cdb, dev->buffer); - dev->buffer[0] = (ret >> 8); - dev->buffer[1] = (ret & 0xff); - dev->buffer[2] = dev->buffer[3] = 0x00; - if (ret) { - scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); - scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, - alloc_length, 0); - } else - scsi_cdrom_buf_free(dev); - return; - } - } else { - scsi_cdrom_invalid_field(dev); - scsi_cdrom_buf_free(dev); - return; - } - break; - - case 0x26: - if (dev->drv->type == CDROM_TYPE_CHINON_CDS431_H42) { /*GPCMD_UNKNOWN_CHINON*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_stop(sc); - scsi_cdrom_command_complete(dev); - } else { - scsi_cdrom_illegal_opcode(dev); + if ((cdb[7] <= 0x7f) || (cdb[7] == 0xff)) { + if (cdb[1] == 0) { + format = cdb[7]; + ret = scsi_cdrom_read_dvd_structure(dev, format, cdb, dev->buffer); + dev->buffer[0] = (ret >> 8); + dev->buffer[1] = (ret & 0xff); + dev->buffer[2] = dev->buffer[3] = 0x00; + if (ret) { + scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); + scsi_cdrom_data_command_finish(dev, alloc_length, alloc_length, + alloc_length, 0); + } else { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20.0 * CDROM_TIME; + scsi_cdrom_set_callback(dev); + } + } + } else + scsi_cdrom_invalid_field(dev); } break; @@ -3183,80 +3493,6 @@ begin: scsi_cdrom_command_complete(dev); break; - case 0xC4: - switch (dev->drv->type) { - case CDROM_TYPE_MATSHITA_501_10b: /*GPCMD_READ_HEADER_MATSUSHITA*/ - cdb[0] = GPCMD_READ_HEADER; - dev->current_cdb[0] = cdb[0]; - goto begin; - break; - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: /*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 = 18; - - memset(dev->buffer, 0, 18); - dev->buffer[0] = 0x00; /*Reserved*/ - dev->buffer[1] = 0x00; /*Reserved*/ - dev->buffer[2] = 0x00; /*Audio Status data length*/ - dev->buffer[3] = 0x00; /*Audio Status data length*/ - dev->buffer[4] = cdrom_get_audio_status_sony(dev->drv, &dev->buffer[6], msf || dev->drv->sony_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 CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: - case CDROM_TYPE_TOSHIBA_SDM1401_1008: /*GPCMD_CADDY_EJECT_TOSHIBA*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_stop(sc); - cdrom_eject(dev->id); - scsi_cdrom_command_complete(dev); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - - case 0xDC: - switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: /*GPCMD_CADDY_EJECT_NEC*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_stop(sc); - cdrom_eject(dev->id); - scsi_cdrom_command_complete(dev); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - case GPCMD_INQUIRY: scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); @@ -3331,39 +3567,39 @@ begin: memset(dev->buffer, 0, 8); if ((cdb[1] & 0xe0) || ((dev->cur_lun > 0x00) && (dev->cur_lun < 0xff))) - dev->buffer[0] = 0x7f; /*No physical device on this LUN*/ + dev->buffer[0] = 0x7f; /* No physical device on this LUN */ else - dev->buffer[0] = 5; /*CD-ROM*/ - dev->buffer[1] = 0x80; /*Removable*/ + dev->buffer[0] = 5; /* CD-ROM */ + dev->buffer[1] = 0x80; /* Removable */ if (dev->drv->bus_type == CDROM_BUS_SCSI) { dev->buffer[3] = 0x02; switch (dev->drv->type) { case CDROM_TYPE_CHINON_CDS431_H42: + case CDROM_TYPE_CHINON_CDX435_M62: case CDROM_TYPE_DEC_RRD45_0436: case CDROM_TYPE_MATSHITA_501_10b: + case CDROM_TYPE_ShinaKen_DM3x1S_104: case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEAC_CD50_100: - case CDROM_TYPE_TEAC_R55S_10R: - case CDROM_TYPE_TEXEL_DMXX24_100: + case CDROM_TYPE_TEXEL_DM3024_100: dev->buffer[2] = 0x00; - dev->buffer[3] = 0x01; /*SCSI-1 compliant*/ + dev->buffer[3] = 0x01; /* SCSI-1 compliant */ + break; + case CDROM_TYPE_TEXEL_DM3028_106: + dev->buffer[2] = 0x02; + dev->buffer[3] = 0x01; /* SCSI-2 compliant */ break; case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: case CDROM_TYPE_NEC_75_103: case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: - dev->buffer[3] = 0x00; /*SCSI unknown version per NEC manuals*/ + dev->buffer[3] = 0x00; /* SCSI unknown version per NEC manuals */ break; case CDROM_TYPE_TOSHIBA_XM3201B_3232: dev->buffer[2] = 0x01; - dev->buffer[3] = 0x01; /*SCSI-1 compliant*/ + dev->buffer[3] = 0x01; /* SCSI-1 compliant */ break; default: - dev->buffer[2] = 0x02; /*SCSI-2 compliant*/ + dev->buffer[2] = 0x02; /* SCSI-2 compliant */ break; } } else { @@ -3374,12 +3610,12 @@ begin: dev->buffer[4] = 31; if (dev->drv->bus_type == CDROM_BUS_SCSI) { switch (dev->drv->type) { - case CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: - dev->buffer[4] = 91; /* Always 91 on Toshiba SCSI-1 (or SCSI-2) CD-ROM drives from 1989-1990*/ - dev->buffer[7] = 0x88; /* Linked Command and Relative Addressing supported */ + case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_XM5701TA_3136: + dev->buffer[4] = 91; /* + Always 91 on Toshiba SCSI-1 (or SCSI-2) + CD-ROM drives from 1989-1990 + */ + dev->buffer[7] = 0x88; /* Linked Command and Relative Addressing supported */ break; case CDROM_TYPE_PIONEER_DRM604X_2403: dev->buffer[4] = 42; @@ -3388,12 +3624,10 @@ begin: case CDROM_TYPE_NEC_38_103: case CDROM_TYPE_NEC_75_103: case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: break; default: - dev->buffer[6] = 0x01; /* 16-bit transfers supported */ - dev->buffer[7] = 0x20; /* Wide bus supported */ + dev->buffer[6] = 0x01; /* 16-bit transfers supported */ + dev->buffer[7] = 0x20; /* Wide bus supported */ break; } } @@ -3417,10 +3651,7 @@ begin: idx = 47; else { switch (dev->drv->type) { - case CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: + case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_XM5701TA_3136: idx = 96; break; default: @@ -3439,17 +3670,12 @@ atapi_out: len = MIN(len, max_len); - scsi_cdrom_set_buf_len(dev, BufLen, &len); + scsi_cdrom_set_buf_len(dev, BufLen, &max_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); @@ -3462,154 +3688,6 @@ atapi_out: scsi_cdrom_command_complete(dev); break; - case 0xC3: - switch (dev->drv->type) { - case CDROM_TYPE_MATSHITA_501_10b: /*GPCMD_READ_TOC_MATSUSHITA*/ - cdb[0] = GPCMD_READ_TOC_PMA_ATIP; - dev->current_cdb[0] = cdb[0]; - goto begin; - break; - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: /*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; - case CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: - case CDROM_TYPE_TOSHIBA_SDM1401_1008: /*GPCMD_SET_STOP_TIME_TOSHIBA*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_command_complete(dev); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - - case 0xDB: - switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: /*GPCMD_SET_STOP_TIME_NEC*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_command_complete(dev); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - - case 0xC2: - switch (dev->drv->type) { - case CDROM_TYPE_MATSHITA_501_10b: /*GPCMD_READ_SUBCHANNEL_MATSUSHITA*/ - cdb[0] = GPCMD_READ_SUBCHANNEL; - dev->current_cdb[0] = cdb[0]; - goto begin; - break; - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: /*GPCMD_READ_SUBCHANNEL_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_log("CD-ROM %i: Getting sub-channel type (%s), code-q = %02x\n", dev->id, msf ? "MSF" : "LBA", cdb[2] & 0x40); - - if (cdb[2] & 0x40) { - scsi_cdrom_buf_alloc(dev, 9); - memset(dev->buffer, 0, 9); - len = 9; - cdrom_get_current_subchannel_sony(dev->drv, dev->buffer, msf || dev->drv->sony_msf); - len = MIN(len, max_len); - scsi_cdrom_set_buf_len(dev, BufLen, &len); - scsi_cdrom_data_command_finish(dev, len, len, len, 0); - } else { - 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; - case CDROM_TYPE_PIONEER_DRM604X_2403: /*GPCMD_READ_SUBCODEQ_PIONEER*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); - - alloc_length = cdb[1] & 0x1f; - len = 9; - - if (!dev->drv->ops) { - scsi_cdrom_not_ready(dev); - return; - } - - if (!alloc_length) { - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - 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; - } - - scsi_cdrom_buf_alloc(dev, len); - len = MIN(len, alloc_length); - - memset(dev->buffer, 0, len); - cdrom_get_current_subcodeq(dev->drv, &dev->buffer[1]); - scsi_cdrom_log("Audio Status = %02x\n", dev->buffer[0]); - - scsi_cdrom_set_buf_len(dev, BufLen, &alloc_length); - scsi_cdrom_data_command_finish(dev, len, len, len, 0); - break; - case CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: - case CDROM_TYPE_TOSHIBA_SDM1401_1008: /*GPCMD_STILL_TOSHIBA*/ - 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; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - case GPCMD_SEEK_6: case GPCMD_SEEK_10: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); @@ -3625,20 +3703,13 @@ atapi_out: default: break; } + dev->drv->seek_diff = ABS((int) (pos - dev->drv->seek_pos)); + if (cdb[0] == GPCMD_SEEK_10) { switch (dev->drv->type) { - case CDROM_TYPE_NEC_25_10a: - case CDROM_TYPE_NEC_38_103: - case CDROM_TYPE_NEC_75_103: - case CDROM_TYPE_NEC_77_106: - case CDROM_TYPE_NEC_211_100: - case CDROM_TYPE_NEC_464_105: - case CDROM_TYPE_TOSHIBA_XM_3433: - case CDROM_TYPE_TOSHIBA_XM3201B_3232: - case CDROM_TYPE_TOSHIBA_XM3301TA_0272: - case CDROM_TYPE_TOSHIBA_XM5701TA_3136: - case CDROM_TYPE_TOSHIBA_SDM1401_1008: + case CDROM_TYPE_NEC_25_10a ... CDROM_TYPE_NEC_464_105: + case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_SDM1401_1008: cdrom_seek(dev->drv, pos, cdb[9] & 0xc0); break; default: @@ -3665,6 +3736,7 @@ atapi_out: dev->buffer[6] = 8; len = 8; + scsi_cdrom_log("CD-ROM Capacity=%x.\n", dev->drv->cdrom_capacity - 1); scsi_cdrom_set_buf_len(dev, BufLen, &len); scsi_cdrom_data_command_finish(dev, len, len, len, 0); @@ -3682,226 +3754,6 @@ atapi_out: scsi_cdrom_command_complete(dev); break; - case 0xC5: - switch (dev->drv->type) { - case CDROM_TYPE_MATSHITA_501_10b: /*GPCMD_PLAY_AUDIO_MATSUSHITA*/ - cdb[0] = GPCMD_PLAY_AUDIO_10; - dev->current_cdb[0] = cdb[0]; - goto begin; - break; - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: /*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; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - - case 0xC8: - switch (dev->drv->type) { - case CDROM_TYPE_MATSHITA_501_10b: /*GPCMD_PLAY_AUDIO_TRACK_INDEX_MATSUSHITA*/ - cdb[0] = GPCMD_PLAY_AUDIO_TRACK_INDEX; - dev->current_cdb[0] = cdb[0]; - goto begin; - break; - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: /*GPCMD_PLAY_AUDIO_SONY*/ - cdb[0] = GPCMD_PLAY_AUDIO_10; - dev->current_cdb[0] = cdb[0]; - dev->sony_vendor = 1; - goto begin; - break; - case CDROM_TYPE_PIONEER_DRM604X_2403: /*GPCMD_AUDIO_TRACK_SEARCH_PIONEER*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (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_track_search_pioneer(dev->drv, pos, cdb[1] & 1); - dev->drv->audio_op = (cdb[1] & 1) ? 0x03 : 0x02; - - if (ret) - scsi_cdrom_command_complete(dev); - else - scsi_cdrom_illegal_mode(dev); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - - case 0xC9: - switch (dev->drv->type) { - case CDROM_TYPE_MATSHITA_501_10b: /*GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10_MATSUSHITA*/ - cdb[0] = GPCMD_PLAY_AUDIO_TRACK_RELATIVE_10; - dev->current_cdb[0] = cdb[0]; - goto begin; - break; - case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: /*GPCMD_PLAYBACK_CONTROL_SONY*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); - dev->sony_vendor = 1; - - len = (cdb[7] << 8) | cdb[8]; - if (!len) { - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_log("CD-ROM %i: PlayBack Control Sony All done - callback set\n", dev->id); - dev->packet_status = PHASE_COMPLETE; - dev->callback = 20.0 * CDROM_TIME; - scsi_cdrom_set_callback(dev); - break; - } - 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 CDROM_TYPE_PIONEER_DRM604X_2403: /*GPCMD_PLAY_AUDIO_PIONEER*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if ((dev->drv->image_path[0] == 0x00) || (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_play_pioneer(dev->drv, pos); - - if (ret) - scsi_cdrom_command_complete(dev); - else - scsi_cdrom_illegal_mode(dev); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - - case 0xCA: - if (dev->drv->type == CDROM_TYPE_PIONEER_DRM604X_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); - } else { - scsi_cdrom_illegal_opcode(dev); - } - break; - - case 0xCB: - switch (dev->drv->type) { - case CDROM_TYPE_MATSHITA_501_10b: /*GPCMD_PAUSE_RESUME_MATSUSHITA*/ - cdb[0] = GPCMD_PAUSE_RESUME; - dev->current_cdb[0] = cdb[0]; - goto begin; - break; - case CDROM_TYPE_PIONEER_DRM604X_2403: /*GPCMD_STOP_PIONEER*/ - scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - scsi_cdrom_stop(sc); - scsi_cdrom_command_complete(dev); - break; - default: - scsi_cdrom_illegal_opcode(dev); - break; - } - break; - - case 0xCC: - if (dev->drv->type == CDROM_TYPE_PIONEER_DRM604X_2403) { /*GPCMD_PLAYBACK_STATUS_PIONEER*/ - 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, 6); - - len = 6; - - memset(dev->buffer, 0, 6); - dev->buffer[0] = cdrom_get_audio_status_pioneer(dev->drv, &dev->buffer[1]); /*Audio status*/ - - 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); - } else { - scsi_cdrom_illegal_opcode(dev); - } - break; - - case 0xE0: - if (dev->drv->type == CDROM_TYPE_PIONEER_DRM604X_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; - } else { - scsi_cdrom_illegal_opcode(dev); - } - break; - - case 0xE5: - if (dev->drv->type == CDROM_TYPE_MATSHITA_501_10b) { /*GPCMD_PLAY_AUDIO_12_MATSUSHITA*/ - cdb[0] = GPCMD_PLAY_AUDIO_12; - dev->current_cdb[0] = cdb[0]; - goto begin; - } else { - scsi_cdrom_illegal_opcode(dev); - } - break; - - case 0xE9: - if (dev->drv->type == CDROM_TYPE_MATSHITA_501_10b) { /*GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12_MATSUSHITA*/ - cdb[0] = GPCMD_PLAY_AUDIO_TRACK_RELATIVE_12; - dev->current_cdb[0] = cdb[0]; - goto begin; - } - fallthrough; default: scsi_cdrom_illegal_opcode(dev); break; @@ -3959,6 +3811,7 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) block_desc_len = dev->buffer[2]; block_desc_len <<= 8; block_desc_len |= dev->buffer[3]; + scsi_cdrom_log("BlockDescLen (6)=%d, ParamListLen (6)=%d.\n", block_desc_len, param_list_len); } else { block_desc_len = dev->buffer[6]; block_desc_len <<= 8; @@ -3967,8 +3820,21 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) } else block_desc_len = 0; + if (block_desc_len >= 8) { + pos = hdr_len + 5; + + dev->drv->sector_size = (dev->drv->sector_size & 0x0000ffff) | (dev->buffer[pos++] << 16); + dev->drv->sector_size = (dev->drv->sector_size & 0x00ff00ff) | (dev->buffer[pos++] << 8); + dev->drv->sector_size = (dev->drv->sector_size & 0x00ffff00) | (dev->buffer[pos++]); + scsi_cdrom_log("CD-ROM %i: Sector size now %i bytes\n", dev->id, dev->drv->sector_size); + } + pos = hdr_len + block_desc_len; +#ifdef ENABLE_SCSI_CDROM_LOG + for (uint16_t j = 0; j < pos; j++) + scsi_cdrom_log("Buffer Mode Select, pos=%d, data=%02x.\n", j, dev->buffer[j]); +#endif while (1) { if (pos >= param_list_len) { scsi_cdrom_log("CD-ROM %i: Buffer has only block descriptor\n", dev->id); @@ -3982,10 +3848,11 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: + if ((page == 0x08) && (page_len == 0x02)) + dev->drv->sony_msf = dev->buffer[pos] & 0x01; + 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; @@ -3998,7 +3865,8 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) 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); + scsi_cdrom_log("CD-ROM %i: Unchangeable value on position " + "%02X on page %02X\n", dev->id, i + 2, page); error |= 1; } } @@ -4018,7 +3886,8 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) 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); + scsi_cdrom_log("CD-ROM %i: Unchangeable value on position " + "%02X on page %02X\n", dev->id, i + 2, page); error |= 1; } } @@ -4031,10 +3900,8 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: val = scsi_cdrom_mode_sense_pages_default_sony_scsi.pages[page][0] & 0x80; break; default: @@ -4060,13 +3927,10 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) case 0xC9: switch (dev->drv->type) { case CDROM_TYPE_DEC_RRD45_0436: - case CDROM_TYPE_SONY_CDU541_10i: - case CDROM_TYPE_SONY_CDU561_18k: - case CDROM_TYPE_SONY_CDU76S_100: - case CDROM_TYPE_TEXEL_DMXX24_100: - for (i = 0; i < 18; i++) { + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: + for (i = 0; i < 18; i++) dev->ms_pages_saved_sony.pages[GPMODE_CDROM_AUDIO_PAGE_SONY][i] = dev->buffer[i]; - } break; default: break; @@ -4303,6 +4167,8 @@ scsi_cdrom_drive_reset(int c) drv->get_channel = scsi_cdrom_get_channel; drv->close = scsi_cdrom_close; + drv->sector_size = 2048; + if (drv->bus_type == CDROM_BUS_SCSI) { valid = 1; @@ -4352,6 +4218,32 @@ scsi_cdrom_drive_reset(int c) scsi_cdrom_log("ATAPI CD-ROM drive %i attached to IDE channel %i\n", c, cdrom[c].ide_channel); } + switch (dev->drv->type) { + case CDROM_TYPE_CHINON_CDS431_H42: + dev->ven_cmd = scsi_cdrom_command_chinon; + break; + case CDROM_TYPE_DEC_RRD45_0436: + case CDROM_TYPE_ShinaKen_DM3x1S_104 ... CDROM_TYPE_SONY_CDU76S_100: + case CDROM_TYPE_TEXEL_DM3024_100 ... CDROM_TYPE_TEXEL_DM3028_106: + dev->ven_cmd = scsi_cdrom_command_dec_sony_texel; + break; + case CDROM_TYPE_MATSHITA_501_10b: + dev->ven_cmd = scsi_cdrom_command_matsushita; + break; + case CDROM_TYPE_NEC_25_10a ... CDROM_TYPE_NEC_464_105: + dev->ven_cmd = scsi_cdrom_command_nec; + break; + case CDROM_TYPE_PIONEER_DRM604X_2403: + dev->ven_cmd = scsi_cdrom_command_pioneer; + break; + case CDROM_TYPE_TOSHIBA_XM_3433 ... CDROM_TYPE_TOSHIBA_SDM1401_1008: + dev->ven_cmd = scsi_cdrom_command_toshiba; + break; + default: + dev->ven_cmd = NULL; + break; + } + if (valid) scsi_cdrom_init(dev); } diff --git a/src/unix/dummy_cdrom_ioctl.c b/src/unix/dummy_cdrom_ioctl.c index bf656177b..8555642e6 100644 --- a/src/unix/dummy_cdrom_ioctl.c +++ b/src/unix/dummy_cdrom_ioctl.c @@ -218,18 +218,14 @@ plat_cdrom_get_sector_size(UNUSED(void *local), UNUSED(uint32_t sector)) } int -plat_cdrom_read_sector(void *local, uint8_t *buffer, int raw, uint32_t sector) +plat_cdrom_read_sector(void *local, uint8_t *buffer, uint32_t sector) { dummy_cdrom_ioctl_t *ioctl = (dummy_cdrom_ioctl_t *) local; plat_cdrom_open(ioctl); - if (raw) - /* Raw */ - dummy_cdrom_ioctl_log("Raw\n"); - else - /* Cooked */ - dummy_cdrom_ioctl_log("Cooked\n"); + /* Raw */ + dummy_cdrom_ioctl_log("Raw\n"); plat_cdrom_close(ioctl);