Extensive rework of SCSI and ATAPI devices and numerous bug fixes and cleanups;

Extensive rework of CD-ROM image handling;
The settings save code now forces some devices' (SCSI disk, CD-ROM, etc.) pointers to NULL before resetting the machine - fixes segmentation faults after changing settings;
Added the NCR 53c825A and 53c875 SCSI controllers;
Fixed IDE/ATAPI DMA;
Slight changed to PCI IDE bus master operation.
This commit is contained in:
OBattler
2018-10-30 13:32:25 +01:00
parent 6410e0ac75
commit 3a8bd15b9d
31 changed files with 3116 additions and 3370 deletions

View File

@@ -8,7 +8,7 @@
*
* Generic CD-ROM drive core.
*
* Version: @(#)cdrom.c 1.0.5 2018/10/26
* Version: @(#)cdrom.c 1.0.6 2018/10/28
*
* Author: Miran Grca, <mgrca8@gmail.com>
*
@@ -30,10 +30,66 @@
#include "../sound/sound.h"
/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong:
there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start
of the audio while audio still plays. With an absolute conversion, the counter is fine. */
#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f)
#define RAW_SECTOR_SIZE 2352
#define COOKED_SECTOR_SIZE 2048
#define MIN_SEEK 2000
#define MAX_SEEK 333333
#pragma pack(push,1)
typedef struct {
uint8_t user_data[2048],
ecc[288];
} m1_data_t;
typedef struct {
uint8_t sub_header[8],
user_data[2328];
} m2_data_t;
typedef union {
m1_data_t m1_data;
m2_data_t m2_data;
uint8_t raw_data[2336];
} sector_data_t;
typedef struct {
uint8_t sync[12];
uint8_t header[4];
sector_data_t data;
} sector_raw_data_t;
typedef union {
sector_raw_data_t sector_data;
uint8_t raw_data[2352];
} sector_t;
typedef struct {
sector_t sector;
uint8_t c2[296];
uint8_t subchannel_raw[96];
uint8_t subchannel_q[16];
uint8_t subchannel_rw[96];
} cdrom_sector_t;
typedef union {
cdrom_sector_t cdrom_sector;
uint8_t buffer[2856];
} sector_buffer_t;
#pragma pack(pop)
static int cdrom_sector_size;
static uint8_t raw_buffer[2856]; /* Needs to be the same size as sector_buffer_t in the structs. */
static uint8_t extra_buffer[296];
cdrom_t cdrom[CDROM_NUM];
@@ -157,36 +213,751 @@ cdrom_seek_time(cdrom_t *dev)
}
void
cdrom_stop(cdrom_t *dev)
{
if (dev->cd_status > CD_STATUS_DATA_ONLY)
dev->cd_status = CD_STATUS_STOPPED;
}
void
cdrom_seek(cdrom_t *dev, uint32_t pos)
{
/* cdrom_log("CD-ROM %i: Seek %08X\n", dev->id, pos); */
if (!dev)
return;
cdrom_log("CD-ROM %i: Seek to LBA %08X\n", dev->id, pos);
dev->seek_pos = pos;
if (dev->ops && dev->ops->stop)
dev->ops->stop(dev);
cdrom_stop(dev);
}
int
cdrom_playing_completed(cdrom_t *dev)
cdrom_audio_callback(cdrom_t *dev, int16_t *output, int len)
{
dev->prev_status = dev->cd_status;
int ret = 1;
if (dev->ops && dev->ops->status)
dev->cd_status = dev->ops->status(dev);
else {
dev->cd_status = CD_STATUS_EMPTY;
if (!dev->sound_on || (dev->cd_status != CD_STATUS_PLAYING)) {
cdrom_log("CD-ROM %i: Audio callback while not playing\n", dev->id);
if (dev->cd_status == CD_STATUS_PLAYING)
dev->seek_pos += (len >> 11);
memset(output, 0, len * 2);
return 0;
}
if (((dev->prev_status == CD_STATUS_PLAYING) || (dev->prev_status == CD_STATUS_PAUSED)) &&
((dev->cd_status != CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_PAUSED)))
return 1;
while (dev->cd_buflen < len) {
if (dev->seek_pos < dev->cd_end) {
if (dev->ops->read_sector(dev, CD_READ_AUDIO,
(uint8_t *) &(dev->cd_buffer[dev->cd_buflen]),
dev->seek_pos)) {
cdrom_log("CD-ROM %i: Read LBA %08X successful\n", dev->id, dev->seek_pos);
dev->seek_pos++;
dev->cd_buflen += (RAW_SECTOR_SIZE / 2);
ret = 1;
} else {
cdrom_log("CD-ROM %i: Read LBA %08X failed\n", dev->id, dev->seek_pos);
memset(&(dev->cd_buffer[dev->cd_buflen]),
0x00, (BUF_SIZE - dev->cd_buflen) * 2);
dev->cd_status = CD_STATUS_STOPPED;
dev->cd_buflen = len;
ret = 0;
}
} else {
cdrom_log("CD-ROM %i: Playing completed\n", dev->id);
memset(&dev->cd_buffer[dev->cd_buflen],
0x00, (BUF_SIZE - dev->cd_buflen) * 2);
dev->cd_status = CD_STATUS_PLAYING_COMPLETED;
dev->cd_buflen = len;
ret = 0;
}
}
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);

View File

@@ -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, <mgrca8@gmail.com>
*
@@ -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);

View File

@@ -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);

