diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index b8935e66e..43ba6b554 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -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, * @@ -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); diff --git a/src/cdrom/cdrom.h b/src/cdrom/cdrom.h index 60f6adc16..92e947af3 100644 --- a/src/cdrom/cdrom.h +++ b/src/cdrom/cdrom.h @@ -8,7 +8,7 @@ * * Generic CD-ROM drive core header. * - * Version: @(#)cdrom.h 1.0.16 2018/10/26 + * Version: @(#)cdrom.h 1.0.17 2018/10/28 * * Author: Miran Grca, * @@ -22,9 +22,24 @@ #define CD_STATUS_EMPTY 0 #define CD_STATUS_DATA_ONLY 1 -#define CD_STATUS_PLAYING 2 -#define CD_STATUS_PAUSED 3 +#define CD_STATUS_PAUSED 2 +#define CD_STATUS_PLAYING 3 #define CD_STATUS_STOPPED 4 +#define CD_STATUS_PLAYING_COMPLETED 5 + +/* Medium changed flag. */ +#define CD_STATUS_MEDIUM_CHANGED 0x80 + +#define CD_TRACK_AUDIO 0x08 +#define CD_TRACK_MODE2 0x04 + +#define CD_READ_DATA 0 +#define CD_READ_AUDIO 1 +#define CD_READ_RAW 2 + +#define CD_TOC_NORMAL 0 +#define CD_TOC_SESSION 1 +#define CD_TOC_RAW 2 #define BUF_SIZE 32768 @@ -51,61 +66,63 @@ enum { struct cdrom; +typedef struct { + uint8_t attr, track, + index, + abs_m, abs_s, abs_f, + rel_m, rel_s, rel_f; +} subchannel_t; + +typedef struct { + int number; + uint8_t attr, m, s, f; +} track_info_t; + /* Define the various CD-ROM drive operations (ops). */ typedef struct { - int (*ready)(struct cdrom *dev); - int (*medium_changed)(struct cdrom *dev); - int (*media_type_id)(struct cdrom *dev); - - int (*audio_callback)(struct cdrom *dev, int16_t *output, int len); - void (*audio_stop)(struct cdrom *dev); - int (*readtoc)(struct cdrom *dev, uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); - int (*readtoc_session)(struct cdrom *dev, uint8_t *b, int msf, int maxlen); - int (*readtoc_raw)(struct cdrom *dev, uint8_t *b, int maxlen); - uint8_t (*getcurrentsubchannel)(struct cdrom *dev, uint8_t *b, int msf); - int (*readsector_raw)(struct cdrom *dev, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len); - uint8_t (*playaudio)(struct cdrom *dev, uint32_t pos, uint32_t len, int ismsf); - void (*pause)(struct cdrom *dev); - void (*resume)(struct cdrom *dev); - uint32_t (*size)(struct cdrom *dev); - int (*status)(struct cdrom *dev); - void (*stop)(struct cdrom *dev); + void (*get_tracks)(struct cdrom *dev, int *first, int *last); + void (*get_track_info)(struct cdrom *dev, uint32_t track, int end, track_info_t *ti); + void (*get_subchannel)(struct cdrom *dev, uint32_t lba, subchannel_t *subc); + int (*sector_size)(struct cdrom *dev, uint32_t lba); + int (*read_sector)(struct cdrom *dev, int type, uint8_t *b, uint32_t lba); + int (*track_type)(struct cdrom *dev, uint32_t lba); void (*exit)(struct cdrom *dev); } cdrom_ops_t; typedef struct cdrom { uint8_t id, - speed, cur_speed, + res, res0, /* Reserved for other ID's. */ + res1, ide_channel, scsi_device_id, bus_type, /* 0 = ATAPI, 1 = SCSI */ bus_mode, /* Bit 0 = PIO suported; Bit 1 = DMA supportd. */ - sound_on; + cd_status, /* Struct variable reserved for + media status. */ + speed, cur_speed; FILE* img_fp; - int img_is_iso, - host_drive, prev_host_drive, - cd_status, prev_status, - cd_buflen, cd_state; + void *priv; - uint32_t seek_pos, seek_diff, - cd_end, - cdrom_capacity; + wchar_t image_path[1024], + prev_image_path[1024]; + + uint32_t sound_on, cdrom_capacity, + pad, seek_pos, + seek_diff, cd_end; + + int host_drive, prev_host_drive, + cd_buflen; const cdrom_ops_t *ops; void *image; - void *priv; - void (*insert)(void *p); void (*close)(void *p); uint32_t (*get_volume)(void *p, int channel); uint32_t (*get_channel)(void *p, int channel); - wchar_t image_path[1024], - *prev_image_path; - int16_t cd_buffer[BUF_SIZE]; } cdrom_t; @@ -114,8 +131,16 @@ extern cdrom_t cdrom[CDROM_NUM]; extern int cdrom_lba_to_msf_accurate(int lba); extern double cdrom_seek_time(cdrom_t *dev); +extern void cdrom_stop(cdrom_t *dev); +extern int cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len); +extern uint8_t cdrom_audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf); +extern void cdrom_audio_pause_resume(cdrom_t *dev, uint8_t resume); +extern uint8_t cdrom_get_current_subchannel(cdrom_t *dev, uint8_t *b, int msf); +extern int cdrom_read_toc(cdrom_t *dev, unsigned char *b, int type, + unsigned char start_track, int msf, int max_len); +extern int cdrom_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, + int cdrom_sector_type, int cdrom_sector_flags, int *len); extern void cdrom_seek(cdrom_t *dev, uint32_t pos); -extern int cdrom_playing_completed(cdrom_t *dev); extern void cdrom_close_handler(uint8_t id); extern void cdrom_insert(uint8_t id); diff --git a/src/cdrom/cdrom_dosbox.cpp b/src/cdrom/cdrom_dosbox.cpp index 0408be688..6bd8fd955 100644 --- a/src/cdrom/cdrom_dosbox.cpp +++ b/src/cdrom/cdrom_dosbox.cpp @@ -135,6 +135,15 @@ bool CDROM_Interface_Image::GetAudioTrackInfo(int track, int& track_number, TMSF return true; } +bool CDROM_Interface_Image::GetAudioTrackEndInfo(int track, int& track_number, TMSF& start, unsigned char& attr) +{ + if (track < 1 || track > (int)tracks.size()) return false; + FRAMES_TO_MSF(tracks[track - 1].start + tracks[track - 1].length + 150, &start.min, &start.sec, &start.fr); + track_number = tracks[track - 1].track_number; + attr = tracks[track - 1].attr; + return true; +} + bool CDROM_Interface_Image::GetAudioSub(int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) { int cur_track = GetTrack(sector); diff --git a/src/cdrom/cdrom_dosbox.h b/src/cdrom/cdrom_dosbox.h index f5dc4f346..e3d346031 100644 --- a/src/cdrom/cdrom_dosbox.h +++ b/src/cdrom/cdrom_dosbox.h @@ -83,6 +83,7 @@ public: virtual bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut) = 0; virtual bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr) = 0; + virtual bool GetAudioTrackEndInfo (int track, int& number, TMSF& start, unsigned char& attr) = 0; virtual bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) = 0; virtual bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen) = 0; @@ -136,6 +137,7 @@ public: bool GetUPC (unsigned char& attr, char* upc); bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut); bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr); + bool GetAudioTrackEndInfo (int track, int& number, TMSF& start, unsigned char& attr); bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos); bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen); bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num); diff --git a/src/cdrom/cdrom_image.cc b/src/cdrom/cdrom_image.cc index f7ac18742..9513943a7 100644 --- a/src/cdrom/cdrom_image.cc +++ b/src/cdrom/cdrom_image.cc @@ -8,7 +8,7 @@ * * CD-ROM image support. * - * Version: @(#)cdrom_image.cc 1.0.6 2018/10/21 + * Version: @(#)cdrom_image.cc 1.0.7 2018/10/28 * * Author: RichardG867, * Miran Grca, @@ -55,218 +55,55 @@ cdrom_image_log(const char *fmt, ...) #endif -#define CD_STATUS_EMPTY 0 -#define CD_STATUS_DATA_ONLY 1 -#define CD_STATUS_PLAYING 2 -#define CD_STATUS_PAUSED 3 -#define CD_STATUS_STOPPED 4 - - /* 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) -#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) - - -enum { - CD_STOPPED = 0, - CD_PLAYING, - CD_PAUSED -}; - - -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]; - - -static int -audio_callback(cdrom_t *dev, int16_t *output, int len) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - int ret = 1; - - if (!dev->sound_on || (dev->cd_state != CD_PLAYING) || dev->img_is_iso) { - cdrom_image_log("image_audio_callback(i): Not playing\n", dev->id); - if (dev->cd_state == CD_PLAYING) - dev->seek_pos += (len >> 11); - memset(output, 0, len * 2); - return 0; - } - - while (dev->cd_buflen < len) { - if (dev->seek_pos < dev->cd_end) { - if (!img->ReadSector((uint8_t *)&dev->cd_buffer[dev->cd_buflen], - true, dev->seek_pos)) { - memset(&dev->cd_buffer[dev->cd_buflen], - 0x00, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_state = CD_STOPPED; - dev->cd_buflen = len; - ret = 0; - } else { - dev->seek_pos++; - dev->cd_buflen += (RAW_SECTOR_SIZE / 2); - ret = 1; - } - } else { - memset(&dev->cd_buffer[dev->cd_buflen], - 0x00, (BUF_SIZE - dev->cd_buflen) * 2); - dev->cd_state = CD_STOPPED; - dev->cd_buflen = len; - ret = 0; - } - } - - memcpy(output, dev->cd_buffer, len * 2); - memmove(dev->cd_buffer, &dev->cd_buffer[len], (BUF_SIZE - len) * 2); - dev->cd_buflen -= len; - - return ret; -} - - static void -audio_stop(cdrom_t *dev) /* audio_stop */ -{ - dev->cd_state = CD_STOPPED; -} - - -static uint8_t -audio_play(cdrom_t *dev, uint32_t pos, uint32_t len, int ismsf) +image_get_tracks(cdrom_t *dev, int *first, int *last) { CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - int number; - uint8_t attr; TMSF tmsf; - int m = 0, s = 0, f = 0; - if (!img) return 0; - - img->GetAudioTrackInfo(img->GetTrack(pos), number, tmsf, attr); - if (attr == DATA_TRACK) { - cdrom_image_log("Can't play data track\n"); - dev->seek_pos = 0; - dev->cd_state = CD_STOPPED; - return 0; - } - - cdrom_image_log("Play audio - %08X %08X %i\n", pos, len, ismsf); - if (ismsf == 2) { - img->GetAudioTrackInfo(pos, number, tmsf, attr); - pos = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; - img->GetAudioTrackInfo(len, number, tmsf, attr); - len = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; - } else if (ismsf == 1) { - m = (pos >> 16) & 0xff; - s = (pos >> 8) & 0xff; - f = pos & 0xff; - - if (pos == 0xffffff) { - cdrom_image_log("Playing from current position (MSF)\n"); - 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_image_log("MSF - pos = %08X len = %08X\n", pos, len); - } else if (ismsf == 0) { - if (pos == 0xffffffff) { - cdrom_image_log("Playing from current position\n"); - pos = dev->seek_pos; - } - len += pos; - } - - dev->seek_pos = pos; - dev->cd_end = len; - dev->cd_state = CD_PLAYING; - dev->cd_buflen = 0; - - return 1; + img->GetAudioTracks(*first, *last, tmsf); } static void -audio_pause(cdrom_t *dev) +image_get_track_info(cdrom_t *dev, uint32_t track, int end, track_info_t *ti) { CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + TMSF tmsf; - if (!img || dev->img_is_iso) return; + if (end) + img->GetAudioTrackEndInfo(track, ti->number, tmsf, ti->attr); + else + img->GetAudioTrackInfo(track, ti->number, tmsf, ti->attr); - if (dev->cd_state == CD_PLAYING) - dev->cd_state = CD_PAUSED; + ti->m = tmsf.min; + ti->s = tmsf.sec; + ti->f = tmsf.fr; } static void -audio_resume(cdrom_t *dev) +image_get_subchannel(cdrom_t *dev, uint32_t lba, subchannel_t *subc) { CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + TMSF rel_pos, abs_pos; - if (!img || dev->img_is_iso) return; + img->GetAudioSub(lba, subc->attr, subc->track, subc->index, + rel_pos, abs_pos); - if (dev->cd_state == CD_PAUSED) - dev->cd_state = CD_PLAYING; -} + subc->abs_m = abs_pos.min; + subc->abs_s = abs_pos.sec; + subc->abs_f = abs_pos.fr; - -static int -image_ready(cdrom_t *dev) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - - if (!img || (wcslen(dev->image_path) == 0)) - return 0; - - return 1; + subc->rel_m = rel_pos.min; + subc->rel_s = rel_pos.sec; + subc->rel_f = rel_pos.fr; } @@ -281,7 +118,8 @@ image_get_last_block(cdrom_t *dev) uint32_t lb = 0; uint32_t address; - if (!img) return 0; + if (!img) + return 0; img->GetAudioTracks(first_track, last_track, tmsf); @@ -296,72 +134,6 @@ image_get_last_block(cdrom_t *dev) } -static int -image_medium_changed(UNUSED(cdrom_t *dev)) -{ - /* There is no way to change the medium within an already mounted image. */ - return 0; -} - - -static uint8_t -image_getcurrentsubchannel(cdrom_t *dev, uint8_t *b, int msf) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - uint8_t attr, track, index, ret; - TMSF relPos, absPos; - uint32_t cdpos; - int pos = 0; - - cdpos = dev->seek_pos; - - if (!img) return 0; - - img->GetAudioSub(cdpos, attr, track, index, relPos, absPos); - - if (dev->img_is_iso) - ret = 0x15; - else { - if (dev->cd_state == CD_PLAYING) - ret = 0x11; - else if (dev->cd_state == CD_PAUSED) - ret = 0x12; - else - ret = 0x13; - } - - b[pos++] = attr; - b[pos++] = track; - b[pos++] = index; - - if (msf) { - b[pos + 3] = (uint8_t)absPos.fr; - b[pos + 2] = (uint8_t)absPos.sec; - b[pos + 1] = (uint8_t)absPos.min; - b[pos] = 0; - pos += 4; - b[pos + 3] = (uint8_t)relPos.fr; - b[pos + 2] = (uint8_t)relPos.sec; - b[pos + 1] = (uint8_t)relPos.min; - b[pos] = 0; - pos += 4; - } else { - uint32_t dat = MSFtoLBA(absPos.min, absPos.sec, absPos.fr) - 150; - b[pos++] = (dat >> 24) & 0xff; - b[pos++] = (dat >> 16) & 0xff; - b[pos++] = (dat >> 8) & 0xff; - b[pos++] = dat & 0xff; - dat = MSFtoLBA(relPos.min, relPos.sec, relPos.fr); - b[pos++] = (dat >> 24) & 0xff; - b[pos++] = (dat >> 16) & 0xff; - b[pos++] = (dat >> 8) & 0xff; - b[pos++] = dat & 0xff; - } - - return ret; -} - - static int image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) { @@ -371,7 +143,8 @@ image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) int m, s, f; int number; - if (!img || dev->img_is_iso) return 0; + if (!img || (dev->cd_status == CD_STATUS_DATA_ONLY)) + return 0; if (ismsf) { m = (pos >> 16) & 0xff; @@ -387,625 +160,52 @@ image_is_track_audio(cdrom_t *dev, uint32_t pos, int ismsf) } +static int +image_sector_size(struct cdrom *dev, uint32_t lba) +{ + CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; + + return img->GetSectorSize(lba); +} + + static int -is_legal(uint8_t id, int type, int flags, int audio, int mode2) +image_read_sector(struct cdrom *dev, int type, uint8_t *b, uint32_t lba) { - if (!(flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); - return 0; - } + CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - if ((type != 1) && !audio) { - if (!(flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Any Data Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); + switch (type) { + case CD_READ_DATA: + return img->ReadSector(b, false, lba); + case CD_READ_AUDIO: + return img->ReadSector(b, true, lba); + case CD_READ_RAW: + if (img->GetSectorSize(lba) == 2352) + return img->ReadSector(b, true, lba); + else + return img->ReadSectorSub(b, lba); + default: + cdrom_image_log("CD-ROM %i: Unknown CD read type\n", dev->id); return 0; - } - - if ((flags & 0x06) == 0x06) { - cdrom_image_log("CD-ROM %i: [Any Data Mode] Invalid error flags\n", id); - return 0; - } - - if (((flags & 0x700) == 0x300) || ((flags & 0x700) > 0x400)) { - cdrom_image_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_image_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_image_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_image_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_image_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) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - uint8_t *bb = rbuf; - - img->ReadSector(rbuf + 16, false, 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) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - - if (img->GetSectorSize(lba) == 2352) - img->ReadSector(raw_buffer, true, lba); - else - img->ReadSectorSub(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) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - - if ((dev->img_is_iso) || (img->GetSectorSize(lba) == 2048)) - read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048); - else if (img->GetSectorSize(lba) == 2352) - img->ReadSector(raw_buffer, true, lba); - else - img->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_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_image_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_image_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_image_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_image_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) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - - if ((dev->img_is_iso) || (img->GetSectorSize(lba) == 2336)) - read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2336); - else if (img->GetSectorSize(lba) == 2352) - img->ReadSector(raw_buffer, true, lba); - else - img->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_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_image_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_image_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_image_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) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - - if ((dev->img_is_iso) || (img->GetSectorSize(lba) == 2048)) - read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2048); - else if (img->GetSectorSize(lba) == 2352) - img->ReadSector(raw_buffer, true, lba); - else - img->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_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_image_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_image_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_image_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_image_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) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - - if ((dev->img_is_iso) || (img->GetSectorSize(lba) == 2324)) - read_sector_to_buffer(dev, raw_buffer, msf, lba, mode2, 2324); - else if (img->GetSectorSize(lba) == 2352) - img->ReadSector(raw_buffer, true, lba); - else - img->ReadSectorSub(raw_buffer, lba); - - cdrom_sector_size = 0; - - if (cdrom_sector_flags & 0x80) { /* Sync */ - cdrom_image_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_image_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_image_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_image_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; } } static int -image_readsector_raw(cdrom_t *dev, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, - int cdrom_sector_flags, int *len) +image_track_type(cdrom_t *dev, uint32_t lba) { CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - uint8_t *b, *temp_b; - uint32_t msf, lba; - int audio, mode2; - int m, s, f; - if (!img || !dev->host_drive) 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->img_is_iso) { - audio = 0; - mode2 = img->IsMode2(lba) ? 1 : 0; - } else { - audio = image_is_track_audio(dev, sector, ismsf); - mode2 = img->IsMode2(lba) ? 1 : 0; - } - mode2 <<= 2; - mode2 |= img->GetMode2Form(lba); - - memset(raw_buffer, 0, 2448); - memset(extra_buffer, 0, 296); - - if (!(cdrom_sector_flags & 0xf0)) { /* 0x00 and 0x08 are illegal modes */ - cdrom_image_log("CD-ROM %i: [Mode 1] 0x00 and 0x08 are illegal modes\n", dev->id); - return 0; - } - - if (!is_legal(dev->id, cdrom_sector_type, cdrom_sector_flags, audio, mode2)) - return 0; - - if ((cdrom_sector_type > 5) && (cdrom_sector_type != 8)) { - cdrom_image_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->img_is_iso) { - cdrom_image_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_image_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_image_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_image_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_image_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_image_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); + if (img) { + if (image_is_track_audio(dev, lba, 0)) + return CD_TRACK_AUDIO; else { - cdrom_image_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 (img->IsMode2(lba)) + return CD_TRACK_MODE2 | img->GetMode2Form(lba); } } - if ((cdrom_sector_flags & 0x06) == 0x02) { - /* Add error flags. */ - cdrom_image_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_image_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_image_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_image_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_image_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; -} - - -static uint32_t -image_size(cdrom_t *dev) -{ - return dev->cdrom_capacity; -} - - -static int -image_readtoc(cdrom_t *dev, unsigned char *b, unsigned char starttrack, int msf, UNUSED(int maxlen), int single) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - int number, len = 4; - int c, d, first_track, last_track; - uint32_t temp; - unsigned char attr; - TMSF tmsf; - - if (!img) return 0; - - img->GetAudioTracks(first_track, last_track, tmsf); - - b[2] = first_track; - b[3] = last_track; - - d = 0; - for (c = 0; c <= last_track; c++) { - img->GetAudioTrackInfo(c+1, number, tmsf, attr); - if (number >= starttrack) { - d=c; - break; - } - } - - if (starttrack != 0xAA) { - img->GetAudioTrackInfo(c+1, number, tmsf, attr); - b[2] = number; - } - - for (c = d; c <= last_track; c++) { - img->GetAudioTrackInfo(c+1, number, tmsf, attr); - - b[len++] = 0; /* reserved */ - b[len++] = attr; - b[len++] = number; /* track number */ - b[len++] = 0; /* reserved */ - - if (msf) { - b[len++] = 0; - b[len++] = tmsf.min; - b[len++] = tmsf.sec; - b[len++] = tmsf.fr; - } else { - temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; - b[len++] = temp >> 24; - b[len++] = temp >> 16; - b[len++] = temp >> 8; - b[len++] = temp; - } - - if (single) - break; - } - - b[0] = (uint8_t)(((len-2) >> 8) & 0xff); - b[1] = (uint8_t)((len-2) & 0xff); - - return len; -} - - -static int -image_readtoc_session(cdrom_t *dev, unsigned char *b, int msf, int maxlen) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - int number, len = 4; - uint8_t attr; - uint32_t temp; - TMSF tmsf; - - if (!img) return 0; - - img->GetAudioTrackInfo(1, number, tmsf, attr); - - if (number == 0) - number = 1; - - b[2] = b[3] = 1; - b[len++] = 0; /* reserved */ - b[len++] = attr; - b[len++] = number; /* track number */ - b[len++] = 0; /* reserved */ - if (msf) { - b[len++] = 0; - b[len++] = tmsf.min; - b[len++] = tmsf.sec; - b[len++] = tmsf.fr; - } else { - temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150. */ - b[len++] = temp >> 24; - b[len++] = temp >> 16; - b[len++] = temp >> 8; - b[len++] = temp; - } - - if (maxlen < len) - return maxlen; - - return len; -} - - -static int -image_readtoc_raw(cdrom_t *dev, unsigned char *b, UNUSED(int maxlen)) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - int first_track, last_track; - int number, track, len = 4; - uint8_t attr; - TMSF tmsf; - - if (!img) return 0; - - img->GetAudioTracks(first_track, last_track, tmsf); - - b[2] = first_track; - b[3] = last_track; - - for (track = first_track; track <= last_track; track++) { - img->GetAudioTrackInfo(track, number, tmsf, attr); - - b[len++] = track; - b[len++]= attr; - b[len++]=0; - b[len++]=0; - b[len++]=0; - b[len++]=0; - b[len++]=0; - b[len++]=0; - b[len++] = tmsf.min; - b[len++] = tmsf.sec; - b[len++] = tmsf.fr; - } - - return len; -} - - -static int -image_status(cdrom_t *dev) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - - if (!img) return CD_STATUS_EMPTY; - - if (dev->img_is_iso) - return CD_STATUS_DATA_ONLY; - - if (img->HasAudioTracks()) { - switch(dev->cd_state) { - case CD_PLAYING: - return CD_STATUS_PLAYING; - - case CD_PAUSED: - return CD_STATUS_PAUSED; - - case CD_STOPPED: - default: - return CD_STATUS_STOPPED; - } - } - - return CD_STATUS_DATA_ONLY; -} - - -static void -image_stop(cdrom_t *dev) -{ - CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; - - if (!img || dev->img_is_iso) return; - - dev->cd_state = CD_STOPPED; + return 0; } @@ -1015,7 +215,7 @@ image_exit(cdrom_t *dev) CDROM_Interface_Image *img = (CDROM_Interface_Image *)dev->image; cdrom_image_log("CDROM: image_exit(%ls)\n", dev->image_path); - dev->cd_state = CD_STOPPED; + dev->cd_status = CD_STATUS_EMPTY; if (img) { delete img; @@ -1026,41 +226,27 @@ cdrom_image_log("CDROM: image_exit(%ls)\n", dev->image_path); } -/* TODO: Check for what data type a mixed CD is. */ -static int -image_media_type_id(cdrom_t *dev) -{ - if (image_size(dev) > 405000) - return 65; /* DVD. */ - - if (dev->img_is_iso) - return 1; /* Data CD. */ - - return 3; /* Mixed mode CD. */ -} - - static const cdrom_ops_t cdrom_image_ops = { - image_ready, - image_medium_changed, - image_media_type_id, - audio_callback, - audio_stop, - image_readtoc, - image_readtoc_session, - image_readtoc_raw, - image_getcurrentsubchannel, - image_readsector_raw, - audio_play, - audio_pause, - audio_resume, - image_size, - image_status, - image_stop, + image_get_tracks, + image_get_track_info, + image_get_subchannel, + image_sector_size, + image_read_sector, + image_track_type, image_exit }; +static int +image_open_abort(cdrom_t *dev) +{ + cdrom_image_close(dev); + dev->ops = NULL; + dev->host_drive = 0; + return 1; +} + + int cdrom_image_open(cdrom_t *dev, const wchar_t *fn) { @@ -1069,28 +255,27 @@ cdrom_image_open(cdrom_t *dev, const wchar_t *fn) wcscpy(dev->image_path, fn); - if (! wcscasecmp(plat_get_extension((wchar_t *) fn), L"ISO")) - dev->img_is_iso = 1; - else - dev->img_is_iso = 0; - /* Create new instance of the CDROM_Image class. */ img = new CDROM_Interface_Image(); + + /* This guarantees that if ops is not NULL, then + neither is the image pointer. */ + if (!img) + return image_open_abort(dev); + dev->image = img; /* Convert filename and open the image. */ memset(temp, '\0', sizeof(temp)); wcstombs(temp, fn, sizeof(temp)); - if (!img->SetDevice(temp, false)) { - cdrom_image_close(dev); - cdrom->ops = NULL; - cdrom->host_drive = 0; - cdrom_image_log("[f] image_open(): cdrom[%i]->ops = %08X\n", dev->id, dev->ops); - return 1; - } + if (!img->SetDevice(temp, false)) + return image_open_abort(dev); /* All good, reset state. */ - dev->cd_state = CD_STOPPED; + if (! wcscasecmp(plat_get_extension((wchar_t *) fn), L"ISO")) + dev->cd_status = CD_STATUS_DATA_ONLY; + else + dev->cd_status = CD_STATUS_STOPPED; dev->seek_pos = 0; dev->cd_buflen = 0; dev->cdrom_capacity = image_get_last_block(dev) + 1; @@ -1105,15 +290,8 @@ cdrom_image_open(cdrom_t *dev, const wchar_t *fn) void cdrom_image_close(cdrom_t *dev) { -cdrom_image_log("CDROM: image_close(%ls)\n", dev->image_path); + cdrom_image_log("CDROM: image_close(%ls)\n", dev->image_path); + if (dev->ops->exit) dev->ops->exit(dev); } - - -void -cdrom_image_reset(UNUSED(cdrom_t *dev)) -{ -cdrom_image_log("CDROM: image_reset(%ls)\n", dev->image_path); - /* Nothing to do. */ -} diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 8a9896735..84c63d40b 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdc_ide.c 1.0.55 2018/10/25 + * Version: @(#)hdc_ide.c 1.0.56 2018/10/28 * * Authors: Sarah Walker, * Miran Grca, @@ -109,7 +109,7 @@ #define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd #define FEATURE_DISABLE_IRQ_SERVICE 0xde -#define IDE_PCI (PCI && pio_override && (ide->board < 2)) +#define IDE_PCI (PCI && !pio_override && (ide->board < 2)) typedef struct { @@ -379,7 +379,7 @@ static int ide_get_max(ide_t *ide, int type) { if (ide_drive_is_atapi(ide)) - return ide->get_max(!IDE_PCI, type); + return ide->get_max(IDE_PCI, type); switch(type) { case TYPE_PIO: /* PIO */ @@ -413,7 +413,7 @@ static int ide_get_timings(ide_t *ide, int type) { if (ide_drive_is_atapi(ide)) - return ide->get_timings(!IDE_PCI, type); + return ide->get_timings(IDE_PCI, type); switch(type) { case TIMINGS_DMA: @@ -551,6 +551,8 @@ ide_identify(ide_t *ide) max_sdma = ide_get_max(ide, TYPE_SDMA); max_mdma = ide_get_max(ide, TYPE_MDMA); max_udma = ide_get_max(ide, TYPE_UDMA); + ide_log("IDE %i: max_pio = %i, max_sdma = %i, max_mdma = %i, max_udma = %i\n", + ide->channel, max_pio, max_sdma, max_mdma, max_udma); if (ide_boards[ide->board]->bit32) ide->buffer[48] |= 1; /*Dword transfers supported*/ @@ -669,18 +671,17 @@ loadhd(ide_t *ide, int d, const wchar_t *fn) void ide_set_signature(ide_t *ide) { - scsi_device_data_t *atapi = (scsi_device_data_t *) ide->p; - ide->sector=1; ide->head=0; if (ide_drive_is_atapi(ide)) { - ide->set_signature(ide->p); - ide->secount = atapi->phase; - ide->cylinder = atapi->request_length; + ide->sc->phase = 1; + ide->sc->request_length = 0xEB14; + ide->secount = ide->sc->phase; + ide->cylinder = ide->sc->request_length; } else { - ide->secount=1; - ide->cylinder=((ide->type == IDE_HDD) ? 0 : 0xFFFF); + ide->secount = 1; + ide->cylinder = ((ide->type == IDE_HDD) ? 0 : 0xFFFF); if (ide->type == IDE_HDD) ide->drive = 0; } @@ -813,7 +814,6 @@ ide_board_close(int board) { ide_t *dev; int c, d; - scsi_device_data_t *atapi; /* Close hard disk image files (if previously open) */ for (d = 0; d < 2; d++) { @@ -824,10 +824,8 @@ ide_board_close(int board) hdd_image_close(dev->hdd_num); if (board < 4) { - if (ide_drive_is_atapi(dev)) { - atapi = (scsi_device_data_t *) dev->p; - atapi->status = DRDY_STAT | DSC_STAT; - } + if (ide_drive_is_atapi(dev)) + dev->sc->status = DRDY_STAT | DSC_STAT; } if (dev->buffer) @@ -943,6 +941,164 @@ ide_set_callback(uint8_t board, int64_t callback) } +/* This is the general ATAPI PIO request function. */ +static void +ide_atapi_pio_request(ide_t *ide, uint8_t out) +{ + scsi_common_t *dev = ide->sc; + + ide_irq_lower(ide_drives[ide->board]); + + dev->status = BSY_STAT; + + if (dev->pos >= dev->packet_len) { + ide_log("%i bytes %s, command done\n", dev->pos, out ? "written" : "read"); + + dev->pos = dev->request_pos = 0; + if (out && ide->phase_data_out) + ide->phase_data_out(dev); + else if (ide->command_stop) + ide->command_stop(dev); + } else { + ide_log("%i bytes %s, %i bytes are still left\n", dev->pos, + out ? "written" : "read", dev->packet_len - dev->pos); + + /* If less than (packet length) bytes are remaining, update packet length + accordingly. */ + if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) + dev->max_transfer_len = dev->packet_len - dev->pos; + ide_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, + dev->max_transfer_len); + + dev->packet_status = out ? PHASE_DATA_OUT : PHASE_DATA_IN; + + dev->status = BSY_STAT; + dev->phase = 1; + if (ide->packet_callback) + ide->packet_callback(dev); + dev->callback = 0LL; + ide_set_callback(ide->board >> 1, dev->callback); + + dev->request_pos = 0; + } +} + + +static uint32_t +ide_atapi_packet_read(ide_t *ide, int length) +{ + scsi_common_t *dev = ide->sc; + + uint16_t *bufferw; + uint32_t *bufferl; + + uint32_t temp = 0; + + if (!dev || !dev->temp_buffer || (dev->packet_status != PHASE_DATA_IN)) + return 0; + + bufferw = (uint16_t *) dev->temp_buffer; + bufferl = (uint32_t *) dev->temp_buffer; + + /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, + which can happen when issuing media access commands with an allocated length below minimum request length + (which is 1 sector = 2048 bytes). */ + switch(length) { + case 1: + temp = (dev->pos < dev->packet_len) ? dev->temp_buffer[dev->pos] : 0; + dev->pos++; + dev->request_pos++; + break; + case 2: + temp = (dev->pos < dev->packet_len) ? bufferw[dev->pos >> 1] : 0; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + temp = (dev->pos < dev->packet_len) ? bufferl[dev->pos >> 2] : 0; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return 0; + } + + if (dev->packet_status == PHASE_DATA_IN) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + ide_atapi_pio_request(ide, 0); + } + return temp; + } else + return 0; +} + + +static void +ide_atapi_packet_write(ide_t *ide, uint32_t val, int length) +{ + scsi_common_t *dev = ide->sc; + + uint8_t *bufferb; + uint16_t *bufferw; + uint32_t *bufferl; + + if (!dev) + return; + + if (dev->packet_status == PHASE_IDLE) + bufferb = dev->atapi_cdb; + else { + if (dev->temp_buffer) + bufferb = dev->temp_buffer; + else + return; + } + + bufferw = (uint16_t *) bufferb; + bufferl = (uint32_t *) bufferb; + + switch(length) { + case 1: + bufferb[dev->pos] = val & 0xff; + dev->pos++; + dev->request_pos++; + break; + case 2: + bufferw[dev->pos >> 1] = val & 0xffff; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + bufferl[dev->pos >> 2] = val; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return; + } + + if (dev->packet_status == PHASE_DATA_OUT) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + ide_atapi_pio_request(ide, 1); + } + return; + } else if (dev->packet_status == PHASE_IDLE) { + if (dev->pos >= 12) { + dev->pos = 0; + dev->status = BSY_STAT; + dev->packet_status = PHASE_COMMAND; + timer_process(); + if (ide->packet_callback) + ide->packet_callback(dev); + timer_update_outstanding(); + } + return; + } +} + + void ide_write_data(ide_t *ide, uint32_t val, int length) { @@ -957,7 +1113,7 @@ ide_write_data(ide_t *ide, uint32_t val, int length) return; if (ide_drive_is_atapi(ide)) - ide->packet_write(ide->p, val, length); + ide_atapi_packet_write(ide, val, length); return; } else { switch(length) { @@ -1048,7 +1204,6 @@ void ide_write_devctl(uint16_t addr, uint8_t val, void *priv) { ide_board_t *dev = (ide_board_t *) priv; - scsi_device_data_t *atapi; ide_t *ide, *ide_other; int ch; @@ -1060,11 +1215,9 @@ ide_write_devctl(uint16_t addr, uint8_t val, void *priv) ide_log("ide_write_devctl %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) { - atapi = (scsi_device_data_t *) ide->p; - timer_process(); if (ide_drive_is_atapi(ide)) - atapi->callback = 0LL; + ide->sc->callback = 0LL; ide_set_callback(ide->board, 500LL * IDE_TIME); timer_update_outstanding(); @@ -1073,7 +1226,7 @@ ide_write_devctl(uint16_t addr, uint8_t val, void *priv) if (ide_other->type != IDE_NONE) ide->reset = 1; if (ide_drive_is_atapi(ide)) - atapi->status = BSY_STAT; + ide->sc->status = BSY_STAT; ide->atastat = ide_other->atastat = BSY_STAT; } @@ -1093,7 +1246,6 @@ void ide_writeb(uint16_t addr, uint8_t val, void *priv) { ide_board_t *dev = (ide_board_t *) priv; - scsi_device_data_t *atapi, *atapi_other; ide_t *ide, *ide_other; int ch; @@ -1109,9 +1261,6 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) return; - atapi = (scsi_device_data_t *) ide->p; - atapi_other = (scsi_device_data_t *) ide_other->p; - switch (addr) { case 0x0: /* Data */ ide_write_data(ide, val | (val << 8), 2); @@ -1121,25 +1270,25 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case 0x1: /* Features */ if (ide_drive_is_atapi(ide)) { ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); - atapi->features = val; + ide->sc->features = val; } ide->cylprecomp = val; if (ide_drive_is_atapi(ide_other)) - atapi_other->features = val; + ide_other->sc->features = val; ide_other->cylprecomp = val; return; case 0x2: /* Sector count */ if (ide_drive_is_atapi(ide)) { ide_log("Sector count write: %i\n", val); - atapi->phase = val; + ide->sc->phase = val; } ide->secount = val; if (ide_drive_is_atapi(ide_other)) { ide_log("Other sector count write: %i\n", val); - atapi_other->phase = val; + ide_other->sc->phase = val; } ide_other->secount = val; return; @@ -1153,15 +1302,15 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case 0x4: /* Cylinder low */ if (ide_drive_is_atapi(ide)) { - atapi->request_length &= 0xFF00; - atapi->request_length |= val; + ide->sc->request_length &= 0xFF00; + ide->sc->request_length |= val; } ide->cylinder = (ide->cylinder & 0xFF00) | val; ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); if (ide_drive_is_atapi(ide_other)) { - atapi_other->request_length &= 0xFF00; - atapi_other->request_length |= val; + ide_other->sc->request_length &= 0xFF00; + ide_other->sc->request_length |= val; } ide_other->cylinder = (ide_other->cylinder & 0xFF00) | val; ide_other->lba_addr = (ide_other->lba_addr & 0xFFF00FF) | (val << 8); @@ -1169,15 +1318,15 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case 0x5: /* Cylinder high */ if (ide_drive_is_atapi(ide)) { - atapi->request_length &= 0xFF; - atapi->request_length |= (val << 8); + ide->sc->request_length &= 0xFF; + ide->sc->request_length |= (val << 8); } ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); if (ide_drive_is_atapi(ide_other)) { - atapi_other->request_length &= 0xFF; - atapi_other->request_length |= (val << 8); + ide_other->sc->request_length &= 0xFF; + ide_other->sc->request_length |= (val << 8); } ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); @@ -1198,20 +1347,20 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->reset = ide_other->reset = 0; if (ide_drive_is_atapi(ide)) { - atapi->status = DRDY_STAT | DSC_STAT; - atapi->error = 1; - atapi->phase = 1; - atapi->request_length = 0xEB14; - atapi->callback = 0LL; + ide->sc->status = DRDY_STAT | DSC_STAT; + ide->sc->error = 1; + ide->sc->phase = 1; + ide->sc->request_length = 0xEB14; + ide->sc->callback = 0LL; ide->cylinder = 0xEB14; } if (ide_drive_is_atapi(ide_other)) { - atapi_other->status = DRDY_STAT | DSC_STAT; - atapi_other->error = 1; - atapi_other->phase = 1; - atapi_other->request_length = 0xEB14; - atapi_other->callback = 0LL; + ide_other->sc->status = DRDY_STAT | DSC_STAT; + ide_other->sc->error = 1; + ide_other->sc->phase = 1; + ide_other->sc->request_length = 0xEB14; + ide_other->sc->callback = 0LL; ide->cylinder = 0xEB14; } @@ -1241,17 +1390,17 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) ide->error=0; if (ide_drive_is_atapi(ide)) - atapi->error = 0; + ide->sc->error = 0; if (((val >= WIN_RECAL) && (val <= 0x1F)) || ((val >= WIN_SEEK) && (val <= 0x7F))) { if (ide_drive_is_atapi(ide)) - atapi->status = DRDY_STAT; + ide->sc->status = DRDY_STAT; else ide->atastat = BSY_STAT; timer_process(); if (ide_drive_is_atapi(ide)) - atapi->callback = 100LL * IDE_TIME; + ide->sc->callback = 100LL * IDE_TIME; ide_set_callback(ide->board, 100LL * IDE_TIME); timer_update_outstanding(); return; @@ -1260,13 +1409,13 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) switch (val) { case WIN_SRST: /* ATAPI Device Reset */ if (ide_drive_is_atapi(ide)) - atapi->status = BSY_STAT; + ide->sc->status = BSY_STAT; else ide->atastat = DRDY_STAT; timer_process(); if (ide_drive_is_atapi(ide)) - atapi->callback = 100LL * IDE_TIME; + ide->sc->callback = 100LL * IDE_TIME; ide_set_callback(ide->board, 100LL * IDE_TIME); timer_update_outstanding(); return; @@ -1287,13 +1436,13 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_READ_DMA: case WIN_READ_DMA_ALT: if (ide_drive_is_atapi(ide)) - atapi->status = BSY_STAT; + ide->sc->status = BSY_STAT; else ide->atastat = BSY_STAT; timer_process(); if (ide_drive_is_atapi(ide)) - atapi->callback = 200LL * IDE_TIME; + ide->sc->callback = 200LL * IDE_TIME; if (ide->type == IDE_HDD) { if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { @@ -1320,8 +1469,8 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_WRITE: case WIN_WRITE_NORETRY: if (ide_drive_is_atapi(ide)) { - atapi->status = DRQ_STAT | DSC_STAT | DRDY_STAT; - atapi->pos = 0; + ide->sc->status = DRQ_STAT | DSC_STAT | DRDY_STAT; + ide->sc->pos = 0; } else { ide->atastat = DRQ_STAT | DSC_STAT | DRDY_STAT; ide->pos=0; @@ -1336,13 +1485,13 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_SET_FEATURES: /* Set Features */ case WIN_READ_NATIVE_MAX: if (ide_drive_is_atapi(ide)) - atapi->status = BSY_STAT; + ide->sc->status = BSY_STAT; else ide->atastat = BSY_STAT; timer_process(); if (ide_drive_is_atapi(ide)) - atapi->callback = 200LL * IDE_TIME; + ide->sc->callback = 200LL * IDE_TIME; if ((ide->type == IDE_HDD) && ((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) { if (ide->secount) @@ -1368,31 +1517,31 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_SPECIFY: /* Initialize Drive Parameters */ if (ide_drive_is_atapi(ide)) - atapi->status = BSY_STAT; + ide->sc->status = BSY_STAT; else ide->atastat = BSY_STAT; timer_process(); if (ide_drive_is_atapi(ide)) - atapi->callback = 30LL * IDE_TIME; + ide->sc->callback = 30LL * IDE_TIME; ide_set_callback(ide->board, 30LL * IDE_TIME); timer_update_outstanding(); return; case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ if (ide_drive_is_atapi(ide)) - atapi->status = BSY_STAT; + ide->sc->status = BSY_STAT; else ide->atastat = BSY_STAT; if (ide_drive_is_atapi(ide_other)) - atapi_other->status = BSY_STAT; + ide_other->sc->status = BSY_STAT; else ide_other->atastat = BSY_STAT; timer_process(); if (ide_drive_is_atapi(ide)) - atapi->callback = 200LL * IDE_TIME; + ide->sc->callback = 200LL * IDE_TIME; ide_set_callback(ide->board, 200LL * IDE_TIME); timer_update_outstanding(); return; @@ -1406,7 +1555,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_CHECKPOWERMODE1: case WIN_SLEEP1: if (ide_drive_is_atapi(ide)) - atapi->status = BSY_STAT; + ide->sc->status = BSY_STAT; else ide->atastat = BSY_STAT; timer_process(); @@ -1417,10 +1566,10 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) case WIN_PACKETCMD: /* ATAPI Packet */ /* Skip the command callback wait, and process immediately. */ if (ide_drive_is_atapi(ide)) { - atapi->packet_status = PHASE_IDLE; - atapi->pos = 0; - atapi->phase = 1; - atapi->status = DRDY_STAT | DRQ_STAT; + ide->sc->packet_status = PHASE_IDLE; + ide->sc->pos = 0; + ide->sc->phase = 1; + ide->sc->status = DRDY_STAT | DRQ_STAT; if (ide->interrupt_drq) ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */ } else { @@ -1436,8 +1585,8 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv) default: ide_bad_command: if (ide_drive_is_atapi(ide)) { - atapi->status = DRDY_STAT | ERR_STAT | DSC_STAT; - atapi->error = ABRT_ERR; + ide->sc->status = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->sc->error = ABRT_ERR; } else { ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; ide->error = ABRT_ERR; @@ -1453,7 +1602,6 @@ ide_bad_command: static uint32_t ide_read_data(ide_t *ide, int length) { - scsi_device_data_t *atapi = (scsi_device_data_t *) ide->p; uint32_t temp = 0; if (!ide->buffer) { @@ -1476,7 +1624,7 @@ ide_read_data(ide_t *ide, int length) if (ide->command == WIN_PACKETCMD) { ide->pos = 0; if (ide_drive_is_atapi(ide)) - temp = ide->packet_read(ide->p, length); + temp = ide_atapi_packet_read(ide, length); else { ide_log("Drive not ATAPI (position: %i)\n", ide->pos); return 0; @@ -1503,8 +1651,8 @@ ide_read_data(ide_t *ide, int length) ide->pos = 0; ide->atastat = DRDY_STAT | DSC_STAT; if (ide_drive_is_atapi(ide)) { - atapi->status = DRDY_STAT | DSC_STAT; - atapi->packet_status = PHASE_IDLE; + ide->sc->status = DRDY_STAT | DSC_STAT; + ide->sc->packet_status = PHASE_IDLE; } if ((ide->command == WIN_READ) || (ide->command == WIN_READ_NORETRY) || (ide->command == WIN_READ_MULTIPLE)) { ide->secount = (ide->secount - 1) & 0xff; @@ -1517,10 +1665,8 @@ ide_read_data(ide_t *ide, int length) else ide_set_callback(ide->board, ide_get_period(ide, 512)); timer_update_outstanding(); - } else { - if (ide->command != WIN_READ_MULTIPLE) - ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); - } + } else if (ide->command != WIN_READ_MULTIPLE) + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); } } @@ -1531,13 +1677,11 @@ ide_read_data(ide_t *ide, int length) static uint8_t ide_status(ide_t *ide, int ch) { - scsi_device_data_t *atapi = (scsi_device_data_t *) ide->p; - if (ide->type == IDE_NONE) return 0; else { if (ide_drive_is_atapi(ide)) - return (atapi->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + return (ide->sc->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); else return ide->atastat; } @@ -1547,7 +1691,6 @@ ide_status(ide_t *ide, int ch) uint8_t ide_readb(uint16_t addr, void *priv) { - scsi_device_data_t *atapi; ide_board_t *dev = (ide_board_t *) priv; int ch; @@ -1555,7 +1698,6 @@ ide_readb(uint16_t addr, void *priv) ch = dev->cur_dev; ide = ide_drives[ch]; - atapi = (scsi_device_data_t *) ide->p; uint8_t temp = 0xff; uint16_t tempw; @@ -1577,7 +1719,7 @@ ide_readb(uint16_t addr, void *priv) temp = 0; else { if (ide_drive_is_atapi(ide)) - temp = atapi->error; + temp = ide->sc->error; else temp = ide->error; } @@ -1598,7 +1740,7 @@ ide_readb(uint16_t addr, void *priv) 1 0 1 Status. */ case 0x2: /* Sector count */ if (ide_drive_is_atapi(ide)) - temp = atapi->phase; + temp = ide->sc->phase; else temp = ide->secount; break; @@ -1612,7 +1754,7 @@ ide_readb(uint16_t addr, void *priv) temp = 0xFF; else { if (ide_drive_is_atapi(ide)) - temp = atapi->request_length & 0xff; + temp = ide->sc->request_length & 0xff; else temp = ide->cylinder & 0xff; } @@ -1623,7 +1765,7 @@ ide_readb(uint16_t addr, void *priv) temp = 0xFF; else { if (ide_drive_is_atapi(ide)) - temp = atapi->request_length >> 8; + temp = ide->sc->request_length >> 8; else temp = ide->cylinder >> 8; } @@ -1725,13 +1867,10 @@ ide_callback(void *priv) int snum, ret, ch; ide_board_t *dev = (ide_board_t *) priv; - scsi_device_data_t *atapi, *atapi_other; ch = dev->cur_dev; ide = ide_drives[ch]; - atapi = (scsi_device_data_t *) ide->p; ide_other = ide_drives[ch ^ 1]; - atapi_other = (scsi_device_data_t *) ide_other->p; ide_set_callback(ide->board, 0LL); @@ -1752,18 +1891,18 @@ ide_callback(void *priv) ide_set_signature(ide); if (ide_drive_is_atapi(ide)) { - atapi->status = DRDY_STAT | DSC_STAT; - atapi->error = 1; + ide->sc->status = DRDY_STAT | DSC_STAT; + ide->sc->error = 1; if (ide->stop) - ide->stop(ide->p); + ide->stop(ide->sc); } ide_set_signature(ide_other); if (ide_drive_is_atapi(ide_other)) { - atapi_other->status = DRDY_STAT | DSC_STAT; - atapi_other->error = 1; + ide_other->sc->status = DRDY_STAT | DSC_STAT; + ide_other->sc->error = 1; if (ide_other->stop) - ide_other->stop(ide_other->p); + ide_other->stop(ide_other->sc); } return; @@ -1798,10 +1937,10 @@ ide_callback(void *priv) ide_set_signature(ide); if (ide_drive_is_atapi(ide)) { - atapi->status = DRDY_STAT | DSC_STAT; - atapi->error = 1; + ide->sc->status = DRDY_STAT | DSC_STAT; + ide->sc->error = 1; if (ide->device_reset) - ide->device_reset(ide->p); + ide->device_reset(ide->sc); } ide_irq_raise(ide); if (ide_drive_is_atapi(ide)) @@ -1813,7 +1952,7 @@ ide_callback(void *priv) case WIN_IDLENOW1: case WIN_SETIDLE1: if (ide_drive_is_atapi(ide)) - atapi->status = DRDY_STAT | DSC_STAT; + ide->sc->status = DRDY_STAT | DSC_STAT; else ide->atastat = DRDY_STAT | DSC_STAT; ide_irq_raise(ide); @@ -1822,8 +1961,8 @@ ide_callback(void *priv) case WIN_CHECKPOWERMODE1: case WIN_SLEEP1: if (ide_drive_is_atapi(ide)) { - atapi->phase = 0xFF; - atapi->status = DRDY_STAT | DSC_STAT; + ide->sc->phase = 0xFF; + ide->sc->status = DRDY_STAT | DSC_STAT; } ide->secount = 0xFF; ide->atastat = DRDY_STAT | DSC_STAT; @@ -1891,10 +2030,6 @@ ide_callback(void *priv) ide_set_callback(ide->board, 6LL * IDE_TIME); return; } else if (ret == 1) { - /* Bus master DMAS error, abort the command. */ - ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); - goto abort_cmd; - } else { /*DMA successful*/ ide_log("IDE %i: DMA read successful\n", ide->channel); @@ -1902,6 +2037,10 @@ ide_callback(void *priv) ide_irq_raise(ide); ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } else { + /* Bus master DMAS error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; } } else { ide_log("IDE %i: DMA read aborted (no bus master)\n", ide->channel); @@ -1974,7 +2113,7 @@ ide_callback(void *priv) goto id_not_found; } - if (ide_bus_master_read) { + if (ide_bus_master_write) { if (ide->secount) ide->sector_pos = ide->secount; else @@ -1990,10 +2129,6 @@ ide_callback(void *priv) ide_set_callback(ide->board, 6LL * IDE_TIME); return; } else if (ret == 1) { - /* Bus master DMA error, abort the command. */ - ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); - goto abort_cmd; - } else { /*DMA successful*/ ide_log("IDE %i: DMA write successful\n", ide->channel); @@ -2003,6 +2138,10 @@ ide_callback(void *priv) ide_irq_raise(ide); ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } else { + /* Bus master DMA error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; } } else { ide_log("IDE %i: DMA write aborted (no bus master)\n", ide->channel); @@ -2060,11 +2199,11 @@ ide_callback(void *priv) case WIN_DRIVE_DIAGNOSTICS: ide_set_signature(ide); - ide->error=1; /*No error detected*/ + ide->error = 1; /*No error detected*/ if (ide_drive_is_atapi(ide)) { - atapi->status = 0; - atapi->error = 1; + ide->sc->status = 0; + ide->sc->error = 1; ide_irq_raise(ide); } else { ide->atastat = DRDY_STAT | DSC_STAT; @@ -2073,11 +2212,11 @@ ide_callback(void *priv) } ide_set_signature(ide_other); - ide_other->error=1; /*No error detected*/ + ide_other->error = 1; /*No error detected*/ if (ide_drive_is_atapi(ide_other)) { - atapi_other->status = 0; - atapi_other->error = 1; + ide_other->sc->status = 0; + ide_other->sc->error = 1; } else { ide_other->atastat = DRDY_STAT | DSC_STAT; ide_other->error = 1; @@ -2105,10 +2244,10 @@ ide_callback(void *priv) if (ide_drive_is_atapi(ide)) { ide_identify(ide); ide->pos = 0; - atapi->phase = 2; - atapi->pos = 0; - atapi->error = 0; - atapi->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->sc->phase = 2; + ide->sc->pos = 0; + ide->sc->error = 0; + ide->sc->status = DRQ_STAT | DRDY_STAT | DSC_STAT; ide_irq_raise(ide); return; } @@ -2123,19 +2262,16 @@ ide_callback(void *priv) return; case WIN_SET_FEATURES: - if (ide->type == IDE_NONE) + if ((ide->type == IDE_NONE) || !ide_set_features(ide)) goto abort_cmd; - if (!ide_set_features(ide)) - goto abort_cmd; - else { - if (ide_drive_is_atapi(ide)) { - atapi->status = DRDY_STAT | DSC_STAT; - atapi->pos = 0; - } - ide->atastat = DRDY_STAT | DSC_STAT; - ide_irq_raise(ide); + if (ide_drive_is_atapi(ide)) { + ide->sc->status = DRDY_STAT | DSC_STAT; + ide->sc->pos = 0; } + + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); return; case WIN_READ_NATIVE_MAX: @@ -2165,7 +2301,7 @@ ide_callback(void *priv) if (!ide_drive_is_atapi(ide) || !ide->packet_callback) goto abort_cmd; - ide->packet_callback(ide->p); + ide->packet_callback(ide->sc); return; case 0xFF: @@ -2175,9 +2311,9 @@ ide_callback(void *priv) abort_cmd: ide->command = 0; if (ide_drive_is_atapi(ide)) { - atapi->status = DRDY_STAT | ERR_STAT | DSC_STAT; - atapi->error = ABRT_ERR; - atapi->pos = 0; + ide->sc->status = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->sc->error = ABRT_ERR; + ide->sc->pos = 0; } else { ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; ide->error = ABRT_ERR; diff --git a/src/disk/hdc_ide.h b/src/disk/hdc_ide.h index 89dd1c2ca..e9eddda90 100644 --- a/src/disk/hdc_ide.h +++ b/src/disk/hdc_ide.h @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdd_ide.h 1.0.12 2018/10/10 + * Version: @(#)hdd_ide.h 1.0.13 2018/10/28 * * Authors: Sarah Walker, * Miran Grca, @@ -27,7 +27,8 @@ enum IDE_ATAPI }; -typedef struct { +#ifdef SCSI_DEVICE_H +typedef struct ide_s { uint8_t atastat, error, command, fdisk; int type, board, @@ -49,19 +50,19 @@ typedef struct { uint8_t *sector_buffer; /* Stuff mostly used by ATAPI */ - void *p; + scsi_common_t *sc; int interrupt_drq; int (*get_max)(int ide_has_dma, int type); int (*get_timings)(int ide_has_dma, int type); - void (*identify)(void *p, int ide_has_dma); - void (*set_signature)(void *p); - void (*packet_write)(void *p, uint32_t val, int length); - uint32_t (*packet_read)(void *p, int length); - void (*stop)(void *p); - void (*packet_callback)(void *p); - void (*device_reset)(void *p); + void (*identify)(struct ide_s *ide, int ide_has_dma); + void (*stop)(scsi_common_t *sc); + void (*packet_callback)(scsi_common_t *sc); + void (*device_reset)(scsi_common_t *sc); + uint8_t (*phase_data_out)(scsi_common_t *sc); + void (*command_stop)(scsi_common_t *sc); } ide_t; +#endif /* Type: 0 = PIO, @@ -95,12 +96,18 @@ enum { extern int ideboard; extern int ide_ter_enabled, ide_qua_enabled; +#ifdef SCSI_DEVICE_H extern ide_t *ide_drives[IDE_NUM]; +#endif extern int64_t idecallback[5]; +#ifdef SCSI_DEVICE_H extern void ide_irq_raise(ide_t *ide); extern void ide_irq_lower(ide_t *ide); +extern void ide_allocate_buffer(ide_t *dev); +extern void ide_atapi_attach(ide_t *dev); +#endif extern void * ide_xtide_init(void); extern void ide_xtide_close(void); @@ -140,8 +147,6 @@ extern void (*ide_bus_master_set_irq)(int channel, void *priv); extern void *ide_bus_master_priv[2]; extern void ide_enable_pio_override(void); -extern void ide_allocate_buffer(ide_t *dev); -extern void ide_atapi_attach(ide_t *dev); #endif /*EMU_IDE_H*/ diff --git a/src/disk/hdd.h b/src/disk/hdd.h index 7efa2a6e3..33e566d41 100644 --- a/src/disk/hdd.h +++ b/src/disk/hdd.h @@ -8,7 +8,7 @@ * * Definitions for the hard disk image handler. * - * Version: @(#)hdd.h 1.0.7 2018/10/26 + * Version: @(#)hdd.h 1.0.8 2018/10/28 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -74,30 +74,28 @@ enum { /* Define the virtual Hard Disk. */ typedef struct { - int8_t is_hdi; /* image type (should rename) */ - int8_t wp; /* disk has been mounted READ-ONLY */ - - uint8_t bus; - - uint8_t mfm_channel; /* should rename and/or unionize */ + uint8_t id; + uint8_t mfm_channel; /* Should rename and/or unionize */ uint8_t esdi_channel; uint8_t xta_channel; uint8_t ide_channel; uint8_t scsi_id; + uint8_t bus, + res; /* Reserved for bus mode */ + uint8_t wp; /* Disk has been mounted READ-ONLY */ + uint8_t pad, pad0; - uint32_t base, - spt, - hpc, /* physical geometry parameters */ - tracks, - at_spt, /* [Translation] parameters */ - at_hpc; - + FILE *f; /* Current file handle to image */ void *priv; - FILE *f; /* current file handle to image */ + wchar_t fn[1024], /* Name of current image file */ + prev_fn[1024]; /* Name of previous image file */ - wchar_t fn[260]; /* name of current image file */ - wchar_t prev_fn[260]; /* name of previous image file */ + uint32_t res0, pad1, + base, + spt, + hpc, /* Physical geometry parameters */ + tracks; } hard_disk_t; @@ -147,7 +145,6 @@ extern int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count); extern uint32_t hdd_image_get_last_sector(uint8_t id); extern uint32_t hdd_image_get_pos(uint8_t id); extern uint8_t hdd_image_get_type(uint8_t id); -extern void hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt); extern void hdd_image_unload(uint8_t id, int fn_preserve); extern void hdd_image_close(uint8_t id); extern void hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size); diff --git a/src/disk/hdd_image.c b/src/disk/hdd_image.c index e183f2dc6..d8bc070d8 100644 --- a/src/disk/hdd_image.c +++ b/src/disk/hdd_image.c @@ -8,7 +8,7 @@ * * Handling of hard disk image files. * - * Version: @(#)hdd_image.c 1.0.19 2018/10/17 + * Version: @(#)hdd_image.c 1.0.20 2018/10/28 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -182,14 +182,14 @@ image_is_vhd(const wchar_t *s, int check_signature) static uint64_t be_to_u64(uint8_t *bytes, int start) { - uint64_t n = ((uint64_t)bytes[start+7] << 0) | - ((uint64_t)bytes[start+6] << 8) | - ((uint64_t)bytes[start+5] << 16) | - ((uint64_t)bytes[start+4] << 24) | - ((uint64_t)bytes[start+3] << 32) | - ((uint64_t)bytes[start+2] << 40) | - ((uint64_t)bytes[start+1] << 48) | - ((uint64_t)bytes[start] << 56); + uint64_t n = ((uint64_t) bytes[start + 7] << 0) | + ((uint64_t) bytes[start + 6] << 8) | + ((uint64_t) bytes[start + 5] << 16) | + ((uint64_t) bytes[start + 4] << 24) | + ((uint64_t) bytes[start + 3] << 32) | + ((uint64_t) bytes[start + 2] << 40) | + ((uint64_t) bytes[start + 1] << 48) | + ((uint64_t) bytes[start ] << 56); return n; } @@ -197,10 +197,10 @@ be_to_u64(uint8_t *bytes, int start) static uint32_t be_to_u32(uint8_t *bytes, int start) { - uint32_t n = ((uint32_t)bytes[start+3] << 0) | - ((uint32_t)bytes[start+2] << 8) | - ((uint32_t)bytes[start+1] << 16) | - ((uint32_t)bytes[start] << 24); + uint32_t n = ((uint32_t) bytes[start + 3] << 0) | + ((uint32_t) bytes[start + 2] << 8) | + ((uint32_t) bytes[start + 1] << 16) | + ((uint32_t) bytes[start ] << 24); return n; } @@ -208,8 +208,8 @@ be_to_u32(uint8_t *bytes, int start) static uint16_t be_to_u16(uint8_t *bytes, int start) { - uint16_t n = ((uint16_t)bytes[start+1] << 0) | - ((uint16_t)bytes[start] <<8); + uint16_t n = ((uint16_t) bytes[start + 1] << 0) | + ((uint16_t) bytes[start ] << 8); return n; } @@ -222,11 +222,11 @@ u64_to_be(uint64_t value, int is_be) res = value; else { uint64_t mask = 0xff00000000000000; - res = ((value & (mask >> 0)) >> 56) | - ((value & (mask >> 8)) >> 40) | + res = ((value & (mask >> 0)) >> 56) | + ((value & (mask >> 8)) >> 40) | ((value & (mask >> 16)) >> 24) | - ((value & (mask >> 24)) >> 8) | - ((value & (mask >> 32)) << 8) | + ((value & (mask >> 24)) >> 8) | + ((value & (mask >> 32)) << 8) | ((value & (mask >> 40)) << 24) | ((value & (mask >> 48)) << 40) | ((value & (mask >> 56)) << 56); @@ -243,9 +243,9 @@ u32_to_be(uint32_t value, int is_be) res = value; else { uint32_t mask = 0xff000000; - res = ((value & (mask >> 0)) >> 24) | - ((value & (mask >> 8)) >> 8) | - ((value & (mask >> 16)) << 8) | + res = ((value & (mask >> 0)) >> 24) | + ((value & (mask >> 8)) >> 8) | + ((value & (mask >> 16)) << 8) | ((value & (mask >> 24)) << 24); } return res; @@ -286,7 +286,7 @@ calc_vhd_timestamp() time_t start_time; time_t curr_time; double vhd_time; - start_time = 946684800; /* 1 Jan 2000 00:00 */ + start_time = 946684800; /* 1 Jan 2000 00:00 */ curr_time = time(NULL); vhd_time = difftime(curr_time, start_time); @@ -498,6 +498,25 @@ hdd_image_init(void) } +static void +hdd_image_gen_vft(int id, vhd_footer_t **vft, uint64_t full_size) +{ + /* Generate new footer. */ + new_vhd_footer(vft); + (*vft)->orig_size = (*vft)->curr_size = full_size; + (*vft)->geom.cyl = hdd[id].tracks; + (*vft)->geom.heads = hdd[id].hpc; + (*vft)->geom.spt = hdd[id].spt; + generate_vhd_checksum(*vft); + vhd_footer_to_bytes((uint8_t *) empty_sector, *vft); + fseeko64(hdd_images[id].file, 0, SEEK_END); + fwrite(empty_sector, 1, 512, hdd_images[id].file); + free(*vft); + *vft = NULL; + hdd_images[id].type = 3; +} + + int hdd_image_load(int id) { @@ -601,23 +620,7 @@ hdd_image_load(int id) if (is_vhd[0]) { /* VHD image. */ - /* Generate new footer. */ - empty_sector_1mb = (char *) malloc(512); - new_vhd_footer(&vft); - vft->orig_size = vft->curr_size = full_size; - vft->geom.cyl = hdd[id].tracks; - vft->geom.heads = hdd[id].hpc; - vft->geom.spt = hdd[id].spt; - generate_vhd_checksum(vft); - memset(empty_sector_1mb, 0, 512); - vhd_footer_to_bytes((uint8_t *) empty_sector_1mb, vft); - fseeko64(hdd_images[id].file, 0, SEEK_END); - fwrite(empty_sector_1mb, 1, 512, hdd_images[id].file); - free(vft); - vft = NULL; - free(empty_sector_1mb); - empty_sector_1mb = NULL; - hdd_images[id].type = 3; + hdd_image_gen_vft(id, &vft, full_size); } return ret; @@ -671,23 +674,17 @@ hdd_image_load(int id) hdd[id].spt = spt; hdd[id].hpc = hpc; hdd[id].tracks = tracks; - fread(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); - fread(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); hdd_images[id].type = 2; } else if (is_vhd[1]) { - empty_sector_1mb = (char *) malloc(512); - memset(empty_sector_1mb, 0, 512); fseeko64(hdd_images[id].file, -512, SEEK_END); - fread(empty_sector_1mb, 1, 512, hdd_images[id].file); + fread(empty_sector, 1, 512, hdd_images[id].file); new_vhd_footer(&vft); - vhd_footer_from_bytes(vft, (uint8_t *) empty_sector_1mb); + vhd_footer_from_bytes(vft, (uint8_t *) empty_sector); if (vft->type != 2) { /* VHD is not fixed size */ hdd_image_log("VHD: Image is not fixed size\n"); free(vft); vft = NULL; - free(empty_sector_1mb); - empty_sector_1mb = NULL; fclose(hdd_images[id].file); hdd_images[id].file = NULL; memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); @@ -699,8 +696,6 @@ hdd_image_load(int id) hdd[id].spt = vft->geom.spt; free(vft); vft = NULL; - free(empty_sector_1mb); - empty_sector_1mb = NULL; hdd_images[id].type = 3; /* If we're here, this means there is a valid VHD footer in the image, which means that by definition, all valid sectors @@ -731,22 +726,7 @@ hdd_image_load(int id) s = ftello64(hdd_images[id].file); if (s == (full_size + hdd_images[id].base)) { /* VHD image. */ - /* Generate new footer. */ - empty_sector_1mb = (char *) malloc(512); - new_vhd_footer(&vft); - vft->orig_size = vft->curr_size = full_size; - vft->geom.cyl = hdd[id].tracks; - vft->geom.heads = hdd[id].hpc; - vft->geom.spt = hdd[id].spt; - generate_vhd_checksum(vft); - memset(empty_sector_1mb, 0, 512); - vhd_footer_to_bytes((uint8_t *) empty_sector_1mb, vft); - fwrite(empty_sector_1mb, 1, 512, hdd_images[id].file); - free(vft); - vft = NULL; - free(empty_sector_1mb); - empty_sector_1mb = NULL; - hdd_images[id].type = 3; + hdd_image_gen_vft(id, &vft, full_size); } } @@ -791,9 +771,7 @@ hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) if ((sectors - sector) < transfer_sectors) transfer_sectors = sectors - sector; - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); - fread(buffer, 1, transfer_sectors << 9, hdd_images[id].file); + hdd_image_read(id, sector, transfer_sectors, buffer); if (count != transfer_sectors) return 1; @@ -819,9 +797,7 @@ hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) if ((sectors - sector) < transfer_sectors) transfer_sectors = sectors - sector; - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); - fwrite(buffer, transfer_sectors << 9, 1, hdd_images[id].file); + hdd_image_write(id, sector, transfer_sectors, buffer); if (count != transfer_sectors) return 1; @@ -836,6 +812,7 @@ hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) hdd_images[id].pos = sector; fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + memset(empty_sector, 0, 512); for (i = 0; i < count; i++) fwrite(empty_sector, 512, 1, hdd_images[id].file); } @@ -844,18 +821,13 @@ hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count) { - uint32_t i = 0; - uint32_t transfer_sectors = count; uint32_t sectors = hdd_sectors(id); if ((sectors - sector) < transfer_sectors) transfer_sectors = sectors - sector; - hdd_images[id].pos = sector; - fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); - for (i = 0; i < transfer_sectors; i++) - fwrite(empty_sector, 1, 512, hdd_images[id].file); + hdd_image_zero(id, sector, transfer_sectors); if (count != transfer_sectors) return 1; @@ -884,19 +856,6 @@ hdd_image_get_type(uint8_t id) } -void -hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt) -{ - if (hdd_images[id].type == 2) { - hdd[id].at_hpc = hpc; - hdd[id].at_spt = spt; - fseeko64(hdd_images[id].file, 0x20, SEEK_SET); - fwrite(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); - fwrite(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); - } -} - - void hdd_image_unload(uint8_t id, int fn_preserve) { diff --git a/src/disk/zip.c b/src/disk/zip.c index ab4fd270c..6c44cdac0 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -9,7 +9,7 @@ * Implementation of the Iomega ZIP drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)zip.c 1.0.34 2018/10/27 + * Version: @(#)zip.c 1.0.34 2018/10/28 * * Author: Miran Grca, * @@ -36,19 +36,6 @@ #include "zip.h" -/* Bits of 'status' */ -#define ERR_STAT 0x01 -#define DRQ_STAT 0x08 /* Data request */ -#define DSC_STAT 0x10 -#define SERVICE_STAT 0x10 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 - -/* Bits of 'error' */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* Media change request */ - - zip_drive_t zip_drives[ZIP_NUM]; @@ -450,7 +437,7 @@ static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = static void zip_command_complete(zip_t *dev); static void zip_init(zip_t *dev); -static void zip_callback(void *p); +static void zip_callback(scsi_common_t *sc); #ifdef ENABLE_ZIP_LOG @@ -486,62 +473,66 @@ find_zip_for_channel(uint8_t channel) } +static int +zip_load_abort(zip_t *dev) +{ + if (dev->drv->f) + fclose(dev->drv->f); + dev->drv->f = NULL; + dev->drv->medium_size = 0; + zip_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; +} + + int zip_load(zip_t *dev, wchar_t *fn) { - int read_only = dev->drv->ui_writeprot; int size = 0; - dev->drv->f = plat_fopen(fn, dev->drv->ui_writeprot ? L"rb" : L"rb+"); - if (!dev->drv->ui_writeprot && !dev->drv->f) { - dev->drv->f = plat_fopen(fn, L"rb"); - read_only = 1; - } - if (dev->drv->f) { - fseek(dev->drv->f, 0, SEEK_END); - size = ftell(dev->drv->f); - - if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { - /* This is a ZDI image. */ - size -= 0x1000; - dev->drv->base = 0x1000; + dev->drv->f = plat_fopen(fn, dev->drv->read_only ? L"rb" : L"rb+"); + if (!dev->drv->f) { + if (!dev->drv->read_only) { + dev->drv->f = plat_fopen(fn, L"rb"); + if (dev->drv->f) + dev->drv->read_only = 1; + else + return zip_load_abort(dev); } else - dev->drv->base = 0; - - if (dev->drv->is_250) { - if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", - ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); - fclose(dev->drv->f); - dev->drv->f = NULL; - dev->drv->medium_size = 0; - zip_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ - return 0; - } - } else { - if (size != (ZIP_SECTORS << 9)) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", - ZIP_SECTORS << 9); - fclose(dev->drv->f); - dev->drv->f = NULL; - dev->drv->medium_size = 0; - zip_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ - return 0; - } - } - - dev->drv->medium_size = size >> 9; - - fseek(dev->drv->f, dev->drv->base, SEEK_SET); - - memcpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path)); - - dev->drv->read_only = read_only; - - return 1; + return zip_load_abort(dev); } - return 0; + fseek(dev->drv->f, 0, SEEK_END); + size = ftell(dev->drv->f); + + if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { + /* This is a ZDI image. */ + size -= 0x1000; + dev->drv->base = 0x1000; + } else + dev->drv->base = 0; + + if (dev->drv->is_250) { + if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", + ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); + return zip_load_abort(dev); + } + } else { + if (size != (ZIP_SECTORS << 9)) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", + ZIP_SECTORS << 9); + return zip_load_abort(dev); + } + } + + dev->drv->medium_size = size >> 9; + + fseek(dev->drv->f, dev->drv->base, SEEK_SET); + + memcpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path)); + + return 1; } @@ -592,18 +583,6 @@ zip_set_callback(zip_t *dev) } -static void -zip_set_signature(void *p) -{ - zip_t *dev = (zip_t *) p; - - if (dev->id >= ZIP_NUM) - return; - dev->phase = 1; - dev->request_length = 0xEB14; -} - - static void zip_init(zip_t *dev) { @@ -619,8 +598,10 @@ zip_init(zip_t *dev) if (dev->drv->bus_type < ZIP_BUS_SCSI) dev->drv->bus_mode |= 1; zip_log("ZIP %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); - if (dev->drv->bus_type < ZIP_BUS_SCSI) - zip_set_signature(dev); + if (dev->drv->bus_type < ZIP_BUS_SCSI) { + dev->phase = 1; + dev->request_length = 0xEB14; + } dev->status = READY_STAT | DSC_STAT; dev->pos = 0; dev->packet_status = 0xff; @@ -663,19 +644,6 @@ zip_current_mode(zip_t *dev) } -/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -static int -zip_err_stat_to_scsi(void *p) -{ - zip_t *dev = (zip_t *) p; - - if (dev->status & ERR_STAT) - return SCSI_STATUS_CHECK_CONDITION; - else - return SCSI_STATUS_OK; -} - - /* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ int zip_atapi_phase_to_scsi(zip_t *dev) @@ -753,25 +721,6 @@ zip_mode_sense_save(zip_t *dev) } -static int -zip_read_capacity(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - zip_t *dev = (zip_t *) p; - int size = 0; - - size = dev->drv->medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 2; /* 512 = 0x0200 */ - *len = 8; - - return 1; -} - - /*SCSI Mode Sense 6/10*/ static uint8_t zip_mode_sense_read(zip_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) @@ -927,7 +876,7 @@ zip_command_common(zip_t *dev) dev->phase = 1; dev->pos = 0; if (dev->packet_status == PHASE_COMPLETE) { - zip_callback((void *) dev); + zip_callback((scsi_common_t *) dev); dev->callback = 0LL; } else { if (dev->drv->bus_type == ZIP_BUS_SCSI) { @@ -1322,15 +1271,16 @@ zip_rezero(zip_t *dev) void -zip_reset(void *p) +zip_reset(scsi_common_t *sc) { - zip_t *dev = (zip_t *) p; + zip_t *dev = (zip_t *) sc; zip_rezero(dev); dev->status = 0; dev->callback = 0LL; zip_set_callback(dev); - zip_set_signature(dev); + dev->phase = 1; + dev->request_length = 0xEB14; dev->packet_status = 0xff; dev->unit_attention = 0; } @@ -1373,9 +1323,9 @@ zip_request_sense(zip_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) static void -zip_request_sense_for_scsi(void *p, uint8_t *buffer, uint8_t alloc_length) +zip_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) { - zip_t *dev = (zip_t *) p; + zip_t *dev = (zip_t *) sc; int ready = 0; ready = (dev->drv->f != NULL); @@ -1412,7 +1362,8 @@ static void zip_buf_alloc(zip_t *dev, uint32_t len) { zip_log("ZIP %i: Allocated buffer length: %i\n", dev->id, len); - dev->buffer = (uint8_t *) malloc(len); + if (!dev->buffer) + dev->buffer = (uint8_t *) malloc(len); } @@ -1428,9 +1379,9 @@ zip_buf_free(zip_t *dev) static void -zip_command(void *p, uint8_t *cdb) +zip_command(scsi_common_t *sc, uint8_t *cdb) { - zip_t *dev = (zip_t *) p; + zip_t *dev = (zip_t *) sc; int pos = 0, block_desc = 0; int ret; int32_t len, max_len; @@ -1555,10 +1506,9 @@ zip_command(void *p, uint8_t *cdb) case GPCMD_MECHANISM_STATUS: zip_set_phase(dev, SCSI_PHASE_DATA_IN); - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + len = (cdb[8] << 8) | cdb[9]; zip_buf_alloc(dev, 8); - zip_set_buf_len(dev, BufLen, &len); memset(dev->buffer, 0, 8); @@ -1609,6 +1559,10 @@ zip_command(void *p, uint8_t *cdb) ret = zip_blocks(dev, &alloc_length, 1, 0); if (ret <= 0) { + zip_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20LL * ZIP_TIME; + zip_set_callback(dev); zip_buf_free(dev); return; } @@ -1705,7 +1659,6 @@ zip_command(void *p, uint8_t *cdb) return; case GPCMD_WRITE_SAME_10: - zip_set_phase(dev, SCSI_PHASE_DATA_OUT); alloc_length = 512; if ((cdb[1] & 6) == 6) { @@ -1736,20 +1689,17 @@ zip_command(void *p, uint8_t *cdb) break; } - max_len = dev->sector_len; - dev->requested_blocks = max_len; /* If we're writing 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; - zip_buf_alloc(dev, dev->packet_len); - - dev->requested_blocks = max_len; - dev->packet_len = alloc_length; - + zip_buf_alloc(dev, alloc_length); zip_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); - zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); + max_len = 1; + dev->requested_blocks = 1; + + dev->packet_len = alloc_length; + + zip_set_phase(dev, SCSI_PHASE_DATA_OUT); + + zip_data_command_finish(dev, 512, 512, alloc_length, 1); if (dev->packet_status != PHASE_COMPLETE) ui_sb_update_icon(SB_ZIP | dev->id, 1); @@ -1986,10 +1936,14 @@ atapi_out: zip_buf_alloc(dev, 8); - if (zip_read_capacity(dev, dev->current_cdb, dev->buffer, (uint32_t *) &len) == 0) { - zip_buf_free(dev); - return; - } + max_len = dev->drv->medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(dev->buffer, 0, 8); + dev->buffer[0] = (max_len >> 24) & 0xff; + dev->buffer[1] = (max_len >> 16) & 0xff; + dev->buffer[2] = (max_len >> 8) & 0xff; + dev->buffer[3] = max_len & 0xff; + dev->buffer[6] = 2; /* 512 = 0x0200 */ + len = 8; zip_set_buf_len(dev, BufLen, &len); @@ -2082,10 +2036,22 @@ atapi_out: } +static void +zip_command_stop(scsi_common_t *sc) +{ + zip_t *dev = (zip_t *) sc; + + zip_command_complete(dev); + zip_buf_free(dev); +} + + /* The command second phase function, needed for Mode Select. */ static uint8_t -zip_phase_data_out(zip_t *dev) +zip_phase_data_out(scsi_common_t *sc) { + zip_t *dev = (zip_t *) sc; + uint16_t block_desc_len; uint16_t pos; @@ -2202,407 +2168,137 @@ zip_phase_data_out(zip_t *dev) } if (error) { + zip_buf_free(dev); zip_invalid_field_pl(dev); return 0; } break; } - return 1; -} - - -/* This is the general ATAPI PIO request function. */ -static void -zip_pio_request(zip_t *dev, uint8_t out) -{ - int ret = 0; - - if (dev->drv->bus_type < ZIP_BUS_SCSI) { - zip_log("ZIP %i: Lowering IDE IRQ\n", dev->id); - ide_irq_lower(ide_drives[dev->drv->ide_channel]); - } - - dev->status = BUSY_STAT; - - if (dev->pos >= dev->packet_len) { - zip_log("ZIP %i: %i bytes %s, command done\n", dev->id, dev->pos, out ? "written" : "read"); - - dev->pos = dev->request_pos = 0; - if (out) { - ret = zip_phase_data_out(dev); - /* If ret = 0 (phase 1 error), then we do not do anything else other than - free the buffer, as the phase and callback have already been set by the - error function. */ - if (ret) - zip_command_complete(dev); - } else - zip_command_complete(dev); - zip_buf_free(dev); - } else { - zip_log("ZIP %i: %i bytes %s, %i bytes are still left\n", dev->id, dev->pos, - out ? "written" : "read", dev->packet_len - dev->pos); - - /* If less than (packet length) bytes are remaining, update packet length - accordingly. */ - if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) - dev->max_transfer_len = dev->packet_len - dev->pos; - zip_log("ZIP %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, - dev->max_transfer_len); - - dev->packet_status = out ? PHASE_DATA_OUT : PHASE_DATA_IN; - - dev->status = BUSY_STAT; - dev->phase = 1; - zip_callback((void *) dev); - dev->callback = 0LL; - zip_set_callback(dev); - - dev->request_pos = 0; - } -} - - -static int -zip_read_from_ide_dma(zip_t *dev) -{ - int ret; - - if (!dev) - return 0; - - if (ide_bus_master_write) { - ret = ide_bus_master_write(dev->drv->ide_channel >> 1, - dev->buffer, dev->packet_len, - ide_bus_master_priv[dev->drv->ide_channel >> 1]); - if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ - return 2; - else if (ret == 1) { /* DMA error. */ - zip_bus_master_error(dev); - return 0; - } else - return 1; - } else - return 0; -} - - -static int -zip_read_from_scsi_dma(uint8_t scsi_id) -{ - zip_t *dev = (zip_t *) scsi_devices[scsi_id].p; - int32_t *BufLen = &scsi_devices[scsi_id].buffer_length; - - if (!dev) - return 0; - - zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(dev->buffer, scsi_devices[scsi_id].cmd_buffer, *BufLen); + zip_command_stop((scsi_common_t *) dev); return 1; } static void -zip_irq_raise(zip_t *dev) +zip_irq_raise(scsi_common_t *sc) { - if (dev->drv->bus_type < ZIP_BUS_SCSI) + zip_t *dev = (zip_t *) sc; + + if (dev->drv && (dev->drv->bus_type < ZIP_BUS_SCSI)) ide_irq_raise(ide_drives[dev->drv->ide_channel]); } static int -zip_read_from_dma(zip_t *dev) +zip_dma(zip_t *dev, int out) { -#ifdef ENABLE_ZIP_LOG - int32_t *BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; -#endif - int ret = 0; + int ret = 1; - if (dev->drv->bus_type == ZIP_BUS_SCSI) - ret = zip_read_from_scsi_dma(dev->drv->scsi_device_id); - else - ret = zip_read_from_ide_dma(dev); + if (dev->drv->bus_type == ZIP_BUS_ATAPI) { + ret = 0; - if (ret != 1) - return ret; + if (out && dev && ide_bus_master_write) { + ret = ide_bus_master_write(dev->drv->ide_channel >> 1, + dev->buffer, dev->packet_len, + ide_bus_master_priv[dev->drv->ide_channel >> 1]); + } else if (!out && dev && ide_bus_master_read) { + ret = ide_bus_master_read(dev->drv->ide_channel >> 1, + dev->buffer, dev->packet_len, + ide_bus_master_priv[dev->drv->ide_channel >> 1]); + } + } - if (dev->drv->bus_type == ZIP_BUS_SCSI) - zip_log("ZIP %i: SCSI Input data length: %i\n", dev->id, *BufLen); - else - zip_log("ZIP %i: ATAPI Input data length: %i\n", dev->id, dev->packet_len); - - ret = zip_phase_data_out(dev); - - if (ret) - return 1; - else - return 0; -} - - -static int -zip_write_to_ide_dma(zip_t *dev) -{ - int ret; - - if (!dev) - return 0; - - if (ide_bus_master_read) { - ret = ide_bus_master_read(dev->drv->ide_channel >> 1, - dev->buffer, dev->packet_len, - ide_bus_master_priv[dev->drv->ide_channel >> 1]); - if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ - return 2; - else if (ret == 1) { /* DMA error. */ - zip_bus_master_error(dev); - return 0; - } else - return 1; - } else - return 0; -} - - -static int -zip_write_to_scsi_dma(uint8_t scsi_id) -{ - zip_t *dev = (zip_t *) scsi_devices[scsi_id].p; - int32_t *BufLen = &scsi_devices[scsi_id].buffer_length; - - if (!dev) - return 0; - - zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(scsi_devices[scsi_id].cmd_buffer, dev->buffer, *BufLen); - zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, - dev->buffer[0], dev->buffer[1], dev->buffer[2], dev->buffer[3], dev->buffer[4], dev->buffer[5], - dev->buffer[6], dev->buffer[7]); - return 1; -} - - -static int -zip_write_to_dma(zip_t *dev) -{ -#ifdef ENABLE_ZIP_LOG - int32_t *BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; -#endif - int ret = 0; - - if (dev->drv->bus_type == ZIP_BUS_SCSI) { - zip_log("Write to SCSI DMA: (ID %02X)\n", dev->drv->scsi_device_id); - ret = zip_write_to_scsi_dma(dev->drv->scsi_device_id); - } else - ret = zip_write_to_ide_dma(dev); - - if (dev->drv->bus_type == ZIP_BUS_SCSI) - zip_log("ZIP %i: SCSI Output data length: %i\n", dev->id, *BufLen); - else - zip_log("ZIP %i: ATAPI Output data length: %i\n", dev->id, dev->packet_len); + if (ret == 0) { + zip_buf_free(dev); + zip_bus_master_error(dev); + } else if (ret == 1) { + if (out) + ret = zip_phase_data_out((scsi_common_t *) dev); + else + zip_command_stop((scsi_common_t *) dev); + } return ret; } static void -zip_callback(void *p) +zip_callback(scsi_common_t *sc) { - zip_t *dev = (zip_t *) p; + zip_t *dev = (zip_t *) sc; int ret; - switch(dev->packet_status) { + switch(sc->packet_status) { case PHASE_IDLE: - zip_log("ZIP %i: PHASE_IDLE\n", dev->id); - dev->pos = 0; - dev->phase = 1; - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + zip_log("ZIP %i: PHASE_IDLE\n", sc->id); + sc->pos = 0; + sc->phase = 1; + sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); return; case PHASE_COMMAND: - zip_log("ZIP %i: PHASE_COMMAND\n", dev->id); - dev->status = BUSY_STAT | (dev->status & ERR_STAT); - memcpy(dev->atapi_cdb, dev->buffer, 12); - zip_command(dev, dev->atapi_cdb); + zip_log("ZIP %i: PHASE_COMMAND\n", sc->id); + sc->status = BUSY_STAT | (sc->status & ERR_STAT); + zip_command(sc, sc->atapi_cdb); return; case PHASE_COMPLETE: - zip_log("ZIP %i: PHASE_COMPLETE\n", dev->id); - dev->status = READY_STAT; - dev->phase = 3; - dev->packet_status = 0xFF; - ui_sb_update_icon(SB_ZIP | dev->id, 0); - zip_irq_raise(dev); + zip_log("ZIP %i: PHASE_COMPLETE\n", sc->id); + sc->status = READY_STAT; + sc->phase = 3; + sc->packet_status = 0xFF; + ui_sb_update_icon(SB_ZIP | sc->id, 0); + zip_irq_raise(sc); return; case PHASE_DATA_OUT: - zip_log("ZIP %i: PHASE_DATA_OUT\n", dev->id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 0; - zip_irq_raise(dev); + zip_log("ZIP %i: PHASE_DATA_OUT\n", sc->id); + sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); + sc->phase = 0; + zip_irq_raise(sc); return; case PHASE_DATA_OUT_DMA: zip_log("ZIP %i: PHASE_DATA_OUT_DMA\n", dev->id); - ret = zip_read_from_dma(dev); + ret = zip_dma(dev, 1); - if ((ret == 1) || (dev->drv->bus_type == ZIP_BUS_SCSI)) { - zip_log("ZIP %i: DMA data out phase done\n"); - zip_buf_free(dev); - zip_command_complete(dev); - } else if (ret == 2) { - zip_log("ZIP %i: DMA out not enabled, wait\n"); + if (ret == 2) { + zip_log("ZIP %i: DMA out not enabled, wait\n", sc->id); zip_command_bus(dev); +#ifdef ENABLE_ZIP_LOG } else { - zip_log("ZIP %i: DMA data out phase failure\n"); - zip_buf_free(dev); + zip_log("ZIP %i: DMA data out phase %s\n", sc->id, ret ? "done" : "failure"); +#endif } return; case PHASE_DATA_IN: - zip_log("ZIP %i: PHASE_DATA_IN\n", dev->id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 2; - zip_irq_raise(dev); + zip_log("ZIP %i: PHASE_DATA_IN\n", sc->id); + sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); + sc->phase = 2; + zip_irq_raise(sc); return; case PHASE_DATA_IN_DMA: - zip_log("ZIP %i: PHASE_DATA_IN_DMA\n", dev->id); - ret = zip_write_to_dma(dev); + zip_log("ZIP %i: PHASE_DATA_IN_DMA\n", sc->id); + ret = zip_dma(dev, 0); - if ((ret == 1) || (dev->drv->bus_type == ZIP_BUS_SCSI)) { - zip_log("ZIP %i: DMA data in phase done\n", dev->id); - zip_buf_free(dev); - zip_command_complete(dev); - } else if (ret == 2) { - zip_log("ZIP %i: DMA in not enabled, wait\n", dev->id); + if (ret == 2) { + zip_log("ZIP %i: DMA in not enabled, wait\n", sc->id); zip_command_bus(dev); +#ifdef ENABLE_ZIP_LOG } else { - zip_log("ZIP %i: DMA data in phase failure\n", dev->id); - zip_buf_free(dev); + zip_log("ZIP %i: DMA data in phase %s\n", sc->id, ret ? "done" : "failure"); +#endif } return; case PHASE_ERROR: - zip_log("ZIP %i: PHASE_ERROR\n", dev->id); - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - dev->packet_status = 0xFF; - zip_irq_raise(dev); - ui_sb_update_icon(SB_ZIP | dev->id, 0); + zip_log("ZIP %i: PHASE_ERROR\n", sc->id); + sc->status = READY_STAT | ERR_STAT; + sc->phase = 3; + sc->packet_status = 0xFF; + zip_irq_raise(sc); + ui_sb_update_icon(SB_ZIP | sc->id, 0); return; } } -static uint32_t -zip_packet_read(void *p, int length) -{ - zip_t *dev = (zip_t *) p; - - uint16_t *zipbufferw; - uint32_t *zipbufferl; - - uint32_t temp = 0; - - if (!dev) - return 0; - - zipbufferw = (uint16_t *) dev->buffer; - zipbufferl = (uint32_t *) dev->buffer; - - if (!dev->buffer) - return 0; - - /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, - which can happen when issuing media access commands with an allocated length below minimum request length - (which is 1 sector = 512 bytes). */ - switch(length) { - case 1: - temp = (dev->pos < dev->packet_len) ? dev->buffer[dev->pos] : 0; - dev->pos++; - dev->request_pos++; - break; - case 2: - temp = (dev->pos < dev->packet_len) ? zipbufferw[dev->pos >> 1] : 0; - dev->pos += 2; - dev->request_pos += 2; - break; - case 4: - temp = (dev->pos < dev->packet_len) ? zipbufferl[dev->pos >> 2] : 0; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return 0; - } - - if (dev->packet_status == PHASE_DATA_IN) { - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - zip_pio_request(dev, 0); - } - return temp; - } else - return 0; -} - - -static void -zip_packet_write(void *p, uint32_t val, int length) -{ - zip_t *dev = (zip_t *) p; - - uint16_t *zipbufferw; - uint32_t *zipbufferl; - - if (!dev) - return; - - if (dev->packet_status == PHASE_IDLE) { - if (!dev->buffer) - zip_buf_alloc(dev, 12); - } - - zipbufferw = (uint16_t *) dev->buffer; - zipbufferl = (uint32_t *) dev->buffer; - - if (!dev->buffer) - return; - - switch(length) { - case 1: - dev->buffer[dev->pos] = val & 0xff; - dev->pos++; - dev->request_pos++; - break; - case 2: - zipbufferw[dev->pos >> 1] = val & 0xffff; - dev->pos += 2; - dev->request_pos += 2; - break; - case 4: - zipbufferl[dev->pos >> 2] = val; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return; - } - - if (dev->packet_status == PHASE_DATA_OUT) { - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - zip_pio_request(dev, 1); - } - return; - } else if (dev->packet_status == PHASE_IDLE) { - if (dev->pos >= 12) { - dev->pos = 0; - dev->status = BUSY_STAT; - dev->packet_status = PHASE_COMMAND; - timer_process(); - zip_callback((void *) dev); - timer_update_outstanding(); - } - return; - } -} - - /* Peform a master init on the entire module. */ void zip_global_init(void) @@ -2612,27 +2308,6 @@ zip_global_init(void) } -static void -zip_100_identify(ide_t *ide) -{ - ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ -} - - -static void -zip_250_identify(ide_t *ide, int ide_has_dma) -{ - ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ - ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ - - if (ide_has_dma) { - ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ - ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ - } -} - - static int zip_get_max(int ide_has_dma, int type) { @@ -2647,10 +2322,10 @@ zip_get_max(int ide_has_dma, int type) ret = -1; break; case TYPE_MDMA: - ret = ide_has_dma ? -1 : 1; + ret = ide_has_dma ? 1 : -1; break; case TYPE_UDMA: - ret = ide_has_dma ? -1 : 2; + ret = ide_has_dma ? 2 : -1; break; } @@ -2683,16 +2358,38 @@ zip_get_timings(int ide_has_dma, int type) static void -zip_identify(void *p, int ide_has_dma) +zip_100_identify(ide_t *ide) +{ + ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ +} + + +static void +zip_250_identify(ide_t *ide, int ide_has_dma) +{ + ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ + + if (ide_has_dma) { + ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ + ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ + } +} + + +static void +zip_identify(ide_t *ide, int ide_has_dma) { - ide_t *ide = (ide_t *) p; zip_t *zip; - zip = (zip_t *) ide->p; + zip = (zip_t *) ide->sc; - /* Using (2<<5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive + /* ATAPI device, direct-access device, removable media, interrupt DRQ: + + Using (2 << 5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive as a LS-120. */ - ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (1<<5); /* ATAPI device, direct-access device, removable media, interrupt DRQ */ + ide->buffer[0] = 0x8000 | (0 << 8) | 0x80 | (1 << 5); ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ ide->buffer[49] = 0x200; /* LBA supported */ ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ @@ -2724,13 +2421,12 @@ zip_drive_reset(int c) /* SCSI ZIP, attach to the SCSI bus. */ sd = &scsi_devices[zip_drives[c].scsi_device_id]; - sd->p = dev; + sd->sc = (scsi_common_t *) dev; sd->command = zip_command; sd->callback = zip_callback; - sd->err_stat_to_scsi = zip_err_stat_to_scsi; sd->request_sense = zip_request_sense_for_scsi; sd->reset = zip_reset; - sd->read_capacity = zip_read_capacity; + sd->command_stop = zip_command_stop; sd->type = SCSI_REMOVABLE_DISK; } else if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) { /* ATAPI CD-ROM, attach to the IDE bus. */ @@ -2739,16 +2435,15 @@ zip_drive_reset(int c) otherwise, we do nothing - it's going to be a drive that's not attached to anything. */ if (id) { - id->p = dev; + id->sc = (scsi_common_t *) dev; id->get_max = zip_get_max; id->get_timings = zip_get_timings; id->identify = zip_identify; - id->set_signature = zip_set_signature; - id->packet_write = zip_packet_write; - id->packet_read = zip_packet_read; id->stop = NULL; id->packet_callback = zip_callback; id->device_reset = zip_reset; + id->phase_data_out = zip_phase_data_out; + id->command_stop = zip_command_stop; id->interrupt_drq = 1; ide_atapi_attach(id); diff --git a/src/disk/zip.h b/src/disk/zip.h index b183d8638..33fd27485 100644 --- a/src/disk/zip.h +++ b/src/disk/zip.h @@ -9,7 +9,7 @@ * Implementation of the Iomega ZIP drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)zip.h 1.0.7 2018/10/26 + * Version: @(#)zip.h 1.0.8 2018/10/28 * * Author: Miran Grca, * @@ -39,22 +39,25 @@ enum { typedef struct { - unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ - uint8_t ide_channel, - bus_mode; /* Bit 0 = PIO suported; + uint8_t id, + res, res0, /* Reserved for other ID's. */ + res1, + ide_channel, scsi_device_id, + bus_type, /* 0 = ATAPI, 1 = SCSI */ + bus_mode, /* Bit 0 = PIO suported; Bit 1 = DMA supportd. */ + read_only, /* Struct variable reserved for + media status. */ + pad, pad0; - unsigned int scsi_device_id, is_250; + FILE *f; + void *priv; wchar_t image_path[1024], prev_image_path[1024]; - int read_only, ui_writeprot; - - uint32_t medium_size, base; - - FILE *f; - void *priv; + uint32_t is_250, medium_size, + base; } zip_drive_t; typedef struct { @@ -76,16 +79,13 @@ typedef struct { int requested_blocks, packet_status, total_length, do_page_save, - unit_attention; + unit_attention, request_pos, + old_len, pad3; uint32_t sector_pos, sector_len, packet_len, pos; int64_t callback; - - int request_pos, old_len; - - uint32_t seek_pos; } zip_t; @@ -116,7 +116,7 @@ extern void zip_insert(zip_t *dev); extern void zip_global_init(void); extern void zip_hard_reset(void); -extern void zip_reset(void *p); +extern void zip_reset(scsi_common_t *sc); extern int zip_load(zip_t *dev, wchar_t *fn); extern void zip_close(); diff --git a/src/intel_piix.c b/src/intel_piix.c index 51bbdf7b2..882943d37 100644 --- a/src/intel_piix.c +++ b/src/intel_piix.c @@ -10,7 +10,7 @@ * word 0 - base address * word 1 - bits 1-15 = byte count, bit 31 = end of transfer * - * Version: @(#)intel_piix.c 1.0.20 2018/10/26 + * Version: @(#)intel_piix.c 1.0.21 2018/10/28 * * Authors: Sarah Walker, * Miran Grca, @@ -652,27 +652,28 @@ piix_bus_master_dma_op(int channel, uint8_t *data, int transfer_length, int out, if (force_end) { piix_log("Total transfer length smaller than sum of all blocks, partial block\n"); dev->status &= ~2; - return 0; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ + return 1; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ } else { if (!transfer_length && !dev->eot) { piix_log("Total transfer length smaller than sum of all blocks, full block\n"); dev->status &= ~2; - return 0; /* We have exhausted the data to transfer but there's more blocks left, break. */ + return 1; /* We have exhausted the data to transfer but there's more blocks left, break. */ } else if (transfer_length && dev->eot) { piix_log("Total transfer length greater than sum of all blocks\n"); dev->status |= 2; - return 1; /* There is data left to transfer but we have reached EOT - return with error. */ + return 0; /* There is data left to transfer but we have reached EOT - return with error. */ } else if (dev->eot) { piix_log("Regular EOT\n"); dev->status &= ~3; - return 0; /* We have regularly reached EOT - clear status and break. */ + return 1; /* We have regularly reached EOT - clear status and break. */ } else { /* We have more to transfer and there are blocks left, get next block. */ piix_bus_master_next_addr(dev); } } } - return 0; + + return 1; } @@ -832,11 +833,11 @@ piix_reset(void *p) for (i = 0; i < CDROM_NUM; i++) { if ((cdrom[i].bus_type == CDROM_BUS_ATAPI) && cdrom[i].priv) - scsi_cdrom_reset(cdrom[i].priv); + scsi_cdrom_reset((scsi_common_t *) cdrom[i].priv); } for (i = 0; i < ZIP_NUM; i++) { if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && zip_drives[i].priv) - zip_reset(zip_drives[i].priv); + zip_reset((scsi_common_t *) zip_drives[i].priv); } } diff --git a/src/pc.c b/src/pc.c index df1750c6e..56c1207b5 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,7 +8,7 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.87 2018/10/26 + * Version: @(#)pc.c 1.0.88 2018/10/28 * * Authors: Sarah Walker, * Miran Grca, @@ -651,10 +651,8 @@ again2: keyboard_init(); joystick_init(); - video_init(); - device_init(); - timer_reset(); + video_init(); fdd_init(); @@ -662,9 +660,6 @@ again2: hdc_init(hdc_name); - pc_full_speed(); - shadowbios = 0; - return(1); } @@ -723,6 +718,8 @@ pc_reset_hard_close(void) device_close_all(); + scsi_device_close_all(); + midi_close(); cdrom_close(); @@ -834,6 +831,8 @@ pc_reset_hard_init(void) pic_reset(); cpu_cache_int_enabled = cpu_cache_ext_enabled = 0; + pc_full_speed(); + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); else @@ -908,6 +907,8 @@ pc_close(thread_t *ptr) device_close_all(); + scsi_device_close_all(); + midi_close(); network_close(); diff --git a/src/scsi/scsi.c b/src/scsi/scsi.c index bea9e7310..6ff1396ff 100644 --- a/src/scsi/scsi.c +++ b/src/scsi/scsi.c @@ -8,7 +8,7 @@ * * Handling of the SCSI controllers. * - * Version: @(#)scsi.c 1.0.22 2018/10/10 + * Version: @(#)scsi.c 1.0.24 2018/10/30 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -37,7 +37,7 @@ #include "scsi_aha154x.h" #include "scsi_buslogic.h" #include "scsi_ncr5380.h" -#include "scsi_ncr53c810.h" +#include "scsi_ncr53c8xx.h" #ifdef WALTJE # include "scsi_wd33c93.h" #endif @@ -55,25 +55,27 @@ typedef const struct { static SCSI_CARD scsi_cards[] = { - { "None", "none", NULL, }, - { "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, }, - { "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, }, - { "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, }, - { "[ISA] BusLogic BT-542BH","bt542bh", &buslogic_device, }, - { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device,}, - { "[ISA] Longshine LCS-6821N","lcs6821n", &scsi_lcs6821n_device,}, - { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, }, - { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, - { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, + { "None", "none", NULL, }, + { "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, }, + { "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, }, + { "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, }, + { "[ISA] BusLogic BT-542BH","bt542bh", &buslogic_device, }, + { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device, }, + { "[ISA] Longshine LCS-6821N","lcs6821n", &scsi_lcs6821n_device, }, + { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, }, + { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, + { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, #ifdef WALTJE - { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, + { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, #endif - { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, - { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device,}, - { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, - { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device,}, - { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device,}, - { "", "", NULL, }, + { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, + { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device, }, + { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, + { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device, }, + { "[PCI] NCR 53C825A", "ncr53c825a", &ncr53c825a_pci_device, }, + { "[PCI] NCR 53C875", "ncr53c875", &ncr53c875_pci_device, }, + { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device, }, + { "", "", NULL, }, }; @@ -129,17 +131,16 @@ int scsi_card_get_from_internal_name(char *s) void scsi_card_init(void) { int i; + scsi_device_t *dev; if (!scsi_cards[scsi_card_current].device) return; for (i = 0; i < SCSI_ID_MAX; i++) { - if (scsi_devices[i].cmd_buffer) - free(scsi_devices[i].cmd_buffer); - scsi_devices[i].cmd_buffer = NULL; + dev = &(scsi_devices[i]); - memset(&scsi_devices[i], 0, sizeof(scsi_device_t)); - scsi_devices[i].type = SCSI_NONE; + memset(dev, 0, sizeof(scsi_device_t)); + dev->type = SCSI_NONE; } device_add(scsi_cards[scsi_card_current].device); diff --git a/src/scsi/scsi_buslogic.c b/src/scsi/scsi_buslogic.c index e18ec2773..3b81c9eb3 100644 --- a/src/scsi/scsi_buslogic.c +++ b/src/scsi/scsi_buslogic.c @@ -11,7 +11,7 @@ * 1 - BT-545S ISA; * 2 - BT-958D PCI * - * Version: @(#)scsi_buslogic.c 1.0.42 2018/10/19 + * Version: @(#)scsi_buslogic.c 1.0.43 2018/10/28 * * Authors: TheCollector1995, * Miran Grca, @@ -574,10 +574,10 @@ BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, int dir) if (dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_OUT) || (ESCSICmd->DataDirection == 0x00))) { buslogic_log("BusLogic BIOS DMA: Reading %i bytes from %08X\n", TransferLength, Address); - DMAPageRead(Address, (uint8_t *)dev->cmd_buffer, TransferLength); + DMAPageRead(Address, (uint8_t *)dev->sc->temp_buffer, TransferLength); } else if (!dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || (ESCSICmd->DataDirection == 0x00))) { buslogic_log("BusLogic BIOS DMA: Writing %i bytes at %08X\n", TransferLength, Address); - DMAPageWrite(Address, (uint8_t *)dev->cmd_buffer, TransferLength); + DMAPageWrite(Address, (uint8_t *)dev->sc->temp_buffer, TransferLength); } } } @@ -624,8 +624,6 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u } } - x54x_buf_alloc(ESCSICmd->TargetId, ESCSICmd->DataLength); - target_cdb_len = 12; if (!scsi_device_valid(sd)) fatal("SCSI target on ID %02i has disappeared\n", ESCSICmd->TargetId); @@ -645,19 +643,15 @@ BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, u } sd->buffer_length = ESCSICmd->DataLength; + scsi_device_command_phase0(sd, temp_cdb); phase = sd->phase; if (phase != SCSI_PHASE_STATUS) { - if (phase == SCSI_PHASE_DATA_IN) - scsi_device_command_phase1(sd); BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, (phase == SCSI_PHASE_DATA_OUT)); - if (phase == SCSI_PHASE_DATA_OUT) - scsi_device_command_phase1(sd); + scsi_device_command_phase1(sd); } - x54x_buf_free(ESCSICmd->TargetId); - buslogic_log("BIOS Request complete\n"); if (sd->status == SCSI_STATUS_OK) { @@ -1155,7 +1149,8 @@ BuslogicPCIRead(int func, int addr, void *p) case 0x13: return buslogic_pci_bar[0].addr_regs[3]; case 0x14: - return (buslogic_pci_bar[1].addr_regs[0] & 0xe0); /*Memory space*/ + // return (buslogic_pci_bar[1].addr_regs[0] & 0xe0); /*Memory space*/ + return 0x00; case 0x15: return buslogic_pci_bar[1].addr_regs[1]; case 0x16: @@ -1255,7 +1250,10 @@ BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) /* Then let's set the PCI regs. */ buslogic_pci_bar[1].addr_regs[addr & 3] = val; /* Then let's calculate the new I/O base. */ - bl->MMIOBase = buslogic_pci_bar[1].addr & 0xffffffe0; + // bl->MMIOBase = buslogic_pci_bar[1].addr & 0xffffffe0; + /* Give it a 4 kB alignment as that's this emulator's granularity. */ + buslogic_pci_bar[1].addr &= 0xffffc000; + bl->MMIOBase = buslogic_pci_bar[1].addr & 0xffffc000; /* Log the new base. */ buslogic_log("BusLogic PCI: New MMIO base is %04X\n" , bl->MMIOBase); /* We're done, so get out of the here. */ diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 739be4af4..a9028e1cd 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)scsi_cdrom.c 1.0.63 2018/10/27 + * Version: @(#)scsi_cdrom.c 1.0.64 2018/10/28 * * Author: Miran Grca, * @@ -39,19 +39,6 @@ #include "scsi_cdrom.h" -/* Bits of 'status' */ -#define ERR_STAT 0x01 -#define DRQ_STAT 0x08 /* Data request */ -#define DSC_STAT 0x10 -#define SERVICE_STAT 0x10 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 - -/* Bits of 'error' */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* Media change request */ - - #pragma pack(push,1) typedef struct { @@ -309,8 +296,6 @@ static const mode_sense_pages_t scsi_cdrom_mode_sense_pages_changeable = { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } }; -uint8_t scsi_cdrom_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - static gesn_cdb_t *gesn_cdb; static gesn_event_header_t *gesn_event_header; @@ -321,7 +306,7 @@ static void scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev); static void scsi_cdrom_init(scsi_cdrom_t *dev); -static void scsi_cdrom_callback(void *p); +static void scsi_cdrom_callback(scsi_common_t *sc); #ifdef ENABLE_SCSI_CDROM_LOG @@ -352,18 +337,6 @@ scsi_cdrom_set_callback(scsi_cdrom_t *dev) } -static void -scsi_cdrom_set_signature(void *p) -{ - scsi_cdrom_t *dev = (scsi_cdrom_t *) p; - - if (!dev) - return; - dev->phase = 1; - dev->request_length = 0xEB14; -} - - static void scsi_cdrom_init(scsi_cdrom_t *dev) { @@ -371,7 +344,7 @@ scsi_cdrom_init(scsi_cdrom_t *dev) return; /* Do a reset (which will also rezero it). */ - scsi_cdrom_reset(dev); + scsi_cdrom_reset((scsi_common_t *) dev); /* Configure the drive. */ dev->requested_blocks = 1; @@ -413,9 +386,9 @@ scsi_cdrom_current_mode(scsi_cdrom_t *dev) /* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ int -scsi_cdrom_err_stat_to_scsi(void *p) +scsi_cdrom_err_stat_to_scsi(scsi_common_t *sc) { - scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; if (dev->status & ERR_STAT) return SCSI_STATUS_CHECK_CONDITION; @@ -516,26 +489,6 @@ scsi_cdrom_mode_sense_save(scsi_cdrom_t *dev) } -int -scsi_cdrom_read_capacity(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - scsi_cdrom_t *dev = (scsi_cdrom_t *) p; - int size = 0; - - if (dev->drv->ops && dev->drv->ops->size) - size = dev->drv->ops->size(dev->drv) - 1; /* IMPORTANT: What's returned is the last LBA block. */ - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 8; /* 2048 = 0x0800 */ - *len = 8; - - return 1; -} - - /*SCSI Mode Sense 6/10*/ static uint8_t scsi_cdrom_mode_sense_read(scsi_cdrom_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) @@ -703,7 +656,7 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) scsi_cdrom_log("CD-ROM %i: Current speed: %ix\n", dev->id, dev->drv->cur_speed); if (dev->packet_status == PHASE_COMPLETE) { - scsi_cdrom_callback(dev); + scsi_cdrom_callback((scsi_common_t *) dev); dev->callback = 0LL; } else { switch(dev->current_cdb[0]) { @@ -777,7 +730,6 @@ scsi_cdrom_command_read(scsi_cdrom_t *dev) { dev->packet_status = PHASE_DATA_IN; scsi_cdrom_command_common(dev); - dev->total_read = 0; } @@ -786,7 +738,6 @@ scsi_cdrom_command_read_dma(scsi_cdrom_t *dev) { dev->packet_status = PHASE_DATA_IN_DMA; scsi_cdrom_command_common(dev); - dev->total_read = 0; } @@ -850,7 +801,6 @@ static void scsi_cdrom_data_command_finish(scsi_cdrom_t *dev, int len, int block static void scsi_cdrom_sense_clear(scsi_cdrom_t *dev, int command) { - dev->previous_command = command; scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = 0; } @@ -1061,19 +1011,17 @@ scsi_cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks) static int scsi_cdrom_read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *len) { - int ret = 0; + int ret = 0, data_pos = 0; + int i = 0, temp_len = 0; uint32_t cdsize = 0; - int i = 0; - int temp_len = 0; - - if (dev->drv->ops && dev->drv->ops->size) - cdsize = dev->drv->ops->size(dev->drv); - else { + if (dev->drv->cd_status == CD_STATUS_EMPTY) { scsi_cdrom_not_ready(dev); return 0; } + cdsize = dev->drv->cdrom_capacity; + if (dev->sector_pos >= cdsize) { scsi_cdrom_log("CD-ROM %i: Trying to read from beyond the end of disc (%i >= %i)\n", dev->id, dev->sector_pos, cdsize); @@ -1092,15 +1040,10 @@ scsi_cdrom_read_data(scsi_cdrom_t *dev, int msf, int type, int flags, int32_t *l *len = 0; for (i = 0; i < dev->requested_blocks; i++) { - if (dev->drv->ops && dev->drv->ops->readsector_raw) - ret = dev->drv->ops->readsector_raw(dev->drv, dev->buffer + dev->data_pos, - dev->sector_pos + i, msf, type, flags, &temp_len); - else { - scsi_cdrom_not_ready(dev); - return 0; - } + ret = cdrom_readsector_raw(dev->drv, dev->buffer + data_pos, + dev->sector_pos + i, msf, type, flags, &temp_len); - dev->data_pos += temp_len; + data_pos += temp_len; dev->old_len += temp_len; *len += temp_len; @@ -1132,8 +1075,6 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch) flags = 0x10; } - dev->data_pos = 0; - if (!dev->sector_len) { scsi_cdrom_command_complete(dev); return -1; @@ -1155,8 +1096,8 @@ scsi_cdrom_read_blocks(scsi_cdrom_t *dev, int32_t *len, int first_batch) } dev->sector_pos += dev->requested_blocks; + dev->drv->seek_pos = dev->sector_pos; dev->sector_len -= dev->requested_blocks; - return 1; } @@ -1170,13 +1111,13 @@ scsi_cdrom_read_dvd_structure(scsi_cdrom_t *dev, int format, const uint8_t *pack switch (format) { case 0x00: /* Physical format information */ - if (dev->drv->ops && dev->drv->ops->size) - total_sectors = (uint64_t) dev->drv->ops->size(dev->drv); - else { + if (dev->drv->cd_status == CD_STATUS_EMPTY) { scsi_cdrom_not_ready(dev); return 0; } + total_sectors = (uint64_t) dev->drv->cdrom_capacity; + if (layer != 0) { scsi_cdrom_invalid_field(dev); return 0; @@ -1285,6 +1226,8 @@ scsi_cdrom_insert(void *p) return; dev->unit_attention = 1; + /* Turn off the medium changed status. */ + dev->drv->cd_status &= ~CD_STATUS_MEDIUM_CHANGED; scsi_cdrom_log("CD-ROM %i: Media insert\n", dev->id); } @@ -1292,7 +1235,7 @@ scsi_cdrom_insert(void *p) static int scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) { - int ready = 0, status = 0; + int ready = 0; if (dev->drv->bus_type == CDROM_BUS_SCSI) { if ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[1] & 0xe0)) { @@ -1323,23 +1266,15 @@ scsi_cdrom_pre_execution_check(scsi_cdrom_t *dev, uint8_t *cdb) return 0; } - if (dev->drv->ops && dev->drv->ops->status) - status = dev->drv->ops->status(dev->drv); - else - status = CD_STATUS_EMPTY; - - if ((status == CD_STATUS_PLAYING) || (status == CD_STATUS_PAUSED)) { + if ((dev->drv->cd_status == CD_STATUS_PLAYING) || (dev->drv->cd_status == CD_STATUS_PAUSED)) { ready = 1; goto skip_ready_check; } - if (dev->drv->ops && dev->drv->ops->medium_changed) { - if (dev->drv->ops->medium_changed(dev->drv)) - scsi_cdrom_insert((void *) dev); - } + if (dev->drv->cd_status & CD_STATUS_MEDIUM_CHANGED) + scsi_cdrom_insert((void *) dev); - if (dev->drv->ops && dev->drv->ops->ready) - ready = dev->drv->ops->ready(dev->drv); + ready = (dev->drv->cd_status != CD_STATUS_EMPTY); skip_ready_check: /* If the drive is not ready, there is no reason to keep the @@ -1399,9 +1334,9 @@ scsi_cdrom_rezero(scsi_cdrom_t *dev) void -scsi_cdrom_reset(void *p) +scsi_cdrom_reset(scsi_common_t *sc) { - scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; if (!dev) return; @@ -1410,7 +1345,8 @@ scsi_cdrom_reset(void *p) dev->status = 0; dev->callback = 0LL; scsi_cdrom_set_callback(dev); - scsi_cdrom_set_signature(dev); + dev->phase = 1; + dev->request_length = 0xEB14; dev->packet_status = 0xff; dev->unit_attention = 0xff; } @@ -1419,8 +1355,6 @@ scsi_cdrom_reset(void *p) static void scsi_cdrom_request_sense(scsi_cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) { - int status = dev->drv->cd_status; - /*Will return 18 bytes of 0*/ if (alloc_length != 0) { memset(buffer, 0, alloc_length); @@ -1429,16 +1363,15 @@ scsi_cdrom_request_sense(scsi_cdrom_t *dev, uint8_t *buffer, uint8_t alloc_lengt buffer[0] = 0x70; - if ((scsi_cdrom_sense_key > 0) && ((status < CD_STATUS_PLAYING) || - (status == CD_STATUS_STOPPED)) && cdrom_playing_completed(dev->drv)) { + if ((scsi_cdrom_sense_key > 0) && (dev->drv->cd_status == CD_STATUS_PLAYING_COMPLETED)) { buffer[2]=SENSE_ILLEGAL_REQUEST; buffer[12]=ASC_AUDIO_PLAY_OPERATION; buffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; - } else if ((scsi_cdrom_sense_key == 0) && (status >= CD_STATUS_PLAYING) && - (status != CD_STATUS_STOPPED)) { + } else if ((scsi_cdrom_sense_key == 0) && ((dev->drv->cd_status == CD_STATUS_PAUSED) || + (dev->drv->cd_status >= CD_STATUS_PLAYING))) { buffer[2]=SENSE_ILLEGAL_REQUEST; buffer[12]=ASC_AUDIO_PLAY_OPERATION; - buffer[13]=(status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; + buffer[13]=(dev->drv->cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; } else { if (dev->unit_attention && (scsi_cdrom_sense_key == 0)) { buffer[2]=SENSE_UNIT_ATTENTION; @@ -1461,20 +1394,14 @@ scsi_cdrom_request_sense(scsi_cdrom_t *dev, uint8_t *buffer, uint8_t alloc_lengt void -scsi_cdrom_request_sense_for_scsi(void *p, uint8_t *buffer, uint8_t alloc_length) +scsi_cdrom_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) { - scsi_cdrom_t *dev = (scsi_cdrom_t *) p; - int ready = 0; + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - if (dev->drv->ops && dev->drv->ops->medium_changed) { - if (dev->drv->ops->medium_changed(dev->drv)) - scsi_cdrom_insert((void *) dev); - } + if (dev->drv->cd_status & CD_STATUS_MEDIUM_CHANGED) + scsi_cdrom_insert((void *) dev); - if (dev->drv->ops && dev->drv->ops->ready) - ready = dev->drv->ops->ready(dev->drv); - - if (!ready && dev->unit_attention) { + if ((dev->drv->cd_status == CD_STATUS_EMPTY) && dev->unit_attention) { /* If the drive is not ready, there is no reason to keep the UNIT ATTENTION condition present, as we only use it to mark disc changes. */ @@ -1505,7 +1432,8 @@ static void scsi_cdrom_buf_alloc(scsi_cdrom_t *dev, uint32_t len) { scsi_cdrom_log("CD-ROM %i: Allocated buffer length: %i\n", dev->id, len); - dev->buffer = (uint8_t *) malloc(len); + if (!dev->buffer) + dev->buffer = (uint8_t *) malloc(len); } @@ -1520,10 +1448,19 @@ scsi_cdrom_buf_free(scsi_cdrom_t *dev) } -void -scsi_cdrom_command(void *p, uint8_t *cdb) +static void +scsi_cdrom_stop(scsi_common_t *sc) { - scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + + cdrom_stop(dev->drv); +} + + +void +scsi_cdrom_command(scsi_common_t *sc, uint8_t *cdb) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; int len, max_len, used_len, alloc_length, msf; int pos = 0, i= 0, size_idx, idx = 0; uint32_t feature; @@ -1555,15 +1492,8 @@ scsi_cdrom_command(void *p, uint8_t *cdb) device_identify_ex[12] = EMU_VERSION[2]; device_identify_ex[13] = EMU_VERSION[3]; - dev->data_pos = 0; - memcpy(dev->current_cdb, cdb, 12); - if (dev->drv->ops && dev->drv->ops->status) - dev->drv->cd_status = dev->drv->ops->status(dev->drv); - else - dev->drv->cd_status = CD_STATUS_EMPTY; - if (cdb[0] != 0) { scsi_cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", dev->id, cdb[0], scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq, dev->unit_attention); @@ -1590,8 +1520,7 @@ scsi_cdrom_command(void *p, uint8_t *cdb) break; case GPCMD_REZERO_UNIT: - if (dev->drv->ops->stop) - dev->drv->ops->stop(dev->drv); + scsi_cdrom_stop(sc); dev->sector_pos = dev->sector_len = 0; dev->drv->seek_diff = dev->drv->seek_pos; cdrom_seek(dev->drv, 0); @@ -1662,41 +1591,12 @@ scsi_cdrom_command(void *p, uint8_t *cdb) return; } - switch (toc_format) { - case 0: /*Normal*/ - if (!dev->drv->ops->readtoc) { - scsi_cdrom_not_ready(dev); - return; - } - len = dev->drv->ops->readtoc(dev->drv, dev->buffer, cdb[6], msf, max_len, - 0); - break; - case 1: /*Multi session*/ - if (!dev->drv->ops->readtoc_session) { - scsi_cdrom_not_ready(dev); - return; - } - len = dev->drv->ops->readtoc_session(dev->drv, dev->buffer, msf, max_len); - dev->buffer[0] = 0; dev->buffer[1] = 0xA; - break; - case 2: /*Raw*/ - if (!dev->drv->ops->readtoc_raw) { - scsi_cdrom_not_ready(dev); - return; - } - len = dev->drv->ops->readtoc_raw(dev->drv, dev->buffer, max_len); - break; - default: - scsi_cdrom_invalid_field(dev); - scsi_cdrom_buf_free(dev); - return; - } - - if (len > max_len) { - len = max_len; - - dev->buffer[0] = ((len - 2) >> 8) & 0xff; - dev->buffer[1] = (len - 2) & 0xff; + if (toc_format < 3) + len = cdrom_read_toc(dev->drv, dev->buffer, toc_format, cdb[6], msf, max_len); + else { + scsi_cdrom_invalid_field(dev); + scsi_cdrom_buf_free(dev); + return; } scsi_cdrom_set_buf_len(dev, BufLen, &len); @@ -1757,9 +1657,6 @@ scsi_cdrom_command(void *p, uint8_t *cdb) break; } - dev->drv->seek_diff = ABS((int) (pos - dev->drv->seek_pos)); - dev->drv->seek_pos = dev->sector_pos; - 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); */ @@ -1777,8 +1674,14 @@ scsi_cdrom_command(void *p, uint8_t *cdb) 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)); + ret = scsi_cdrom_read_blocks(dev, &alloc_length, 1); if (ret <= 0) { + scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->packet_status = PHASE_COMPLETE; + dev->callback = 20LL * CDROM_TIME; + scsi_cdrom_set_callback(dev); scsi_cdrom_buf_free(dev); return; } @@ -1850,25 +1753,34 @@ scsi_cdrom_command(void *p, uint8_t *cdb) 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 > 405000) + 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; - if (dev->drv->ops && dev->drv->ops->media_type_id) - dev->buffer[1] = dev->drv->ops->media_type_id(dev->drv); - else - dev->buffer[1] = 0x70; + 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; - if (dev->drv->ops && dev->drv->ops->media_type_id) - dev->buffer[2] = dev->drv->ops->media_type_id(dev->drv); - else - dev->buffer[2] = 0x70; + 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; @@ -1926,9 +1838,8 @@ scsi_cdrom_command(void *p, uint8_t *cdb) * the number of sectors from the media tells us which profile * to use as current. 0 means there is no media */ - if (dev->drv->ops && dev->drv->ops->ready && - dev->drv->ops->ready(dev->drv)) { - len = dev->drv->ops->size(dev->drv); + 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; @@ -2114,16 +2025,11 @@ scsi_cdrom_command(void *p, uint8_t *cdb) 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 */ - if (dev->drv->ops && dev->drv->ops->size) { - dev->buffer[24] = (dev->drv->ops->size(dev->drv) >> 24) & 0xff; /* track size */ - dev->buffer[25] = (dev->drv->ops->size(dev->drv) >> 16) & 0xff; /* track size */ - dev->buffer[26] = (dev->drv->ops->size(dev->drv) >> 8) & 0xff; /* track size */ - dev->buffer[27] = dev->drv->ops->size(dev->drv) & 0xff; /* track size */ - } else { - scsi_cdrom_not_ready(dev); - scsi_cdrom_buf_free(dev); - return; - } + + dev->buffer[24] = (dev->drv->cdrom_capacity >> 24) & 0xff; /* track size */ + dev->buffer[25] = (dev->drv->cdrom_capacity >> 16) & 0xff; /* track size */ + dev->buffer[26] = (dev->drv->cdrom_capacity >> 8) & 0xff; /* track size */ + dev->buffer[27] = dev->drv->cdrom_capacity & 0xff; /* track size */ if (len > max_len) { len = max_len; @@ -2172,10 +2078,7 @@ scsi_cdrom_command(void *p, uint8_t *cdb) break; } - if (dev->drv->ops && dev->drv->ops->playaudio) - ret = dev->drv->ops->playaudio(dev->drv, pos, len, msf); - else - ret = 0; + ret = cdrom_audio_play(dev->drv, pos, len, msf); if (ret) scsi_cdrom_command_complete(dev); @@ -2222,13 +2125,8 @@ scsi_cdrom_command(void *p, uint8_t *cdb) dev->buffer[pos++] = 0; dev->buffer[pos++] = 0; /*Subchannel length*/ dev->buffer[pos++] = cdb[3] & 3; /*Format code*/ if (cdb[3] == 1) { - if (dev->drv->ops && dev->drv->ops->getcurrentsubchannel) - dev->buffer[1] = dev->drv->ops->getcurrentsubchannel(dev->drv, &dev->buffer[5], msf); - else { - scsi_cdrom_not_ready(dev); - scsi_cdrom_buf_free(dev); - return; - } + dev->buffer[1] = cdrom_get_current_subchannel(dev->drv, &dev->buffer[5], msf); + switch(dev->drv->cd_status) { case CD_STATUS_PLAYING: dev->buffer[1] = 0x11; @@ -2263,15 +2161,7 @@ scsi_cdrom_command(void *p, uint8_t *cdb) scsi_cdrom_buf_alloc(dev, alloc_length); - if (dev->drv->ops && dev->drv->ops->size) - len = dev->drv->ops->size(dev->drv); - else { - scsi_cdrom_not_ready(dev); - scsi_cdrom_buf_free(dev); - return; - } - - if ((cdb[7] < 0xc0) && (len <= 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; @@ -2302,16 +2192,14 @@ scsi_cdrom_command(void *p, uint8_t *cdb) switch(cdb[4] & 3) { case 0: /* Stop the disc. */ - if (dev->drv->ops && dev->drv->ops->stop) - dev->drv->ops->stop(dev->drv); + scsi_cdrom_stop(sc); break; case 1: /* Start the disc and read the TOC. */ - if (dev->drv->ops && dev->drv->ops->medium_changed) - dev->drv->ops->medium_changed(dev->drv); /* This causes a TOC reload. */ + /* This makes no sense under emulation as this would do + absolutely nothing, so just break. */ break; case 2: /* Eject the disc if possible. */ - if (dev->drv->ops && dev->drv->ops->stop) - dev->drv->ops->stop(dev->drv); + scsi_cdrom_stop(sc); cdrom_eject(dev->id); break; case 3: /* Load the disc (close tray). */ @@ -2423,22 +2311,7 @@ atapi_out: case GPCMD_PAUSE_RESUME_ALT: case GPCMD_PAUSE_RESUME: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - - if (cdb[8] & 1) { - if (dev->drv->ops && dev->drv->ops->resume) - dev->drv->ops->resume(dev->drv); - else { - scsi_cdrom_illegal_mode(dev); - break; - } - } else { - if (dev->drv->ops && dev->drv->ops->pause) - dev->drv->ops->pause(dev->drv); - else { - scsi_cdrom_illegal_mode(dev); - break; - } - } + cdrom_audio_pause_resume(dev->drv, cdb[8] & 0x01); scsi_cdrom_command_complete(dev); break; @@ -2464,10 +2337,14 @@ atapi_out: scsi_cdrom_buf_alloc(dev, 8); - if (scsi_cdrom_read_capacity(dev, dev->current_cdb, dev->buffer, (uint32_t *) &len) == 0) { - scsi_cdrom_buf_free(dev); - return; - } + /* IMPORTANT: What's returned is the last LBA block. */ + memset(dev->buffer, 0, 8); + dev->buffer[0] = (dev->drv->cdrom_capacity >> 24) & 0xff; + dev->buffer[1] = (dev->drv->cdrom_capacity >> 16) & 0xff; + dev->buffer[2] = (dev->drv->cdrom_capacity >> 8) & 0xff; + dev->buffer[3] = dev->drv->cdrom_capacity & 0xff; + dev->buffer[6] = 8; + len = 8; scsi_cdrom_set_buf_len(dev, BufLen, &len); @@ -2477,12 +2354,12 @@ atapi_out: case GPCMD_STOP_PLAY_SCAN: scsi_cdrom_set_phase(dev, SCSI_PHASE_STATUS); - if (dev->drv->ops && dev->drv->ops->stop) - dev->drv->ops->stop(dev->drv); - else { + if (dev->drv->cd_status <= CD_STATUS_DATA_ONLY) { scsi_cdrom_illegal_mode(dev); break; } + + scsi_cdrom_stop(sc); scsi_cdrom_command_complete(dev); break; @@ -2498,10 +2375,21 @@ atapi_out: } +static void +scsi_cdrom_command_stop(scsi_common_t *sc) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + + scsi_cdrom_command_complete(dev); + scsi_cdrom_buf_free(dev); +} + + /* The command second phase function, needed for Mode Select. */ static uint8_t -scsi_cdrom_phase_data_out(scsi_cdrom_t *dev) +scsi_cdrom_phase_data_out(scsi_common_t *sc) { + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; uint16_t block_desc_len, pos; uint16_t i = 0; @@ -2572,405 +2460,135 @@ scsi_cdrom_phase_data_out(scsi_cdrom_t *dev) if (error) { scsi_cdrom_invalid_field_pl(dev); + scsi_cdrom_buf_free(dev); return 0; } break; } - return 1; -} - - -/* This is the general ATAPI PIO request function. */ -static void -scsi_cdrom_pio_request(scsi_cdrom_t *dev, uint8_t out) -{ - int ret = 0; - - if (dev->drv->bus_type < CDROM_BUS_SCSI) { - scsi_cdrom_log("CD-ROM %i: Lowering IDE IRQ\n", dev->id); - ide_irq_lower(ide_drives[dev->drv->ide_channel]); - } - - dev->status = BUSY_STAT; - - if (dev->pos >= dev->packet_len) { - scsi_cdrom_log("CD-ROM %i: %i bytes %s, command done\n", dev->id, dev->pos, out ? "written" : "read"); - - dev->pos = dev->request_pos = 0; - if (out) { - ret = scsi_cdrom_phase_data_out(dev); - /* If ret = 0 (phase 1 error), then we do not do anything else other than - free the buffer, as the phase and callback have already been set by the - error function. */ - if (ret) - scsi_cdrom_command_complete(dev); - } else - scsi_cdrom_command_complete(dev); - scsi_cdrom_buf_free(dev); - } else { - scsi_cdrom_log("CD-ROM %i: %i bytes %s, %i bytes are still left\n", dev->id, dev->pos, - out ? "written" : "read", dev->packet_len - dev->pos); - - /* If less than (packet length) bytes are remaining, update packet length - accordingly. */ - if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) - dev->max_transfer_len = dev->packet_len - dev->pos; - scsi_cdrom_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, - dev->max_transfer_len); - - dev->packet_status = out ? PHASE_DATA_OUT : PHASE_DATA_IN; - - dev->status = BUSY_STAT; - dev->phase = 1; - scsi_cdrom_callback(dev); - dev->callback = 0LL; - scsi_cdrom_set_callback(dev); - - dev->request_pos = 0; - } -} - - -static int -scsi_cdrom_read_from_ide_dma(scsi_cdrom_t *dev) -{ - int ret; - - if (!dev) - return 0; - - if (ide_bus_master_write) { - ret = ide_bus_master_write(dev->drv->ide_channel >> 1, - dev->buffer, dev->packet_len, - ide_bus_master_priv[dev->drv->ide_channel >> 1]); - if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ - return 2; - else if (ret == 1) { /* DMA error. */ - scsi_cdrom_bus_master_error(dev); - return 0; - } else - return 1; - } else - return 0; - - return 0; -} - - -static int -scsi_cdrom_read_from_scsi_dma(uint8_t scsi_id) -{ - scsi_cdrom_t *dev = scsi_devices[scsi_id].p; - int32_t *BufLen = &scsi_devices[scsi_id].buffer_length; - - if (!dev) - return 0; - - scsi_cdrom_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(dev->buffer, scsi_devices[scsi_id].cmd_buffer, *BufLen); + scsi_cdrom_command_stop((scsi_common_t *) dev); return 1; } static void -scsi_cdrom_irq_raise(scsi_cdrom_t *dev) +scsi_cdrom_irq_raise(scsi_common_t *sc) { - if (dev->drv->bus_type < CDROM_BUS_SCSI) + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + + if (dev->drv && (dev->drv->bus_type < CDROM_BUS_SCSI)) ide_irq_raise(ide_drives[dev->drv->ide_channel]); } static int -scsi_cdrom_read_from_dma(scsi_cdrom_t *dev) +scsi_cdrom_dma(scsi_cdrom_t *dev, int out) { -#ifdef ENABLE_SCSI_CDROM_LOG - int32_t *BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; -#endif - int ret = 0; + int ret = 1; - if (dev->drv->bus_type == CDROM_BUS_SCSI) - ret = scsi_cdrom_read_from_scsi_dma(dev->drv->scsi_device_id); - else - ret = scsi_cdrom_read_from_ide_dma(dev); + if (dev->drv->bus_type == CDROM_BUS_ATAPI) { + ret = 0; - if (ret != 1) - return ret; + if (out && dev && ide_bus_master_write) { + ret = ide_bus_master_write(dev->drv->ide_channel >> 1, + dev->buffer, dev->packet_len, + ide_bus_master_priv[dev->drv->ide_channel >> 1]); + } else if (!out && dev && ide_bus_master_read) { + ret = ide_bus_master_read(dev->drv->ide_channel >> 1, + dev->buffer, dev->packet_len, + ide_bus_master_priv[dev->drv->ide_channel >> 1]); + } + } - if (dev->drv->bus_type == CDROM_BUS_SCSI) - scsi_cdrom_log("CD-ROM %i: SCSI Input data length: %i\n", dev->id, *BufLen); - else - scsi_cdrom_log("CD-ROM %i: ATAPI Input data length: %i\n", dev->id, dev->packet_len); - - ret = scsi_cdrom_phase_data_out(dev); - - if (ret) - return 1; - else - return 0; -} - - -static int -scsi_cdrom_write_to_ide_dma(scsi_cdrom_t *dev) -{ - int ret; - - if (!dev) - return 0; - - if (ide_bus_master_read) { - ret = ide_bus_master_read(dev->drv->ide_channel >> 1, - dev->buffer, dev->packet_len, - ide_bus_master_priv[dev->drv->ide_channel >> 1]); - if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ - return 2; - else if (ret == 1) { /* DMA error. */ - scsi_cdrom_bus_master_error(dev); - return 0; - } else - return 1; - } else - return 0; -} - - -static int -scsi_cdrom_write_to_scsi_dma(uint8_t scsi_id) -{ - scsi_cdrom_t *dev = scsi_devices[scsi_id].p; - int32_t *BufLen = &scsi_devices[scsi_id].buffer_length; - - if (!dev) - return 0; - - scsi_cdrom_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(scsi_devices[scsi_id].cmd_buffer, dev->buffer, *BufLen); - scsi_cdrom_log("CD-ROM %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, - dev->buffer[0], dev->buffer[1], dev->buffer[2], dev->buffer[3], dev->buffer[4], dev->buffer[5], - dev->buffer[6], dev->buffer[7]); - return 1; -} - - -static int -scsi_cdrom_write_to_dma(scsi_cdrom_t *dev) -{ -#ifdef ENABLE_SCSI_CDROM_LOG - int32_t *BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length; -#endif - int ret = 0; - - if (dev->drv->bus_type == CDROM_BUS_SCSI) { - scsi_cdrom_log("Write to SCSI DMA: (ID %02X)\n", dev->drv->scsi_device_id); - ret = scsi_cdrom_write_to_scsi_dma(dev->drv->scsi_device_id); - } else - ret = scsi_cdrom_write_to_ide_dma(dev); - - if (dev->drv->bus_type == CDROM_BUS_SCSI) - scsi_cdrom_log("CD-ROM %i: SCSI Output data length: %i\n", dev->id, *BufLen); - else - scsi_cdrom_log("CD-ROM %i: ATAPI Output data length: %i\n", dev->id, dev->packet_len); + if (ret == 0) { + scsi_cdrom_buf_free(dev); + scsi_cdrom_bus_master_error(dev); + } else if (ret == 1) { + if (out) + ret = scsi_cdrom_phase_data_out((scsi_common_t *) dev); + else + scsi_cdrom_command_stop((scsi_common_t *) dev); + } return ret; } static void -scsi_cdrom_callback(void *p) +scsi_cdrom_callback(scsi_common_t *sc) { - scsi_cdrom_t *dev = (scsi_cdrom_t *) p; + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; int ret; - switch(dev->packet_status) { + switch(sc->packet_status) { case PHASE_IDLE: - scsi_cdrom_log("CD-ROM %i: PHASE_IDLE\n", dev->id); - dev->pos = 0; - dev->phase = 1; - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + scsi_cdrom_log("CD-ROM %i: PHASE_IDLE\n", sc->id); + sc->pos = 0; + sc->phase = 1; + sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); return; case PHASE_COMMAND: scsi_cdrom_log("CD-ROM %i: PHASE_COMMAND\n", dev->id); - dev->status = BUSY_STAT | (dev->status & ERR_STAT); - memcpy(dev->atapi_cdb, dev->buffer, 12); - scsi_cdrom_command(dev, dev->atapi_cdb); + sc->status = BUSY_STAT | (dev->status & ERR_STAT); + scsi_cdrom_command(sc, sc->atapi_cdb); return; case PHASE_COMPLETE: scsi_cdrom_log("CD-ROM %i: PHASE_COMPLETE\n", dev->id); - dev->status = READY_STAT; - dev->phase = 3; - dev->packet_status = 0xFF; - ui_sb_update_icon(SB_CDROM | dev->id, 0); - scsi_cdrom_irq_raise(dev); + sc->status = READY_STAT; + sc->phase = 3; + sc->packet_status = 0xFF; + ui_sb_update_icon(SB_CDROM | sc->id, 0); + scsi_cdrom_irq_raise(sc); return; case PHASE_DATA_OUT: scsi_cdrom_log("CD-ROM %i: PHASE_DATA_OUT\n", dev->id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 0; - scsi_cdrom_irq_raise(dev); + sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); + sc->phase = 0; + scsi_cdrom_irq_raise(sc); return; case PHASE_DATA_OUT_DMA: - scsi_cdrom_log("CD-ROM %i: PHASE_DATA_OUT_DMA\n", dev->id); - ret = scsi_cdrom_read_from_dma(dev); + scsi_cdrom_log("CD-ROM %i: PHASE_DATA_OUT_DMA\n", sc->id); + ret = scsi_cdrom_dma(dev, 1); - if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { - scsi_cdrom_log("CD-ROM %i: DMA data out phase done\n"); - scsi_cdrom_buf_free(dev); - scsi_cdrom_command_complete(dev); - } else if (ret == 2) { - scsi_cdrom_log("CD-ROM %i: DMA out not enabled, wait\n"); + if (ret == 2) { + scsi_cdrom_log("CD-ROM %i: DMA out not enabled, wait\n", sc->id); scsi_cdrom_command_bus(dev); +#ifdef ENABLE_SCSI_CDROM_LOG } else { - scsi_cdrom_log("CD-ROM %i: DMA data out phase failure\n"); - scsi_cdrom_buf_free(dev); + scsi_cdrom_log("CD-ROM %i: DMA data out phase %s\n", sc->id, ret ? "done" : "failure"); +#endif } return; case PHASE_DATA_IN: - scsi_cdrom_log("CD-ROM %i: PHASE_DATA_IN\n", dev->id); - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); - dev->phase = 2; - scsi_cdrom_irq_raise(dev); + scsi_cdrom_log("CD-ROM %i: PHASE_DATA_IN\n", sc->id); + sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); + sc->phase = 2; + scsi_cdrom_irq_raise(sc); return; case PHASE_DATA_IN_DMA: scsi_cdrom_log("CD-ROM %i: PHASE_DATA_IN_DMA\n", dev->id); - ret = scsi_cdrom_write_to_dma(dev); + ret = scsi_cdrom_dma(dev, 0); - if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { - scsi_cdrom_log("CD-ROM %i: DMA data in phase done\n", dev->id); - scsi_cdrom_buf_free(dev); - scsi_cdrom_command_complete(dev); - } else if (ret == 2) { - scsi_cdrom_log("CD-ROM %i: DMA in not enabled, wait\n", dev->id); + if (ret == 2) { + scsi_cdrom_log("CD-ROM %i: DMA in not enabled, wait\n", sc->id); scsi_cdrom_command_bus(dev); +#ifdef ENABLE_SCSI_CDROM_LOG } else { - scsi_cdrom_log("CD-ROM %i: DMA data in phase failure\n", dev->id); - scsi_cdrom_buf_free(dev); + scsi_cdrom_log("CD-ROM %i: DMA data in phase %s\n", sc->id, ret ? "done" : "failure"); +#endif } return; case PHASE_ERROR: - scsi_cdrom_log("CD-ROM %i: PHASE_ERROR\n", dev->id); - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; - scsi_cdrom_irq_raise(dev); - ui_sb_update_icon(SB_CDROM | dev->id, 0); + scsi_cdrom_log("CD-ROM %i: PHASE_ERROR\n", sc->id); + sc->status = READY_STAT | ERR_STAT; + sc->phase = 3; + scsi_cdrom_irq_raise(sc); + ui_sb_update_icon(SB_CDROM | sc->id, 0); return; } } -static uint32_t -scsi_cdrom_packet_read(void *p, int length) -{ - scsi_cdrom_t *dev = (scsi_cdrom_t *) p; - - uint16_t *cdbufferw; - uint32_t *cdbufferl; - - uint32_t temp = 0; - - if (!dev) - return 0; - - cdbufferw = (uint16_t *) dev->buffer; - cdbufferl = (uint32_t *) dev->buffer; - - if (!dev->buffer) - return 0; - - /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, - which can happen when issuing media access commands with an allocated length below minimum request length - (which is 1 sector = 2048 bytes). */ - switch(length) { - case 1: - temp = (dev->pos < dev->packet_len) ? dev->buffer[dev->pos] : 0; - dev->pos++; - dev->request_pos++; - break; - case 2: - temp = (dev->pos < dev->packet_len) ? cdbufferw[dev->pos >> 1] : 0; - dev->pos += 2; - dev->request_pos += 2; - break; - case 4: - temp = (dev->pos < dev->packet_len) ? cdbufferl[dev->pos >> 2] : 0; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return 0; - } - - if (dev->packet_status == PHASE_DATA_IN) { - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - scsi_cdrom_pio_request(dev, 0); - } - return temp; - } else - return 0; -} - - -static void -scsi_cdrom_packet_write(void *p, uint32_t val, int length) -{ - scsi_cdrom_t *dev = (scsi_cdrom_t *) p; - - uint16_t *cdbufferw; - uint32_t *cdbufferl; - - if (!dev) - return; - - if ((dev->packet_status == PHASE_IDLE) && !dev->buffer) - scsi_cdrom_buf_alloc(dev, 12); - - cdbufferw = (uint16_t *) dev->buffer; - cdbufferl = (uint32_t *) dev->buffer; - - if (!dev->buffer) - return; - - switch(length) { - case 1: - dev->buffer[dev->pos] = val & 0xff; - dev->pos++; - dev->request_pos++; - break; - case 2: - cdbufferw[dev->pos >> 1] = val & 0xffff; - dev->pos += 2; - dev->request_pos += 2; - break; - case 4: - cdbufferl[dev->pos >> 2] = val; - dev->pos += 4; - dev->request_pos += 4; - break; - default: - return; - } - - if (dev->packet_status == PHASE_DATA_OUT) { - if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { - /* Time for a DRQ. */ - scsi_cdrom_pio_request(dev, 1); - } - return; - } else if (dev->packet_status == PHASE_IDLE) { - if (dev->pos >= 12) { - dev->pos = 0; - dev->status = BUSY_STAT; - dev->packet_status = PHASE_COMMAND; - timer_process(); - scsi_cdrom_callback(dev); - timer_update_outstanding(); - } - return; - } -} - - static void scsi_cdrom_close(void *p) { @@ -2981,16 +2599,6 @@ scsi_cdrom_close(void *p) } -static void -scsi_cdrom_stop(void *p) -{ - scsi_cdrom_t *dev = (scsi_cdrom_t *) p; - - if (dev->drv->ops && dev->drv->ops->stop) - dev->drv->ops->stop(dev->drv); -} - - static int scsi_cdrom_get_max(int ide_has_dma, int type) { @@ -3001,13 +2609,13 @@ scsi_cdrom_get_max(int ide_has_dma, int type) ret = ide_has_dma ? 4 : 0; break; case TYPE_SDMA: - ret = ide_has_dma ? -1 : 2; + ret = ide_has_dma ? 2 : -1; break; case TYPE_MDMA: - ret = ide_has_dma ? -1 : 2; + ret = ide_has_dma ? 2 : -1; break; case TYPE_UDMA: - ret = ide_has_dma ? -1 : 2; + ret = ide_has_dma ? 2 : -1; break; default: ret = -1; @@ -3046,9 +2654,8 @@ scsi_cdrom_get_timings(int ide_has_dma, int type) * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command */ static void -scsi_cdrom_identify(void *p, int ide_has_dma) +scsi_cdrom_identify(ide_t *ide, int ide_has_dma) { - ide_t *ide = (ide_t *) p; #if 0 scsi_cdrom_t *dev; char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; @@ -3114,13 +2721,12 @@ scsi_cdrom_drive_reset(int c) /* SCSI CD-ROM, attach to the SCSI bus. */ sd = &scsi_devices[drv->scsi_device_id]; - sd->p = dev; + sd->sc = (scsi_common_t *) dev; sd->command = scsi_cdrom_command; sd->callback = scsi_cdrom_callback; - sd->err_stat_to_scsi = scsi_cdrom_err_stat_to_scsi; sd->request_sense = scsi_cdrom_request_sense_for_scsi; sd->reset = scsi_cdrom_reset; - sd->read_capacity = scsi_cdrom_read_capacity; + sd->command_stop = scsi_cdrom_command_stop; sd->type = SCSI_REMOVABLE_CDROM; scsi_cdrom_log("SCSI CD-ROM drive %i attached to SCSI ID %i\n", c, cdrom[c].scsi_device_id); @@ -3131,16 +2737,15 @@ scsi_cdrom_drive_reset(int c) otherwise, we do nothing - it's going to be a drive that's not attached to anything. */ if (id) { - id->p = dev; + id->sc = (scsi_common_t *) dev; id->get_max = scsi_cdrom_get_max; id->get_timings = scsi_cdrom_get_timings; id->identify = scsi_cdrom_identify; - id->set_signature = scsi_cdrom_set_signature; - id->packet_write = scsi_cdrom_packet_write; - id->packet_read = scsi_cdrom_packet_read; id->stop = scsi_cdrom_stop; id->packet_callback = scsi_cdrom_callback; id->device_reset = scsi_cdrom_reset; + id->phase_data_out = scsi_cdrom_phase_data_out; + id->command_stop = scsi_cdrom_command_stop; id->interrupt_drq = 0; ide_atapi_attach(id); diff --git a/src/scsi/scsi_cdrom.h b/src/scsi/scsi_cdrom.h index de4e5ff1b..7b47db55d 100644 --- a/src/scsi/scsi_cdrom.h +++ b/src/scsi/scsi_cdrom.h @@ -43,19 +43,13 @@ typedef struct { int requested_blocks, packet_status, total_length, do_page_save, - unit_attention; + unit_attention, request_pos, + old_len, media_status; uint32_t sector_pos, sector_len, packet_len, pos; int64_t callback; - - int media_status, data_pos, - request_pos, total_read, - old_len; - - uint8_t previous_command, - pad3, pad4, pad5; } scsi_cdrom_t; #endif @@ -69,7 +63,7 @@ extern scsi_cdrom_t *scsi_cdrom[CDROM_NUM]; #define scsi_cdrom_drive cdrom_drives[id].host_drive -extern void scsi_cdrom_reset(void *p); +extern void scsi_cdrom_reset(scsi_common_t *sc); #endif /*EMU_SCSI_CDROM_H*/ diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index 781d7e248..b6bfb7b70 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -8,7 +8,7 @@ * * The generic SCSI device command handler. * - * Version: @(#)scsi_device.c 1.0.21 2018/10/13 + * Version: @(#)scsi_device.c 1.0.22 2018/10/28 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -35,71 +35,81 @@ uint8_t scsi_null_device_sense[18] = { 0x70,0,SENSE_ILLEGAL_REQUEST,0,0,0,0,0,0, static uint8_t scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb) { - if (dev->command && dev->err_stat_to_scsi) { - dev->command(dev->p, cdb); - return dev->err_stat_to_scsi(dev->p); + if (dev->command) { + dev->command(dev->sc, cdb); + + if (dev->sc->status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; } else return SCSI_STATUS_CHECK_CONDITION; } -static void scsi_device_target_callback(scsi_device_t *dev) +static void +scsi_device_target_callback(scsi_device_t *dev) { if (dev->callback) - dev->callback(dev->p); + dev->callback(dev->sc); return; } -static int scsi_device_target_err_stat_to_scsi(scsi_device_t *dev) +static int +scsi_device_target_err_stat_to_scsi(scsi_device_t *dev) { - if (dev->err_stat_to_scsi) - return dev->err_stat_to_scsi(dev->p); + if (dev->sc) + if (dev->sc->status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; else return SCSI_STATUS_CHECK_CONDITION; } -int64_t scsi_device_get_callback(scsi_device_t *dev) +int64_t +scsi_device_get_callback(scsi_device_t *dev) { - scsi_device_data_t *sdd = (scsi_device_data_t *) dev->p; - - if (sdd) - return sdd->callback; + if (dev->sc) + return dev->sc->callback; else return -1LL; } -uint8_t *scsi_device_sense(scsi_device_t *dev) +uint8_t * +scsi_device_sense(scsi_device_t *dev) { - scsi_device_data_t *sdd = (scsi_device_data_t *) dev->p; - - if (sdd) - return sdd->sense; + if (dev->sc) + return dev->sc->sense; else return scsi_null_device_sense; } -void scsi_device_request_sense(scsi_device_t *dev, uint8_t *buffer, uint8_t alloc_length) +void +scsi_device_request_sense(scsi_device_t *dev, uint8_t *buffer, uint8_t alloc_length) { if (dev->request_sense) - dev->request_sense(dev->p, buffer, alloc_length); + dev->request_sense(dev->sc, buffer, alloc_length); else memcpy(buffer, scsi_null_device_sense, alloc_length); } -void scsi_device_reset(scsi_device_t *dev) +void +scsi_device_reset(scsi_device_t *dev) { if (dev->reset) - dev->reset(dev->p); + dev->reset(dev->sc); } -int scsi_device_present(scsi_device_t *dev) +int +scsi_device_present(scsi_device_t *dev) { if (dev->type == SCSI_NONE) return 0; @@ -108,25 +118,28 @@ int scsi_device_present(scsi_device_t *dev) } -int scsi_device_valid(scsi_device_t *dev) +int +scsi_device_valid(scsi_device_t *dev) { - if (dev->p) + if (dev->sc) return 1; else return 0; } -int scsi_device_cdb_length(scsi_device_t *dev) +int +scsi_device_cdb_length(scsi_device_t *dev) { /* Right now, it's 12 for all devices. */ return 12; } -void scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb) +void +scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb) { - if (!dev->p) { + if (!dev->sc) { dev->phase = SCSI_PHASE_STATUS; dev->status = SCSI_STATUS_CHECK_CONDITION; return; @@ -143,9 +156,11 @@ void scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb) /* If the phase is DATA IN or DATA OUT, finish this here. */ } -void scsi_device_command_phase1(scsi_device_t *dev) + +void +scsi_device_command_phase1(scsi_device_t *dev) { - if (!dev->p) + if (!dev->sc) return; /* Call the second phase. */ @@ -155,7 +170,25 @@ void scsi_device_command_phase1(scsi_device_t *dev) scsi_device_target_callback(dev); } -int32_t *scsi_device_get_buf_len(scsi_device_t *dev) + +void +scsi_device_command_stop(scsi_device_t *dev) { - return &dev->buffer_length; + if (!dev->command_stop) + dev->command_stop(dev->sc); + scsi_device_target_callback(dev); +} + + +void +scsi_device_close_all(void) +{ + int i; + scsi_device_t *dev; + + for (i = 0; i < SCSI_ID_MAX; i++) { + dev = &(scsi_devices[i]); + if (dev->command_stop && dev->sc) + dev->command_stop(dev->sc); + } } diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index 643266663..bd2b77569 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -8,7 +8,7 @@ * * Definitions for the generic SCSI device command handler. * - * Version: @(#)scsi_device.h 1.0.12 2018/10/11 + * Version: @(#)scsi_device.h 1.0.14 2018/10/28 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -28,6 +28,18 @@ #endif +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + /* SCSI commands. */ #define GPCMD_TEST_UNIT_READY 0x00 #define GPCMD_REZERO_UNIT 0x01 @@ -291,59 +303,55 @@ typedef struct } scsi_bus_t; #endif -typedef struct { - uint8_t *cmd_buffer; - - int32_t buffer_length; - - uint8_t status, phase; - uint16_t type; - - void *p; - - void (*command)(void *p, uint8_t *cdb); - void (*callback)(void *p); - int (*err_stat_to_scsi)(void *p); - void (*request_sense)(void *p, uint8_t *buffer, uint8_t alloc_length); - void (*reset)(void *p); - int (*read_capacity)(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len); -} scsi_device_t; - -#pragma pack(push,1) typedef struct { - uint8_t pages[0x40][0x40]; + uint8_t pages[0x40][0x40]; } mode_sense_pages_t; -#pragma pack(pop) /* This is so we can access the common elements to all SCSI device structs without knowing the device type. */ -typedef struct { +typedef struct scsi_common_s { mode_sense_pages_t ms_pages_saved; void *p; uint8_t *temp_buffer, - pad[16], /* This is atapi_cdb in ATAPI-supporting devices, - and pad in SCSI-only devices. */ + atapi_cdb[16], /* This is atapi_cdb in ATAPI-supporting devices, + and pad in SCSI-only devices. */ current_cdb[16], sense[256]; uint8_t status, phase, error, id, - features, pad0, - pad1, pad2; + features, pad, + pad0, pad1; uint16_t request_length, max_transfer_len; int requested_blocks, packet_status, total_length, do_page_save, - unit_attention; + unit_attention, request_pos, + old_len, media_status; uint32_t sector_pos, sector_len, packet_len, pos; int64_t callback; -} scsi_device_data_t; +} scsi_common_t; + +typedef struct { + int32_t buffer_length; + + uint8_t status, phase; + uint16_t type; + + scsi_common_t *sc; + + void (*command)(scsi_common_t *sc, uint8_t *cdb); + void (*callback)(scsi_common_t *sc); + void (*request_sense)(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length); + void (*reset)(scsi_common_t *sc); + void (*command_stop)(scsi_common_t *sc); +} scsi_device_t; /* These are based on the INQUIRY values. */ #define SCSI_NONE 0x0060 @@ -371,6 +379,7 @@ extern int scsi_device_valid(scsi_device_t *dev); extern int scsi_device_cdb_length(scsi_device_t *dev); extern void scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb); extern void scsi_device_command_phase1(scsi_device_t *dev); -extern int32_t *scsi_device_get_buf_len(scsi_device_t *dev); +extern void scsi_device_command_stop(scsi_device_t *dev); +extern void scsi_device_close_all(void); #endif /*SCSI_DEVICE_H*/ diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 968df53b6..35a85dace 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -6,7 +6,7 @@ * * Emulation of SCSI fixed disks. * - * Version: @(#)scsi_disk.c 1.0.27 2018/10/27 + * Version: @(#)scsi_disk.c 1.0.28 2018/10/28 * * Author: Miran Grca, * @@ -26,27 +26,13 @@ #include "../piix.h" #include "../disk/hdd.h" #include "../disk/hdc.h" +#include "scsi_device.h" #include "../disk/hdc_ide.h" #include "../plat.h" #include "../ui.h" -#include "scsi_device.h" #include "scsi_disk.h" -/* Bits of 'status' */ -#define ERR_STAT 0x01 -#define DRQ_STAT 0x08 /* Data request */ -#define DSC_STAT 0x10 -#define SERVICE_STAT 0x10 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 - -/* Bits of 'error' */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* Media change request */ - -#define MAX_BLOCKS_AT_ONCE 340 - #define scsi_disk_sense_error dev->sense[0] #define scsi_disk_sense_key dev->sense[2] #define scsi_disk_asc dev->sense[12] @@ -136,7 +122,7 @@ static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable = } }; -static void scsi_disk_callback(void *p); +static void scsi_disk_callback(scsi_common_t *sc); #ifdef ENABLE_SCSI_DISK_LOG @@ -159,19 +145,6 @@ scsi_disk_log(const char *fmt, ...) #endif -/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -static int -scsi_disk_err_stat_to_scsi(void *p) -{ - scsi_disk_t *dev = (scsi_disk_t *) p; - - if (dev->status & ERR_STAT) - return SCSI_STATUS_CHECK_CONDITION; - else - return SCSI_STATUS_OK; -} - - void scsi_disk_mode_sense_load(scsi_disk_t *dev) { @@ -206,25 +179,6 @@ scsi_disk_mode_sense_save(scsi_disk_t *dev) } -static int -scsi_disk_read_capacity(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - scsi_disk_t *dev = (scsi_disk_t *) p; - int size = 0; - - size = hdd_image_get_last_sector(dev->id); - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 2; /* 512 = 0x0200 */ - *len = 8; - - return 1; -} - - /*SCSI Mode Sense 6/10*/ uint8_t scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) @@ -292,7 +246,7 @@ scsi_disk_command_common(scsi_disk_t *dev) dev->status = BUSY_STAT; dev->phase = 1; if (dev->packet_status == PHASE_COMPLETE) { - scsi_disk_callback((void *) dev); + scsi_disk_callback((scsi_common_t *) dev); dev->callback = 0LL; } else dev->callback = -1LL; /* Speed depends on SCSI controller */ @@ -485,9 +439,9 @@ scsi_disk_rezero(scsi_disk_t *dev) static void -scsi_disk_reset(void *p) +scsi_disk_reset(scsi_common_t *sc) { - scsi_disk_t *dev = (scsi_disk_t *) p; + scsi_disk_t *dev = (scsi_disk_t *) sc; scsi_disk_rezero(dev); dev->status = 0; @@ -522,9 +476,9 @@ scsi_disk_request_sense(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length, static void -scsi_disk_request_sense_for_scsi(void *p, uint8_t *buffer, uint8_t alloc_length) +scsi_disk_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length) { - scsi_disk_t *dev = (scsi_disk_t *) p; + scsi_disk_t *dev = (scsi_disk_t *) sc; scsi_disk_request_sense(dev, buffer, alloc_length, 0); } @@ -544,9 +498,29 @@ scsi_disk_set_buf_len(scsi_disk_t *dev, int32_t *BufLen, int32_t *src_len) static void -scsi_disk_command(void *p, uint8_t *cdb) +scsi_disk_buf_alloc(scsi_disk_t *dev, uint32_t len) { - scsi_disk_t *dev = (scsi_disk_t *) p; + scsi_disk_log("SCSI HD %i: Allocated buffer length: %i\n", dev->id, len); + if (!dev->temp_buffer) + dev->temp_buffer = (uint8_t *) malloc(len); +} + + +static void +scsi_disk_buf_free(scsi_disk_t *dev) +{ + if (dev->temp_buffer) { + scsi_disk_log("SCSI HD %i: Freeing buffer...\n", dev->id); + free(dev->temp_buffer); + dev->temp_buffer = NULL; + } +} + + +static void +scsi_disk_command(scsi_common_t *sc, uint8_t *cdb) +{ + scsi_disk_t *dev = (scsi_disk_t *) sc; #ifdef ENABLE_SCSI_DISK_LOG uint8_t *hdbufferb; #endif @@ -631,6 +605,7 @@ scsi_disk_command(void *p, uint8_t *cdb) break; } + scsi_disk_buf_alloc(dev, 256); scsi_disk_set_buf_len(dev, BufLen, &len); if (*BufLen < cdb[4]) @@ -638,14 +613,21 @@ scsi_disk_command(void *p, uint8_t *cdb) len = (cdb[1] & 1) ? 8 : 18; + scsi_disk_request_sense(dev, dev->temp_buffer, *BufLen, cdb[1] & 1); scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); scsi_disk_data_command_finish(dev, len, len, cdb[4], 0); break; case GPCMD_MECHANISM_STATUS: - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - scsi_disk_set_buf_len(dev, BufLen, &len); scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + len = (cdb[8] << 8) | cdb[9]; + + scsi_disk_buf_alloc(dev, 8); + scsi_disk_set_buf_len(dev, BufLen, &len); + + memset(dev->temp_buffer, 0, 8); + dev->temp_buffer[5] = 1; + scsi_disk_data_command_finish(dev, 8, 8, len, 0); break; @@ -684,10 +666,17 @@ scsi_disk_command(void *p, uint8_t *cdb) dev->requested_blocks = max_len; alloc_length = dev->packet_len = max_len << 9; - + scsi_disk_buf_alloc(dev, dev->packet_len); scsi_disk_set_buf_len(dev, BufLen, &alloc_length); scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + if ((dev->requested_blocks > 0) && (*BufLen > 0)) { + if (dev->packet_len > (uint32_t) *BufLen) + hdd_image_read(dev->id, dev->sector_pos, *BufLen >> 9, dev->temp_buffer); + else + hdd_image_read(dev->id, dev->sector_pos, dev->requested_blocks, dev->temp_buffer); + } + if (dev->requested_blocks > 1) scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 0); else @@ -748,6 +737,7 @@ scsi_disk_command(void *p, uint8_t *cdb) dev->requested_blocks = max_len; alloc_length = dev->packet_len = max_len << 9; + scsi_disk_buf_alloc(dev, dev->packet_len); scsi_disk_set_buf_len(dev, BufLen, &alloc_length); scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); @@ -759,6 +749,9 @@ scsi_disk_command(void *p, uint8_t *cdb) return; case GPCMD_WRITE_SAME_10: + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + if ((cdb[1] & 6) == 6) { scsi_disk_invalid_field(dev); return; @@ -766,7 +759,6 @@ scsi_disk_command(void *p, uint8_t *cdb) dev->sector_len = (cdb[7] << 8) | cdb[8]; dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); if ((dev->sector_pos > last_sector) || ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { @@ -782,18 +774,15 @@ scsi_disk_command(void *p, uint8_t *cdb) break; } - max_len = 1; - dev->requested_blocks = max_len; - - alloc_length = dev->packet_len = max_len << 9; - + scsi_disk_buf_alloc(dev, alloc_length); scsi_disk_set_buf_len(dev, BufLen, &alloc_length); + + max_len = 1; + dev->requested_blocks = 1; + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); - if (dev->requested_blocks > 1) - scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 1); - else - scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 1); + scsi_disk_data_command_finish(dev, 512, 512, alloc_length, 1); return; case GPCMD_MODE_SENSE_6: @@ -802,16 +791,17 @@ scsi_disk_command(void *p, uint8_t *cdb) block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - if (cdb[0] == GPCMD_MODE_SENSE_6) + if (cdb[0] == GPCMD_MODE_SENSE_6) { len = cdb[4]; - else + scsi_disk_buf_alloc(dev, 256); + } else { len = (cdb[8] | (cdb[7] << 8)); + scsi_disk_buf_alloc(dev, 65536); + } + memset(dev->temp_buffer, 0, len); alloc_length = len; - dev->temp_buffer = (uint8_t *) malloc(65536); - memset(dev->temp_buffer, 0, 65536); - if (cdb[0] == GPCMD_MODE_SENSE_6) { len = scsi_disk_mode_sense(dev, dev->temp_buffer, 4, cdb[2], block_desc); if (len > alloc_length) @@ -824,8 +814,8 @@ scsi_disk_command(void *p, uint8_t *cdb) len = scsi_disk_mode_sense(dev, dev->temp_buffer, 8, cdb[2], block_desc); if (len > alloc_length) len = alloc_length; - dev->temp_buffer[0]=(len - 2) >> 8; - dev->temp_buffer[1]=(len - 2) & 255; + dev->temp_buffer[0] = (len - 2) >> 8; + dev->temp_buffer[1] = (len - 2) & 255; dev->temp_buffer[2] = 0; if (block_desc) { dev->temp_buffer[6] = 0; @@ -848,10 +838,13 @@ scsi_disk_command(void *p, uint8_t *cdb) case GPCMD_MODE_SELECT_10: scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); - if (cdb[0] == GPCMD_MODE_SELECT_6) + if (cdb[0] == GPCMD_MODE_SELECT_6) { len = cdb[4]; - else + scsi_disk_buf_alloc(dev, 256); + } else { len = (cdb[7] << 8) | cdb[8]; + scsi_disk_buf_alloc(dev, 65536); + } scsi_disk_set_buf_len(dev, BufLen, &len); dev->total_length = len; @@ -872,7 +865,7 @@ scsi_disk_command(void *p, uint8_t *cdb) break; } - dev->temp_buffer = malloc(1024); + scsi_disk_buf_alloc(dev, 65536); if (cdb[1] & 1) { preamble_len = 4; @@ -891,8 +884,7 @@ scsi_disk_command(void *p, uint8_t *cdb) break; case 0x83: if (idx + 24 > max_len) { - free(dev->temp_buffer); - dev->temp_buffer = NULL; + scsi_disk_buf_free(dev); scsi_disk_data_phase_error(dev); return; } @@ -919,9 +911,8 @@ scsi_disk_command(void *p, uint8_t *cdb) break; default: scsi_disk_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - free(dev->temp_buffer); - dev->temp_buffer = NULL; scsi_disk_invalid_field(dev); + scsi_disk_buf_free(dev); return; } } else { @@ -988,12 +979,16 @@ atapi_out: break; case GPCMD_READ_CDROM_CAPACITY: - dev->temp_buffer = (uint8_t *) malloc(8); + scsi_disk_buf_alloc(dev, 8); - if (scsi_disk_read_capacity(dev, dev->current_cdb, dev->temp_buffer, (uint32_t *) &len) == 0) { - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - return; - } + max_len = hdd_image_get_last_sector(dev->id); + memset(dev->temp_buffer, 0, 8); + dev->temp_buffer[0] = (max_len >> 24) & 0xff; + dev->temp_buffer[1] = (max_len >> 16) & 0xff; + dev->temp_buffer[2] = (max_len >> 8) & 0xff; + dev->temp_buffer[3] = max_len & 0xff; + dev->temp_buffer[6] = 2; + len = 8; scsi_disk_set_buf_len(dev, BufLen, &len); @@ -1011,62 +1006,19 @@ atapi_out: static void -scsi_disk_phase_data_in(scsi_disk_t *dev) +scsi_disk_command_stop(scsi_common_t *sc) { - uint8_t *hdbufferb = scsi_devices[dev->drv->scsi_id].cmd_buffer; - int32_t *BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length; + scsi_disk_t *dev = (scsi_disk_t *) sc; - if (!*BufLen) { - scsi_disk_log("scsi_disk_phase_data_in(): Buffer length is 0\n"); - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - - return; - } - - switch (dev->current_cdb[0]) { - case GPCMD_REQUEST_SENSE: - scsi_disk_log("SCSI HDD %i: %08X, %08X\n", dev->id, hdbufferb, *BufLen); - scsi_disk_request_sense(dev, hdbufferb, *BufLen, dev->current_cdb[1] & 1); - break; - case GPCMD_MECHANISM_STATUS: - memset(hdbufferb, 0, *BufLen); - hdbufferb[5] = 1; - break; - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - if ((dev->requested_blocks > 0) && (*BufLen > 0)) { - if (dev->packet_len > (uint32_t) *BufLen) - hdd_image_read(dev->id, dev->sector_pos, *BufLen >> 9, hdbufferb); - else - hdd_image_read(dev->id, dev->sector_pos, dev->requested_blocks, hdbufferb); - } - break; - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - case GPCMD_INQUIRY: - case GPCMD_READ_CDROM_CAPACITY: - scsi_disk_log("scsi_disk_phase_data_in(): Filling buffer (%08X, %08X)\n", hdbufferb, dev->temp_buffer); - memcpy(hdbufferb, dev->temp_buffer, *BufLen); - free(dev->temp_buffer); - dev->temp_buffer = NULL; - scsi_disk_log("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", - hdbufferb[0], hdbufferb[1], hdbufferb[2], hdbufferb[3], hdbufferb[4], hdbufferb[5], hdbufferb[6], hdbufferb[7], - hdbufferb[8], hdbufferb[9], hdbufferb[10], hdbufferb[11], hdbufferb[12], hdbufferb[13], hdbufferb[14], hdbufferb[15]); - break; - default: - fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]); - break; - } - - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_command_complete(dev); + scsi_disk_buf_free(dev); } static void -scsi_disk_phase_data_out(scsi_disk_t *dev) +scsi_disk_phase_data_out(scsi_common_t *sc) { - uint8_t *hdbufferb = scsi_devices[dev->drv->scsi_id].cmd_buffer; + scsi_disk_t *dev = (scsi_disk_t *) sc; int i; int32_t *BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length; uint32_t last_sector = hdd_image_get_last_sector(dev->id); @@ -1093,9 +1045,9 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) case GPCMD_WRITE_AND_VERIFY_12: if ((dev->requested_blocks > 0) && (*BufLen > 0)) { if (dev->packet_len > (uint32_t) *BufLen) - hdd_image_write(dev->id, dev->sector_pos, *BufLen >> 9, hdbufferb); + hdd_image_write(dev->id, dev->sector_pos, *BufLen >> 9, dev->temp_buffer); else - hdd_image_write(dev->id, dev->sector_pos, dev->requested_blocks, hdbufferb); + hdd_image_write(dev->id, dev->sector_pos, dev->requested_blocks, dev->temp_buffer); } break; case GPCMD_WRITE_SAME_10: @@ -1106,24 +1058,24 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) for (i = dev->sector_pos; i <= (int) last_to_write; i++) { if (dev->current_cdb[1] & 2) { - hdbufferb[0] = (i >> 24) & 0xff; - hdbufferb[1] = (i >> 16) & 0xff; - hdbufferb[2] = (i >> 8) & 0xff; - hdbufferb[3] = i & 0xff; + dev->temp_buffer[0] = (i >> 24) & 0xff; + dev->temp_buffer[1] = (i >> 16) & 0xff; + dev->temp_buffer[2] = (i >> 8) & 0xff; + dev->temp_buffer[3] = i & 0xff; } else if (dev->current_cdb[1] & 4) { s = (i % dev->drv->spt); h = ((i - s) / dev->drv->spt) % dev->drv->hpc; c = ((i - s) / dev->drv->spt) / dev->drv->hpc; - hdbufferb[0] = (c >> 16) & 0xff; - hdbufferb[1] = (c >> 8) & 0xff; - hdbufferb[2] = c & 0xff; - hdbufferb[3] = h & 0xff; - hdbufferb[4] = (s >> 24) & 0xff; - hdbufferb[5] = (s >> 16) & 0xff; - hdbufferb[6] = (s >> 8) & 0xff; - hdbufferb[7] = s & 0xff; + dev->temp_buffer[0] = (c >> 16) & 0xff; + dev->temp_buffer[1] = (c >> 8) & 0xff; + dev->temp_buffer[2] = c & 0xff; + dev->temp_buffer[3] = h & 0xff; + dev->temp_buffer[4] = (s >> 24) & 0xff; + dev->temp_buffer[5] = (s >> 16) & 0xff; + dev->temp_buffer[6] = (s >> 8) & 0xff; + dev->temp_buffer[7] = s & 0xff; } - hdd_image_write(dev->id, i, 1, hdbufferb); + hdd_image_write(dev->id, i, 1, dev->temp_buffer); } break; case GPCMD_MODE_SELECT_6: @@ -1134,20 +1086,20 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) hdr_len = 4; if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = hdbufferb[2]; + block_desc_len = dev->temp_buffer[2]; block_desc_len <<= 8; - block_desc_len |= hdbufferb[3]; + block_desc_len |= dev->temp_buffer[3]; } else { - block_desc_len = hdbufferb[6]; + block_desc_len = dev->temp_buffer[6]; block_desc_len <<= 8; - block_desc_len |= hdbufferb[7]; + block_desc_len |= dev->temp_buffer[7]; } pos = hdr_len + block_desc_len; while(1) { - page = hdbufferb[pos] & 0x3F; - page_len = hdbufferb[pos + 1]; + page = dev->temp_buffer[pos] & 0x3F; + page_len = dev->temp_buffer[pos + 1]; pos += 2; @@ -1156,7 +1108,7 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) else { for (i = 0; i < page_len; i++) { ch = scsi_disk_mode_sense_pages_changeable.pages[page][i + 2]; - val = hdbufferb[pos + i]; + val = dev->temp_buffer[pos + i]; old_val = dev->ms_pages_saved.pages[page][i + 2]; if (val != old_val) { if (ch) @@ -1177,54 +1129,48 @@ scsi_disk_phase_data_out(scsi_disk_t *dev) break; } - if (error) + if (error) { + scsi_disk_buf_free(dev); scsi_disk_invalid_field_pl(dev); + } break; default: fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]); break; } - scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_command_stop((scsi_common_t *) dev); } /* If the result is 1, issue an IRQ, otherwise not. */ static void -scsi_disk_callback(void *p) +scsi_disk_callback(scsi_common_t *sc) { - scsi_disk_t *dev = (scsi_disk_t *) p; - - switch(dev->packet_status) { + switch(sc->packet_status) { case PHASE_IDLE: scsi_disk_log("SCSI HD %i: PHASE_IDLE\n", dev->id); - dev->phase = 1; - dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + sc->phase = 1; + sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); return; case PHASE_COMPLETE: scsi_disk_log("SCSI HD %i: PHASE_COMPLETE\n", dev->id); - dev->status = READY_STAT; - dev->phase = 3; - dev->packet_status = 0xFF; + sc->status = READY_STAT; + sc->phase = 3; + sc->packet_status = 0xFF; return; case PHASE_DATA_OUT_DMA: scsi_disk_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", dev->id); - scsi_disk_phase_data_out(dev); - dev->packet_status = PHASE_COMPLETE; - dev->status = READY_STAT; - dev->phase = 3; + scsi_disk_phase_data_out(sc); return; case PHASE_DATA_IN_DMA: scsi_disk_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", dev->id); - scsi_disk_phase_data_in(dev); - dev->packet_status = PHASE_COMPLETE; - dev->status = READY_STAT; - dev->phase = 3; + scsi_disk_command_stop(sc); return; case PHASE_ERROR: scsi_disk_log("SCSI HD %i: PHASE_ERROR\n", dev->id); - dev->status = READY_STAT | ERR_STAT; - dev->phase = 3; + sc->status = READY_STAT | ERR_STAT; + sc->phase = 3; return; } } @@ -1263,13 +1209,12 @@ scsi_disk_hard_reset(void) /* SCSI disk, attach to the SCSI bus. */ sd = &scsi_devices[hdd[c].scsi_id]; - sd->p = dev; + sd->sc = (scsi_common_t *) dev; sd->command = scsi_disk_command; sd->callback = scsi_disk_callback; - sd->err_stat_to_scsi = scsi_disk_err_stat_to_scsi; sd->request_sense = scsi_disk_request_sense_for_scsi; sd->reset = scsi_disk_reset; - sd->read_capacity = scsi_disk_read_capacity; + sd->command_stop = scsi_disk_command_stop; sd->type = SCSI_FIXED_DISK; dev->id = c; @@ -1290,13 +1235,15 @@ scsi_disk_close(void) int c; for (c = 0; c < HDD_NUM; c++) { - dev = hdd[c].priv; - - if (dev) { + if (hdd[c].bus == HDD_BUS_SCSI) { hdd_image_close(c); - free(dev); - hdd[c].priv = NULL; + dev = hdd[c].priv; + + if (dev) { + free(dev); + hdd[c].priv = NULL; + } } } } diff --git a/src/scsi/scsi_disk.h b/src/scsi/scsi_disk.h index 60b24cd7c..220183c3f 100644 --- a/src/scsi/scsi_disk.h +++ b/src/scsi/scsi_disk.h @@ -33,7 +33,8 @@ typedef struct { int requested_blocks, packet_status, total_length, do_page_save, - unit_attention; + unit_attention, pad5, + pad6, pad7; uint32_t sector_pos, sector_len, packet_len, pos; diff --git a/src/scsi/scsi_ncr5380.c b/src/scsi/scsi_ncr5380.c index 4a05e9b88..e35c0cdf2 100644 --- a/src/scsi/scsi_ncr5380.c +++ b/src/scsi/scsi_ncr5380.c @@ -9,7 +9,7 @@ * Implementation of the NCR 5380 series of SCSI Host Adapters * made by NCR. These controllers were designed for the ISA bus. * - * Version: @(#)scsi_ncr5380.c 1.0.23 2018/10/18 + * Version: @(#)scsi_ncr5380.c 1.0.24 2018/10/28 * * Authors: Sarah Walker, * TheCollector1995, @@ -286,7 +286,7 @@ ncr_wait_process(ncr5380_t *ncr_dev) if (ncr->new_phase == SCSI_PHASE_DATA_IN) { ncr_log("Data In bus phase\n"); - ncr->tx_data = dev->cmd_buffer[ncr->data_pos++]; + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; ncr->state = STATE_DATAIN; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; } else if (ncr->new_phase == SCSI_PHASE_STATUS) { @@ -963,8 +963,6 @@ ncr_callback(void *priv) /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ if (dev->buffer_length && (dev->phase == SCSI_PHASE_DATA_IN || dev->phase == SCSI_PHASE_DATA_OUT)) { - dev->cmd_buffer = (uint8_t *) malloc(dev->buffer_length); - p = scsi_device_get_callback(dev); req_len = MIN(64, dev->buffer_length); if (p <= 0LL) @@ -982,10 +980,6 @@ ncr_callback(void *priv) } else { /* Other command - execute immediately. */ ncr->new_phase = dev->phase; - - if (ncr->new_phase == SCSI_PHASE_DATA_IN) - scsi_device_command_phase1(dev); - ncr->wait_data = 4; } } @@ -995,17 +989,13 @@ ncr_callback(void *priv) ncr_log("Data In ACK=%02x\n", ncr->bus_host & BUS_ACK); if (ncr->bus_host & BUS_ACK) { if (ncr->data_pos >= dev->buffer_length) { - if (dev->cmd_buffer != NULL) { - free(dev->cmd_buffer); - dev->cmd_buffer = NULL; - } - + scsi_device_command_phase1(dev); ncr->cur_bus &= ~BUS_REQ; ncr->new_phase = SCSI_PHASE_STATUS; ncr->wait_data = 4; ncr->wait_complete = 8; } else { - ncr->tx_data = dev->cmd_buffer[ncr->data_pos++]; + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; ncr->clear_req = 3; ncr->cur_bus &= ~BUS_REQ; @@ -1017,16 +1007,10 @@ ncr_callback(void *priv) ncr_log("Data Out ACK=%02x\n", ncr->bus_host & BUS_ACK); if (ncr->bus_host & BUS_ACK) { - dev->cmd_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); if (ncr->data_pos >= dev->buffer_length) { scsi_device_command_phase1(dev); - - if (dev->cmd_buffer != NULL) { - free(dev->cmd_buffer); - dev->cmd_buffer = NULL; - } - ncr->cur_bus &= ~BUS_REQ; ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); ncr->new_phase = SCSI_PHASE_STATUS; @@ -1076,17 +1060,13 @@ ncr_callback(void *priv) ncr->bus_host = get_bus_host(ncr); if (ncr->data_pos >= dev->buffer_length) { - if (dev->cmd_buffer != NULL) { - free(dev->cmd_buffer); - dev->cmd_buffer = NULL; - } - + scsi_device_command_phase1(dev); ncr->cur_bus &= ~BUS_REQ; ncr->new_phase = SCSI_PHASE_STATUS; ncr->wait_data = 4; ncr->wait_complete = 8; } else { - ncr->tx_data = dev->cmd_buffer[ncr->data_pos++]; + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; ncr->clear_req = 3; ncr->cur_bus &= ~BUS_REQ; @@ -1141,16 +1121,10 @@ ncr_callback(void *priv) ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; ncr->bus_host |= BUS_SETDATA(data); - dev->cmd_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); if (ncr->data_pos >= dev->buffer_length) { scsi_device_command_phase1(dev); - - if (dev->cmd_buffer != NULL) { - free(dev->cmd_buffer); - dev->cmd_buffer = NULL; - } - ncr->cur_bus &= ~BUS_REQ; ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); ncr->new_phase = SCSI_PHASE_STATUS; @@ -1199,17 +1173,13 @@ ncr_callback(void *priv) ncr->bus_host = get_bus_host(ncr); if (ncr->data_pos >= dev->buffer_length) { - if (dev->cmd_buffer != NULL) { - free(dev->cmd_buffer); - dev->cmd_buffer = NULL; - } - + scsi_device_command_phase1(dev); ncr->cur_bus &= ~BUS_REQ; ncr->new_phase = SCSI_PHASE_STATUS; ncr->wait_data = 4; ncr->wait_complete = 8; } else { - ncr->tx_data = dev->cmd_buffer[ncr->data_pos++]; + ncr->tx_data = dev->sc->temp_buffer[ncr->data_pos++]; ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; ncr->clear_req = 3; ncr->cur_bus &= ~BUS_REQ; @@ -1250,16 +1220,10 @@ ncr_callback(void *priv) ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; ncr->bus_host |= BUS_SETDATA(data); - dev->cmd_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + dev->sc->temp_buffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); if (ncr->data_pos >= dev->buffer_length) { scsi_device_command_phase1(dev); - - if (dev->cmd_buffer != NULL) { - free(dev->cmd_buffer); - dev->cmd_buffer = NULL; - } - ncr->cur_bus &= ~BUS_REQ; ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); ncr->new_phase = SCSI_PHASE_STATUS; diff --git a/src/scsi/scsi_ncr53c810.c b/src/scsi/scsi_ncr53c8xx.c similarity index 50% rename from src/scsi/scsi_ncr53c810.c rename to src/scsi/scsi_ncr53c8xx.c index b8196b24d..686a1b8ef 100644 --- a/src/scsi/scsi_ncr53c810.c +++ b/src/scsi/scsi_ncr53c8xx.c @@ -6,11 +6,14 @@ * * This file is part of the 86Box distribution. * - * Implementation of the NCR 53C810 SCSI Host Adapter made by - * NCR and later Symbios and LSI. This controller was designed - * for the PCI bus. + * Implementation of the NCR 53C810 and 53C875 SCSI Host + * Adapters made by NCR and later Symbios and LSI. These + * controllers were designed for the PCI bus. * - * Version: @(#)scsi_ncr53c810.c 1.0.16 2018/10/18 + * To do: Identify the type of serial EEPROM used and its + * interface. + * + * Version: @(#)scsi_ncr53c8xx.c 1.0.17 2018/10/30 * * Authors: Paul Brook (QEMU) * Artyom Tarasenko (QEMU) @@ -42,9 +45,13 @@ #include "../plat.h" #include "scsi.h" #include "scsi_device.h" -#include "scsi_ncr53c810.h" +#include "scsi_ncr53c8xx.h" -#define NCR53C810_ROM L"roms/scsi/ncr53c810/NCR307.BIN" +#define NCR53C8XX_ROM L"roms/scsi/ncr53c8xx/NCR307.BIN" + +#define CHIP_810 0x01 +#define CHIP_825 0x03 +#define CHIP_875 0x0f #define NCR_SCNTL0_TRG 0x01 #define NCR_SCNTL0_AAP 0x02 @@ -170,13 +177,13 @@ #define NCR_BUF_SIZE 4096 -typedef struct ncr53c810_request { +typedef struct ncr53c8xx_request { uint32_t tag; uint32_t dma_len; uint8_t *dma_buf; uint32_t pending; int out; -} ncr53c810_request; +} ncr53c8xx_request; typedef enum { @@ -189,8 +196,11 @@ typedef enum } scsi_state_t; typedef struct { + wchar_t *nvr_path; uint8_t pci_slot; + uint8_t chip; int has_bios; + int BIOSBase; rom_t bios; int PCIBase; int MMIOBase; @@ -205,23 +215,23 @@ typedef struct { int msg_action; int msg_len; uint8_t msg[NCR_MAX_MSGIN_LEN]; +#ifdef USE_NVRAM + uint16_t nvram; + uint8_t nvram_t; + uint8_t nvram_op; + uint8_t nvram_param; + uint8_t nvram_start; + uint8_t nvram_index; +#endif + uint8_t ram[NCR_BUF_SIZE]; /* NCR 53c875 RAM (4 kB). */ /* 0 if SCRIPTS are running or stopped. * 1 if a Wait Reselect instruction has been issued. - * 2 if processing DMA from ncr53c810_execute_script. + * 2 if processing DMA from ncr53c8xx_execute_script. * 3 if a DMA operation is in progress. */ int waiting; uint8_t current_lun; - uint8_t select_id; - int command_complete; - ncr53c810_request *current; - int irq; - - uint32_t dsa; - uint32_t temp; - uint32_t dnad; - uint32_t dbc; uint8_t istat; uint8_t dcmd; uint8_t dstat; @@ -237,8 +247,6 @@ typedef struct { uint8_t ctest3; uint8_t ctest4; uint8_t ctest5; - uint32_t dsp; - uint32_t dsps; uint8_t dmode; uint8_t dcntl; uint8_t scntl0; @@ -256,19 +264,37 @@ typedef struct { uint8_t stest1; uint8_t stest2; uint8_t stest3; - uint8_t sidl; + uint8_t sidl0; + uint8_t sidl1; uint8_t stime0; - uint8_t respid; - uint32_t scratcha; - uint32_t scratchb; + uint8_t respid0; + uint8_t respid1; uint8_t sbr; uint8_t chip_rev; + uint8_t gpreg; + uint8_t slpar; + uint8_t swide; + uint8_t gpcntl; + uint8_t last_command; + + int command_complete; + ncr53c8xx_request *current; + + int irq; + + uint32_t dsa; + uint32_t temp; + uint32_t dnad; + uint32_t dbc; + uint32_t dsp; + uint32_t dsps; + uint32_t scratcha, scratchb, scratchc, scratchd; + uint32_t scratche, scratchf, scratchg, scratchh; + uint32_t scratchi, scratchj; int last_level; void *hba_private; - uint8_t gpreg0; uint32_t buffer_pos; int32_t temp_buf_len; - uint8_t last_command; uint8_t sstop; @@ -277,31 +303,31 @@ typedef struct { int64_t timer_period; int64_t timer_enabled; -} ncr53c810_t; +} ncr53c8xx_t; -#ifdef ENABLE_NCR53C810_LOG -int ncr53c810_do_log = ENABLE_NCR53C810_LOG; +#ifdef ENABLE_NCR53C8XX_LOG +int ncr53c8xx_do_log = ENABLE_NCR53C8XX_LOG; static void -ncr53c810_log(const char *fmt, ...) +ncr53c8xx_log(const char *fmt, ...) { va_list ap; - if (ncr53c810_do_log) { + if (ncr53c8xx_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } } #else -#define ncr53c810_log(fmt, ...) +#define ncr53c8xx_log(fmt, ...) #endif -static uint8_t ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset); -static void ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val); +static uint8_t ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset); +static void ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val); static __inline__ int32_t @@ -325,18 +351,18 @@ deposit32(uint32_t value, int start, int length, static __inline__ int -ncr53c810_irq_on_rsl(ncr53c810_t *dev) +ncr53c8xx_irq_on_rsl(ncr53c8xx_t *dev) { return (dev->sien0 & NCR_SIST0_RSL) && (dev->scid & NCR_SCID_RRE); } static void -ncr53c810_soft_reset(ncr53c810_t *dev) +ncr53c8xx_soft_reset(ncr53c8xx_t *dev) { int i; - ncr53c810_log("LSI Reset\n"); + ncr53c8xx_log("LSI Reset\n"); dev->timer_period = dev->timer_enabled = 0; dev->carry = 0; @@ -350,6 +376,14 @@ ncr53c810_soft_reset(ncr53c810_t *dev) dev->temp = 0; dev->scratcha = 0; dev->scratchb = 0; + dev->scratchc = 0; + dev->scratchd = 0; + dev->scratche = 0; + dev->scratchf = 0; + dev->scratchg = 0; + dev->scratchh = 0; + dev->scratchi = 0; + dev->scratchj = 0; dev->istat = 0; dev->dcmd = 0x40; dev->dstat = NCR_DSTAT_DFE; @@ -372,7 +406,10 @@ ncr53c810_soft_reset(ncr53c810_t *dev) dev->scntl0 = 0xc0; dev->scntl1 = 0; dev->scntl2 = 0; - dev->scntl3 = 0; + if (dev->chip >= CHIP_825) + dev->scntl3 = 8; + else + dev->scntl3 = 0; dev->sstat0 = 0; dev->sstat1 = 0; dev->scid = 7; @@ -380,85 +417,100 @@ ncr53c810_soft_reset(ncr53c810_t *dev) dev->socl = 0; dev->sdid = 0; dev->ssid = 0; - dev->stest1 = 0; + dev->stest1 = 0; dev->stest2 = 0; dev->stest3 = 0; - dev->sidl = 0; + dev->sidl0 = 0; + dev->sidl1 = 0; dev->stime0 = 0; - dev->respid = 0x80; + dev->stime0 = 1; + dev->respid0 = 0x80; + dev->respid1 = 0x00; dev->sbr = 0; dev->last_level = 0; - dev->gpreg0 = 0; + dev->gpreg = 0; + dev->slpar = 0; dev->sstop = 1; + dev->gpcntl = 0x0f; +#ifdef USE_NVRAM + dev->nvram_t = dev->nvram_index = 0; +#endif - /* This is *NOT* a wide SCSI controller, so do not touch - SCSI devices with ID's >= 8. */ - for (i = 0; i < 8; i++) - scsi_device_reset(&scsi_devices[i]); + if (dev->chip >= CHIP_825) { + /* This *IS* a wide SCSI controller, so reset all SCSI + devices. */ + for (i = 0; i < 16; i++) + scsi_device_reset(&scsi_devices[i]); + } else { + /* This is *NOT* a wide SCSI controller, so do not touch + SCSI devices with ID's >= 8. */ + for (i = 0; i < 8; i++) + scsi_device_reset(&scsi_devices[i]); + } } static void -ncr53c810_read(ncr53c810_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) +ncr53c8xx_read(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) { uint32_t i = 0; - ncr53c810_log("ncr53c810_read(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); + ncr53c8xx_log("ncr53c8xx_read(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); if (dev->dmode & NCR_DMODE_SIOM) { - ncr53c810_log("NCR 810: Reading from I/O address %04X\n", (uint16_t) addr); + ncr53c8xx_log("NCR 810: Reading from I/O address %04X\n", (uint16_t) addr); for (i = 0; i < len; i++) buf[i] = inb((uint16_t) (addr + i)); } else { - ncr53c810_log("NCR 810: Reading from memory address %08X\n", addr); + ncr53c8xx_log("NCR 810: Reading from memory address %08X\n", addr); DMAPageRead(addr, buf, len); } } static void -ncr53c810_write(ncr53c810_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) +ncr53c8xx_write(ncr53c8xx_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) { uint32_t i = 0; - ncr53c810_log("ncr53c810_write(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); + ncr53c8xx_log("ncr53c8xx_write(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); if (dev->dmode & NCR_DMODE_DIOM) { - ncr53c810_log("NCR 810: Writing to I/O address %04X\n", (uint16_t) addr); + ncr53c8xx_log("NCR 810: Writing to I/O address %04X\n", (uint16_t) addr); for (i = 0; i < len; i++) outb((uint16_t) (addr + i), buf[i]); } else { - ncr53c810_log("NCR 810: Writing to memory address %08X\n", addr); + ncr53c8xx_log("NCR 810: Writing to memory address %08X\n", addr); DMAPageWrite(addr, buf, len); } } static __inline__ uint32_t -read_dword(ncr53c810_t *dev, uint32_t addr) +read_dword(ncr53c8xx_t *dev, uint32_t addr) { uint32_t buf; - ncr53c810_log("Reading the next DWORD from memory (%08X)...\n", addr); + ncr53c8xx_log("Reading the next DWORD from memory (%08X)...\n", addr); DMAPageRead(addr, (uint8_t *)&buf, 4); return buf; } static -void do_irq(ncr53c810_t *dev, int level) +void do_irq(ncr53c8xx_t *dev, int level) { if (level) { pci_set_irq(dev->pci_slot, PCI_INTA); - ncr53c810_log("Raising IRQ...\n"); + ncr53c8xx_log("Raising IRQ...\n"); } else { pci_clear_irq(dev->pci_slot, PCI_INTA); - ncr53c810_log("Lowering IRQ...\n"); + ncr53c8xx_log("Lowering IRQ...\n"); } } static void -ncr53c810_update_irq(ncr53c810_t *dev) +ncr53c8xx_update_irq(ncr53c8xx_t *dev) { int level; @@ -486,7 +538,7 @@ ncr53c810_update_irq(ncr53c810_t *dev) } if (level != dev->last_level) { - ncr53c810_log("Update IRQ level %d dstat %02x sist %02x%02x\n", + ncr53c8xx_log("Update IRQ level %d dstat %02x sist %02x%02x\n", level, dev->dstat, dev->sist1, dev->sist0); dev->last_level = level; do_irq(dev, level); /* Only do something with the IRQ if the new level differs from the previous one. */ @@ -496,12 +548,12 @@ ncr53c810_update_irq(ncr53c810_t *dev) /* Stop SCRIPTS execution and raise a SCSI interrupt. */ static void -ncr53c810_script_scsi_interrupt(ncr53c810_t *dev, int stat0, int stat1) +ncr53c8xx_script_scsi_interrupt(ncr53c8xx_t *dev, int stat0, int stat1) { uint32_t mask0; uint32_t mask1; - ncr53c810_log("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", + ncr53c8xx_log("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", stat1, stat0, dev->sist1, dev->sist0); dev->sist0 |= stat0; dev->sist1 |= stat1; @@ -512,47 +564,47 @@ ncr53c810_script_scsi_interrupt(ncr53c810_t *dev, int stat0, int stat1) mask1 = dev->sien1 | ~(NCR_SIST1_GEN | NCR_SIST1_HTH); mask1 &= ~NCR_SIST1_STO; if ((dev->sist0 & mask0) || (dev->sist1 & mask1)) { - ncr53c810_log("NCR 810: IRQ-mandated stop\n"); + ncr53c8xx_log("NCR 810: IRQ-mandated stop\n"); dev->sstop = 1; dev->timer_period = dev->timer_enabled = 0; } - ncr53c810_update_irq(dev); + ncr53c8xx_update_irq(dev); } /* Stop SCRIPTS execution and raise a DMA interrupt. */ static void -ncr53c810_script_dma_interrupt(ncr53c810_t *dev, int stat) +ncr53c8xx_script_dma_interrupt(ncr53c8xx_t *dev, int stat) { - ncr53c810_log("DMA Interrupt 0x%x prev 0x%x\n", stat, dev->dstat); + ncr53c8xx_log("DMA Interrupt 0x%x prev 0x%x\n", stat, dev->dstat); dev->dstat |= stat; - ncr53c810_update_irq(dev); + ncr53c8xx_update_irq(dev); dev->sstop = 1; dev->timer_period = dev->timer_enabled = 0; } static __inline__ void -ncr53c810_set_phase(ncr53c810_t *dev, int phase) +ncr53c8xx_set_phase(ncr53c8xx_t *dev, int phase) { dev->sstat1 = (dev->sstat1 & ~PHASE_MASK) | phase; } static void -ncr53c810_bad_phase(ncr53c810_t *dev, int out, int new_phase) +ncr53c8xx_bad_phase(ncr53c8xx_t *dev, int out, int new_phase) { /* Trigger a phase mismatch. */ - ncr53c810_log("Phase mismatch interrupt\n"); - ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); + ncr53c8xx_log("Phase mismatch interrupt\n"); + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); dev->sstop = 1; dev->timer_period = dev->timer_enabled = 0; - ncr53c810_set_phase(dev, new_phase); + ncr53c8xx_set_phase(dev, new_phase); } static void -ncr53c810_disconnect(ncr53c810_t *dev) +ncr53c8xx_disconnect(ncr53c8xx_t *dev) { dev->scntl1 &= ~NCR_SCNTL1_CON; dev->sstat1 &= ~PHASE_MASK; @@ -562,37 +614,37 @@ ncr53c810_disconnect(ncr53c810_t *dev) static void -ncr53c810_bad_selection(ncr53c810_t *dev, uint32_t id) +ncr53c8xx_bad_selection(ncr53c8xx_t *dev, uint32_t id) { - ncr53c810_log("Selected absent target %d\n", id); - ncr53c810_script_scsi_interrupt(dev, 0, NCR_SIST1_STO); - ncr53c810_disconnect(dev); + ncr53c8xx_log("Selected absent target %d\n", id); + ncr53c8xx_script_scsi_interrupt(dev, 0, NCR_SIST1_STO); + ncr53c8xx_disconnect(dev); } /* Callback to indicate that the SCSI layer has completed a command. */ static void -ncr53c810_command_complete(void *priv, uint32_t status) +ncr53c8xx_command_complete(void *priv, uint32_t status) { - ncr53c810_t *dev = (ncr53c810_t *)priv; + ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; int out; out = (dev->sstat1 & PHASE_MASK) == PHASE_DO; - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Command complete status=%d\n", dev->current->tag, dev->current_lun, dev->last_command, (int)status); + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Command complete status=%d\n", dev->current->tag, dev->current_lun, dev->last_command, (int)status); dev->status = status; dev->command_complete = 2; if (dev->waiting && dev->dbc != 0) { /* Raise phase mismatch for short transfers. */ - ncr53c810_bad_phase(dev, out, PHASE_ST); + ncr53c8xx_bad_phase(dev, out, PHASE_ST); } else - ncr53c810_set_phase(dev, PHASE_ST); + ncr53c8xx_set_phase(dev, PHASE_ST); dev->sstop = 0; } static void -ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) +ncr53c8xx_do_dma(ncr53c8xx_t *dev, int out, uint8_t id) { uint32_t addr, tdbc; int count; @@ -600,13 +652,13 @@ ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) scsi_device_t *sd = &scsi_devices[id]; if ((!scsi_device_present(sd))) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command); + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command); return; } if (!dev->current->dma_len) { /* Wait until data is available. */ - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA no data available\n", id, dev->current_lun, dev->last_command); + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA no data available\n", id, dev->current_lun, dev->last_command); return; } @@ -617,35 +669,32 @@ ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) addr = dev->dnad; - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA addr=0x%08x len=%d cur_len=%d dev->dbc=%d\n", id, dev->current_lun, dev->last_command, dev->dnad, dev->temp_buf_len, count, tdbc); + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA addr=0x%08x len=%d cur_len=%d dev->dbc=%d\n", id, dev->current_lun, dev->last_command, dev->dnad, dev->temp_buf_len, count, tdbc); dev->dnad += count; dev->dbc -= count; if (out) - ncr53c810_read(dev, addr, sd->cmd_buffer + dev->buffer_pos, count); + ncr53c8xx_read(dev, addr, sd->sc->temp_buffer + dev->buffer_pos, count); else { - if (!dev->buffer_pos) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DI\n", id, dev->current_lun, dev->last_command); - scsi_device_command_phase1(&scsi_devices[dev->current->tag]); - } - ncr53c810_write(dev, addr, sd->cmd_buffer + dev->buffer_pos, count); +#ifdef ENABLE_NCR53C8XX_LOG + if (!dev->buffer_pos) + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DI\n", id, dev->current_lun, dev->last_command); +#endif + ncr53c8xx_write(dev, addr, sd->sc->temp_buffer + dev->buffer_pos, count); } dev->temp_buf_len -= count; dev->buffer_pos += count; if (dev->temp_buf_len <= 0) { - if (out) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DO\n", id, dev->current_lun, dev->last_command); - scsi_device_command_phase1(&scsi_devices[id]); - } - if (sd->cmd_buffer != NULL) { - free(sd->cmd_buffer); - sd->cmd_buffer = NULL; - } - ncr53c810_command_complete(dev, sd->status); + scsi_device_command_phase1(&scsi_devices[id]); +#ifdef ENABLE_NCR53C8XX_LOG + if (out) + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DO\n", id, dev->current_lun, dev->last_command); +#endif + ncr53c8xx_command_complete(dev, sd->status); } else { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Resume SCRIPTS\n", id, dev->current_lun, dev->last_command); + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Resume SCRIPTS\n", id, dev->current_lun, dev->last_command); dev->sstop = 0; } } @@ -653,19 +702,19 @@ ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) /* Queue a byte for a MSG IN phase. */ static void -ncr53c810_add_msg_byte(ncr53c810_t *dev, uint8_t data) +ncr53c8xx_add_msg_byte(ncr53c8xx_t *dev, uint8_t data) { if (dev->msg_len >= NCR_MAX_MSGIN_LEN) - ncr53c810_log("MSG IN data too long\n"); + ncr53c8xx_log("MSG IN data too long\n"); else { - ncr53c810_log("MSG IN 0x%02x\n", data); + ncr53c8xx_log("MSG IN 0x%02x\n", data); dev->msg[dev->msg_len++] = data; } } static int -ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) +ncr53c8xx_do_command(ncr53c8xx_t *dev, uint8_t id) { scsi_device_t *sd; uint8_t buf[12]; @@ -677,7 +726,7 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) memset(buf, 0, 12); DMAPageRead(dev->dnad, buf, MIN(12, dev->dbc)); if (dev->dbc > 12) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: CDB length %i too big\n", id, dev->current_lun, buf[0], dev->dbc); + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: CDB length %i too big\n", id, dev->current_lun, buf[0], dev->dbc); dev->dbc = 12; } dev->sfbr = buf[0]; @@ -685,19 +734,23 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) sd = &scsi_devices[id]; if (!scsi_device_present(sd)) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]); - ncr53c810_bad_selection(dev, id); + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]); + ncr53c8xx_bad_selection(dev, id); return 0; } - dev->current = (ncr53c810_request*)malloc(sizeof(ncr53c810_request)); + dev->current = (ncr53c8xx_request*)malloc(sizeof(ncr53c8xx_request)); dev->current->tag = id; sd->buffer_length = -1; - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DBC=%i\n", id, dev->current_lun, buf[0], dev->dbc); + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DBC=%i\n", id, dev->current_lun, buf[0], dev->dbc); dev->last_command = buf[0]; + /* Make sure bits 5-7 of the CDB have the correct LUN. */ + if ((buf[1] & 0xe0) != (dev->current_lun << 5)) + buf[1] = (buf[1] & 0x1f) | (dev->current_lun << 5); + scsi_device_command_phase0(&scsi_devices[dev->current->tag], buf); dev->hba_private = (void *)dev->current; @@ -707,13 +760,13 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) dev->temp_buf_len = sd->buffer_length; if (sd->buffer_length > 0) { - sd->cmd_buffer = (uint8_t *)malloc(sd->buffer_length); + /* This should be set to the underlying device's buffer by command phase 0. */ dev->current->dma_len = sd->buffer_length; } if ((sd->phase == SCSI_PHASE_DATA_IN) && (sd->buffer_length > 0)) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); - ncr53c810_set_phase(dev, PHASE_DI); + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); + ncr53c8xx_set_phase(dev, PHASE_DI); p = scsi_device_get_callback(&scsi_devices[dev->current->tag]); if (p <= 0LL) { period = ((double) sd->buffer_length) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ @@ -722,8 +775,8 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) dev->timer_period += p; return 1; } else if ((sd->phase == SCSI_PHASE_DATA_OUT) && (sd->buffer_length > 0)) { - ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, buf[0]); - ncr53c810_set_phase(dev, PHASE_DO); + ncr53c8xx_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, buf[0]); + ncr53c8xx_set_phase(dev, PHASE_DO); p = scsi_device_get_callback(&scsi_devices[dev->current->tag]); if (p <= 0LL) { period = ((double) sd->buffer_length) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ @@ -732,41 +785,41 @@ ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) dev->timer_period += p; return 1; } else { - ncr53c810_command_complete(dev, sd->status); + ncr53c8xx_command_complete(dev, sd->status); return 0; } } static void -ncr53c810_do_status(ncr53c810_t *dev) +ncr53c8xx_do_status(ncr53c8xx_t *dev) { uint8_t status; - ncr53c810_log("Get status len=%d status=%d\n", dev->dbc, dev->status); + ncr53c8xx_log("Get status len=%d status=%d\n", dev->dbc, dev->status); if (dev->dbc != 1) - ncr53c810_log("Bad Status move\n"); + ncr53c8xx_log("Bad Status move\n"); dev->dbc = 1; status = dev->status; dev->sfbr = status; - ncr53c810_write(dev, dev->dnad, &status, 1); - ncr53c810_set_phase(dev, PHASE_MI); + ncr53c8xx_write(dev, dev->dnad, &status, 1); + ncr53c8xx_set_phase(dev, PHASE_MI); dev->msg_action = 1; - ncr53c810_add_msg_byte(dev, 0); /* COMMAND COMPLETE */ + ncr53c8xx_add_msg_byte(dev, 0); /* COMMAND COMPLETE */ } static void -ncr53c810_do_msgin(ncr53c810_t *dev) +ncr53c8xx_do_msgin(ncr53c8xx_t *dev) { uint32_t len; - ncr53c810_log("Message in len=%d/%d\n", dev->dbc, dev->msg_len); + ncr53c8xx_log("Message in len=%d/%d\n", dev->dbc, dev->msg_len); dev->sfbr = dev->msg[0]; len = dev->msg_len; if (len > dev->dbc) len = dev->dbc; - ncr53c810_write(dev, dev->dnad, dev->msg, len); + ncr53c8xx_write(dev, dev->dnad, dev->msg, len); /* Linux drivers rely on the last byte being in the SIDL. */ - dev->sidl = dev->msg[len - 1]; + dev->sidl0 = dev->msg[len - 1]; dev->msg_len -= len; if (dev->msg_len) memmove(dev->msg, dev->msg + len, dev->msg_len); @@ -775,16 +828,16 @@ ncr53c810_do_msgin(ncr53c810_t *dev) switch to PHASE_MO. */ switch (dev->msg_action) { case 0: - ncr53c810_set_phase(dev, PHASE_CMD); + ncr53c8xx_set_phase(dev, PHASE_CMD); break; case 1: - ncr53c810_disconnect(dev); + ncr53c8xx_disconnect(dev); break; case 2: - ncr53c810_set_phase(dev, PHASE_DO); + ncr53c8xx_set_phase(dev, PHASE_DO); break; case 3: - ncr53c810_set_phase(dev, PHASE_DI); + ncr53c8xx_set_phase(dev, PHASE_DI); break; default: abort(); @@ -795,7 +848,7 @@ ncr53c810_do_msgin(ncr53c810_t *dev) /* Read the next byte during a MSGOUT phase. */ static uint8_t -ncr53c810_get_msgbyte(ncr53c810_t *dev) +ncr53c8xx_get_msgbyte(ncr53c8xx_t *dev) { uint8_t data; DMAPageRead(dev->dnad, &data, 1); @@ -807,7 +860,7 @@ ncr53c810_get_msgbyte(ncr53c810_t *dev) /* Skip the next n bytes during a MSGOUT phase. */ static void -ncr53c810_skip_msgbytes(ncr53c810_t *dev, unsigned int n) +ncr53c8xx_skip_msgbytes(ncr53c8xx_t *dev, unsigned int n) { dev->dnad += n; dev->dbc -= n; @@ -815,116 +868,103 @@ ncr53c810_skip_msgbytes(ncr53c810_t *dev, unsigned int n) static void -ncr53c810_bad_message(ncr53c810_t *dev, uint8_t msg) +ncr53c8xx_bad_message(ncr53c8xx_t *dev, uint8_t msg) { - ncr53c810_log("Unimplemented message 0x%02x\n", msg); - ncr53c810_set_phase(dev, PHASE_MI); - ncr53c810_add_msg_byte(dev, 7); /* MESSAGE REJECT */ + ncr53c8xx_log("Unimplemented message 0x%02x\n", msg); + ncr53c8xx_set_phase(dev, PHASE_MI); + ncr53c8xx_add_msg_byte(dev, 7); /* MESSAGE REJECT */ dev->msg_action = 0; } static void -ncr53c810_do_msgout(ncr53c810_t *dev, uint8_t id) +ncr53c8xx_do_msgout(ncr53c8xx_t *dev, uint8_t id) { uint8_t msg; int len; -#ifdef ENABLE_NCR53C810_LOG +#ifdef ENABLE_NCR53C8xx_LOG uint32_t current_tag; #endif scsi_device_t *sd; sd = &scsi_devices[id]; -#ifdef ENABLE_NCR53C810_LOG +#ifdef ENABLE_NCR53C8xx_LOG current_tag = id; #endif - ncr53c810_log("MSG out len=%d\n", dev->dbc); + ncr53c8xx_log("MSG out len=%d\n", dev->dbc); while (dev->dbc) { - msg = ncr53c810_get_msgbyte(dev); + msg = ncr53c8xx_get_msgbyte(dev); dev->sfbr = msg; switch (msg) { case 0x04: - ncr53c810_log("MSG: Disconnect\n"); - ncr53c810_disconnect(dev); + ncr53c8xx_log("MSG: Disconnect\n"); + ncr53c8xx_disconnect(dev); break; case 0x08: - ncr53c810_log("MSG: No Operation\n"); - ncr53c810_set_phase(dev, PHASE_CMD); + ncr53c8xx_log("MSG: No Operation\n"); + ncr53c8xx_set_phase(dev, PHASE_CMD); break; case 0x01: - len = ncr53c810_get_msgbyte(dev); - msg = ncr53c810_get_msgbyte(dev); + len = ncr53c8xx_get_msgbyte(dev); + msg = ncr53c8xx_get_msgbyte(dev); (void) len; /* avoid a warning about unused variable*/ - ncr53c810_log("Extended message 0x%x (len %d)\n", msg, len); + ncr53c8xx_log("Extended message 0x%x (len %d)\n", msg, len); switch (msg) { case 1: - ncr53c810_log("SDTR (ignored)\n"); - ncr53c810_skip_msgbytes(dev, 2); + ncr53c8xx_log("SDTR (ignored)\n"); + ncr53c8xx_skip_msgbytes(dev, 2); break; case 3: - ncr53c810_log("WDTR (ignored)\n"); - ncr53c810_skip_msgbytes(dev, 1); + ncr53c8xx_log("WDTR (ignored)\n"); + ncr53c8xx_skip_msgbytes(dev, 1); + break; + case 5: + ncr53c8xx_log("PPR (ignored)\n"); + ncr53c8xx_skip_msgbytes(dev, 5); break; default: - ncr53c810_bad_message(dev, msg); + ncr53c8xx_bad_message(dev, msg); return; } break; case 0x20: /* SIMPLE queue */ - id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; - ncr53c810_log("SIMPLE queue tag=0x%x\n", id & 0xff); + id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; + ncr53c8xx_log("SIMPLE queue tag=0x%x\n", id & 0xff); break; case 0x21: /* HEAD of queue */ - ncr53c810_log("HEAD queue not implemented\n"); - id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; + ncr53c8xx_log("HEAD queue not implemented\n"); + id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; break; case 0x22: /* ORDERED queue */ - ncr53c810_log("ORDERED queue not implemented\n"); - id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; + ncr53c8xx_log("ORDERED queue not implemented\n"); + id |= ncr53c8xx_get_msgbyte(dev) | NCR_TAG_VALID; break; case 0x0d: /* The ABORT TAG message clears the current I/O process only. */ - ncr53c810_log("MSG: ABORT TAG tag=0x%x\n", current_tag); - if (sd->cmd_buffer) { - free(sd->cmd_buffer); - sd->cmd_buffer = NULL; - } - ncr53c810_disconnect(dev); + ncr53c8xx_log("MSG: Abort Tag\n"); + scsi_device_command_stop(sd); + ncr53c8xx_disconnect(dev); break; case 0x06: case 0x0e: case 0x0c: - /* The ABORT message clears all I/O processes for the selecting - initiator on the specified logical unit of the target. */ - if (msg == 0x06) - ncr53c810_log("MSG: ABORT tag=0x%x\n", current_tag); - /* The CLEAR QUEUE message clears all I/O processes for all - initiators on the specified logical unit of the target. */ - if (msg == 0x0e) - ncr53c810_log("MSG: CLEAR QUEUE tag=0x%x\n", current_tag); - /* The BUS DEVICE RESET message clears all I/O processes for all - initiators on all logical units of the target. */ - if (msg == 0x0c) - ncr53c810_log("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag); - /* clear the current I/O process */ - if (sd->cmd_buffer) { - free(sd->cmd_buffer); - sd->cmd_buffer = NULL; - } - ncr53c810_disconnect(dev); + scsi_device_command_stop(sd); + ncr53c8xx_disconnect(dev); break; default: if ((msg & 0x80) == 0) { - ncr53c810_bad_message(dev, msg); + ncr53c8xx_bad_message(dev, msg); return; } else { + /* 0x80 to 0xff are IDENTIFY messages. */ + ncr53c8xx_log("MSG: Identify\n"); dev->current_lun = msg & 7; - ncr53c810_log("Select LUN %d\n", dev->current_lun); - ncr53c810_set_phase(dev, PHASE_CMD); + ncr53c8xx_log("Select LUN %d\n", dev->current_lun); + ncr53c8xx_set_phase(dev, PHASE_CMD); } break; } @@ -933,16 +973,16 @@ ncr53c810_do_msgout(ncr53c810_t *dev, uint8_t id) static void -ncr53c810_memcpy(ncr53c810_t *dev, uint32_t dest, uint32_t src, int count) +ncr53c8xx_memcpy(ncr53c8xx_t *dev, uint32_t dest, uint32_t src, int count) { int n; uint8_t buf[NCR_BUF_SIZE]; - ncr53c810_log("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); + ncr53c8xx_log("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); while (count) { n = (count > NCR_BUF_SIZE) ? NCR_BUF_SIZE : count; - ncr53c810_read(dev, src, buf, n); - ncr53c810_write(dev, dest, buf, n); + ncr53c8xx_read(dev, src, buf, n); + ncr53c8xx_write(dev, dest, buf, n); src += n; dest += n; count -= n; @@ -951,13 +991,13 @@ ncr53c810_memcpy(ncr53c810_t *dev, uint32_t dest, uint32_t src, int count) static void -ncr53c810_process_script(ncr53c810_t *dev) +ncr53c8xx_process_script(ncr53c8xx_t *dev) { uint32_t insn, addr, id, buf[2], dest; int opcode, insn_processed = 0, reg, operator, cond, jmp, n, i, c; int32_t offset; uint8_t op0, op1, data8, mask, data[7]; -#ifdef ENABLE_NCR53C810_LOG +#ifdef ENABLE_NCR53C8xx_LOG uint8_t *pp; #endif @@ -976,28 +1016,28 @@ again: return; } addr = read_dword(dev, dev->dsp + 4); - ncr53c810_log("SCRIPTS dsp=%08x opcode %08x arg %08x\n", dev->dsp, insn, addr); + ncr53c8xx_log("SCRIPTS dsp=%08x opcode %08x arg %08x\n", dev->dsp, insn, addr); dev->dsps = addr; dev->dcmd = insn >> 24; dev->dsp += 8; switch (insn >> 30) { case 0: /* Block move. */ - ncr53c810_log("00: Block move\n"); + ncr53c8xx_log("00: Block move\n"); if (dev->sist1 & NCR_SIST1_STO) { - ncr53c810_log("Delayed select timeout\n"); + ncr53c8xx_log("Delayed select timeout\n"); dev->sstop = 1; break; } - ncr53c810_log("Block Move DBC=%d\n", dev->dbc); + ncr53c8xx_log("Block Move DBC=%d\n", dev->dbc); dev->dbc = insn & 0xffffff; - ncr53c810_log("Block Move DBC=%d now\n", dev->dbc); + ncr53c8xx_log("Block Move DBC=%d now\n", dev->dbc); /* ??? Set ESA. */ if (insn & (1 << 29)) { /* Indirect addressing. */ /* Should this respect SIOM? */ addr = read_dword(dev, addr); - ncr53c810_log("Indirect Block Move address: %08X\n", addr); + ncr53c8xx_log("Indirect Block Move address: %08X\n", addr); } else if (insn & (1 << 28)) { /* Table indirect addressing. */ @@ -1012,26 +1052,26 @@ again: * table, bits [31:24] */ } if ((dev->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { - ncr53c810_log("Wrong phase got %d expected %d\n", + ncr53c8xx_log("Wrong phase got %d expected %d\n", dev->sstat1 & PHASE_MASK, (insn >> 24) & 7); - ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); break; } dev->dnad = addr; switch (dev->sstat1 & 0x7) { case PHASE_DO: - ncr53c810_log("Data Out Phase\n"); + ncr53c8xx_log("Data Out Phase\n"); dev->waiting = 0; - ncr53c810_do_dma(dev, 1, dev->sdid); + ncr53c8xx_do_dma(dev, 1, dev->sdid); break; case PHASE_DI: - ncr53c810_log("Data In Phase\n"); + ncr53c8xx_log("Data In Phase\n"); dev->waiting = 0; - ncr53c810_do_dma(dev, 0, dev->sdid); + ncr53c8xx_do_dma(dev, 0, dev->sdid); break; case PHASE_CMD: - ncr53c810_log("Command Phase\n"); - c = ncr53c810_do_command(dev, dev->sdid); + ncr53c8xx_log("Command Phase\n"); + c = ncr53c8xx_do_command(dev, dev->sdid); if (!c || dev->sstop || dev->waiting || ((dev->sstat1 & 0x7) == PHASE_ST)) break; @@ -1042,29 +1082,29 @@ again: dev->timer_period += (40LL * TIMER_USEC); if (dev->dcntl & NCR_DCNTL_SSM) - ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SSI); + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SSI); return; case PHASE_ST: - ncr53c810_log("Status Phase\n"); - ncr53c810_do_status(dev); + ncr53c8xx_log("Status Phase\n"); + ncr53c8xx_do_status(dev); break; case PHASE_MO: - ncr53c810_log("MSG Out Phase\n"); - ncr53c810_do_msgout(dev, dev->sdid); + ncr53c8xx_log("MSG Out Phase\n"); + ncr53c8xx_do_msgout(dev, dev->sdid); break; case PHASE_MI: - ncr53c810_log("MSG In Phase\n"); - ncr53c810_do_msgin(dev); + ncr53c8xx_log("MSG In Phase\n"); + ncr53c8xx_do_msgin(dev); break; default: - ncr53c810_log("Unimplemented phase %d\n", dev->sstat1 & PHASE_MASK); + ncr53c8xx_log("Unimplemented phase %d\n", dev->sstat1 & PHASE_MASK); } dev->dfifo = dev->dbc & 0xff; dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); break; case 1: /* IO or Read/Write instruction. */ - ncr53c810_log("01: I/O or Read/Write instruction\n"); + ncr53c8xx_log("01: I/O or Read/Write instruction\n"); opcode = (insn >> 27) & 7; if (opcode < 5) { if (insn & (1 << 25)) @@ -1079,54 +1119,53 @@ again: case 0: /* Select */ dev->sdid = id; if (dev->scntl1 & NCR_SCNTL1_CON) { - ncr53c810_log("Already reselected, jumping to alternative address\n"); + ncr53c8xx_log("Already reselected, jumping to alternative address\n"); dev->dsp = dev->dnad; break; } dev->sstat0 |= NCR_SSTAT0_WOA; dev->scntl1 &= ~NCR_SCNTL1_IARB; if (!scsi_device_present(&scsi_devices[id])) { - ncr53c810_bad_selection(dev, id); + ncr53c8xx_bad_selection(dev, id); break; } - ncr53c810_log("Selected target %d%s\n", + ncr53c8xx_log("Selected target %d%s\n", id, insn & (1 << 24) ? " ATN" : ""); - dev->select_id = id << 8; dev->scntl1 |= NCR_SCNTL1_CON; if (insn & (1 << 24)) dev->socl |= NCR_SOCL_ATN; - ncr53c810_set_phase(dev, PHASE_MO); + ncr53c8xx_set_phase(dev, PHASE_MO); dev->waiting = 0; break; case 1: /* Disconnect */ - ncr53c810_log("Wait Disconnect\n"); + ncr53c8xx_log("Wait Disconnect\n"); dev->scntl1 &= ~NCR_SCNTL1_CON; break; case 2: /* Wait Reselect */ - ncr53c810_log("Wait Reselect\n"); + ncr53c8xx_log("Wait Reselect\n"); if (dev->istat & NCR_ISTAT_SIGP) dev->dsp = dev->dnad; /* If SIGP is set, this command causes an immediate jump to DNAD. */ else { - if (!ncr53c810_irq_on_rsl(dev)) + if (!ncr53c8xx_irq_on_rsl(dev)) dev->waiting = 1; } break; case 3: /* Set */ - ncr53c810_log("Set%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", + ncr53c8xx_log("Set%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", insn & (1 << 6) ? " ACK" : "", insn & (1 << 9) ? " TM" : "", insn & (1 << 10) ? " CC" : ""); if (insn & (1 << 3)) { dev->socl |= NCR_SOCL_ATN; - ncr53c810_set_phase(dev, PHASE_MO); + ncr53c8xx_set_phase(dev, PHASE_MO); } if (insn & (1 << 9)) - ncr53c810_log("Target mode not implemented\n"); + ncr53c8xx_log("Target mode not implemented\n"); if (insn & (1 << 10)) dev->carry = 1; break; case 4: /* Clear */ - ncr53c810_log("Clear%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", + ncr53c8xx_log("Clear%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", insn & (1 << 6) ? " ACK" : "", insn & (1 << 9) ? " TM" : "", insn & (1 << 10) ? " CC" : ""); @@ -1149,12 +1188,12 @@ again: break; case 6: /* To SFBR */ if (operator) - op0 = ncr53c810_reg_readb(dev, reg); + op0 = ncr53c8xx_reg_readb(dev, reg); op1 = data8; break; case 7: /* Read-modify-write */ if (operator) - op0 = ncr53c810_reg_readb(dev, reg); + op0 = ncr53c8xx_reg_readb(dev, reg); if (insn & (1 << 23)) op1 = dev->sfbr; else @@ -1201,7 +1240,7 @@ again: switch (opcode) { case 5: /* From SFBR */ case 7: /* Read-modify-write */ - ncr53c810_reg_writeb(dev, reg, op0); + ncr53c8xx_reg_writeb(dev, reg, op0); break; case 6: /* To SFBR */ dev->sfbr = op0; @@ -1211,29 +1250,29 @@ again: break; case 2: /* Transfer Control. */ - ncr53c810_log("02: Transfer Control\n"); + ncr53c8xx_log("02: Transfer Control\n"); if ((insn & 0x002e0000) == 0) { - ncr53c810_log("NOP\n"); + ncr53c8xx_log("NOP\n"); break; } if (dev->sist1 & NCR_SIST1_STO) { - ncr53c810_log("Delayed select timeout\n"); + ncr53c8xx_log("Delayed select timeout\n"); dev->sstop = 1; break; } cond = jmp = (insn & (1 << 19)) != 0; if (cond == jmp && (insn & (1 << 21))) { - ncr53c810_log("Compare carry %d\n", dev->carry == jmp); + ncr53c8xx_log("Compare carry %d\n", dev->carry == jmp); cond = dev->carry != 0; } if (cond == jmp && (insn & (1 << 17))) { - ncr53c810_log("Compare phase %d %c= %d\n", (dev->sstat1 & PHASE_MASK), + ncr53c8xx_log("Compare phase %d %c= %d\n", (dev->sstat1 & PHASE_MASK), jmp ? '=' : '!', ((insn >> 24) & 7)); cond = (dev->sstat1 & PHASE_MASK) == ((insn >> 24) & 7); } if (cond == jmp && (insn & (1 << 18))) { mask = (~insn >> 8) & 0xff; - ncr53c810_log("Compare data 0x%x & 0x%x %c= 0x%x\n", dev->sfbr, mask, + ncr53c8xx_log("Compare data 0x%x & 0x%x %c= 0x%x\n", dev->sfbr, mask, jmp ? '=' : '!', insn & mask); cond = (dev->sfbr & mask) == (insn & mask); } @@ -1244,38 +1283,38 @@ again: } switch ((insn >> 27) & 7) { case 0: /* Jump */ - ncr53c810_log("Jump to 0x%08x\n", addr); + ncr53c8xx_log("Jump to 0x%08x\n", addr); dev->adder = addr; dev->dsp = addr; break; case 1: /* Call */ - ncr53c810_log("Call 0x%08x\n", addr); + ncr53c8xx_log("Call 0x%08x\n", addr); dev->temp = dev->dsp; dev->dsp = addr; break; case 2: /* Return */ - ncr53c810_log("Return to 0x%08x\n", dev->temp); + ncr53c8xx_log("Return to 0x%08x\n", dev->temp); dev->dsp = dev->temp; break; case 3: /* Interrupt */ - ncr53c810_log("Interrupt 0x%08x\n", dev->dsps); + ncr53c8xx_log("Interrupt 0x%08x\n", dev->dsps); if ((insn & (1 << 20)) != 0) { dev->istat |= NCR_ISTAT_INTF; - ncr53c810_update_irq(dev); + ncr53c8xx_update_irq(dev); } else - ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SIR); + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SIR); break; default: - ncr53c810_log("Illegal transfer control\n"); - ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_IID); + ncr53c8xx_log("Illegal transfer control\n"); + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_IID); break; } } else - ncr53c810_log("Control condition failed\n"); + ncr53c8xx_log("Control condition failed\n"); break; case 3: - ncr53c810_log("00: Memory move\n"); + ncr53c8xx_log("00: Memory move\n"); if ((insn & (1 << 29)) == 0) { /* Memory move. */ /* ??? The docs imply the destination address is loaded into @@ -1283,9 +1322,9 @@ again: the value being presrved. */ dest = read_dword(dev, dev->dsp); dev->dsp += 4; - ncr53c810_memcpy(dev, dest, addr, insn & 0xffffff); + ncr53c8xx_memcpy(dev, dest, addr, insn & 0xffffff); } else { -#ifdef ENABLE_NCR53C810_LOG +#ifdef ENABLE_NCR53C8xx_LOG pp = data; #endif @@ -1295,59 +1334,57 @@ again: reg = (insn >> 16) & 0xff; if (insn & (1 << 24)) { DMAPageRead(addr, data, n); - ncr53c810_log("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n, addr, - *(unsigned *)pp); for (i = 0; i < n; i++) - ncr53c810_reg_writeb(dev, reg + i, data[i]); + ncr53c8xx_reg_writeb(dev, reg + i, data[i]); } else { - ncr53c810_log("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); + ncr53c8xx_log("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); for (i = 0; i < n; i++) - data[i] = ncr53c810_reg_readb(dev, reg + i); + data[i] = ncr53c8xx_reg_readb(dev, reg + i); DMAPageWrite(addr, data, n); } } break; default: - ncr53c810_log("%02X: Unknown command\n", (uint8_t) (insn >> 30)); + ncr53c8xx_log("%02X: Unknown command\n", (uint8_t) (insn >> 30)); } dev->timer_period += (40LL * TIMER_USEC); - ncr53c810_log("instructions processed %i\n", insn_processed); + ncr53c8xx_log("instructions processed %i\n", insn_processed); if (insn_processed > 10000 && !dev->waiting) { /* Some windows drivers make the device spin waiting for a memory location to change. If we have been executed a lot of code then assume this is the case and force an unexpected device disconnect. This is apparently sufficient to beat the drivers into submission. */ - ncr53c810_log("Some windows drivers make the device spin...\n"); + ncr53c8xx_log("Some windows drivers make the device spin...\n"); if (!(dev->sien0 & NCR_SIST0_UDC)) - ncr53c810_log("inf. loop with UDC masked\n"); - ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_UDC, 0); - ncr53c810_disconnect(dev); + ncr53c8xx_log("inf. loop with UDC masked\n"); + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_UDC, 0); + ncr53c8xx_disconnect(dev); } else if (!dev->sstop && !dev->waiting) { if (dev->dcntl & NCR_DCNTL_SSM) { - ncr53c810_log("NCR 810: SCRIPTS: Single-step mode\n"); - ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SSI); + ncr53c8xx_log("NCR 810: SCRIPTS: Single-step mode\n"); + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_SSI); } else { - ncr53c810_log("NCR 810: SCRIPTS: Normal mode\n"); + ncr53c8xx_log("NCR 810: SCRIPTS: Normal mode\n"); if (insn_processed < 100) goto again; } } else { if (dev->sstop) - ncr53c810_log("NCR 810: SCRIPTS: Stopped\n"); + ncr53c8xx_log("NCR 810: SCRIPTS: Stopped\n"); if (dev->waiting) - ncr53c810_log("NCR 810: SCRIPTS: Waiting\n"); + ncr53c8xx_log("NCR 810: SCRIPTS: Waiting\n"); } - ncr53c810_log("SCRIPTS execution stopped\n"); + ncr53c8xx_log("SCRIPTS execution stopped\n"); } static void -ncr53c810_execute_script(ncr53c810_t *dev) +ncr53c8xx_execute_script(ncr53c8xx_t *dev) { dev->sstop = 0; dev->timer_period = 40LL * TIMER_USEC; @@ -1356,16 +1393,16 @@ ncr53c810_execute_script(ncr53c810_t *dev) static void -ncr53c810_callback(void *p) +ncr53c8xx_callback(void *p) { - ncr53c810_t *dev = (ncr53c810_t *) p; + ncr53c8xx_t *dev = (ncr53c8xx_t *) p; dev->timer_period = 0; if (!dev->sstop) { if (dev->waiting) dev->timer_period = 40LL * TIMER_USEC; else - ncr53c810_process_script(dev); + ncr53c8xx_process_script(dev); } if (dev->sstop) { @@ -1376,8 +1413,148 @@ ncr53c810_callback(void *p) } +#ifdef USE_NVRAM static void -ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) +ncr53c8xx_eeprom(ncr53c8xx_t *dev, int save) +{ + FILE *f; + + if (save) + f = nvr_fopen(dev->nvr_path, L"wb"); + else + f = nvr_fopen(dev->nvr_path, L"rb"); + if (f) + { + if (save) { + fwrite((uint8_t *) &dev->nvram, 1, 1, f); + fwrite(((uint8_t *) &dev->nvram) + 1, 1, 1, f); + } else { + fread((uint8_t *) &dev->nvram, 1, 1, f); + fread(((uint8_t *) &dev->nvram) + 1, 1, 1, f); + } + fclose(f); + f = NULL; + } +} + + +#define ADDRESS_LENGTH 9 +#define ADDRESS_END (ADDRESS_LENGTH + 2) +#define ADDRESS_SHIFT (ADDRESS_LENGTH - 2) +#define ADDRESS_MASK 0x3f +#define DATA_LENGTH 8 +#define DATA_START (ADDRESS_END + 1) +#define DATA_END (ADDRESS_END + DATA_LENGTH) + + +static void +ncr53c8xx_serial_eeprom_write(ncr53c8xx_t *dev, uint8_t val) +{ + uint8_t temp, old = dev->nvram_t; + dev->nvram_t = val & 0x03; + + if (val & 0x02) { + if (!dev->nvram_index) { + /* First signal clocked in after clock is high, start bit. */ + dev->nvram_start = 1; + ncr53c8xx_log("[W] Serial EEPROM: Start bit\n"); + dev->nvram_op = 0; + } else if ((dev->nvram_index == 1) || (dev->nvram_index == 2)) { + if (!dev->nvram_start) + return; + + dev->nvram_op = (val & 0x01) << (dev->nvram_index - 1); + if (dev->nvram_index == 2) { + // ncr53c8xx_log("[W] Serial EEPROM: Opcode: %01X\n", dev->nvram_op); + dev->nvram_param = 0; + } + } else if ((dev->nvram_index >= 3) && (dev->nvram_index <= ADDRESS_END)) { + if (!dev->nvram_start) + return; + + dev->nvram_param = (val & 0x01) << (dev->nvram_index - 3); + if (dev->nvram_index < ADDRESS_END) { + dev->nvram_index++; + return; + } + + switch (dev->nvram_op) { + case 0x00: + temp = dev->nvram_param >> ADDRESS_SHIFT; + switch(temp) { + case 0x00: + ncr53c8xx_log("[W] Serial EEPROM: EWDS\n"); + break; + case 0x01: + ncr53c8xx_log("[W] Serial EEPROM: WRAL\n"); + break; + case 0x02: + ncr53c8xx_log("[W] Serial EEPROM: ERAL\n"); + break; + case 0x03: + ncr53c8xx_log("[W] Serial EEPROM: EWEN\n"); + break; + default: + ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN 00\n"); + break; + } + dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; + return; + case 0x01: + ncr53c8xx_log("[W] Serial EEPROM: WRITE\n"); + break; + case 0x02: + ncr53c8xx_log("[W] Serial EEPROM: READ\n"); + break; + case 0x03: + ncr53c8xx_log("[W] Serial EEPROM: ERASE\n"); + break; + default: + ncr53c8xx_log("[W] Serial EEPROM: UNKNOWN\n"); + break; + } + } else if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { + if (!dev->nvram_start) + return; + + if (dev->nvram_index == DATA_END) { + ncr53c8xx_log("[W] Serial EEPROM: Data end\n"); + dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; + return; + } + } + dev->nvram_index++; + } +} + + +static uint8_t +ncr53c8xx_serial_eeprom_read(ncr53c8xx_t *dev) +{ + uint8_t temp = 0; + + if (dev->gpreg & 0x02) { + if ((dev->nvram_index >= DATA_START) && (dev->nvram_index <= DATA_END)) { + if (!dev->nvram_start) + return temp; + + dev->nvram_index++; + + if (dev->nvram_index == DATA_END) { + ncr53c8xx_log("[R] Serial EEPROM: Data end\n"); + dev->nvram_start = dev->nvram_index = dev->nvram_op = dev->nvram_param = 0; + return temp; + } + } + } + + return temp; +} +#endif + + +static void +ncr53c8xx_reg_writeb(ncr53c8xx_t *dev, uint32_t offset, uint8_t val) { uint8_t tmp = 0; @@ -1393,7 +1570,7 @@ ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) case addr + 3: dev->name &= 0x00ffffff; dev->name |= val << 24; break; #ifdef DEBUG_NCR_REG - ncr53c810_log("Write reg %02x = %02x\n", offset, val); + ncr53c8xx_log("Write reg %02x = %02x\n", offset, val); #endif dev->regop = 1; @@ -1404,23 +1581,21 @@ ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) if (val & NCR_SCNTL0_START) { /* Looks like this (turn on bit 4 of SSTAT0 to mark arbitration in progress) is enough to make BIOS v4.x happy. */ - ncr53c810_log("NCR 810: Selecting SCSI ID %i\n", dev->sdid); - dev->select_id = dev->sdid; + ncr53c8xx_log("NCR 810: Selecting SCSI ID %i\n", dev->sdid); dev->sstat0 |= 0x10; } break; case 0x01: /* SCNTL1 */ dev->scntl1 = val & ~NCR_SCNTL1_SST; if (val & NCR_SCNTL1_IARB) { - dev->select_id = dev->sdid; - ncr53c810_log("Arbitration lost\n"); + ncr53c8xx_log("Arbitration lost\n"); dev->sstat0 |= 0x08; dev->waiting = 0; } if (val & NCR_SCNTL1_RST) { if (!(dev->sstat0 & NCR_SSTAT0_RST)) { dev->sstat0 |= NCR_SSTAT0_RST; - ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_RST, 0); + ncr53c8xx_script_scsi_interrupt(dev, NCR_SIST0_RST, 0); } } else dev->sstat0 &= ~NCR_SSTAT0_RST; @@ -1440,12 +1615,17 @@ ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) break; case 0x06: /* SDID */ if ((dev->ssid & 0x80) && (val & 0xf) != (dev->ssid & 0xf)) - ncr53c810_log("Destination ID does not match SSID\n"); + ncr53c8xx_log("Destination ID does not match SSID\n"); dev->sdid = val & 0xf; break; - case 0x07: /* GPREG0 */ - ncr53c810_log("NCR 810: GPREG0 write %02X\n", val); - dev->gpreg0 = val & 0x03; + case 0x07: /* GPREG */ + ncr53c8xx_log("NCR 810: GPREG write %02X\n", val); + tmp = dev->gpreg; + dev->gpreg = val & 0xfe; +#ifdef USE_NVRAM + if ((dev->gpcntl & 0xc3) == 0x00) + ncr53c8xx_serial_eeprom_write(dev, val & 0x03); +#endif break; case 0x08: /* SFBR */ /* The CPU is not allowed to write to this register. However the @@ -1453,7 +1633,7 @@ ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) dev->sfbr = val; break; case 0x09: /* SOCL */ - ncr53c810_log("NCR 810: SOCL write %02X\n", val); + ncr53c8xx_log("NCR 810: SOCL write %02X\n", val); dev->socl = val; break; case 0x0a: case 0x0b: @@ -1464,25 +1644,25 @@ ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) return; CASE_SET_REG32(dsa, 0x10) case 0x14: /* ISTAT */ - ncr53c810_log("ISTAT write: %02X\n", val); + ncr53c8xx_log("ISTAT write: %02X\n", val); tmp = dev->istat; dev->istat = (dev->istat & 0x0f) | (val & 0xf0); if ((val & NCR_ISTAT_ABRT) && !(val & NCR_ISTAT_SRST)) - ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_ABRT); + ncr53c8xx_script_dma_interrupt(dev, NCR_DSTAT_ABRT); if (val & NCR_ISTAT_INTF) { dev->istat &= ~NCR_ISTAT_INTF; - ncr53c810_update_irq(dev); + ncr53c8xx_update_irq(dev); } if ((dev->waiting == 1) && (val & NCR_ISTAT_SIGP)) { - ncr53c810_log("Woken by SIGP\n"); + ncr53c8xx_log("Woken by SIGP\n"); dev->waiting = 0; dev->dsp = dev->dnad; - /* ncr53c810_execute_script(dev); */ + /* ncr53c8xx_execute_script(dev); */ } if ((val & NCR_ISTAT_SRST) && !(tmp & NCR_ISTAT_SRST)) { - ncr53c810_soft_reset(dev); - ncr53c810_update_irq(dev); + ncr53c8xx_soft_reset(dev); + ncr53c8xx_update_irq(dev); dev->istat = 0; } break; @@ -1507,12 +1687,12 @@ ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) CASE_SET_REG32(temp, 0x1c) case 0x21: /* CTEST4 */ if (val & 7) - ncr53c810_log("Unimplemented CTEST4-FBL 0x%x\n", val); + ncr53c8xx_log("Unimplemented CTEST4-FBL 0x%x\n", val); dev->ctest4 = val; break; case 0x22: /* CTEST5 */ if (val & (NCR_CTEST5_ADCK | NCR_CTEST5_BBCK)) - ncr53c810_log("CTEST5 DMA increment not implemented\n"); + ncr53c8xx_log("CTEST5 DMA increment not implemented\n"); dev->ctest5 = val; break; CASE_SET_REG24(dbc, 0x24) @@ -1533,7 +1713,7 @@ ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) dev->dsp &= 0x00ffffff; dev->dsp |= val << 24; if (!(dev->dmode & NCR_DMODE_MAN) && dev->sstop) - ncr53c810_execute_script(dev); + ncr53c8xx_execute_script(dev); break; CASE_SET_REG32(dsps, 0x30) CASE_SET_REG32(scratcha, 0x34) @@ -1541,9 +1721,9 @@ ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) dev->dmode = val; break; case 0x39: /* DIEN */ - ncr53c810_log("DIEN write: %02X\n", val); + ncr53c8xx_log("DIEN write: %02X\n", val); dev->dien = val; - ncr53c810_update_irq(dev); + ncr53c8xx_update_irq(dev); break; case 0x3a: /* SBR */ dev->sbr = val; @@ -1551,50 +1731,65 @@ ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) case 0x3b: /* DCNTL */ dev->dcntl = val & ~(NCR_DCNTL_PFF | NCR_DCNTL_STD); if ((val & NCR_DCNTL_STD) && dev->sstop) - ncr53c810_execute_script(dev); + ncr53c8xx_execute_script(dev); break; case 0x40: /* SIEN0 */ dev->sien0 = val; - ncr53c810_update_irq(dev); + ncr53c8xx_update_irq(dev); break; case 0x41: /* SIEN1 */ dev->sien1 = val; - ncr53c810_update_irq(dev); + ncr53c8xx_update_irq(dev); break; - case 0x47: /* GPCNTL0 */ + case 0x47: /* GPCNTL */ + ncr53c8xx_log("GPCNTL write: %02X\n", val); + dev->gpcntl = val; break; case 0x48: /* STIME0 */ dev->stime0 = val; break; case 0x49: /* STIME1 */ if (val & 0xf) { - ncr53c810_log("General purpose timer not implemented\n"); + ncr53c8xx_log("General purpose timer not implemented\n"); /* ??? Raising the interrupt immediately seems to be sufficient to keep the FreeBSD driver happy. */ - ncr53c810_script_scsi_interrupt(dev, 0, NCR_SIST1_GEN); + ncr53c8xx_script_scsi_interrupt(dev, 0, NCR_SIST1_GEN); } break; - case 0x4a: /* RESPID */ - dev->respid = val; + case 0x4a: /* RESPID0 */ + dev->respid0 = val; + break; + case 0x4b: /* RESPID1 */ + if (dev->chip >= CHIP_825) + dev->respid1 = val; break; case 0x4d: /* STEST1 */ dev->stest1 = val; break; case 0x4e: /* STEST2 */ if (val & 1) - ncr53c810_log("Low level mode not implemented\n"); + ncr53c8xx_log("Low level mode not implemented\n"); dev->stest2 = val; break; case 0x4f: /* STEST3 */ if (val & 0x41) - ncr53c810_log("SCSI FIFO test mode not implemented\n"); + ncr53c8xx_log("SCSI FIFO test mode not implemented\n"); dev->stest3 = val; break; case 0x54: + case 0x55: break; CASE_SET_REG32(scratchb, 0x5c) + CASE_SET_REG32(scratchc, 0x60) + CASE_SET_REG32(scratchd, 0x64) + CASE_SET_REG32(scratche, 0x68) + CASE_SET_REG32(scratchf, 0x6c) + CASE_SET_REG32(scratchg, 0x70) + CASE_SET_REG32(scratchh, 0x74) + CASE_SET_REG32(scratchi, 0x78) + CASE_SET_REG32(scratchj, 0x7c) default: - ncr53c810_log("Unhandled writeb 0x%x = 0x%x\n", offset, val); + ncr53c8xx_log("Unhandled writeb 0x%x = 0x%x\n", offset, val); } #undef CASE_SET_REG24 #undef CASE_SET_REG32 @@ -1602,7 +1797,7 @@ ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) static uint8_t -ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset) +ncr53c8xx_reg_readb(ncr53c8xx_t *dev, uint32_t offset) { uint8_t tmp; #define CASE_GET_REG24(name, addr) \ @@ -1616,38 +1811,63 @@ ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset) case addr + 2: return (dev->name >> 16) & 0xff; \ case addr + 3: return (dev->name >> 24) & 0xff; +#define CASE_GET_REG32_COND(name, addr) \ + case addr: if (dev->chip >= CHIP_825) \ + return dev->name & 0xff; \ + else \ + return 0x00; \ + case addr + 1: if (dev->chip >= CHIP_825) \ + return (dev->name >> 8) & 0xff; \ + else \ + return 0x00; \ + case addr + 2: if (dev->chip >= CHIP_825) \ + return (dev->name >> 16) & 0xff; \ + else \ + return 0x00; \ + case addr + 3: if (dev->chip >= CHIP_825) \ + return (dev->name >> 24) & 0xff; \ + else \ + return 0x00; + dev->regop = 1; switch (offset) { case 0x00: /* SCNTL0 */ - ncr53c810_log("NCR 810: Read SCNTL0 %02X\n", dev->scntl0); + ncr53c8xx_log("NCR 810: Read SCNTL0 %02X\n", dev->scntl0); return dev->scntl0; case 0x01: /* SCNTL1 */ - ncr53c810_log("NCR 810: Read SCNTL1 %02X\n", dev->scntl1); + ncr53c8xx_log("NCR 810: Read SCNTL1 %02X\n", dev->scntl1); return dev->scntl1; case 0x02: /* SCNTL2 */ - ncr53c810_log("NCR 810: Read SCNTL2 %02X\n", dev->scntl2); + ncr53c8xx_log("NCR 810: Read SCNTL2 %02X\n", dev->scntl2); return dev->scntl2; case 0x03: /* SCNTL3 */ - ncr53c810_log("NCR 810: Read SCNTL3 %02X\n", dev->scntl3); + ncr53c8xx_log("NCR 810: Read SCNTL3 %02X\n", dev->scntl3); return dev->scntl3; case 0x04: /* SCID */ - ncr53c810_log("NCR 810: Read SCID %02X\n", dev->scid); - return dev->scid; + ncr53c8xx_log("NCR 810: Read SCID %02X\n", dev->scid); + return dev->scid & ~0x40; case 0x05: /* SXFER */ - ncr53c810_log("NCR 810: Read SXFER %02X\n", dev->sxfer); + ncr53c8xx_log("NCR 810: Read SXFER %02X\n", dev->sxfer); return dev->sxfer; case 0x06: /* SDID */ - ncr53c810_log("NCR 810: Read SDID %02X\n", dev->sdid); + ncr53c8xx_log("NCR 810: Read SDID %02X\n", dev->sdid); return dev->sdid; - case 0x07: /* GPREG0 */ - ncr53c810_log("NCR 810: Read GPREG0 %02X\n", dev->gpreg0 & 3); - return dev->gpreg0 & 3; + case 0x07: /* GPREG */ +#ifdef USE_NVRAM + tmp = (dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e; + if ((dev->gpcntl & 0xc3) == 0x01) + tmp |= ncr53c8xx_serial_eeprom_read(dev); +#else + tmp = ((dev->gpreg & (dev->gpcntl ^ 0x1f)) & 0x1e) | 0x01; +#endif + ncr53c8xx_log("NCR 810: Read GPREG %02X\n", tmp); + return tmp; case 0x08: /* Revision ID */ - ncr53c810_log("NCR 810: Read REVID 00\n"); + ncr53c8xx_log("NCR 810: Read REVID 00\n"); return 0x00; case 0xa: /* SSID */ - ncr53c810_log("NCR 810: Read SSID %02X\n", dev->ssid); + ncr53c8xx_log("NCR 810: Read SSID %02X\n", dev->ssid); return dev->ssid; case 0xb: /* SBCL */ /* Bit 7 = REQ (SREQ/ status) @@ -1659,40 +1879,44 @@ ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset) Bit 1 = C/D (SC_D/ status) Bit 0 = I/O (SI_O/ status) */ tmp = (dev->sstat1 & 7); - ncr53c810_log("NCR 810: Read SBCL %02X\n", tmp); + ncr53c8xx_log("NCR 810: Read SBCL %02X\n", tmp); return tmp; /* For now, return the MSG, C/D, and I/O bits from SSTAT1. */ case 0xc: /* DSTAT */ tmp = dev->dstat | NCR_DSTAT_DFE; if ((dev->istat & NCR_ISTAT_INTF) == 0) dev->dstat = 0; - ncr53c810_update_irq(dev); - ncr53c810_log("NCR 810: Read DSTAT %02X\n", tmp); + ncr53c8xx_update_irq(dev); + ncr53c8xx_log("NCR 810: Read DSTAT %02X\n", tmp); return tmp; case 0x0d: /* SSTAT0 */ - ncr53c810_log("NCR 810: Read SSTAT0 %02X\n", dev->sstat0); + ncr53c8xx_log("NCR 810: Read SSTAT0 %02X\n", dev->sstat0); return dev->sstat0; case 0x0e: /* SSTAT1 */ - ncr53c810_log("NCR 810: Read SSTAT1 %02X\n", dev->sstat1); + ncr53c8xx_log("NCR 810: Read SSTAT1 %02X\n", dev->sstat1); return dev->sstat1; case 0x0f: /* SSTAT2 */ - ncr53c810_log("NCR 810: Read SSTAT2 %02X\n", dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2); + ncr53c8xx_log("NCR 810: Read SSTAT2 %02X\n", dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2); return dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2; CASE_GET_REG32(dsa, 0x10) case 0x14: /* ISTAT */ - ncr53c810_log("NCR 810: Read ISTAT %02X\n", dev->istat); + ncr53c8xx_log("NCR 810: Read ISTAT %02X\n", dev->istat); tmp = dev->istat; return tmp; case 0x16: /* MBOX0 */ - ncr53c810_log("NCR 810: Read MBOX0 %02X\n", dev->mbox0); + if (dev->chip >= CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read MBOX0 %02X\n", dev->mbox0); return dev->mbox0; case 0x17: /* MBOX1 */ - ncr53c810_log("NCR 810: Read MBOX1 %02X\n", dev->mbox1); + if (dev->chip >= CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read MBOX1 %02X\n", dev->mbox1); return dev->mbox1; case 0x18: /* CTEST0 */ - ncr53c810_log("NCR 810: Read CTEST0 FF\n"); + ncr53c8xx_log("NCR 810: Read CTEST0 FF\n"); return 0xff; case 0x19: /* CTEST1 */ - ncr53c810_log("NCR 810: Read CTEST1 F0\n"); + ncr53c8xx_log("NCR 810: Read CTEST1 F0\n"); return 0xf0; /* dma fifo empty */ case 0x1a: /* CTEST2 */ tmp = dev->ctest2 | NCR_CTEST2_DACK | NCR_CTEST2_CM; @@ -1700,110 +1924,144 @@ ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset) dev->istat &= ~NCR_ISTAT_SIGP; tmp |= NCR_CTEST2_SIGP; } - ncr53c810_log("NCR 810: Read CTEST2 %02X\n", tmp); + ncr53c8xx_log("NCR 810: Read CTEST2 %02X\n", tmp); return tmp; case 0x1b: /* CTEST3 */ - ncr53c810_log("NCR 810: Read CTEST3 %02X\n", - (dev->ctest3 & (0x08 | 0x02 | 0x01)) | dev->chip_rev); - return (dev->ctest3 & (0x08 | 0x02 | 0x01)) | dev->chip_rev; + ncr53c8xx_log("NCR 810: Read CTEST3 %02X\n", + (dev->ctest3 & (0x08 | 0x02 | 0x01)) | ((dev->chip_rev & 0x0f) << 4)); + return (dev->ctest3 & (0x08 | 0x02 | 0x01)) | ((dev->chip_rev & 0x0f) << 4); CASE_GET_REG32(temp, 0x1c) case 0x20: /* DFIFO */ - ncr53c810_log("NCR 810: Read DFIFO 00\n"); + ncr53c8xx_log("NCR 810: Read DFIFO 00\n"); return 0; case 0x21: /* CTEST4 */ - ncr53c810_log("NCR 810: Read CTEST4 %02X\n", dev->ctest4); + ncr53c8xx_log("NCR 810: Read CTEST4 %02X\n", dev->ctest4); return dev->ctest4; case 0x22: /* CTEST5 */ - ncr53c810_log("NCR 810: Read CTEST5 %02X\n", dev->ctest5); + ncr53c8xx_log("NCR 810: Read CTEST5 %02X\n", dev->ctest5); return dev->ctest5; case 0x23: /* CTEST6 */ - ncr53c810_log("NCR 810: Read CTEST6 00\n"); + ncr53c8xx_log("NCR 810: Read CTEST6 00\n"); return 0; CASE_GET_REG24(dbc, 0x24) case 0x27: /* DCMD */ - ncr53c810_log("NCR 810: Read DCMD %02X\n", dev->dcmd); + ncr53c8xx_log("NCR 810: Read DCMD %02X\n", dev->dcmd); return dev->dcmd; CASE_GET_REG32(dnad, 0x28) CASE_GET_REG32(dsp, 0x2c) CASE_GET_REG32(dsps, 0x30) CASE_GET_REG32(scratcha, 0x34) case 0x38: /* DMODE */ - ncr53c810_log("NCR 810: Read DMODE %02X\n", dev->dmode); + ncr53c8xx_log("NCR 810: Read DMODE %02X\n", dev->dmode); return dev->dmode; case 0x39: /* DIEN */ - ncr53c810_log("NCR 810: Read DIEN %02X\n", dev->dien); + ncr53c8xx_log("NCR 810: Read DIEN %02X\n", dev->dien); return dev->dien; case 0x3a: /* SBR */ - ncr53c810_log("NCR 810: Read SBR %02X\n", dev->sbr); + ncr53c8xx_log("NCR 810: Read SBR %02X\n", dev->sbr); return dev->sbr; case 0x3b: /* DCNTL */ - ncr53c810_log("NCR 810: Read DCNTL %02X\n", dev->dcntl); + ncr53c8xx_log("NCR 810: Read DCNTL %02X\n", dev->dcntl); return dev->dcntl; CASE_GET_REG32(adder, 0x3c) /* ADDER Output (Debug of relative jump address) */ case 0x40: /* SIEN0 */ - ncr53c810_log("NCR 810: Read SIEN0 %02X\n", dev->sien0); + ncr53c8xx_log("NCR 810: Read SIEN0 %02X\n", dev->sien0); return dev->sien0; case 0x41: /* SIEN1 */ - ncr53c810_log("NCR 810: Read SIEN1 %02X\n", dev->sien1); + ncr53c8xx_log("NCR 810: Read SIEN1 %02X\n", dev->sien1); return dev->sien1; case 0x42: /* SIST0 */ tmp = dev->sist0; - dev->sist0 = 0; - ncr53c810_update_irq(dev); - ncr53c810_log("NCR 810: Read SIST0 %02X\n", tmp); + dev->sist0 = 0x00; + ncr53c8xx_update_irq(dev); + ncr53c8xx_log("NCR 810: Read SIST0 %02X\n", tmp); return tmp; case 0x43: /* SIST1 */ tmp = dev->sist1; - dev->sist1 = 0; - ncr53c810_update_irq(dev); - ncr53c810_log("NCR 810: Read SIST1 %02X\n", tmp); + dev->sist1 = 0x00; + ncr53c8xx_update_irq(dev); + ncr53c8xx_log("NCR 810: Read SIST1 %02X\n", tmp); return tmp; + case 0x44: /* SLPAR */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read SLPAR %02X\n", dev->stime0); + return dev->slpar; + case 0x45: /* SWIDE */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read SWIDE %02X\n", dev->stime0); + return dev->swide; case 0x46: /* MACNTL */ - ncr53c810_log("NCR 810: Read MACNTL 4F\n"); + ncr53c8xx_log("NCR 810: Read MACNTL 4F\n"); return 0x4f; - case 0x47: /* GPCNTL0 */ - ncr53c810_log("NCR 810: Read GPCNTL0 0F\n"); - return 0x0f; + case 0x47: /* GPCNTL */ + ncr53c8xx_log("NCR 810: Read GPCNTL %02X\n", dev->gpcntl); + return dev->gpcntl; case 0x48: /* STIME0 */ - ncr53c810_log("NCR 810: Read STIME0 %02X\n", dev->stime0); + ncr53c8xx_log("NCR 810: Read STIME0 %02X\n", dev->stime0); return dev->stime0; - case 0x4a: /* RESPID */ - ncr53c810_log("NCR 810: Read RESPID %02X\n", dev->respid); - return dev->respid; + case 0x4a: /* RESPID0 */ + if (dev->chip >= CHIP_825) + ncr53c8xx_log("NCR 810: Read RESPID0 %02X\n", dev->respid0); + else + ncr53c8xx_log("NCR 810: Read RESPID %02X\n", dev->respid0); + return dev->respid0; + case 0x4b: /* RESPID1 */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read RESPID1 %02X\n", dev->respid1); + return dev->respid1; case 0x4c: /* STEST0 */ - ncr53c810_log("NCR 810: Read STEST0 %02X\n", dev->stest1); + ncr53c8xx_log("NCR 810: Read STEST0 %02X\n", dev->stest1); return 0x00; case 0x4d: /* STEST1 */ - ncr53c810_log("NCR 810: Read STEST1 %02X\n", dev->stest1); + ncr53c8xx_log("NCR 810: Read STEST1 %02X\n", dev->stest1); return dev->stest1; case 0x4e: /* STEST2 */ - ncr53c810_log("NCR 810: Read STEST2 %02X\n", dev->stest2); + ncr53c8xx_log("NCR 810: Read STEST2 %02X\n", dev->stest2); return dev->stest2; case 0x4f: /* STEST3 */ - ncr53c810_log("NCR 810: Read STEST3 %02X\n", dev->stest3); + ncr53c8xx_log("NCR 810: Read STEST3 %02X\n", dev->stest3); return dev->stest3; - case 0x50: /* SIDL */ + case 0x50: /* SIDL0 */ /* This is needed by the linux drivers. We currently only update it during the MSG IN phase. */ - ncr53c810_log("NCR 810: Read SIDL %02X\n", dev->sidl); - return dev->sidl; + if (dev->chip >= CHIP_825) + ncr53c8xx_log("NCR 810: Read SIDL0 %02X\n", dev->sidl0); + else + ncr53c8xx_log("NCR 810: Read SIDL %02X\n", dev->sidl0); + return dev->sidl0; + case 0x51: /* SIDL1 */ + if (dev->chip < CHIP_825) + return 0x00; + ncr53c8xx_log("NCR 810: Read SIDL1 %02X\n", dev->sidl1); + return dev->sidl1; case 0x52: /* STEST4 */ - ncr53c810_log("NCR 810: Read STEST4 E0\n"); + ncr53c8xx_log("NCR 810: Read STEST4 E0\n"); return 0xe0; case 0x58: /* SBDL */ /* Some drivers peek at the data bus during the MSG IN phase. */ if ((dev->sstat1 & PHASE_MASK) == PHASE_MI) { - ncr53c810_log("NCR 810: Read SBDL %02X\n", dev->msg[0]); + ncr53c8xx_log("NCR 810: Read SBDL %02X\n", dev->msg[0]); return dev->msg[0]; } - ncr53c810_log("NCR 810: Read SBDL 00\n"); + ncr53c8xx_log("NCR 810: Read SBDL 00\n"); return 0; case 0x59: /* SBDL high */ - ncr53c810_log("NCR 810: Read SBDLH 00\n"); + ncr53c8xx_log("NCR 810: Read SBDLH 00\n"); return 0; CASE_GET_REG32(scratchb, 0x5c) + CASE_GET_REG32_COND(scratchc, 0x60) + CASE_GET_REG32_COND(scratchd, 0x64) + CASE_GET_REG32_COND(scratche, 0x68) + CASE_GET_REG32_COND(scratchf, 0x6c) + CASE_GET_REG32_COND(scratchg, 0x70) + CASE_GET_REG32_COND(scratchh, 0x74) + CASE_GET_REG32_COND(scratchi, 0x78) + CASE_GET_REG32_COND(scratchj, 0x7c) } - ncr53c810_log("readb 0x%x\n", offset); + ncr53c8xx_log("readb 0x%x\n", offset); return 0; #undef CASE_GET_REG24 @@ -1812,198 +2070,303 @@ ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset) static uint8_t -ncr53c810_io_readb(uint16_t addr, void *p) +ncr53c8xx_io_readb(uint16_t addr, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; - return ncr53c810_reg_readb(dev, addr & 0xff); + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + return ncr53c8xx_reg_readb(dev, addr & 0xff); } static uint16_t -ncr53c810_io_readw(uint16_t addr, void *p) +ncr53c8xx_io_readw(uint16_t addr, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; uint16_t val; addr &= 0xff; - val = ncr53c810_reg_readb(dev, addr); - val |= ncr53c810_reg_readb(dev, addr + 1) << 8; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; return val; } static uint32_t -ncr53c810_io_readl(uint16_t addr, void *p) +ncr53c8xx_io_readl(uint16_t addr, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; uint32_t val; addr &= 0xff; - val = ncr53c810_reg_readb(dev, addr); - val |= ncr53c810_reg_readb(dev, addr + 1) << 8; - val |= ncr53c810_reg_readb(dev, addr + 2) << 16; - val |= ncr53c810_reg_readb(dev, addr + 3) << 24; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; + val |= ncr53c8xx_reg_readb(dev, addr + 2) << 16; + val |= ncr53c8xx_reg_readb(dev, addr + 3) << 24; return val; } static void -ncr53c810_io_writeb(uint16_t addr, uint8_t val, void *p) +ncr53c8xx_io_writeb(uint16_t addr, uint8_t val, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; - ncr53c810_reg_writeb(dev, addr & 0xff, val); + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + ncr53c8xx_reg_writeb(dev, addr & 0xff, val); } static void -ncr53c810_io_writew(uint16_t addr, uint16_t val, void *p) +ncr53c8xx_io_writew(uint16_t addr, uint16_t val, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; addr &= 0xff; - ncr53c810_reg_writeb(dev, addr, val & 0xff); - ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); } static void -ncr53c810_io_writel(uint16_t addr, uint32_t val, void *p) +ncr53c8xx_io_writel(uint16_t addr, uint32_t val, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; addr &= 0xff; - ncr53c810_reg_writeb(dev, addr, val & 0xff); - ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); - ncr53c810_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); - ncr53c810_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); } static void -ncr53c810_mmio_writeb(uint32_t addr, uint8_t val, void *p) +ncr53c8xx_mmio_writeb(uint32_t addr, uint8_t val, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - ncr53c810_reg_writeb(dev, addr & 0xff, val); + ncr53c8xx_reg_writeb(dev, addr & 0xff, val); } static void -ncr53c810_mmio_writew(uint32_t addr, uint16_t val, void *p) +ncr53c8xx_mmio_writew(uint32_t addr, uint16_t val, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; - - addr &= 0xff; - ncr53c810_reg_writeb(dev, addr, val & 0xff); - ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + addr &= 0xff; + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); } static void -ncr53c810_mmio_writel(uint32_t addr, uint32_t val, void *p) +ncr53c8xx_mmio_writel(uint32_t addr, uint32_t val, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - addr &= 0xff; - ncr53c810_reg_writeb(dev, addr, val & 0xff); - ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); - ncr53c810_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); - ncr53c810_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); + addr &= 0xff; + ncr53c8xx_reg_writeb(dev, addr, val & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); + ncr53c8xx_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); } static uint8_t -ncr53c810_mmio_readb(uint32_t addr, void *p) +ncr53c8xx_mmio_readb(uint32_t addr, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; - - return ncr53c810_reg_readb(dev, addr & 0xff); + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + return ncr53c8xx_reg_readb(dev, addr & 0xff); } static uint16_t -ncr53c810_mmio_readw(uint32_t addr, void *p) +ncr53c8xx_mmio_readw(uint32_t addr, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; - uint16_t val; - - addr &= 0xff; - val = ncr53c810_reg_readb(dev, addr); - val |= ncr53c810_reg_readb(dev, addr + 1) << 8; - return val; + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint16_t val; + + addr &= 0xff; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; + return val; } - + static uint32_t -ncr53c810_mmio_readl(uint32_t addr, void *p) +ncr53c8xx_mmio_readl(uint32_t addr, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; - uint32_t val; - - addr &= 0xff; - val = ncr53c810_reg_readb(dev, addr); - val |= ncr53c810_reg_readb(dev, addr + 1) << 8; - val |= ncr53c810_reg_readb(dev, addr + 2) << 16; - val |= ncr53c810_reg_readb(dev, addr + 3) << 24; - return val; + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + uint32_t val; + + addr &= 0xff; + val = ncr53c8xx_reg_readb(dev, addr); + val |= ncr53c8xx_reg_readb(dev, addr + 1) << 8; + val |= ncr53c8xx_reg_readb(dev, addr + 2) << 16; + val |= ncr53c8xx_reg_readb(dev, addr + 3) << 24; + + return val; } static void -ncr53c810_io_set(ncr53c810_t *dev, uint32_t base, uint16_t len) +ncr53c8xx_ram_writeb(uint32_t addr, uint8_t val, void *p) { - ncr53c810_log("NCR53c810: [PCI] Setting I/O handler at %04X\n", base); - io_sethandler(base, len, - ncr53c810_io_readb, ncr53c810_io_readw, ncr53c810_io_readl, - ncr53c810_io_writeb, ncr53c810_io_writew, ncr53c810_io_writel, dev); + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + dev->ram[addr & 0x0fff] = val; } static void -ncr53c810_io_remove(ncr53c810_t *dev, uint32_t base, uint16_t len) +ncr53c8xx_ram_writew(uint32_t addr, uint16_t val, void *p) { - ncr53c810_log("NCR53c810: Removing I/O handler at %04X\n", base); - io_removehandler(base, len, - ncr53c810_io_readb, ncr53c810_io_readw, ncr53c810_io_readl, - ncr53c810_io_writeb, ncr53c810_io_writew, ncr53c810_io_writel, dev); + ncr53c8xx_ram_writeb(addr, val & 0xff, p); + ncr53c8xx_ram_writeb(addr + 1, (val >> 8) & 0xff, p); } static void -ncr53c810_mem_init(ncr53c810_t *dev, uint32_t addr) +ncr53c8xx_ram_writel(uint32_t addr, uint32_t val, void *p) { - mem_mapping_add(&dev->mmio_mapping, addr, 0x100, - ncr53c810_mmio_readb, ncr53c810_mmio_readw, ncr53c810_mmio_readl, - ncr53c810_mmio_writeb, ncr53c810_mmio_writew, ncr53c810_mmio_writel, - NULL, MEM_MAPPING_EXTERNAL, dev); + ncr53c8xx_ram_writeb(addr, val & 0xff, p); + ncr53c8xx_ram_writeb(addr + 1, (val >> 8) & 0xff, p); + ncr53c8xx_ram_writeb(addr + 2, (val >> 16) & 0xff, p); + ncr53c8xx_ram_writeb(addr + 3, (val >> 24) & 0xff, p); +} + + +static uint8_t +ncr53c8xx_ram_readb(uint32_t addr, void *p) +{ + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; + + return dev->ram[addr & 0x0fff]; +} + + +static uint16_t +ncr53c8xx_ram_readw(uint32_t addr, void *p) +{ + uint16_t val; + + val = ncr53c8xx_ram_readb(addr, p); + val |= ncr53c8xx_ram_readb(addr + 1, p) << 8; + + return val; +} + + +static uint32_t +ncr53c8xx_ram_readl(uint32_t addr, void *p) +{ + uint32_t val; + + val = ncr53c8xx_ram_readb(addr, p); + val |= ncr53c8xx_ram_readb(addr + 1, p) << 8; + val |= ncr53c8xx_ram_readb(addr + 2, p) << 16; + val |= ncr53c8xx_ram_readb(addr + 3, p) << 24; + + return val; } static void -ncr53c810_mem_set_addr(ncr53c810_t *dev, uint32_t base) +ncr53c8xx_io_set(ncr53c8xx_t *dev, uint32_t base, uint16_t len) +{ + ncr53c8xx_log("NCR53c8xx: [PCI] Setting I/O handler at %04X\n", base); + io_sethandler(base, len, + ncr53c8xx_io_readb, ncr53c8xx_io_readw, ncr53c8xx_io_readl, + ncr53c8xx_io_writeb, ncr53c8xx_io_writew, ncr53c8xx_io_writel, dev); +} + + +static void +ncr53c8xx_io_remove(ncr53c8xx_t *dev, uint32_t base, uint16_t len) +{ + ncr53c8xx_log("NCR53c8xx: Removing I/O handler at %04X\n", base); + io_removehandler(base, len, + ncr53c8xx_io_readb, ncr53c8xx_io_readw, ncr53c8xx_io_readl, + ncr53c8xx_io_writeb, ncr53c8xx_io_writew, ncr53c8xx_io_writel, dev); +} + + +static void +ncr53c8xx_mem_init(ncr53c8xx_t *dev, uint32_t addr) +{ + mem_mapping_add(&dev->mmio_mapping, addr, 0x100, + ncr53c8xx_mmio_readb, ncr53c8xx_mmio_readw, ncr53c8xx_mmio_readl, + ncr53c8xx_mmio_writeb, ncr53c8xx_mmio_writew, ncr53c8xx_mmio_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); +} + + +static void +ncr53c8xx_ram_init(ncr53c8xx_t *dev, uint32_t addr) +{ + mem_mapping_add(&dev->ram_mapping, addr, 0x1000, + ncr53c8xx_ram_readb, ncr53c8xx_ram_readw, ncr53c8xx_ram_readl, + ncr53c8xx_ram_writeb, ncr53c8xx_ram_writew, ncr53c8xx_ram_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); +} + + +static void +ncr53c8xx_mem_set_addr(ncr53c8xx_t *dev, uint32_t base) { mem_mapping_set_addr(&dev->mmio_mapping, base, 0x100); } static void -ncr53c810_mem_disable(ncr53c810_t *dev) +ncr53c8xx_ram_set_addr(ncr53c8xx_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->ram_mapping, base, 0x1000); +} + + +#ifdef USE_BIOS_BAR +static void +ncr53c8xx_bios_set_addr(ncr53c8xx_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->bios.mapping, base, 0x10000); +} +#endif + + +static void +ncr53c8xx_mem_disable(ncr53c8xx_t *dev) { mem_mapping_disable(&dev->mmio_mapping); } -uint8_t ncr53c810_pci_regs[256]; -bar_t ncr53c810_pci_bar[2]; +static void +ncr53c8xx_ram_disable(ncr53c8xx_t *dev) +{ + mem_mapping_disable(&dev->ram_mapping); +} + + +#ifdef USE_BIOS_BAR +static void +ncr53c8xx_bios_disable(ncr53c8xx_t *dev) +{ + mem_mapping_disable(&dev->bios.mapping); +} +#endif + + +uint8_t ncr53c8xx_pci_regs[256]; +bar_t ncr53c8xx_pci_bar[4]; static uint8_t -ncr53c810_pci_read(int func, int addr, void *p) +ncr53c8xx_pci_read(int func, int addr, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; - ncr53c810_log("NCR53c810: Reading register %02X\n", addr & 0xff); + ncr53c8xx_log("NCR53c8xx: Reading register %02X\n", addr & 0xff); - if ((addr >= 0x80) && (addr <= 0xDF)) - return ncr53c810_reg_readb(dev, addr & 0x7F); + if ((addr >= 0x80) && (addr <= 0xFF)) + return ncr53c8xx_reg_readb(dev, addr & 0x7F); switch (addr) { case 0x00: @@ -2011,17 +2374,17 @@ ncr53c810_pci_read(int func, int addr, void *p) case 0x01: return 0x10; case 0x02: - return 0x01; + return dev->chip; case 0x03: return 0x00; case 0x04: - return ncr53c810_pci_regs[0x04] & 0x57; /*Respond to IO and memory accesses*/ + return ncr53c8xx_pci_regs[0x04] & 0x57; /*Respond to IO and memory accesses*/ case 0x05: - return ncr53c810_pci_regs[0x05] & 0x01; + return ncr53c8xx_pci_regs[0x05] & 0x01; case 0x07: return 2; case 0x08: - return 0x10; /*Revision ID*/ + return dev->chip_rev; /*Revision ID*/ case 0x09: return 0; /*Programming interface*/ case 0x0A: @@ -2030,33 +2393,69 @@ ncr53c810_pci_read(int func, int addr, void *p) return 1; /*Class code*/ case 0x0C: case 0x0D: - return ncr53c810_pci_regs[addr]; + return ncr53c8xx_pci_regs[addr]; case 0x0E: return 0; /*Header type */ case 0x10: return 1; /*I/O space*/ case 0x11: - return ncr53c810_pci_bar[0].addr_regs[1]; + return ncr53c8xx_pci_bar[0].addr_regs[1]; case 0x12: - return ncr53c810_pci_bar[0].addr_regs[2]; + return ncr53c8xx_pci_bar[0].addr_regs[2]; case 0x13: - return ncr53c810_pci_bar[0].addr_regs[3]; + return ncr53c8xx_pci_bar[0].addr_regs[3]; case 0x14: return 0; /*Memory space*/ case 0x15: - return ncr53c810_pci_bar[1].addr_regs[1]; + return ncr53c8xx_pci_bar[1].addr_regs[1]; case 0x16: - return ncr53c810_pci_bar[1].addr_regs[2]; + return ncr53c8xx_pci_bar[1].addr_regs[2]; case 0x17: - return ncr53c810_pci_bar[1].addr_regs[3]; + return ncr53c8xx_pci_bar[1].addr_regs[3]; + case 0x18: + return 0; /*Memory space*/ + case 0x19: + if (dev->chip < CHIP_825) + return 0; + return ncr53c8xx_pci_bar[2].addr_regs[1]; + case 0x1A: + if (dev->chip < CHIP_825) + return 0; + return ncr53c8xx_pci_bar[2].addr_regs[2]; + case 0x1B: + if (dev->chip < CHIP_825) + return 0; + return ncr53c8xx_pci_bar[2].addr_regs[3]; case 0x2C: return 0x00; case 0x2D: + if (dev->chip >= CHIP_825) + return 0; return 0x10; case 0x2E: + if (dev->chip >= CHIP_825) + return 0; return 0x01; case 0x2F: return 0x00; +#ifdef USE_BIOS_BAR + case 0x30: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[0]; + case 0x31: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[1]; + case 0x32: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[2]; + case 0x33: + if ((dev->chip < CHIP_825) || !dev->has_bios) + return 0; + return ncr53c8xx_pci_bar[3].addr_regs[3]; +#endif case 0x3C: return dev->irq; case 0x3D: @@ -2072,61 +2471,59 @@ ncr53c810_pci_read(int func, int addr, void *p) static void -ncr53c810_pci_write(int func, int addr, uint8_t val, void *p) +ncr53c8xx_pci_write(int func, int addr, uint8_t val, void *p) { - ncr53c810_t *dev = (ncr53c810_t *)p; + ncr53c8xx_t *dev = (ncr53c8xx_t *)p; uint8_t valxor; - ncr53c810_log("NCR53c810: Write value %02X to register %02X\n", val, addr & 0xff); + ncr53c8xx_log("NCR53c8xx: Write value %02X to register %02X\n", val, addr & 0xff); - if ((addr >= 0x80) && (addr <= 0xDF)) { - ncr53c810_reg_writeb(dev, addr & 0x7F, val); + if ((addr >= 0x80) && (addr <= 0xFF)) { + ncr53c8xx_reg_writeb(dev, addr & 0x7F, val); return; } switch (addr) { case 0x04: - valxor = (val & 0x57) ^ ncr53c810_pci_regs[addr]; + valxor = (val & 0x57) ^ ncr53c8xx_pci_regs[addr]; if (valxor & PCI_COMMAND_IO) { - ncr53c810_io_remove(dev, dev->PCIBase, 0x0100); - if ((dev->PCIBase != 0) && (val & PCI_COMMAND_IO)) { - ncr53c810_io_set(dev, dev->PCIBase, 0x0100); - } + ncr53c8xx_io_remove(dev, dev->PCIBase, 0x0100); + if ((dev->PCIBase != 0) && (val & PCI_COMMAND_IO)) + ncr53c8xx_io_set(dev, dev->PCIBase, 0x0100); } if (valxor & PCI_COMMAND_MEM) { - ncr53c810_mem_disable(dev); - if ((dev->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) { - ncr53c810_mem_set_addr(dev, dev->MMIOBase); - } + ncr53c8xx_mem_disable(dev); + if ((dev->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) + ncr53c8xx_mem_set_addr(dev, dev->MMIOBase); } - ncr53c810_pci_regs[addr] = val & 0x57; + ncr53c8xx_pci_regs[addr] = val & 0x57; break; case 0x05: - ncr53c810_pci_regs[addr] = val & 0x01; + ncr53c8xx_pci_regs[addr] = val & 0x01; break; case 0x0C: case 0x0D: - ncr53c810_pci_regs[addr] = val; + ncr53c8xx_pci_regs[addr] = val; break; case 0x10: case 0x11: case 0x12: case 0x13: /* I/O Base set. */ /* First, remove the old I/O. */ - ncr53c810_io_remove(dev, dev->PCIBase, 0x0100); + ncr53c8xx_io_remove(dev, dev->PCIBase, 0x0100); /* Then let's set the PCI regs. */ - ncr53c810_pci_bar[0].addr_regs[addr & 3] = val; + ncr53c8xx_pci_bar[0].addr_regs[addr & 3] = val; /* Then let's calculate the new I/O base. */ - ncr53c810_pci_bar[0].addr &= 0xff00; - dev->PCIBase = ncr53c810_pci_bar[0].addr; + ncr53c8xx_pci_bar[0].addr &= 0xff00; + dev->PCIBase = ncr53c8xx_pci_bar[0].addr; /* Log the new base. */ - ncr53c810_log("NCR53c810: New I/O base is %04X\n" , dev->PCIBase); + ncr53c8xx_log("NCR53c8xx: New I/O base is %04X\n" , dev->PCIBase); /* We're done, so get out of the here. */ - if (ncr53c810_pci_regs[4] & PCI_COMMAND_IO) { + if (ncr53c8xx_pci_regs[4] & PCI_COMMAND_IO) { if (dev->PCIBase != 0) { - ncr53c810_io_set(dev, dev->PCIBase, 0x0100); + ncr53c8xx_io_set(dev, dev->PCIBase, 0x0100); } } return; @@ -2134,23 +2531,63 @@ ncr53c810_pci_write(int func, int addr, uint8_t val, void *p) case 0x15: case 0x16: case 0x17: /* MMIO Base set. */ /* First, remove the old I/O. */ - ncr53c810_mem_disable(dev); + ncr53c8xx_mem_disable(dev); /* Then let's set the PCI regs. */ - ncr53c810_pci_bar[1].addr_regs[addr & 3] = val; + ncr53c8xx_pci_bar[1].addr_regs[addr & 3] = val; /* Then let's calculate the new I/O base. */ - dev->MMIOBase = ncr53c810_pci_bar[1].addr & 0xffffff00; + ncr53c8xx_pci_bar[1].addr &= 0xffffc000; + dev->MMIOBase = ncr53c8xx_pci_bar[1].addr & 0xffffc000; /* Log the new base. */ - ncr53c810_log("NCR53c810: New MMIO base is %08X\n" , dev->MMIOBase); + ncr53c8xx_log("NCR53c8xx: New MMIO base is %08X\n" , dev->MMIOBase); /* We're done, so get out of the here. */ - if (ncr53c810_pci_regs[4] & PCI_COMMAND_MEM) { + if (ncr53c8xx_pci_regs[4] & PCI_COMMAND_MEM) { if (dev->MMIOBase != 0) { - ncr53c810_mem_set_addr(dev, dev->MMIOBase); + ncr53c8xx_mem_set_addr(dev, dev->MMIOBase); } } return; + case 0x19: case 0x1A: case 0x1B: + if (dev->chip < CHIP_825) + return; + /* RAM Base set. */ + /* First, remove the old I/O. */ + ncr53c8xx_ram_disable(dev); + /* Then let's set the PCI regs. */ + ncr53c8xx_pci_bar[2].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c8xx_pci_bar[2].addr &= 0xffffc000; + dev->RAMBase = ncr53c8xx_pci_bar[2].addr & 0xffffc000; + /* Log the new base. */ + ncr53c8xx_log("NCR53c8xx: New RAM base is %08X\n" , dev->RAMBase); + /* We're done, so get out of the here. */ + if (dev->RAMBase != 0) + ncr53c8xx_ram_set_addr(dev, dev->RAMBase); + return; + +#ifdef USE_BIOS_BAR + case 0x30: case 0x31: case 0x32: case 0x33: + return; + if ((dev->chip < CHIP_825) || !dev->has_bios) + return; + /* BIOS Base set. */ + /* First, remove the old I/O. */ + ncr53c8xx_bios_disable(dev); + /* Then let's set the PCI regs. */ + ncr53c8xx_pci_bar[3].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c8xx_pci_bar[3].addr &= 0xffff0001; + dev->BIOSBase = ncr53c8xx_pci_bar[3].addr & 0xffff0000; + /* Log the new base. */ + ncr53c8xx_log("NCR53c8xx: New BIOS base is %08X\n" , dev->BIOSBase); + /* We're done, so get out of the here. */ + if (ncr53c8xx_pci_bar[3].addr & 0x00000001) + ncr53c8xx_bios_set_addr(dev, dev->BIOSBase); + return; +#endif + case 0x3C: - ncr53c810_pci_regs[addr] = val; + ncr53c8xx_pci_regs[addr] = val; dev->irq = val; return; } @@ -2158,41 +2595,70 @@ ncr53c810_pci_write(int func, int addr, uint8_t val, void *p) static void * -ncr53c810_init(const device_t *info) +ncr53c8xx_init(const device_t *info) { - ncr53c810_t *dev; + ncr53c8xx_t *dev; - dev = malloc(sizeof(ncr53c810_t)); - memset(dev, 0x00, sizeof(ncr53c810_t)); + dev = malloc(sizeof(ncr53c8xx_t)); + memset(dev, 0x00, sizeof(ncr53c8xx_t)); dev->chip_rev = 0; - dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, ncr53c810_pci_read, ncr53c810_pci_write, dev); + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, ncr53c8xx_pci_read, ncr53c8xx_pci_write, dev); - ncr53c810_pci_bar[0].addr_regs[0] = 1; - ncr53c810_pci_bar[1].addr_regs[0] = 0; - ncr53c810_pci_regs[0x04] = 3; + ncr53c8xx_pci_bar[0].addr_regs[0] = 1; + ncr53c8xx_pci_bar[1].addr_regs[0] = 0; + dev->chip = info->local; + ncr53c8xx_pci_regs[0x04] = 3; - ncr53c810_mem_init(dev, 0x0fffff00); - ncr53c810_mem_disable(dev); - - ncr53c810_soft_reset(dev); - - timer_add(ncr53c810_callback, &dev->timer_period, &dev->timer_enabled, dev); + ncr53c8xx_mem_init(dev, 0x0fffff00); + ncr53c8xx_mem_disable(dev); dev->has_bios = device_get_config_int("bios"); - - /* Enable our BIOS space in PCI, if needed. */ if (dev->has_bios) - rom_init(&dev->bios, NCR53C810_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + if (dev->chip >= CHIP_825) { + if (dev->chip == CHIP_875) { + dev->chip_rev = 0x04; + dev->nvr_path = L"ncr53c875.nvr"; + } else { + dev->chip_rev = 0x26; + dev->nvr_path = L"ncr53c825a.nvr"; + } + ncr53c8xx_pci_bar[2].addr_regs[0] = 0; + ncr53c8xx_pci_bar[3].addr = 0xffff0000; + /* Need to make it align on a 16k boundary as that's this emulator's + memory mapping granularity. */ + ncr53c8xx_ram_init(dev, 0x0fffc000); + ncr53c8xx_ram_disable(dev); + +#ifdef USE_BIOS_BAR + if (dev->has_bios) + ncr53c8xx_bios_disable(dev); +#endif + } else { + if (dev->has_bios) + rom_init(&dev->bios, NCR53C8XX_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + dev->nvr_path = L"ncr53c810.nvr"; + } + +#ifdef USE_NVRAM + /* Load the serial EEPROM. */ + ncr53c8xx_eeprom(dev, 0); +#endif + + ncr53c8xx_soft_reset(dev); + + timer_add(ncr53c8xx_callback, &dev->timer_period, &dev->timer_enabled, dev); return(dev); } static void -ncr53c810_close(void *priv) +ncr53c8xx_close(void *priv) { - ncr53c810_t *dev = (ncr53c810_t *)priv; + ncr53c8xx_t *dev = (ncr53c8xx_t *)priv; if (dev) { free(dev); @@ -2201,7 +2667,7 @@ ncr53c810_close(void *priv) } -static const device_config_t ncr53c810_pci_config[] = { +static const device_config_t ncr53c8xx_pci_config[] = { { "bios", "Enable BIOS", CONFIG_BINARY, "", 0 }, @@ -2215,8 +2681,28 @@ const device_t ncr53c810_pci_device = { "NCR 53c810 (SCSI)", DEVICE_PCI, - 0, - ncr53c810_init, ncr53c810_close, NULL, + 0x01, + ncr53c8xx_init, ncr53c8xx_close, NULL, NULL, NULL, NULL, - ncr53c810_pci_config + ncr53c8xx_pci_config +}; + +const device_t ncr53c825a_pci_device = +{ + "NCR 53c825A (SCSI)", + DEVICE_PCI, + CHIP_825, + ncr53c8xx_init, ncr53c8xx_close, NULL, + NULL, NULL, NULL, + ncr53c8xx_pci_config +}; + +const device_t ncr53c875_pci_device = +{ + "NCR 53c875 (SCSI)", + DEVICE_PCI, + CHIP_875, + ncr53c8xx_init, ncr53c8xx_close, NULL, + NULL, NULL, NULL, + ncr53c8xx_pci_config }; diff --git a/src/scsi/scsi_ncr53c810.h b/src/scsi/scsi_ncr53c8xx.h similarity index 61% rename from src/scsi/scsi_ncr53c810.h rename to src/scsi/scsi_ncr53c8xx.h index 29666e935..bf2136e0d 100644 --- a/src/scsi/scsi_ncr53c810.h +++ b/src/scsi/scsi_ncr53c8xx.h @@ -6,11 +6,11 @@ * * This file is part of the 86Box distribution. * - * Implementation of the NCR 53C810 SCSI Host Adapter made by - * NCR and later Symbios and LSI. This controller was designed - * for the PCI bus. + * Implementation of the NCR 53C810 and 53C875 SCSI Host + * Adapters made by NCR and later Symbios and LSI. These + * controllers were designed for the PCI bus. * - * Version: @(#)scsi_ncr53c810.c 1.0.1 2018/03/18 + * Version: @(#)scsi_ncr53c8xx.c 1.0.2 2018/10/30 * * Authors: TheCollector1995, * Miran Grca, @@ -21,11 +21,13 @@ * Copyright 2009-2018 Artyom Tarasenko. * Copyright 2017,2018 Miran Grca. */ -#ifndef SCSI_NCR5C3810_H -# define SCSI_NCR53C810_H +#ifndef SCSI_NCR5C38XX_H +# define SCSI_NCR53C8XX_H extern const device_t ncr53c810_pci_device; +extern const device_t ncr53c825a_pci_device; +extern const device_t ncr53c875_pci_device; -#endif /*SCSI_NCR53C810_H*/ +#endif /*SCSI_NCR53C8XX_H*/ diff --git a/src/scsi/scsi_x54x.c b/src/scsi/scsi_x54x.c index 59e93b961..a1c97f548 100644 --- a/src/scsi/scsi_x54x.c +++ b/src/scsi/scsi_x54x.c @@ -11,7 +11,7 @@ * series of SCSI Host Adapters made by Mylex. * These controllers were designed for various buses. * - * Version: @(#)scsi_x54x.c 1.0.25 2018/10/18 + * Version: @(#)scsi_x54x.c 1.0.26 2018/10/28 * * Authors: TheCollector1995, * Miran Grca, @@ -261,34 +261,23 @@ x54x_bios_scsi_command(scsi_device_t *dev, uint8_t *cdb, uint8_t *buf, int len, if (dev->phase == SCSI_PHASE_STATUS) return(completion_code(scsi_device_sense(dev))); - dev->cmd_buffer = (uint8_t *)malloc(dev->buffer_length); - - if (dev->phase == SCSI_PHASE_DATA_IN) { - scsi_device_command_phase1(dev); - - if (len > 0) { + if (len > 0) { + if (dev->phase == SCSI_PHASE_DATA_IN) { if (buf) - memcpy(buf, dev->cmd_buffer, dev->buffer_length); + memcpy(buf, dev->sc->temp_buffer, dev->buffer_length); else - DMAPageWrite(addr, dev->cmd_buffer, dev->buffer_length); - } - } else if (dev->phase == SCSI_PHASE_DATA_OUT) { - if (len > 0) { + DMAPageWrite(addr, dev->sc->temp_buffer, dev->buffer_length); + } else if (dev->phase == SCSI_PHASE_DATA_OUT) { if (buf) - memcpy(dev->cmd_buffer, buf, dev->buffer_length); + memcpy(dev->sc->temp_buffer, buf, dev->buffer_length); else - DMAPageRead(addr, dev->cmd_buffer, dev->buffer_length); + DMAPageRead(addr, dev->sc->temp_buffer, dev->buffer_length); } - - scsi_device_command_phase1(dev); } - if (dev->cmd_buffer != NULL) { - free(dev->cmd_buffer); - dev->cmd_buffer = NULL; - } + scsi_device_command_phase1(dev); - return(completion_code(scsi_device_sense(dev))); + return (completion_code(scsi_device_sense(dev))); } @@ -439,11 +428,6 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) dev = &scsi_devices[cmd->id]; dev->buffer_length = 0; - if (dev->cmd_buffer != NULL) { - free(dev->cmd_buffer); - dev->cmd_buffer = NULL; - } - if (! scsi_device_present(dev)) { x54x_log("BIOS Target ID %i has no device attached\n", cmd->id); ret = 0x80; @@ -473,10 +457,6 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) * length for SCSI sense, and no command-specific * indication is given. */ - dev->buffer_length = 14; - dev->cmd_buffer = (uint8_t *)malloc(14); - memset(dev->cmd_buffer, 0x00, 14); - if (sector_len > 0) { x54x_log("BIOS DMA: Reading 14 bytes at %08X\n", dma_address); @@ -484,11 +464,6 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) scsi_device_sense(dev), 14); } - if (dev && (dev->cmd_buffer != NULL)) { - free(dev->cmd_buffer); - dev->cmd_buffer = NULL; - } - return(0); break; @@ -506,9 +481,6 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) cdb[5] = lba & 0xff; if (cmd->command != 0x0c) cdb[8] = sector_len; -#if 0 - x54x_log("BIOS CMD(READ/WRITE/VERIFY, %08lx, %d)\n", lba, cmd->secount); -#endif ret = x54x_bios_scsi_command(dev, cdb, NULL, sector_len, dma_address); if (cmd->command == 0x0c) @@ -552,8 +524,6 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) target_check(cmd->id); dev->buffer_length = 6; - dev->cmd_buffer = (uint8_t *)malloc(dev->buffer_length); - memset(dev->cmd_buffer, 0x00, dev->buffer_length); buf = (uint8_t *) malloc(6); if (cmd->command == 0x08) @@ -565,11 +535,6 @@ x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) DMAPageWrite(dma_address, buf, 4); free(buf); - if (dev->cmd_buffer != NULL) { - free(dev->cmd_buffer); - dev->cmd_buffer = NULL; - } - break; } @@ -831,11 +796,11 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) if (read_from_host && DataToTransfer) { x54x_log("Reading S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); - DMAPageRead(Address, &(scsi_devices[req->TargetID].cmd_buffer[sg_pos]), DataToTransfer); + DMAPageRead(Address, &(scsi_devices[req->TargetID].sc->temp_buffer[sg_pos]), DataToTransfer); } else if (write_to_host && DataToTransfer) { x54x_log("Writing S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); - DMAPageWrite(Address, &(scsi_devices[req->TargetID].cmd_buffer[sg_pos]), DataToTransfer); + DMAPageWrite(Address, &(scsi_devices[req->TargetID].sc->temp_buffer[sg_pos]), DataToTransfer); } else x54x_log("No action on S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); @@ -855,39 +820,15 @@ x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) if ((DataLength > 0) && (BufLen > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { if (read_from_host) - DMAPageRead(Address, scsi_devices[req->TargetID].cmd_buffer, MIN(BufLen, (int) DataLength)); + DMAPageRead(Address, scsi_devices[req->TargetID].sc->temp_buffer, MIN(BufLen, (int) DataLength)); else if (write_to_host) - DMAPageWrite(Address, scsi_devices[req->TargetID].cmd_buffer, MIN(BufLen, (int) DataLength)); + DMAPageWrite(Address, scsi_devices[req->TargetID].sc->temp_buffer, MIN(BufLen, (int) DataLength)); } } } } -void -x54x_buf_alloc(uint8_t id, int length) -{ - if (scsi_devices[id].cmd_buffer != NULL) { - free(scsi_devices[id].cmd_buffer); - scsi_devices[id].cmd_buffer = NULL; - } - - x54x_log("Allocating data buffer (%i bytes)\n", length); - scsi_devices[id].cmd_buffer = (uint8_t *) malloc(length); - memset(scsi_devices[id].cmd_buffer, 0, length); -} - - -void -x54x_buf_free(uint8_t id) -{ - if (scsi_devices[id].cmd_buffer != NULL) { - free(scsi_devices[id].cmd_buffer); - scsi_devices[id].cmd_buffer = NULL; - } -} - - static uint8_t ConvertSenseLength(uint8_t RequestSenseLength) { @@ -959,7 +900,6 @@ x54x_scsi_cmd(x54x_t *dev) uint8_t temp_cdb[12]; uint32_t i, SenseBufferAddress; int target_data_len, target_cdb_len = 12; - int32_t *BufLen; int64_t p; scsi_device_t *sd; @@ -995,10 +935,7 @@ x54x_scsi_cmd(x54x_t *dev) dev->Residue = 0; - BufLen = scsi_device_get_buf_len(sd); - *BufLen = target_data_len; - - x54x_log("Command buffer: %08X\n", scsi_devices[id].cmd_buffer); + sd->buffer_length = target_data_len; scsi_device_command_phase0(sd, temp_cdb); @@ -1009,26 +946,21 @@ x54x_scsi_cmd(x54x_t *dev) if (phase != SCSI_PHASE_STATUS) { if ((temp_cdb[0] == 0x03) && (req->CmdBlock.common.ControlByte == 0x03)) { /* Request sense in non-data mode - sense goes to sense buffer. */ - *BufLen = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); - x54x_buf_alloc(id, *BufLen); - scsi_device_command_phase1(sd); - if ((sd->status != SCSI_STATUS_OK) && (*BufLen > 0)) { + sd->buffer_length = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); + if ((sd->status != SCSI_STATUS_OK) && (sd->buffer_length > 0)) { SenseBufferAddress = SenseBufferPointer(req); - DMAPageWrite(SenseBufferAddress, scsi_devices[id].cmd_buffer, *BufLen); - x54x_add_to_period(*BufLen); + DMAPageWrite(SenseBufferAddress, scsi_devices[id].sc->temp_buffer, sd->buffer_length); + x54x_add_to_period(sd->buffer_length); } + scsi_device_command_phase1(sd); } else { p = scsi_device_get_callback(sd); if (p <= 0LL) - x54x_add_to_period(*BufLen); + x54x_add_to_period(sd->buffer_length); else dev->media_period += p; - x54x_buf_alloc(id, MIN(target_data_len, *BufLen)); - if (phase == SCSI_PHASE_DATA_OUT) - x54x_buf_dma_transfer(req, bit24, target_data_len, 1); + x54x_buf_dma_transfer(req, bit24, target_data_len, (phase == SCSI_PHASE_DATA_OUT)); scsi_device_command_phase1(sd); - if (phase == SCSI_PHASE_DATA_IN) - x54x_buf_dma_transfer(req, bit24, target_data_len, 0); SenseBufferFree(req, (sd->status != SCSI_STATUS_OK)); } @@ -1037,8 +969,6 @@ x54x_scsi_cmd(x54x_t *dev) x54x_set_residue(req, target_data_len); - x54x_buf_free(id); - x54x_log("Request complete\n"); if (sd->status == SCSI_STATUS_OK) { @@ -1378,9 +1308,6 @@ x54x_in(uint16_t port, void *priv) break; } -#if 0 - x54x_log("%s: Read Port 0x%02X, Value %02X\n", dev->name, port, ret); -#endif return(ret); } diff --git a/src/scsi/scsi_x54x.h b/src/scsi/scsi_x54x.h index 21e539087..267181ba3 100644 --- a/src/scsi/scsi_x54x.h +++ b/src/scsi/scsi_x54x.h @@ -11,7 +11,7 @@ * of SCSI Host Adapters made by Mylex. * These controllers were designed for various buses. * - * Version: @(#)scsi_x54x.h 1.0.9 2018/10/21 + * Version: @(#)scsi_x54x.h 1.0.10 2018/10/28 * * Authors: TheCollector1995, * Miran Grca, @@ -500,8 +500,6 @@ typedef struct { extern void x54x_reset_ctrl(x54x_t *dev, uint8_t Reset); -extern void x54x_buf_alloc(uint8_t id, int length); -extern void x54x_buf_free(uint8_t id); extern uint8_t x54x_mbo_process(x54x_t *dev); extern void x54x_wait_for_poll(void); extern void x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len); diff --git a/src/sound/sound.c b/src/sound/sound.c index d96c2cf7f..1885052cc 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -8,7 +8,7 @@ * * Sound emulation core. * - * Version: @(#)sound.c 1.0.24 2018/10/26 + * Version: @(#)sound.c 1.0.25 2018/10/28 * * Authors: Sarah Walker, * Miran Grca, @@ -205,9 +205,9 @@ static void sound_cd_clean_buffers(void) { if (sound_is_float) - memset(cd_out_buffer, 0, 2 * sizeof(float)); + memset(cd_out_buffer, 0, (CD_BUFLEN * 2) * sizeof(float)); else - memset(cd_out_buffer_int16, 0, 2 * sizeof(int16_t)); + memset(cd_out_buffer_int16, 0, (CD_BUFLEN * 2) * sizeof(int16_t)); } @@ -230,14 +230,12 @@ sound_cd_thread(void *param) sound_cd_clean_buffers(); for (i = 0; i < CDROM_NUM; i++) { - if ((cdrom[i].bus_type == CDROM_BUS_DISABLED) || !cdrom[i].ops) + if ((cdrom[i].bus_type == CDROM_BUS_DISABLED) || + (cdrom[i].cd_status == CD_STATUS_EMPTY)) continue; - if (cdrom[i].ops->audio_callback) { - r = cdrom[i].ops->audio_callback(&(cdrom[i]), cd_buffer[i], CD_BUFLEN * 2); - if (!cdrom[i].bus_type || !cdrom[i].sound_on || !r) + r = cdrom_audio_callback(&(cdrom[i]), cd_buffer[i], CD_BUFLEN * 2); + if (!cdrom[i].bus_type || !cdrom[i].sound_on || !r) continue; - } else - continue; if (cdrom[i].get_volume) { audio_vol_l = (float) (cdrom[i].get_volume(cdrom[i].priv, 0)); @@ -480,8 +478,7 @@ sound_cd_thread_reset(void) int available_cdrom_drives = 0; for (i = 0; i < CDROM_NUM; i++) { - if (cdrom[i].ops && cdrom[i].ops->audio_stop) - cdrom[i].ops->audio_stop(&(cdrom[i])); + cdrom_stop(&(cdrom[i])); if (cdrom[i].bus_type != CDROM_BUS_DISABLED) available_cdrom_drives++; diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 076c0e97e..bad6fcabc 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -8,7 +8,7 @@ # # Makefile for Win32 (MinGW32) environment. # -# Version: @(#)Makefile.mingw 1.0.133 2018/10/22 +# Version: @(#)Makefile.mingw 1.0.134 2018/10/26 # # Authors: Miran Grca, # Fred N. van Kempen, @@ -483,7 +483,7 @@ SCSIOBJ := scsi.o scsi_device.o \ scsi_cdrom.o scsi_disk.o \ scsi_x54x.o \ scsi_aha154x.o scsi_buslogic.o \ - scsi_ncr5380.o scsi_ncr53c810.o + scsi_ncr5380.o scsi_ncr53c8xx.o NETOBJ := network.o \ net_pcap.o \ diff --git a/src/win/win_settings.c b/src/win/win_settings.c index a4d771d87..0e0f33052 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -8,7 +8,7 @@ * * Windows 86Box Settings dialog handler. * - * Version: @(#)win_settings.c 1.0.72 2018/10/26 + * Version: @(#)win_settings.c 1.0.73 2018/10/30 * * Authors: Miran Grca, * David Hrdlička, @@ -477,6 +477,10 @@ win_settings_save(void) /* Hard disks category */ memcpy(hdd, temp_hdd, HDD_NUM * sizeof(hard_disk_t)); + for (i = 0; i < HDD_NUM; i++) { + hdd[i].f = NULL; + hdd[i].priv = NULL; + } /* Floppy drives category */ for (i = 0; i < FDD_NUM; i++) { @@ -487,7 +491,21 @@ win_settings_save(void) /* Removable devices category */ memcpy(cdrom, temp_cdrom, CDROM_NUM * sizeof(cdrom_t)); + for (i = 0; i < CDROM_NUM; i++) { + cdrom[i].img_fp = NULL; + cdrom[i].priv = NULL; + cdrom[i].ops = NULL; + cdrom[i].image = NULL; + cdrom[i].insert = NULL; + cdrom[i].close = NULL; + cdrom[i].get_volume = NULL; + cdrom[i].get_channel = NULL; + } memcpy(zip_drives, temp_zip_drives, ZIP_NUM * sizeof(zip_drive_t)); + for (i = 0; i < ZIP_NUM; i++) { + zip_drives[i].f = NULL; + zip_drives[i].priv = NULL; + } /* Mark configuration as changed. */ config_changed = 1; diff --git a/src/win/win_stbar.c b/src/win/win_stbar.c index 63845bc29..92151d87b 100644 --- a/src/win/win_stbar.c +++ b/src/win/win_stbar.c @@ -8,7 +8,7 @@ * * Implement the application's Status Bar. * - * Version: @(#)win_stbar.c 1.0.23 2018/10/26 + * Version: @(#)win_stbar.c 1.0.24 2018/10/28 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -780,7 +780,7 @@ ui_sb_mount_zip_img(uint8_t id, int part, uint8_t wp, wchar_t *file_name) zip_t *dev = (zip_t *) zip_drives[id].priv; zip_disk_close(dev); - zip_drives[id].ui_writeprot = wp; + zip_drives[id].read_only = wp; zip_load(dev, file_name); zip_insert(dev); if (sb_ready) { @@ -906,8 +906,6 @@ StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (!file_dlg_w_st(hwnd, IDS_2075, cdrom[id].image_path, 0)) { cdrom[id].prev_host_drive = cdrom[id].host_drive; wcscpy(temp_path, wopenfilestring); - if (!cdrom[id].prev_image_path) - cdrom[id].prev_image_path = (wchar_t *) malloc(1024 * sizeof(wchar_t)); wcscpy(cdrom[id].prev_image_path, cdrom[id].image_path); if (cdrom[id].ops && cdrom[id].ops->exit) cdrom[id].ops->exit(&(cdrom[id])); diff --git a/src/win/win_ui.c b/src/win/win_ui.c index d76477f1a..4b897b09f 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -870,7 +870,7 @@ ui_init(int nCmdShow) plat_resize(scrnsz_x, scrnsz_y); /* Fire up the machine. */ - pc_reset_hard(); + pc_reset_hard_init(); /* Set the PAUSE mode depending on the renderer. */ plat_pause(0);