Extensive rework of SCSI and ATAPI devices and numerous bug fixes and cleanups;
Extensive rework of CD-ROM image handling; The settings save code now forces some devices' (SCSI disk, CD-ROM, etc.) pointers to NULL before resetting the machine - fixes segmentation faults after changing settings; Added the NCR 53c825A and 53c875 SCSI controllers; Fixed IDE/ATAPI DMA; Slight changed to PCI IDE bus master operation.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Generic CD-ROM drive core.
|
||||
*
|
||||
* Version: @(#)cdrom.c 1.0.5 2018/10/26
|
||||
* Version: @(#)cdrom.c 1.0.6 2018/10/28
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
@@ -30,10 +30,66 @@
|
||||
#include "../sound/sound.h"
|
||||
|
||||
|
||||
/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong:
|
||||
there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start
|
||||
of the audio while audio still plays. With an absolute conversion, the counter is fine. */
|
||||
#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f)
|
||||
|
||||
#define RAW_SECTOR_SIZE 2352
|
||||
#define COOKED_SECTOR_SIZE 2048
|
||||
|
||||
#define MIN_SEEK 2000
|
||||
#define MAX_SEEK 333333
|
||||
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct {
|
||||
uint8_t user_data[2048],
|
||||
ecc[288];
|
||||
} m1_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t sub_header[8],
|
||||
user_data[2328];
|
||||
} m2_data_t;
|
||||
|
||||
typedef union {
|
||||
m1_data_t m1_data;
|
||||
m2_data_t m2_data;
|
||||
uint8_t raw_data[2336];
|
||||
} sector_data_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t sync[12];
|
||||
uint8_t header[4];
|
||||
sector_data_t data;
|
||||
} sector_raw_data_t;
|
||||
|
||||
typedef union {
|
||||
sector_raw_data_t sector_data;
|
||||
uint8_t raw_data[2352];
|
||||
} sector_t;
|
||||
|
||||
typedef struct {
|
||||
sector_t sector;
|
||||
uint8_t c2[296];
|
||||
uint8_t subchannel_raw[96];
|
||||
uint8_t subchannel_q[16];
|
||||
uint8_t subchannel_rw[96];
|
||||
} cdrom_sector_t;
|
||||
|
||||
typedef union {
|
||||
cdrom_sector_t cdrom_sector;
|
||||
uint8_t buffer[2856];
|
||||
} sector_buffer_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
static int cdrom_sector_size;
|
||||
static uint8_t raw_buffer[2856]; /* Needs to be the same size as sector_buffer_t in the structs. */
|
||||
static uint8_t extra_buffer[296];
|
||||
|
||||
|
||||
cdrom_t cdrom[CDROM_NUM];
|
||||
|
||||
|
||||
@@ -157,36 +213,751 @@ cdrom_seek_time(cdrom_t *dev)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cdrom_stop(cdrom_t *dev)
|
||||
{
|
||||
if (dev->cd_status > CD_STATUS_DATA_ONLY)
|
||||
dev->cd_status = CD_STATUS_STOPPED;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cdrom_seek(cdrom_t *dev, uint32_t pos)
|
||||
{
|
||||
/* cdrom_log("CD-ROM %i: Seek %08X\n", dev->id, pos); */
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
cdrom_log("CD-ROM %i: Seek to LBA %08X\n", dev->id, pos);
|
||||
|
||||
dev->seek_pos = pos;
|
||||
if (dev->ops && dev->ops->stop)
|
||||
dev->ops->stop(dev);
|
||||
cdrom_stop(dev);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdrom_playing_completed(cdrom_t *dev)
|
||||
cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len)
|
||||
{
|
||||
dev->prev_status = dev->cd_status;
|
||||
int ret = 1;
|
||||
|
||||
if (dev->ops && dev->ops->status)
|
||||
dev->cd_status = dev->ops->status(dev);
|
||||
else {
|
||||
dev->cd_status = CD_STATUS_EMPTY;
|
||||
if (!dev->sound_on || (dev->cd_status != CD_STATUS_PLAYING)) {
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (((dev->prev_status == CD_STATUS_PLAYING) || (dev->prev_status == CD_STATUS_PAUSED)) &&
|
||||
((dev->cd_status != CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_PAUSED)))
|
||||
return 1;
|
||||
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)) {
|
||||
cdrom_log("CD-ROM %i: Read LBA %08X successful\n", dev->id, dev->seek_pos);
|
||||
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;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
memcpy(output, dev->cd_buffer, len * 2);
|
||||
memmove(dev->cd_buffer, &dev->cd_buffer[len], (BUF_SIZE - len) * 2);
|
||||
dev->cd_buflen -= len;
|
||||
|
||||
cdrom_log("CD-ROM %i: Audio callback returning %i\n", dev->id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
uint8_t
|
||||
cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf)
|
||||
{
|
||||
track_info_t ti;
|
||||
int m = 0, s = 0, f = 0;
|
||||
|
||||
if (dev->cd_status == CD_STATUS_DATA_ONLY)
|
||||
return 0;
|
||||
|
||||
cdrom_log("CD-ROM %i: Play audio - %08X %08X %i\n", dev->id, pos, len, ismsf);
|
||||
if (ismsf == 2) {
|
||||
dev->ops->get_track_info(dev, pos, 0, &ti);
|
||||
pos = MSFtoLBA(ti.m, ti.s, ti.f) - 150;
|
||||
/* We have to end at the *end* of the specified track,
|
||||
not at the beginning. */
|
||||
dev->ops->get_track_info(dev, len, 1, &ti);
|
||||
len = MSFtoLBA(ti.m, ti.s, ti.f) - 150;
|
||||
} else if (ismsf == 1) {
|
||||
m = (pos >> 16) & 0xff;
|
||||
s = (pos >> 8) & 0xff;
|
||||
f = pos & 0xff;
|
||||
|
||||
if (pos == 0xffffff) {
|
||||
cdrom_log("CD-ROM %i: Playing from current position (MSF)\n", dev->id);
|
||||
pos = dev->seek_pos;
|
||||
} else
|
||||
pos = MSFtoLBA(m, s, f) - 150;
|
||||
|
||||
m = (len >> 16) & 0xff;
|
||||
s = (len >> 8) & 0xff;
|
||||
f = len & 0xff;
|
||||
len = MSFtoLBA(m, s, f) - 150;
|
||||
|
||||
cdrom_log("CD-ROM %i: MSF - pos = %08X len = %08X\n", dev->id, pos, len);
|
||||
} else if (ismsf == 0) {
|
||||
if (pos == 0xffffffff) {
|
||||
cdrom_log("CD-ROM %i: Playing from current position\n", dev->id);
|
||||
pos = dev->seek_pos;
|
||||
}
|
||||
len += pos;
|
||||
}
|
||||
|
||||
/* Do this at this point, since it's at this point that we know the
|
||||
actual LBA position to start playing from. */
|
||||
if (!(dev->ops->track_type(dev, pos) & CD_TRACK_AUDIO)) {
|
||||
pclog("CD-ROM %i: LBA %08X not on an audio track\n", dev->id, pos);
|
||||
cdrom_stop(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev->seek_pos = pos;
|
||||
dev->cd_end = len;
|
||||
dev->cd_status = CD_STATUS_PLAYING;
|
||||
dev->cd_buflen = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
cdrom_audio_pause_resume(cdrom_t *dev, uint8_t resume)
|
||||
{
|
||||
if ((dev->cd_status == CD_STATUS_PLAYING) || (dev->cd_status == CD_STATUS_PAUSED))
|
||||
dev->cd_status = (dev->cd_status & 0xfe) | (resume & 0x01);
|
||||
}
|
||||
|
||||
|
||||
uint8_t
|
||||
cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf)
|
||||
{
|
||||
uint8_t ret;
|
||||
subchannel_t subc;
|
||||
int pos = 0;
|
||||
|
||||
dev->ops->get_subchannel(dev, dev->seek_pos, &subc);
|
||||
cdrom_log("CD-ROM %i: Returned subchannel at %02i:%02i.%02i\n", subc.abs_m, subc.abs_s, subc.abs_f);
|
||||
|
||||
if (dev->cd_status == CD_STATUS_DATA_ONLY)
|
||||
ret = 0x15;
|
||||
else {
|
||||
if (dev->cd_status == CD_STATUS_PLAYING)
|
||||
ret = 0x11;
|
||||
else if (dev->cd_status == CD_STATUS_PAUSED)
|
||||
ret = 0x12;
|
||||
else
|
||||
ret = 0x13;
|
||||
}
|
||||
|
||||
b[pos++] = subc.attr;
|
||||
b[pos++] = subc.track;
|
||||
b[pos++] = subc.index;
|
||||
|
||||
if (msf) {
|
||||
b[pos] = 0;
|
||||
b[pos + 1] = subc.abs_m;
|
||||
b[pos + 2] = subc.abs_s;
|
||||
b[pos + 3] = subc.abs_f;
|
||||
pos += 4;
|
||||
b[pos] = 0;
|
||||
b[pos + 1] = subc.rel_m;
|
||||
b[pos + 2] = subc.rel_s;
|
||||
b[pos + 3] = subc.rel_f;
|
||||
pos += 4;
|
||||
} else {
|
||||
uint32_t 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;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
read_toc_normal(cdrom_t *dev, unsigned char *b, unsigned char start_track, int msf)
|
||||
{
|
||||
track_info_t ti;
|
||||
int len = 4;
|
||||
int c, d, first_track, last_track;
|
||||
uint32_t temp;
|
||||
|
||||
dev->ops->get_tracks(dev, &first_track, &last_track);
|
||||
|
||||
b[2] = first_track;
|
||||
b[3] = last_track;
|
||||
|
||||
d = 0;
|
||||
for (c = 0; c <= last_track; c++) {
|
||||
dev->ops->get_track_info(dev, c + 1, 0, &ti);
|
||||
if (ti.number >= start_track) {
|
||||
d = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (start_track != 0xAA) {
|
||||
dev->ops->get_track_info(dev, c + 1, 0, &ti);
|
||||
b[2] = ti.number;
|
||||
}
|
||||
|
||||
for (c = d; c <= last_track; c++) {
|
||||
dev->ops->get_track_info(dev, c + 1, 0, &ti);
|
||||
|
||||
b[len++] = 0; /* reserved */
|
||||
b[len++] = ti.attr;
|
||||
b[len++] = ti.number; /* track number */
|
||||
b[len++] = 0; /* reserved */
|
||||
|
||||
if (msf) {
|
||||
b[len++] = 0;
|
||||
b[len++] = ti.m;
|
||||
b[len++] = ti.s;
|
||||
b[len++] = ti.f;
|
||||
} else {
|
||||
temp = MSFtoLBA(ti.m, ti.s, ti.f) - 150;
|
||||
b[len++] = temp >> 24;
|
||||
b[len++] = temp >> 16;
|
||||
b[len++] = temp >> 8;
|
||||
b[len++] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
read_toc_session(cdrom_t *dev, unsigned char *b, int msf)
|
||||
{
|
||||
track_info_t ti;
|
||||
int len = 4;
|
||||
uint32_t temp;
|
||||
|
||||
dev->ops->get_track_info(dev, 1, 0, &ti);
|
||||
|
||||
if (ti.number == 0)
|
||||
ti.number = 1;
|
||||
|
||||
b[2] = b[3] = 1;
|
||||
b[len++] = 0; /* reserved */
|
||||
b[len++] = ti.attr;
|
||||
b[len++] = ti.number; /* track number */
|
||||
b[len++] = 0; /* reserved */
|
||||
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; /* Do the - 150. */
|
||||
b[len++] = temp >> 24;
|
||||
b[len++] = temp >> 16;
|
||||
b[len++] = temp >> 8;
|
||||
b[len++] = temp;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
read_toc_raw(cdrom_t *dev, unsigned char *b)
|
||||
{
|
||||
track_info_t ti;
|
||||
int first_track, last_track;
|
||||
int track, len = 4;
|
||||
|
||||
dev->ops->get_tracks(dev, &first_track, &last_track);
|
||||
|
||||
b[2] = first_track;
|
||||
b[3] = last_track;
|
||||
|
||||
for (track = first_track; track <= last_track; track++) {
|
||||
dev->ops->get_track_info(dev, track, 0, &ti);
|
||||
|
||||
b[len++] = track;
|
||||
b[len++] = ti.attr;
|
||||
b[len++] = 0;
|
||||
b[len++] = 0;
|
||||
b[len++] = 0;
|
||||
b[len++] = 0;
|
||||
b[len++] = 0;
|
||||
b[len++] = 0;
|
||||
b[len++] = ti.m;
|
||||
b[len++] = ti.s;
|
||||
b[len++] = ti.f;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, unsigned char start_track, int msf, int max_len)
|
||||
{
|
||||
int len;
|
||||
|
||||
switch(type) {
|
||||
case CD_TOC_NORMAL:
|
||||
len = read_toc_normal(dev, b, start_track, msf);
|
||||
break;
|
||||
case CD_TOC_SESSION:
|
||||
len = read_toc_session(dev, b, msf);
|
||||
break;
|
||||
case CD_TOC_RAW:
|
||||
len = read_toc_raw(dev, b);
|
||||
break;
|
||||
default:
|
||||
cdrom_log("CD-ROM %i: Unknown TOC read type: %i\n", dev->id, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = MIN(len, max_len);
|
||||
|
||||
b[0] = (uint8_t) (((len - 2) >> 8) & 0xff);
|
||||
b[1] = (uint8_t) ((len - 2) & 0xff);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
track_type_is_valid(uint8_t id, int type, int flags, int audio, int mode2)
|
||||
{
|
||||
if (!(flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */
|
||||
cdrom_log("CD-ROM %i: [Any Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((type != 1) && !audio) {
|
||||
if (!(flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */
|
||||
cdrom_log("CD-ROM %i: [Any Data Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((flags & 0x06) == 0x06) {
|
||||
cdrom_log("CD-ROM %i: [Any Data Mode] Invalid error flags\n", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (((flags & 0x700) == 0x300) || ((flags & 0x700) > 0x400)) {
|
||||
cdrom_log("CD-ROM %i: [Any Data Mode] Invalid subchannel data flags (%02X)\n", id, flags & 0x700);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((flags & 0x18) == 0x08) { /* EDC/ECC without user data is an illegal mode */
|
||||
cdrom_log("CD-ROM %i: [Any Data Mode] EDC/ECC without user data is an illegal mode\n", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (((flags & 0xf0) == 0x90) || ((flags & 0xf0) == 0xc0)) { /* 0x90/0x98/0xC0/0xC8 are illegal modes */
|
||||
cdrom_log("CD-ROM %i: [Any Data Mode] 0x90/0x98/0xC0/0xC8 are illegal modes\n", id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (((type > 3) && (type != 8)) || (mode2 && (mode2 & 0x03))) {
|
||||
if ((flags & 0xf0) == 0x30) { /* 0x30/0x38 are illegal modes */
|
||||
cdrom_log("CD-ROM %i: [Any XA Mode 2] 0x30/0x38 are illegal modes\n", id);
|
||||
return 0;
|
||||
}
|
||||
if (((flags & 0xf0) == 0xb0) || ((flags & 0xf0) == 0xd0)) { /* 0xBx and 0xDx are illegal modes */
|
||||
cdrom_log("CD-ROM %i: [Any XA Mode 2] 0xBx and 0xDx are illegal modes\n", id);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
read_sector_to_buffer(cdrom_t *dev, uint8_t *rbuf, uint32_t msf, uint32_t lba, int mode2, int len)
|
||||
{
|
||||
uint8_t *bb = rbuf;
|
||||
|
||||
dev->ops->read_sector(dev, CD_READ_DATA, rbuf + 16, 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);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
read_audio(cdrom_t *dev, uint32_t lba, uint8_t *b)
|
||||
{
|
||||
dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba);
|
||||
|
||||
memcpy(b, raw_buffer, 2352);
|
||||
|
||||
cdrom_sector_size = 2352;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
read_mode1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b)
|
||||
{
|
||||
if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2048))
|
||||
read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048);
|
||||
else
|
||||
dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba);
|
||||
|
||||
cdrom_sector_size = 0;
|
||||
|
||||
if (cdrom_sector_flags & 0x80) { /* Sync */
|
||||
cdrom_log("CD-ROM %i: [Mode 1] Sync\n", dev->id);
|
||||
memcpy(b, raw_buffer, 12);
|
||||
cdrom_sector_size += 12;
|
||||
b += 12;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x20) { /* Header */
|
||||
cdrom_log("CD-ROM %i: [Mode 1] Header\n", dev->id);
|
||||
memcpy(b, raw_buffer + 12, 4);
|
||||
cdrom_sector_size += 4;
|
||||
b += 4;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x40) { /* Sub-header */
|
||||
if (!(cdrom_sector_flags & 0x10)) { /* No user data */
|
||||
cdrom_log("CD-ROM %i: [Mode 1] Sub-header\n", dev->id);
|
||||
memcpy(b, raw_buffer + 16, 8);
|
||||
cdrom_sector_size += 8;
|
||||
b += 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x10) { /* User data */
|
||||
cdrom_log("CD-ROM %i: [Mode 1] User data\n", dev->id);
|
||||
memcpy(b, raw_buffer + 16, 2048);
|
||||
cdrom_sector_size += 2048;
|
||||
b += 2048;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x08) { /* EDC/ECC */
|
||||
cdrom_log("CD-ROM %i: [Mode 1] EDC/ECC\n", dev->id);
|
||||
memcpy(b, raw_buffer + 2064, 288);
|
||||
cdrom_sector_size += 288;
|
||||
b += 288;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
read_mode2_non_xa(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b)
|
||||
{
|
||||
if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2336))
|
||||
read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2336);
|
||||
else
|
||||
dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba);
|
||||
|
||||
cdrom_sector_size = 0;
|
||||
|
||||
if (cdrom_sector_flags & 0x80) { /* Sync */
|
||||
cdrom_log("CD-ROM %i: [Mode 2 Formless] Sync\n", dev->id);
|
||||
memcpy(b, raw_buffer, 12);
|
||||
cdrom_sector_size += 12;
|
||||
b += 12;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x20) { /* Header */
|
||||
cdrom_log("CD-ROM %i: [Mode 2 Formless] Header\n", dev->id);
|
||||
memcpy(b, raw_buffer + 12, 4);
|
||||
cdrom_sector_size += 4;
|
||||
b += 4;
|
||||
}
|
||||
|
||||
/* Mode 1 sector, expected type is 1 type. */
|
||||
if (cdrom_sector_flags & 0x40) { /* Sub-header */
|
||||
cdrom_log("CD-ROM %i: [Mode 2 Formless] Sub-header\n", dev->id);
|
||||
memcpy(b, raw_buffer + 16, 8);
|
||||
cdrom_sector_size += 8;
|
||||
b += 8;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x10) { /* User data */
|
||||
cdrom_log("CD-ROM %i: [Mode 2 Formless] User data\n", dev->id);
|
||||
memcpy(b, raw_buffer + 24, 2336);
|
||||
cdrom_sector_size += 2336;
|
||||
b += 2336;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
read_mode2_xa_form1(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b)
|
||||
{
|
||||
if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2048))
|
||||
read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048);
|
||||
else
|
||||
dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba);
|
||||
|
||||
cdrom_sector_size = 0;
|
||||
|
||||
if (cdrom_sector_flags & 0x80) { /* Sync */
|
||||
cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Sync\n", dev->id);
|
||||
memcpy(b, raw_buffer, 12);
|
||||
cdrom_sector_size += 12;
|
||||
b += 12;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x20) { /* Header */
|
||||
cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Header\n", dev->id);
|
||||
memcpy(b, raw_buffer + 12, 4);
|
||||
cdrom_sector_size += 4;
|
||||
b += 4;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x40) { /* Sub-header */
|
||||
cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] Sub-header\n", dev->id);
|
||||
memcpy(b, raw_buffer + 16, 8);
|
||||
cdrom_sector_size += 8;
|
||||
b += 8;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x10) { /* User data */
|
||||
cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] User data\n", dev->id);
|
||||
memcpy(b, raw_buffer + 24, 2048);
|
||||
cdrom_sector_size += 2048;
|
||||
b += 2048;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x08) { /* EDC/ECC */
|
||||
cdrom_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC\n", dev->id);
|
||||
memcpy(b, raw_buffer + 2072, 280);
|
||||
cdrom_sector_size += 280;
|
||||
b += 280;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
read_mode2_xa_form2(cdrom_t *dev, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b)
|
||||
{
|
||||
if ((dev->cd_status == CD_STATUS_DATA_ONLY) || (dev->ops->sector_size(dev, lba) == 2324))
|
||||
read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2324);
|
||||
else
|
||||
dev->ops->read_sector(dev, CD_READ_RAW, raw_buffer, lba);
|
||||
|
||||
cdrom_sector_size = 0;
|
||||
|
||||
if (cdrom_sector_flags & 0x80) { /* Sync */
|
||||
cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Sync\n", dev->id);
|
||||
memcpy(b, raw_buffer, 12);
|
||||
cdrom_sector_size += 12;
|
||||
b += 12;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x20) { /* Header */
|
||||
cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Header\n", dev->id);
|
||||
memcpy(b, raw_buffer + 12, 4);
|
||||
cdrom_sector_size += 4;
|
||||
b += 4;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x40) { /* Sub-header */
|
||||
cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] Sub-header\n", dev->id);
|
||||
memcpy(b, raw_buffer + 16, 8);
|
||||
cdrom_sector_size += 8;
|
||||
b += 8;
|
||||
}
|
||||
|
||||
if (cdrom_sector_flags & 0x10) { /* User data */
|
||||
cdrom_log("CD-ROM %i: [XA Mode 2 Form 2] User data\n", dev->id);
|
||||
memcpy(b, raw_buffer + 24, 2328);
|
||||
cdrom_sector_size += 2328;
|
||||
b += 2328;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type,
|
||||
int cdrom_sector_flags, int *len)
|
||||
{
|
||||
uint8_t *b, *temp_b;
|
||||
uint32_t msf, lba;
|
||||
int audio = 0, mode2 = 0;
|
||||
int m, s, f;
|
||||
|
||||
if (dev->cd_status == CD_STATUS_EMPTY)
|
||||
return 0;
|
||||
|
||||
b = temp_b = buffer;
|
||||
|
||||
*len = 0;
|
||||
|
||||
if (ismsf) {
|
||||
m = (sector >> 16) & 0xff;
|
||||
s = (sector >> 8) & 0xff;
|
||||
f = sector & 0xff;
|
||||
lba = MSFtoLBA(m, s, f) - 150;
|
||||
msf = sector;
|
||||
} else {
|
||||
lba = sector;
|
||||
msf = cdrom_lba_to_msf_accurate(sector);
|
||||
}
|
||||
|
||||
if (dev->ops->track_type)
|
||||
audio = dev->ops->track_type(dev, lba);
|
||||
|
||||
mode2 = audio & ~CD_TRACK_AUDIO;
|
||||
audio &= CD_TRACK_AUDIO;
|
||||
|
||||
memset(raw_buffer, 0, 2448);
|
||||
memset(extra_buffer, 0, 296);
|
||||
|
||||
if (!(cdrom_sector_flags & 0xf0)) { /* 0x00 and 0x08 are illegal modes */
|
||||
cdrom_log("CD-ROM %i: [Mode 1] 0x00 and 0x08 are illegal modes\n", dev->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!track_type_is_valid(dev->id, cdrom_sector_type, cdrom_sector_flags, audio, mode2))
|
||||
return 0;
|
||||
|
||||
if ((cdrom_sector_type > 5) && (cdrom_sector_type != 8)) {
|
||||
cdrom_log("CD-ROM %i: Attempting to read an unrecognized sector type from an image\n", dev->id);
|
||||
return 0;
|
||||
} else if (cdrom_sector_type == 1) {
|
||||
if (!audio || (dev->cd_status == CD_STATUS_DATA_ONLY)) {
|
||||
cdrom_log("CD-ROM %i: [Audio] Attempting to read an audio sector from a data image\n", dev->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
read_audio(dev, lba, temp_b);
|
||||
} else if (cdrom_sector_type == 2) {
|
||||
if (audio || mode2) {
|
||||
cdrom_log("CD-ROM %i: [Mode 1] Attempting to read a sector of another type\n", dev->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, 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;
|
||||
}
|
||||
|
||||
read_mode2_non_xa(dev, cdrom_sector_flags, lba, msf, mode2, 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);
|
||||
} 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;
|
||||
}
|
||||
|
||||
read_mode2_xa_form2(dev, cdrom_sector_flags, lba, msf, mode2, 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))
|
||||
read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b);
|
||||
else if (!mode2)
|
||||
read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, 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);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (mode2) {
|
||||
if ((mode2 & 0x03) == 0x01)
|
||||
read_mode2_xa_form1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b);
|
||||
else if ((mode2 & 0x03) == 0x02)
|
||||
read_mode2_xa_form2(dev, cdrom_sector_flags, lba, msf, mode2, temp_b);
|
||||
else
|
||||
read_mode2_non_xa(dev, cdrom_sector_flags, lba, msf, mode2, temp_b);
|
||||
} else {
|
||||
if (audio)
|
||||
read_audio(dev, lba, temp_b);
|
||||
else
|
||||
read_mode1(dev, cdrom_sector_flags, lba, msf, mode2, temp_b);
|
||||
}
|
||||
}
|
||||
|
||||
if ((cdrom_sector_flags & 0x06) == 0x02) {
|
||||
/* Add error flags. */
|
||||
cdrom_log("CD-ROM %i: Error flags\n", dev->id);
|
||||
memcpy(b + cdrom_sector_size, extra_buffer, 294);
|
||||
cdrom_sector_size += 294;
|
||||
} else if ((cdrom_sector_flags & 0x06) == 0x04) {
|
||||
/* Add error flags. */
|
||||
cdrom_log("CD-ROM %i: Full error flags\n", dev->id);
|
||||
memcpy(b + cdrom_sector_size, extra_buffer, 296);
|
||||
cdrom_sector_size += 296;
|
||||
}
|
||||
|
||||
if ((cdrom_sector_flags & 0x700) == 0x100) {
|
||||
cdrom_log("CD-ROM %i: Raw subchannel data\n", dev->id);
|
||||
memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96);
|
||||
cdrom_sector_size += 96;
|
||||
} else if ((cdrom_sector_flags & 0x700) == 0x200) {
|
||||
cdrom_log("CD-ROM %i: Q subchannel data\n", dev->id);
|
||||
memcpy(b + cdrom_sector_size, raw_buffer + 2352, 16);
|
||||
cdrom_sector_size += 16;
|
||||
} else if ((cdrom_sector_flags & 0x700) == 0x400) {
|
||||
cdrom_log("CD-ROM %i: R/W subchannel data\n", dev->id);
|
||||
memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96);
|
||||
cdrom_sector_size += 96;
|
||||
}
|
||||
|
||||
*len = cdrom_sector_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -219,7 +990,7 @@ cdrom_hard_reset(void)
|
||||
for (i = 0; i < CDROM_NUM; i++) {
|
||||
dev = &cdrom[i];
|
||||
if (dev->bus_type) {
|
||||
cdrom_log("CDROM %i: hard_reset\n", i);
|
||||
cdrom_log("CD-ROM %i: Hard reset\n", i);
|
||||
|
||||
dev->id = i;
|
||||
|
||||
@@ -235,11 +1006,10 @@ cdrom_hard_reset(void)
|
||||
break;
|
||||
}
|
||||
|
||||
dev->cd_status = CD_STATUS_EMPTY;
|
||||
|
||||
if (dev->host_drive == 200) {
|
||||
if (dev->host_drive == 200)
|
||||
cdrom_image_open(dev, dev->image_path);
|
||||
cdrom_image_reset(dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,14 +1026,13 @@ cdrom_close(void)
|
||||
for (i = 0; i < CDROM_NUM; i++) {
|
||||
dev = &cdrom[i];
|
||||
|
||||
if (dev->close)
|
||||
dev->close(dev->priv);
|
||||
|
||||
if (dev->ops && dev->ops->exit)
|
||||
dev->ops->exit(dev);
|
||||
|
||||
dev->ops = NULL;
|
||||
|
||||
if (dev->close)
|
||||
dev->close(dev->priv);
|
||||
|
||||
dev->priv = NULL;
|
||||
|
||||
cdrom_drive_reset(dev);
|
||||
@@ -296,15 +1065,8 @@ cdrom_eject(uint8_t id)
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->prev_image_path) {
|
||||
free(dev->prev_image_path);
|
||||
dev->prev_image_path = NULL;
|
||||
}
|
||||
|
||||
if (dev->host_drive == 200) {
|
||||
dev->prev_image_path = (wchar_t *) malloc(1024 * sizeof(wchar_t));
|
||||
if (dev->host_drive == 200)
|
||||
wcscpy(dev->prev_image_path, dev->image_path);
|
||||
}
|
||||
|
||||
dev->prev_host_drive = dev->host_drive;
|
||||
dev->host_drive = 0;
|
||||
@@ -341,8 +1103,6 @@ cdrom_reload(uint8_t id)
|
||||
if (dev->prev_host_drive == 200) {
|
||||
/* Reload a previous image. */
|
||||
wcscpy(dev->image_path, dev->prev_image_path);
|
||||
free(dev->prev_image_path);
|
||||
dev->prev_image_path = NULL;
|
||||
cdrom_image_open(dev, dev->image_path);
|
||||
|
||||
cdrom_insert(id);
|
||||
|
||||
Reference in New Issue
Block a user