View File

@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -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, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -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,15 +671,14 @@ 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);
@@ -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,12 +1665,10 @@ 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)
} else if (ide->command != WIN_READ_MULTIPLE)
ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0);
}
}
}
return temp;
}
@@ -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);
@@ -2063,8 +2202,8 @@ ide_callback(void *priv)
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;
@@ -2076,8 +2215,8 @@ ide_callback(void *priv)
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->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;

View File

@@ -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, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -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*/

View File

@@ -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, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -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);

View File

@@ -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, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -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)
{

View File

@@ -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, <mgrca8@gmail.com>
*
@@ -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,18 +473,35 @@ 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, 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");
read_only = 1;
if (dev->drv->f)
dev->drv->read_only = 1;
else
return zip_load_abort(dev);
} else
return zip_load_abort(dev);
}
if (dev->drv->f) {
fseek(dev->drv->f, 0, SEEK_END);
size = ftell(dev->drv->f);
@@ -512,21 +516,13 @@ zip_load(zip_t *dev, wchar_t *fn)
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;
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);
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;
return zip_load_abort(dev);
}
}
@@ -536,14 +532,9 @@ zip_load(zip_t *dev, wchar_t *fn)
memcpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path));
dev->drv->read_only = read_only;
return 1;
}
return 0;
}
void
zip_disk_reload(zip_t *dev)
@@ -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,6 +1362,7 @@ static void
zip_buf_alloc(zip_t *dev, uint32_t len)
{
zip_log("ZIP %i: Allocated buffer length: %i\n", dev->id, 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,402 +2168,132 @@ 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 (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) {
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 (ret == 2) /* DMA not enabled, wait for it to be enabled. */
return 2;
else if (ret == 1) { /* DMA error. */
}
}
if (ret == 0) {
zip_buf_free(dev);
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 if (ret == 1) {
if (out)
ret = zip_phase_data_out((scsi_common_t *) dev);
else
zip_log("ZIP %i: ATAPI Output data length: %i\n", dev->id, dev->packet_len);
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);
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();
}
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;
}
}
@@ -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);

View File

@@ -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, <mgrca8@gmail.com>
*
@@ -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();

View File

@@ -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, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -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);
}
}

View File

@@ -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, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -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();

View File

@@ -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, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -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
@@ -72,6 +72,8 @@ static SCSI_CARD scsi_cards[] = {
{ "[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);

View File

@@ -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, <mariogplayer@gmail.com>
* Miran Grca, <mgrca8@gmail.com>
@@ -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);
}
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. */

File diff suppressed because it is too large Load Diff

View File

@@ -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*/

View File

@@ -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, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -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);
}
}

View File

@@ -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, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -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];
} 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,
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*/

View File

@@ -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, <mgrca8@gmail.com>
*
@@ -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)
@@ -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++) {
if (hdd[c].bus == HDD_BUS_SCSI) {
hdd_image_close(c);
dev = hdd[c].priv;
if (dev) {
hdd_image_close(c);
free(dev);
hdd[c].priv = NULL;
}
}
}
}

View File

@@ -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;

View File

@@ -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, <http://pcem-emulator.co.uk/>
* TheCollector1995, <mariogplayer@gmail.com>
@@ -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;

File diff suppressed because it is too large Load Diff

View File

@@ -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, <mariogplayer@gmail.com>
* Miran Grca, <mgrca8@gmail.com>
@@ -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*/

View File

@@ -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, <mariogplayer@gmail.com>
* Miran Grca, <mgrca8@gmail.com>
@@ -261,32 +261,21 @@ 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 (len > 0) {
if (dev->phase == SCSI_PHASE_DATA_IN) {
scsi_device_command_phase1(dev);
if (len > 0) {
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);
}
DMAPageWrite(addr, dev->sc->temp_buffer, dev->buffer_length);
} else if (dev->phase == SCSI_PHASE_DATA_OUT) {
if (len > 0) {
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;
}
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);
}

View File

@@ -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, <mariogplayer@gmail.com>
* Miran Grca, <mgrca8@gmail.com>
@@ -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);

View File

@@ -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, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -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);
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++;

View File

@@ -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, <mgrca8@gmail.com>
# Fred N. van Kempen, <decwiz@yahoo.com>
@@ -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 \

View File

@@ -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, <mgrca8@gmail.com>
* David Hrdlička, <hrdlickadavid@outlook.com>
@@ -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;

View File

@@ -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, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -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]));

View File

@@ -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);