1
0
mirror of https://github.com/mist-devel/mist-firmware.git synced 2026-04-27 20:58:59 +00:00

ATAPI CDROM support

- PACKET command set and subset of MMC-3 in hdd.c
- ISO file "parsing" in cue_parser
- CDROM configuration in Minimig menu
This commit is contained in:
Gyorgy Szombathelyi
2022-08-15 01:17:13 +02:00
parent a72b3a4823
commit 067cce11be
10 changed files with 1017 additions and 218 deletions

View File

@@ -488,6 +488,9 @@ static void ApplyConfiguration(char reloadkickstart)
case HDF_CARD:
siprintf(s, "\nHardfile %d: using entire SD card", i);
break;
case HDF_CDROM:
siprintf(s, "\nHardfile %d: CDROM", i);
break;
default:
siprintf(s, "\nHardfile %d: using SD card partition %d", i, hdf[i].type-HDF_CARD); // Number from 1
break;

View File

@@ -4,6 +4,7 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "cue_parser.h"
#ifdef CUE_PARSER_TEST
#define cue_parser_debugf(a, ...) printf(a"\n", ## __VA_ARGS__)
@@ -19,6 +20,7 @@
#define TOKEN_AUDIO "AUDIO"
#define TOKEN_MODE1_2048 "MODE1/2048"
#define TOKEN_MODE1_2352 "MODE1/2352"
#define TOKEN_MODE2_2352 "MODE2/2352"
#define TOKEN_PREGAP "PREGAP"
#define TOKEN_INDEX "INDEX"
@@ -143,143 +145,177 @@ char cue_parse(const char *filename, IDXFile *image)
int track = 0, x, pregap = 0, tracklen;
msf_t msf;
int lba, lastindex1 = 0;
char e[3];
memset(&toc, 0, sizeof(toc));
// open ini file
#ifdef CUE_PARSER_TEST
if ((cue_fp = fopen(filename, "rb")) == NULL) {
#else
if (f_open(&cue_file, filename, FA_READ) != FR_OK) {
#endif
cue_parser_debugf("Can't open file %s !", filename);
return CUE_RES_NOTFOUND;
const char *ext = GetExtension(filename);
e[0] = e[1] = e[2] = ' ';
if (ext) {
if (ext[0]) e[0] = toupper(ext[0]);
if (ext[1]) e[1] = toupper(ext[1]);
if (ext[2]) e[2] = toupper(ext[2]);
}
#ifdef CUE_PARSER_TEST
fseek(cue_fp, 0L, SEEK_END);
cue_size = ftell(cue_fp);
fseek(cue_fp, 0L, SEEK_SET);
#else
cue_parser_debugf("Opened file %s with size %llu bytes.", filename, f_size(&cue_file));
#endif
cue_pt = 0;
// parse ini
while (1) {
// get line
word_status = cue_getword(word);
if (word_status != CUE_NOWORD) {
//cue_parser_debugf("next word(%d): \"%s\".", word_status, word);
switch (mode) {
case MODE_NONE:
submode = 0;
if (!strcmp(word, TOKEN_FILE)) mode = MODE_FILE; else
if (!strcmp(word, TOKEN_TRACK)) mode = MODE_TRACK; else
if (!strcmp(word, TOKEN_PREGAP)) mode = MODE_PREGAP; else
if (!strcmp(word, TOKEN_INDEX)) mode = MODE_INDEX;
break;
case MODE_FILE:
if (submode == 0) {
pregap = 0;
cue_parser_debugf("Filename: %s", word);
if (bin_valid) {
// only one .bin supported
error = CUE_RES_UNS;
} else {
#ifdef CUE_PARSER_TEST
bin_valid = 1;
}
#else
toc.file = image;
if (IDXOpen(toc.file, word, FA_READ) == FR_OK)
bin_valid = 1;
else
error = CUE_RES_BINERR;
}
#endif
} else if (submode == 1) {
cue_parser_debugf("Filemode: %s", word);
mode = 0;
}
submode++;
break;
case MODE_TRACK:
if (submode == 0) {
x = strtol(word, 0, 10);
cue_parser_debugf("Trackno: %d -> %d (%s)", track, x, word);
if (!x || x > 99 || x != (track + 1)) error = CUE_RES_INVALID; else track = x;
} else if (submode == 1) {
cue_parser_debugf("Trackmode: %s", word);
if (!strcmp(word, TOKEN_AUDIO)) {
toc.tracks[track-1].sector_size = 2352;
toc.tracks[track-1].type = SECTOR_AUDIO;
} else if (!strcmp(word, TOKEN_MODE1_2352)) {
toc.tracks[track-1].sector_size = 2352;
toc.tracks[track-1].type = SECTOR_DATA;
} else if (!strcmp(word, TOKEN_MODE1_2048)) {
toc.tracks[track-1].sector_size = 2048;
toc.tracks[track-1].type = SECTOR_DATA;
} else {
error = CUE_RES_INVALID;
}
mode = 0;
}
submode++;
break;
case MODE_PREGAP:
cue_parser_debugf("Pregap size: %s", word);
if (!ParseMSF(word, &msf)) {
error = CUE_RES_INVALID;
} else {
pregap += MSF2LBA(msf.m, msf.s, msf.f) + 150;
}
mode = 0;
break;
case MODE_INDEX:
if (submode == 0) {
cue_parser_debugf("Index: %s", word);
index = strtol(word, 0, 10);
} else if (submode == 1) {
if (!ParseMSF(word, &msf)) {
error = CUE_RES_INVALID;
} else {
lba = MSF2LBA(msf.m, msf.s, msf.f);
if (index == 0) {
if (track > 1 && !toc.tracks[track - 2].end) {
toc.tracks[track - 2].end = lba + 150 + pregap;
}
} else if (index == 1) {
toc.tracks[track - 1].start = lba + 150 + pregap;
if (track > 1) {
tracklen = lba - lastindex1;
toc.tracks[track - 1].offset = toc.tracks[track - 2].offset + (tracklen * toc.tracks[track - 2].sector_size);
if (!toc.tracks[track-2].end) toc.tracks[track - 2].end = toc.tracks[track - 1].start - 1;
} else {
toc.tracks[0].offset = (lba + 150) * toc.tracks[0].sector_size;
}
lastindex1 = lba;
}
}
cue_parser_debugf("Pos: (%s) = %d:%d:%d (%d)", word, msf.m, msf.s, msf.f, error);
mode = 0;
}
submode++;
break;
}
if (!memcmp(e, "ISO", 3)) {
// open iso file
#ifdef CUE_PARSER_TEST
bin_valid = 1;
#else
toc.file = image;
if (IDXOpen(toc.file, filename, FA_READ) == FR_OK) {
bin_valid = 1;
track = 1;
toc.tracks[0].sector_size = 2048;
toc.tracks[0].type = SECTOR_DATA;
toc.tracks[0].offset = 0;
toc.tracks[0].start = 0;
} else {
error = CUE_RES_BINERR;
}
// if end of file or error, stop
if (word_status == CUE_EOT || error) break;
#endif
} else {
// open cue file
#ifdef CUE_PARSER_TEST
if ((cue_fp = fopen(filename, "rb")) == NULL) {
#else
if (f_open(&cue_file, filename, FA_READ) != FR_OK) {
#endif
cue_parser_debugf("Can't open file %s !", filename);
return CUE_RES_NOTFOUND;
}
#ifdef CUE_PARSER_TEST
fseek(cue_fp, 0L, SEEK_END);
cue_size = ftell(cue_fp);
fseek(cue_fp, 0L, SEEK_SET);
#else
cue_parser_debugf("Opened file %s with size %llu bytes.", filename, f_size(&cue_file));
#endif
cue_pt = 0;
// parse cue
while (1) {
// get line
word_status = cue_getword(word);
if (word_status != CUE_NOWORD) {
//cue_parser_debugf("next word(%d): \"%s\".", word_status, word);
switch (mode) {
case MODE_NONE:
submode = 0;
if (!strcmp(word, TOKEN_FILE)) mode = MODE_FILE; else
if (!strcmp(word, TOKEN_TRACK)) mode = MODE_TRACK; else
if (!strcmp(word, TOKEN_PREGAP)) mode = MODE_PREGAP; else
if (!strcmp(word, TOKEN_INDEX)) mode = MODE_INDEX;
break;
case MODE_FILE:
if (submode == 0) {
pregap = 0;
cue_parser_debugf("Filename: %s", word);
if (bin_valid) {
// only one .bin supported
error = CUE_RES_UNS;
} else {
#ifdef CUE_PARSER_TEST
bin_valid = 1;
}
#else
toc.file = image;
if (IDXOpen(toc.file, word, FA_READ) == FR_OK)
bin_valid = 1;
else
error = CUE_RES_BINERR;
}
#endif
} else if (submode == 1) {
cue_parser_debugf("Filemode: %s", word);
mode = 0;
}
submode++;
break;
case MODE_TRACK:
if (submode == 0) {
x = strtol(word, 0, 10);
cue_parser_debugf("Trackno: %d -> %d (%s)", track, x, word);
if (!x || x > 99 || x != (track + 1)) error = CUE_RES_INVALID; else track = x;
} else if (submode == 1) {
cue_parser_debugf("Trackmode: %s", word);
if (!strcmp(word, TOKEN_AUDIO)) {
toc.tracks[track-1].sector_size = 2352;
toc.tracks[track-1].type = SECTOR_AUDIO;
} else if (!strcmp(word, TOKEN_MODE1_2352)) {
toc.tracks[track-1].sector_size = 2352;
toc.tracks[track-1].type = SECTOR_DATA;
} else if (!strcmp(word, TOKEN_MODE2_2352)) {
toc.tracks[track-1].sector_size = 2352;
toc.tracks[track-1].type = SECTOR_DATA;
} else if (!strcmp(word, TOKEN_MODE1_2048)) {
toc.tracks[track-1].sector_size = 2048;
toc.tracks[track-1].type = SECTOR_DATA;
} else {
error = CUE_RES_INVALID;
}
mode = 0;
}
submode++;
break;
case MODE_PREGAP:
cue_parser_debugf("Pregap size: %s", word);
if (!ParseMSF(word, &msf)) {
error = CUE_RES_INVALID;
} else {
pregap += MSF2LBA(msf.m, msf.s, msf.f) + 150;
}
mode = 0;
break;
case MODE_INDEX:
if (submode == 0) {
cue_parser_debugf("Index: %s", word);
index = strtol(word, 0, 10);
} else if (submode == 1) {
if (!ParseMSF(word, &msf)) {
error = CUE_RES_INVALID;
} else {
lba = MSF2LBA(msf.m, msf.s, msf.f);
if (index == 0) {
if (track > 1 && !toc.tracks[track - 2].end) {
toc.tracks[track - 2].end = lba + 150 + pregap;
}
} else if (index == 1) {
toc.tracks[track - 1].start = lba + 150 + pregap;
if (track > 1) {
tracklen = lba - lastindex1;
toc.tracks[track - 1].offset = toc.tracks[track - 2].offset + (tracklen * toc.tracks[track - 2].sector_size);
if (!toc.tracks[track-2].end) toc.tracks[track - 2].end = toc.tracks[track - 1].start - 1;
} else {
toc.tracks[0].offset = (lba + 150) * toc.tracks[0].sector_size;
}
lastindex1 = lba;
}
}
cue_parser_debugf("Pos: (%s) = %d:%d:%d (%d)", word, msf.m, msf.s, msf.f, error);
mode = 0;
}
submode++;
break;
}
}
// if end of file or error, stop
if (word_status == CUE_EOT || error) break;
}
#ifdef CUE_PARSER_TEST
// close file
fclose(cue_fp);
#else
f_close(&cue_file);
#endif
}
#ifdef CUE_PARSER_TEST
// close file
fclose(cue_fp);
#else
f_close(&cue_file);
#ifndef CUE_PARSET_TEST
if (!bin_valid)
error = CUE_RES_BINERR;
else if (error) f_close(&toc.file->file);
else if (error)
f_close(&toc.file->file);
else {
IDXIndex(toc.file);
if (track > 0) {
@@ -293,6 +329,7 @@ char cue_parse(const char *filename, IDXFile *image)
} else {
toc.last = track;
toc.end = toc.tracks[track-1].end;
toc.valid = 1;
}
iprintf("Tracks in the CUE file %s : %d\n", filename, toc.last);

View File

@@ -26,9 +26,9 @@ typedef struct
typedef struct
{
int valid;
int end;
int last;
int sectorSize;
cd_track_t tracks[100];
#ifndef CUE_PARSER_TEST
IDXFile *file; // the .bin file

659
hdd.c
View File

@@ -35,14 +35,33 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "hdd_internal.h"
#include "menu.h"
#include "fpga.h"
#include "scsi.h"
#include "cue_parser.h"
#include "debug.h"
hardfileTYPE *hardfile[HARDFILES];
// hardfile structure
hdfTYPE hdf[HARDFILES];
#define AUDIO_PLAYING 0x11
#define AUDIO_PAUSED 0x12
#define AUDIO_COMPLETE 0x13
#define AUDIO_ERROR 0x14
#define AUDIO_NOSTAT 0x15
typedef struct
{
unsigned char key;
unsigned char asc;
unsigned char ascq;
unsigned int currentlba;
unsigned int endlba;
unsigned char audiostatus;
} cdrom_t;
static cdrom_t cdrom;
static void SwapBytes(char *c, unsigned int len)
{
char temp;
@@ -229,6 +248,19 @@ static void IdentifyDevice(unsigned short *pBuffer, unsigned char unit)
pBuffer[61] = (unsigned short)(total_sectors >> 16);
}
// IdentifiyDevice()
// builds Identify Packet Device struct
static void IdentifyPacketDevice(unsigned short *pBuffer, unsigned char unit)
{
memset(pBuffer, 0, 512);
pBuffer[0] = 0x8580;
memcpy((char*)&pBuffer[10], "iMTSiMiniMCgRDMO ", 20); // serial number - byte swapped
memcpy((char*)&pBuffer[23], ".100 ", 8); // firmware version - byte swapped
memcpy((char*)&pBuffer[27], " ", 40); // Model number - byte swapped
pBuffer[49] = 0x0100;
pBuffer[53] = 1;
pBuffer[82] = 0x4214;
}
// chs2lba()
static unsigned long chs2lba(unsigned short cylinder, unsigned char head, unsigned short sector, unsigned char unit, char lbamode)
@@ -301,6 +333,559 @@ static void WriteStatus(unsigned char status)
DisableFpga();
}
static void WritePacket(unsigned char unit, const unsigned char *buf, unsigned short bufsize, char lastpacket)
{
unsigned short bytes;
while (bufsize) {
bytes = MIN(bufsize, 2048);
while (!(GetFPGAStatus() & CMD_IDECMD)); // wait for empty sector buffer
WriteTaskFile(0, 0x02, 0, bytes & 0xff, (bytes>>8) & 0xff, 0xa0 | ((unit & 0x01)<<4));
EnableFpga();
SPI(CMD_IDE_DATA_WR); // write data command
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
spi_write(buf, bytes);
DisableFpga();
buf += bytes;
bufsize -= bytes;
if (lastpacket && !bufsize)
WriteStatus(IDE_STATUS_IRQ | IDE_STATUS_END);
else
WriteStatus(IDE_STATUS_IRQ);
}
}
static void cdrom_setsense(unsigned char key, unsigned char asc, unsigned char ascq)
{
cdrom.key = key;
cdrom.asc = asc;
cdrom.ascq = ascq;
}
static void cdrom_ok()
{
cdrom.key = cdrom.asc = cdrom.ascq = 0;
}
static void cdrom_send_error(unsigned char unit)
{
WriteTaskFile((cdrom.key << 4) | 0x04, 0x03, 0, 0, 0, 0xa0 | ((unit & 0x01)<<4));
WriteStatus(IDE_STATUS_END | IDE_STATUS_ERR | IDE_STATUS_IRQ);
}
static void PKT_Read(unsigned char unit, unsigned int lba, unsigned int len, unsigned short bytelimit)
{
UINT br;
if (!toc.valid) {
cdrom_setsense(SENSEKEY_NOT_READY, 0x3a, 0);
cdrom_send_error(unit);
return;
}
cdrom.audiostatus = AUDIO_NOSTAT;
WriteStatus(IDE_STATUS_RDY | IDE_STATUS_PKT); // pio in (class 1) command type
while ((bytelimit >= 2048) && (len--)) {
unsigned char track = cue_gettrackbylba(lba);
int offset = (lba - toc.tracks[track].start) * toc.tracks[track].sector_size + toc.tracks[track].offset;
hdd_debugf("lba: %d track: %d, offset: %d", lba, track, offset);
if (toc.tracks[track].type != SECTOR_DATA) {
cdrom_setsense(SENSEKEY_ILLEGAL_REQUEST, 0x26, 2);
cdrom_send_error(unit);
return;
}
cdrom.currentlba = lba;
if (toc.tracks[track].sector_size != 2048) offset+=16;
f_lseek(&toc.file->file, offset);
f_read(&toc.file->file, sector_buffer, 2048, &br);
bytelimit-=2048;
lba++;
WritePacket(unit, sector_buffer, 2048, bytelimit < 2048);
}
cdrom_ok();
WriteStatus(IDE_STATUS_END);
}
static void PKT_Read12(unsigned char *cmd, unsigned char unit, unsigned short bytelimit)
{
hdd_debugf("IDE%d: PKT_Read12 (bufsize=%d)", unit, bytelimit);
unsigned int lba = cmd[5] | (cmd[4] << 8) | (cmd[3] << 16) | (cmd[2] << 24);
unsigned int len = cmd[9] | (cmd[8] << 8) | (cmd[7] << 16) | (cmd[6] << 24);
PKT_Read(unit, lba, len, bytelimit);
}
static void PKT_Read10(unsigned char *cmd, unsigned char unit, unsigned short bytelimit)
{
hdd_debugf("IDE%d: PKT_Read10 (bufsize=%d)", unit, bytelimit);
unsigned int lba = cmd[5] | (cmd[4] << 8) | (cmd[3] << 16) | (cmd[2] << 24);
unsigned int len = cmd[8] | (cmd[7] << 8);
PKT_Read(unit, lba, len, bytelimit);
}
static void PKT_PlayAudio(unsigned char unit, unsigned int start, unsigned int end)
{
if (!toc.valid) {
cdrom_setsense(SENSEKEY_NOT_READY, 0x3a, 0);
cdrom_send_error(unit);
return;
}
if (start > toc.end || end > toc.end || start > end) {
cdrom_setsense(SENSEKEY_ILLEGAL_REQUEST, 0x21, 0);
cdrom_send_error(unit);
return;
}
unsigned char track = cue_gettrackbylba(start);
if (toc.tracks[track].type != SECTOR_AUDIO) {
cdrom_setsense(SENSEKEY_ILLEGAL_REQUEST, 0x64, 0);
cdrom_send_error(unit);
return;
}
cdrom.currentlba = start;
cdrom.endlba = end;
cdrom.audiostatus = AUDIO_PLAYING;
cdrom_ok();
WriteTaskFile(0, 0x03, 0, 0, 0, 0xa0 | ((unit & 0x01)<<4));
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
}
static void PKT_PlayAudioMSF(unsigned char *cmd, unsigned char unit)
{
hdd_debugf("IDE%d: PKT_PlayAudioMSF", unit);
unsigned int start = (cmd[2] == 0xff && cmd[3] == 0xff && cmd[5] == 0xff) ? cdrom.currentlba : MSF2LBA(cmd[3], cmd[4], cmd[5]);
unsigned int end = MSF2LBA(cmd[6], cmd[7], cmd[8]);
PKT_PlayAudio(unit, start, end);
}
static void PKT_PlayAudio10(unsigned char *cmd, unsigned char unit)
{
hdd_debugf("IDE%d: PKT_PlayAudio10", unit);
unsigned int start = (cmd[2] << 24) | (cmd[3] << 16) | (cmd[4] << 8) | cmd[5];
if (start == 0xffffffff) start = cdrom.currentlba;
unsigned int end = start + (cmd[7] << 8) + cmd[8];
PKT_PlayAudio(unit, start, end);
}
static void PKT_PauseResume(unsigned char *cmd, unsigned char unit)
{
hdd_debugf("IDE%d: PKT_PauseResume", unit);
int resume = cmd[8] & 0x01;
if (!toc.valid) {
cdrom_setsense(SENSEKEY_NOT_READY, 0x3a, 0);
cdrom_send_error(unit);
return;
}
if ((resume && cdrom.audiostatus != AUDIO_PAUSED) || (!resume && cdrom.audiostatus != AUDIO_PLAYING)) {
cdrom_setsense(SENSEKEY_ILLEGAL_REQUEST, 0x2c, 0);
cdrom_send_error(unit);
} else {
cdrom.audiostatus = resume ? AUDIO_PLAYING : AUDIO_PAUSED;
cdrom_ok();
WriteTaskFile(0, 0x03, 0, 0, 0, 0xa0 | ((unit & 0x01)<<4));
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
}
}
static void PKT_StopPlayScan(unsigned char *cmd, unsigned char unit)
{
hdd_debugf("IDE%d: PKT_StopPlayScan", unit);
if (!toc.valid) {
cdrom_setsense(SENSEKEY_NOT_READY, 0x3a, 0);
cdrom_send_error(unit);
return;
}
cdrom.audiostatus = AUDIO_NOSTAT;
cdrom_ok();
WriteTaskFile(0, 0x03, 0, 0, 0, 0xa0 | ((unit & 0x01)<<4));
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
}
static void PKT_SubChannel(unsigned char *cmd, unsigned char unit, unsigned short bytelimit)
{
hdd_debugf("IDE%d: PKT_SubChannel (bufsize=%d)", unit, bytelimit);
unsigned short bufsize = MIN(bytelimit, (cmd[7] << 8) | cmd[8]);
unsigned char track;
unsigned char msftime = cmd[1] & 0x02;
unsigned short respsize = 0;
if (!toc.valid) {
cdrom_setsense(SENSEKEY_NOT_READY, 0x3a, 0);
cdrom_send_error(unit);
return;
}
track = cue_gettrackbylba(cdrom.currentlba);
if (track >= toc.last) track = toc.last - 1;
memset(sector_buffer, 0, 24);
sector_buffer[1] = cdrom.audiostatus;
switch (cmd[3]) {
case 1:
// current position
respsize = (cmd[2] & 0x40) ? 16 : 4;
sector_buffer[4] = 0x01;
sector_buffer[5] = (1 << 4) | ((toc.tracks[track-1].type == SECTOR_DATA) ? 4 : 0);
sector_buffer[6] = track + 1;
sector_buffer[7] = cdrom.currentlba >= toc.tracks[track].start ? 1 : 0; // TODO: support more than 1 indices
unsigned int rellba = cdrom.currentlba - toc.tracks[track].start;
iprintf("track = %d, rellba = %d\n", track, rellba);
if (msftime) {
msf_t MSF;
LBA2MSF(cdrom.currentlba+150, &MSF);
sector_buffer[9] = MSF.m;
sector_buffer[10] = MSF.s;
sector_buffer[11] = MSF.f;
LBA2MSF(rellba, &MSF);
sector_buffer[13] = MSF.m;
sector_buffer[14] = MSF.s;
sector_buffer[15] = MSF.f;
} else {
sector_buffer[8] = (cdrom.currentlba >> 24) & 0xff;
sector_buffer[9] = (cdrom.currentlba >> 16) & 0xff;
sector_buffer[10] = (cdrom.currentlba >> 8) & 0xff;
sector_buffer[11] = cdrom.currentlba & 0xff;
sector_buffer[12] = (rellba >> 24) & 0xff;
sector_buffer[13] = (rellba >> 16) & 0xff;
sector_buffer[14] = (rellba >> 8) & 0xff;
sector_buffer[15] = rellba & 0xff;
}
break;
case 2:
// Media Catalog number
respsize = 24;
sector_buffer[4] = 0x02;
break;
case 3:
// ISRC
respsize = 24;
sector_buffer[4] = 0x02;
break;
default:
// reserved
break;
}
sector_buffer[3] = respsize - 4;
cdrom_ok();
bufsize = MIN(bufsize, respsize);
WriteStatus(IDE_STATUS_RDY | IDE_STATUS_PKT); // pio in (class 1) command type
WritePacket(unit, sector_buffer, bufsize, 1);
}
static void PKT_ReadCapacity(unsigned char *cmd, unsigned char unit, unsigned short bytelimit)
{
hdd_debugf("IDE%d: PKT_ReadCapacity (bufsize=%d)", unit, bytelimit);
if (!toc.valid) {
cdrom_setsense(SENSEKEY_NOT_READY, 0x3a, 0);
cdrom_send_error(unit);
return;
}
sector_buffer[0] = (toc.end >> 24) & 0xff;
sector_buffer[1] = (toc.end >> 16) & 0xff;
sector_buffer[2] = (toc.end >> 8) & 0xff;
sector_buffer[3] = toc.end & 0xff;
sector_buffer[4] = sector_buffer[5] = 0;
sector_buffer[6] = (2048 >> 8) & 0xff;
sector_buffer[7] = 2048 & 0xff;
hexdump(sector_buffer, 8, 0);
cdrom_ok();
WriteStatus(IDE_STATUS_RDY | IDE_STATUS_PKT); // pio in (class 1) command type
WritePacket(unit, sector_buffer, MIN(bytelimit, 8), 1);
}
static void PKT_ReadTOC(unsigned char *cmd, unsigned char unit, unsigned short bytelimit)
{
hdd_debugf("IDE%d: PKT_ReadTOC (bufsize=%d)", unit, bytelimit);
unsigned short bufsize = MIN(bytelimit, (cmd[7] << 8) | cmd[8]);
unsigned char track = cmd[6];
unsigned char msftime = cmd[1] & 0x02;
unsigned short tocsize = 2;
unsigned char *p = sector_buffer;
int lba;
if (!toc.valid) {
cdrom_setsense(SENSEKEY_NOT_READY, 0x3a, 0);
cdrom_send_error(unit);
return;
}
switch(cmd[2] & 0x0f) {
case 0:
hdd_debugf("TOC format 0");
if (track > toc.last && track != 0xAA) {
cdrom_setsense(SENSEKEY_ILLEGAL_REQUEST, 0x26, 2);
cdrom_send_error(unit);
return;
}
sector_buffer[2] = 1;
sector_buffer[3] = toc.last;
p += 4;
for (int i=1; i<=toc.last; i++) {
if (i>=track) {
p[0] = p[3] = 0;
p[1] = (1 << 4) | ((toc.tracks[i-1].type == SECTOR_DATA) ? 4 : 0);
p[2] = i;
lba = toc.tracks[i-1].start;
hdd_debugf("track %d lba: %d", i, lba);
if (msftime) {
msf_t MSF;
LBA2MSF(lba+150, &MSF);
p[4] = 0;
p[5] = MSF.m;
p[6] = MSF.s;
p[7] = MSF.f;
} else {
p[4] = (lba >> 24) & 0xff;
p[5] = (lba >> 16) & 0xff;
p[6] = (lba >> 8) & 0xff;
p[7] = lba & 0xff;
}
p+=8;
tocsize+=8;
}
}
p[0] = p[3] = 0;
p[1] = 0x14;
p[2] = 0xAA;
lba = toc.end;
if (msftime) {
msf_t MSF;
LBA2MSF(lba+150, &MSF);
p[4] = 0;
p[5] = MSF.m;
p[6] = MSF.s;
p[7] = MSF.f;
} else {
p[4] = (lba >> 24) & 0xff;
p[5] = (lba >> 16) & 0xff;
p[6] = (lba >> 8) & 0xff;
p[7] = lba & 0xff;
}
tocsize += 8;
break;
case 1:
hdd_debugf("TOC format 1");
tocsize = 12;
memset(sector_buffer, 0, tocsize);
sector_buffer[2] = sector_buffer[3] = 1; // first/last session numbers
sector_buffer[5] = (1 << 4) | ((toc.tracks[0].type == SECTOR_DATA) ? 4 : 0);
sector_buffer[6] = 1;
lba = toc.tracks[0].start;
if (msftime) {
msf_t MSF;
LBA2MSF(lba+150, &MSF);
sector_buffer[5] = MSF.m;
sector_buffer[6] = MSF.s;
sector_buffer[7] = MSF.f;
} else {
sector_buffer[4] = (lba >> 24) & 0xff;
sector_buffer[5] = (lba >> 16) & 0xff;
sector_buffer[6] = (lba >> 8) & 0xff;
sector_buffer[7] = lba & 0xff;
}
break;
default:
cdrom_setsense(SENSEKEY_ILLEGAL_REQUEST, 0x26, 1);
cdrom_send_error(unit);
return;
}
sector_buffer[0] = (tocsize>>8) & 0xff;
sector_buffer[1] = tocsize & 0xff;
cdrom_ok();
bufsize = MIN(bufsize, tocsize);
hexdump(sector_buffer, bufsize, 0);
WriteStatus(IDE_STATUS_RDY | IDE_STATUS_PKT); // pio in (class 1) command type
WritePacket(unit, sector_buffer, bufsize, 1);
}
static void PKT_ModeSense(unsigned char *cmd, unsigned char unit, unsigned short bytelimit, unsigned char page)
{
//TODO: implement
cdrom_setsense(SENSEKEY_ILLEGAL_REQUEST, 0x20, 0);
cdrom_send_error(unit);
}
static void PKT_ModeSense10(unsigned char *cmd, unsigned char unit, unsigned short bytelimit)
{
hdd_debugf("IDE%d: PKT_ModeSense10 (bufsize=%d)", unit, bytelimit);
unsigned short bufsize = MIN(bytelimit, (cmd[7] << 8) | cmd[8]);
unsigned char page = cmd[2] & 0x3f;
PKT_ModeSense(cmd, unit, bytelimit, page);
}
static void PKT_ModeSense6(unsigned char *cmd, unsigned char unit, unsigned short bytelimit)
{
hdd_debugf("IDE%d: PKT_ModeSense6 (bufsize=%d)", unit, bytelimit);
unsigned short bufsize = MIN(bytelimit, cmd[4]);
unsigned char page = cmd[2] & 0x3f;
PKT_ModeSense(cmd, unit, bytelimit, page);
}
static void PKT_Inquiry(unsigned char *cmd, unsigned char unit, unsigned short bytelimit)
{
hdd_debugf("IDE%d: PKT_Inquiry (bufsize=%d)", unit, bytelimit);
unsigned short bufsize = MIN(bytelimit, (cmd[3] << 8) | cmd[4]);
INQUIRYDATA_t *inq = (INQUIRYDATA_t*)&sector_buffer;
memset(sector_buffer, 0, 36);
inq->DeviceType = 0x05; // MMC3
inq->RemovableMedia = 1; // removable
inq->Versions = 0x02;
inq->ResponseDataFormat = 0x02;
memcpy(inq->VendorId, "MiST ", 8);
memcpy(inq->ProductId, "CDROM ", 16);
bufsize = MIN(bufsize, 36);
cdrom_ok();
WriteStatus(IDE_STATUS_RDY | IDE_STATUS_PKT); // pio in (class 1) command type
WritePacket(unit, sector_buffer, bufsize, 1);
}
static void PKT_TestUnitReady(unsigned char *cmd, unsigned char unit)
{
hdd_debugf("IDE%d: PKT_TestUnitReady", unit);
WriteTaskFile(0, 0x03, 0, 0, 0, 0xa0 | ((unit & 0x01)<<4));
if (toc.valid) {
cdrom_ok();
WriteTaskFile(0, 0x03, 0, 0, 0, 0xa0 | ((unit & 0x01)<<4));
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
} else {
cdrom_setsense(SENSEKEY_NOT_READY, 0x3a, 0);
cdrom_send_error(unit);
WriteStatus(IDE_STATUS_END | IDE_STATUS_ERR | IDE_STATUS_IRQ);
}
}
static void PKT_RequestSense(unsigned char *cmd, unsigned char unit, unsigned short bytelimit)
{
hdd_debugf("IDE%d: PKT_RequestSense (bufsize=%d)", unit, bytelimit);
unsigned short bufsize = MIN(bytelimit, cmd[4]);
SENSEDATA_t *sense = (SENSEDATA_t*)&sector_buffer;
memset(sector_buffer, 0, 16);
sense->ErrorCode = 0x70;
sense->Valid = 1;
sense->SenseKey = cdrom.key;
sense->AdditionalSenseCode = cdrom.asc;
sense->AdditionalSenseCodeQualifier = cdrom.ascq;
bufsize = MIN(bufsize, 16);
WriteStatus(IDE_STATUS_RDY | IDE_STATUS_PKT); // pio in (class 1) command type
WritePacket(unit, sector_buffer, bufsize, 1);
}
static void PKT_StartStopUnit(unsigned char *cmd, unsigned char unit)
{
hdd_debugf("IDE%d: PKT_StartStopUnit", unit);
char start = cmd[4] & 0x01;
if ((start && toc.valid) || !start) {
cdrom_ok();
WriteTaskFile(0, 0x03, 0, 0, 0, 0xa0 | ((unit & 0x01)<<4));
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
} else {
cdrom_setsense(SENSEKEY_NOT_READY, 0x3A, 0);
cdrom_send_error(unit);
}
}
// ATA_Packet()
static inline void ATA_Packet(unsigned char *tfr, unsigned char unit, unsigned short bytelimit)
{
unsigned char cmdpkt[12];
hdd_debugf("IDE%d: ATA_Packet", unit);
if (hdf[unit].type != HDF_CDROM) {
tfr[TFR_ERR] = 0x02; // command aborted
WriteTaskFile(tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ | IDE_STATUS_ERR);
return;
}
if (!bytelimit) bytelimit = 0xfffe;
tfr[TFR_ERR] = 0x00;
tfr[TFR_SCOUNT] = 0x01; //C/D flag
WriteTaskFile(tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
WriteStatus(IDE_STATUS_REQ | IDE_STATUS_PKT); // wait for command packet
unsigned long to = GetTimer(20);
while (!(GetFPGAStatus() & CMD_IDEDAT)) { // wait for full write buffer
if (CheckTimer(to)) {
cdrom_setsense(SENSEKEY_NOT_READY, 0x04, 0);
cdrom_send_error(unit);
return;
}
}
EnableFpga();
SPI(CMD_IDE_DATA_RD); // read data command
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
SPI(0x00);
for (int i=0; i<12; i++) {
cmdpkt[i] = SPI(0xFF);
}
DisableFpga();
hdd_debugf("CMD: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
cmdpkt[0], cmdpkt[1], cmdpkt[2], cmdpkt[3], cmdpkt[4], cmdpkt[5],
cmdpkt[6], cmdpkt[7], cmdpkt[8], cmdpkt[9], cmdpkt[10], cmdpkt[11]);
switch(cmdpkt[0]) {
case 0:
PKT_TestUnitReady(cmdpkt, unit);
break;
case 3:
PKT_RequestSense(cmdpkt, unit, bytelimit);
break;
case 0x12:
PKT_Inquiry(cmdpkt, unit, bytelimit);
break;
case 0x1a:
PKT_ModeSense6(cmdpkt, unit, bytelimit);
break;
case 0x5a:
PKT_ModeSense10(cmdpkt, unit, bytelimit);
break;
case 0x43:
PKT_ReadTOC(cmdpkt, unit, bytelimit);
break;
case 0x25:
PKT_ReadCapacity(cmdpkt, unit, bytelimit);
break;
case 0x28:
PKT_Read10(cmdpkt, unit, bytelimit);
break;
case 0xA8:
PKT_Read12(cmdpkt, unit, bytelimit);
break;
case 0x42:
PKT_SubChannel(cmdpkt, unit, bytelimit);
break;
case 0x45:
PKT_PlayAudio10(cmdpkt, unit);
break;
case 0x47:
PKT_PlayAudioMSF(cmdpkt, unit);
break;
case 0x4B:
PKT_PauseResume(cmdpkt, unit);
break;
case 0x4E:
PKT_StopPlayScan(cmdpkt, unit);
break;
case 0x1B:
PKT_StartStopUnit(cmdpkt, unit);
break;
default:
iprintf("HDD%d: Unknown PACKET command: %02x\n", unit, cmdpkt[0]);
cdrom_setsense(SENSEKEY_ILLEGAL_REQUEST, 0x3a, 0);
cdrom_send_error(unit);
break;
}
}
// ATA_Recalibrate()
static inline void ATA_Recalibrate(unsigned char* tfr, unsigned char unit)
@@ -321,15 +906,37 @@ static inline void ATA_Diagnostic(unsigned char* tfr)
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
}
// ATA_IdentifyDevice()
static inline void ATA_IdentifyDevice(unsigned char* tfr, unsigned char unit)
static void ATA_IdentifyDevice(unsigned char* tfr, unsigned char unit, char packet)
{
int i;
unsigned short *id = (unsigned short *)sector_buffer;
// Identify Device (0xec)
hdd_debugf("IDE%d: Identify Device", unit);
IdentifyDevice(id, unit);
hdd_debugf("IDE%d: Identify %s Device", unit, packet ? "Packet" : "");
tfr[TFR_SCOUNT] = 0x01;
tfr[TFR_SNUM] = 0x01;
if (hdf[unit].type == HDF_CDROM) {
tfr[TFR_ERR] = 0x02; // command aborted
tfr[TFR_CYLL] = 0x14;
tfr[TFR_CYLH] = 0xEB;
tfr[TFR_SDH] = 0x00;
} else {
tfr[TFR_ERR] = 0x00;
tfr[TFR_CYLL] = 0x00;
tfr[TFR_CYLH] = 0x00;
tfr[TFR_SDH] = 0x00;
}
if ((!packet && hdf[unit].type == HDF_CDROM) || (packet && hdf[unit].type != HDF_CDROM)) {
WriteTaskFile(tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ | IDE_STATUS_ERR);
return;
}
if (packet)
IdentifyPacketDevice(id, unit);
else
IdentifyDevice(id, unit);
WriteTaskFile(0, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type
EnableFpga();
@@ -369,6 +976,30 @@ static inline void ATA_SetMultipleMode(unsigned char* tfr, unsigned char unit)
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
}
static inline void ATA_NOP(unsigned char *tfr, unsigned char unit)
{
WriteTaskFile(tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
}
static inline void ATA_DeviceReset(unsigned char *tfr, unsigned char unit)
{
hdd_debugf("Device Reset");
hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]);
tfr[TFR_SCOUNT] = 0x01;
tfr[TFR_SNUM] = 0x01;
tfr[TFR_ERR] = 0x00;
//tfr[TFR_SDH] = 0x00;
if (hdf[unit].type == HDF_CDROM) {
tfr[TFR_CYLL] = 0x14;
tfr[TFR_CYLH] = 0xEB;
} else {
tfr[TFR_CYLL] = 0x00;
tfr[TFR_CYLH] = 0x00;
}
WriteTaskFile(tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]);
WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ);
}
// ATA_ReadSectors()
static inline void ATA_ReadSectors(unsigned char* tfr, unsigned short sector, unsigned short cylinder, unsigned char head, unsigned char unit, unsigned short sector_count, unsigned char multiple, char lbamode)
@@ -663,7 +1294,9 @@ void HandleHDD(unsigned char c1, unsigned char c2, unsigned char cs1ena)
} else if (tfr[7] == ACMD_DIAGNOSTIC) {
ATA_Diagnostic(tfr);
} else if (tfr[7] == ACMD_IDENTIFY_DEVICE) {
ATA_IdentifyDevice(tfr, unit);
ATA_IdentifyDevice(tfr, unit, 0);
} else if (tfr[7] == ACMD_IDENTIFY_PACKET_DEVICE) {
ATA_IdentifyDevice(tfr, unit, 1);
} else if (tfr[7] == ACMD_INITIALIZE_DEVICE_PARAMETERS) {
ATA_Initialize(tfr, unit);
} else if (tfr[7] == ACMD_SET_MULTIPLE_MODE) {
@@ -676,6 +1309,12 @@ void HandleHDD(unsigned char c1, unsigned char c2, unsigned char cs1ena)
ATA_WriteSectors(tfr, sector, cylinder, head, unit, sector_count ,0, lbamode);
} else if (tfr[7] == ACMD_WRITE_MULTIPLE) {
ATA_WriteSectors(tfr, sector, cylinder, head, unit, sector_count, 1, lbamode);
} else if (tfr[7] == ACMD_PACKET) {
ATA_Packet(tfr, unit, cylinder);
} else if (tfr[7] == ACMD_DEVICE_RESET) {
ATA_DeviceReset(tfr, unit);
} else if (tfr[7] == ACMD_NOP) {
ATA_NOP(tfr, unit);
} else {
hdd_debugf("Unknown ATA command");
hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]);
@@ -812,6 +1451,14 @@ unsigned char OpenHardfile(unsigned char unit)
GetHardfileGeometry(&hdf[unit]);
return 1;
break;
case HDF_CDROM:
hdf[unit].type = HDF_CDROM;
hardfile[unit]->present = 1;
cdrom.key = cdrom.asc = cdrom.ascq = 0;
cdrom.currentlba = 0;
cdrom.audiostatus = AUDIO_NOSTAT;
return 1;
break;
}
hardfile[unit]->present = 0;
return 0;

16
hdd.h
View File

@@ -17,11 +17,14 @@
#define CMD_IDE_STATUS_WR 0xF0
#define IDE_STATUS_END 0x80
#define IDE_STATUS_PKT 0x20
#define IDE_STATUS_IRQ 0x10
#define IDE_STATUS_RDY 0x08
#define IDE_STATUS_REQ 0x04
#define IDE_STATUS_ERR 0x01
#define ACMD_NOP 0x00
#define ACMD_DEVICE_RESET 0x08
#define ACMD_RECALIBRATE 0x10
#define ACMD_DIAGNOSTIC 0x90
#define ACMD_IDENTIFY_DEVICE 0xEC
@@ -31,6 +34,8 @@
#define ACMD_READ_MULTIPLE 0xC4
#define ACMD_WRITE_MULTIPLE 0xC5
#define ACMD_SET_MULTIPLE_MODE 0xC6
#define ACMD_PACKET 0xA0
#define ACMD_IDENTIFY_PACKET_DEVICE 0xA1
#define HDF_DISABLED 0
#define HDF_FILE 1
@@ -39,6 +44,7 @@
#define HDF_CARDPART1 4
#define HDF_CARDPART2 5
#define HDF_CARDPART3 6
#define HDF_CDROM 10
#define HDF_TYPEMASK 15
#define HDF_SYNTHRDB 128 // flag to indicate whether we should auto-synthesize a RigidDiskBlock
@@ -49,10 +55,18 @@
#define HARDFILES 4
#define TFR_ERR 1
#define TFR_SCOUNT 2
#define TFR_SNUM 3
#define TFR_CYLL 4
#define TFR_CYLH 5
#define TFR_SDH 6
#define TFR_STAT 7
// types
typedef struct
{
unsigned char enabled; // 0: Disabled, 1: Hard file, 2: MMC (entire card), 3-6: Partition 1-4 of MMC card
unsigned char enabled; // 0: Disabled, 1: Hard file, 2: MMC (entire card), 3-6: Partition 1-4 of MMC card, 10-CDROM
unsigned char present;
char name[64];
} hardfileTYPE;

View File

@@ -13,6 +13,7 @@
#include "boot.h"
#include "user_io.h"
#include "misc_cfg.h"
#include "cue_parser.h"
// TODO!
#define SPIN() asm volatile ( "mov r0, r0\n\t" \
@@ -201,6 +202,20 @@ static char HardFileSelected(uint8_t idx, const char *SelectedName) {
return 0;
}
static char CueISOFileSelected(uint8_t idx, const char *SelectedName) {
int hdf_idx;
if (idx == 10) // master drive selected
hdf_idx = t_ide_idx << 1;
else if (idx == 12) // slave drive selected
hdf_idx = (t_ide_idx << 1) + 1;
else // invalid
return 0;
char res;
res = cue_parse(SelectedName, &sd_image[hdf_idx]);
if (res) ErrorMessage(cue_error_msg[res-1], res);
}
static char KickstartReload(uint8_t idx) {
if (idx == 0) {// yes
CloseMenu();
@@ -409,6 +424,8 @@ static char GetMenuItem_Minimig(uint8_t idx, char action, menu_item_t *item) {
strcpy(s, slave ? " Slave : " : " Master : ");
if(config.hardfile[(t_ide_idx << 1)+slave].enabled==(HDF_FILE|HDF_SYNTHRDB))
strcat(s,"Hardfile (filesys)");
else if(config.hardfile[(t_ide_idx << 1)+slave].enabled==HDF_CDROM)
strcat(s,"CDROM");
else
strcat(s, config_hdf_msg[config.hardfile[(t_ide_idx << 1)+slave].enabled & HDF_TYPEMASK]);
item->item = s;
@@ -421,11 +438,14 @@ static char GetMenuItem_Minimig(uint8_t idx, char action, menu_item_t *item) {
uint8_t slave = idx == 12;
if (config.hardfile[(t_ide_idx << 1)+slave].present) {
strcpy(s, " ");
strncpy(&s[14], config.hardfile[(t_ide_idx << 1)+slave].name, sizeof(config.hardfile[0].name));
if(config.hardfile[(t_ide_idx << 1)+slave].enabled == HDF_CDROM)
strcpy(&s[14], toc.valid ? "* Inserted *" : "* Empty *");
else
strncpy(&s[14], config.hardfile[(t_ide_idx << 1)+slave].name, sizeof(config.hardfile[0].name));
} else
strcpy(s, " ** file not found **");
item->item = s;
item->active = config.enable_ide[t_ide_idx] && ((config.hardfile[(t_ide_idx << 1)+slave].enabled&HDF_TYPEMASK)==HDF_FILE);
item->active = config.enable_ide[t_ide_idx] && (config.hardfile[(t_ide_idx << 1)+slave].enabled&HDF_TYPEMASK&(HDF_FILE | HDF_CDROM));
item->stipple = !item->active;
}
break;
@@ -623,15 +643,35 @@ static char GetMenuItem_Minimig(uint8_t idx, char action, menu_item_t *item) {
} else if(config.hardfile[hdf_idx].enabled==(HDF_FILE|HDF_SYNTHRDB)) {
config.hardfile[hdf_idx].enabled&=~HDF_SYNTHRDB;
config.hardfile[hdf_idx].enabled +=1;
} else if(config.hardfile[hdf_idx].enabled==(HDF_CARDPART0+partitioncount)) {
// only one CDROM is supported, so check if already choosen
if (config.hardfile[0].enabled != HDF_CDROM &&
config.hardfile[1].enabled != HDF_CDROM &&
config.hardfile[2].enabled != HDF_CDROM &&
config.hardfile[3].enabled != HDF_CDROM) {
config.hardfile[hdf_idx].enabled = HDF_CDROM;
} else {
config.hardfile[hdf_idx].enabled = HDF_FILE;
}
} else if(config.hardfile[hdf_idx].enabled==HDF_CDROM) {
config.hardfile[hdf_idx].enabled = HDF_FILE;
} else {
config.hardfile[hdf_idx].enabled +=1;
config.hardfile[hdf_idx].enabled %=HDF_CARDPART0+partitioncount;
}
}
break;
case 10:
case 12:
SelectFileNG("HDF", SCAN_LFN, HardFileSelected, 0);
case 12: {
uint8_t hdf_idx = (t_ide_idx << 1) + (idx == 12);
if(config.hardfile[hdf_idx].enabled==HDF_CDROM) {
if(toc.valid)
toc.valid = 0;
else
SelectFileNG("CUEISO", SCAN_DIR | SCAN_LFN, CueISOFileSelected, 0);
} else {
SelectFileNG("HDF", SCAN_LFN, HardFileSelected, 0);
}
}
break;
// Page 2 - Settings

82
scsi.h Normal file
View File

@@ -0,0 +1,82 @@
/*
scsi.h
*/
#ifndef SCSI_H
#define SCSI_H
#define SENSEKEY_NO_SENSE 0x0
#define SENSEKEY_SOFT_ERROR 0x1
#define SENSEKEY_NOT_READY 0x2
#define SENSEKEY_MEDIUM_ERROR 0x3
#define SENSEKEY_HARDWARE_ERROR 0x4
#define SENSEKEY_ILLEGAL_REQUEST 0x5
#define SENSEKEY_UNIT_ATTENTION 0x6
#define SENSEKEY_ABORTED_COMMAND 0xB
typedef struct {
uint8_t DeviceType : 5;
uint8_t DeviceTypeQualifier : 3;
uint8_t DeviceTypeModifier : 7;
uint8_t RemovableMedia : 1;
uint8_t Versions;
uint8_t ResponseDataFormat : 4;
uint8_t HiSupport : 1;
uint8_t NormACA : 1;
uint8_t ReservedBit : 1;
uint8_t AERC : 1;
uint8_t AdditionalLength;
uint8_t Reserved[2];
uint8_t SoftReset : 1;
uint8_t CommandQueue : 1;
uint8_t Reserved2 : 1;
uint8_t LinkedCommands : 1;
uint8_t Synchronous : 1;
uint8_t Wide16Bit : 1;
uint8_t Wide32Bit : 1;
uint8_t RelativeAddressing : 1;
uint8_t VendorId[8];
uint8_t ProductId[16];
uint8_t ProductRevisionLevel[4];
uint8_t VendorSpecific[20];
uint8_t Reserved3[2];
uint8_t VersionDescriptors[8];
uint8_t Reserved4[30];
} __attribute__ ((packed)) INQUIRYDATA_t;
typedef struct {
uint8_t ErrorCode :7;
uint8_t Valid :1;
uint8_t SegmentNumber;
uint8_t SenseKey :4;
uint8_t Reserved :1;
uint8_t IncorrectLength :1;
uint8_t EndOfMedia :1;
uint8_t FileMark :1;
uint8_t Information[4];
uint8_t AdditionalSenseLength;
uint8_t CommandSpecificInformation[4];
uint8_t AdditionalSenseCode;
uint8_t AdditionalSenseCodeQualifier;
uint8_t FieldReplaceableUnitCode;
uint8_t SenseKeySpecific[3];
} __attribute__ ((packed)) SENSEDATA_t;
typedef struct {
uint32_t LBA;
uint32_t blocklen;
} __attribute__ ((packed)) CAPACITYDATA_t;
typedef struct {
uint8_t Reserved[3];
uint8_t Length;
uint32_t Blocks;
uint8_t DescriptorType :1;
uint8_t Reserved2 : 7;
uint8_t Blocklen[3];
} __attribute__ ((packed)) FORMATCAPACITYDATA_t;
#endif

View File

@@ -8,6 +8,7 @@
#include <stdio.h>
#include "swab.h"
#include "scsi.h"
#include "utils.h"
#include "storage_control.h"
#include "fat_compat.h"
@@ -15,14 +16,6 @@
#include "FatFs/diskio.h"
#include "debug.h"
#define SENSEKEY_NO_SENSE 0x0
#define SENSEKEY_NOT_READY 0x2
#define SENSEKEY_MEDIUM_ERROR 0x3
#define SENSEKEY_HARDWARE_ERROR 0x4
#define SENSEKEY_ILLEGAL_REQUEST 0x5
#define SENSEKEY_UNIT_ATTENTION 0x6
#define SENSEKEY_ABORTED_COMMAND 0xB
typedef struct
{
uint8_t key;
@@ -49,68 +42,6 @@ typedef struct {
uint8_t bCSWStatus;
} __attribute__ ((packed)) CSW_t;
typedef struct {
uint8_t DeviceType : 5;
uint8_t DeviceTypeQualifier : 3;
uint8_t DeviceTypeModifier : 7;
uint8_t RemovableMedia : 1;
uint8_t Versions;
uint8_t ResponseDataFormat : 4;
uint8_t HiSupport : 1;
uint8_t NormACA : 1;
uint8_t ReservedBit : 1;
uint8_t AERC : 1;
uint8_t AdditionalLength;
uint8_t Reserved[2];
uint8_t SoftReset : 1;
uint8_t CommandQueue : 1;
uint8_t Reserved2 : 1;
uint8_t LinkedCommands : 1;
uint8_t Synchronous : 1;
uint8_t Wide16Bit : 1;
uint8_t Wide32Bit : 1;
uint8_t RelativeAddressing : 1;
uint8_t VendorId[8];
uint8_t ProductId[16];
uint8_t ProductRevisionLevel[4];
uint8_t VendorSpecific[20];
uint8_t Reserved3[2];
uint8_t VersionDescriptors[8];
uint8_t Reserved4[30];
} __attribute__ ((packed)) INQUIRYDATA_t;
typedef struct {
uint8_t ErrorCode :7;
uint8_t Valid :1;
uint8_t SegmentNumber;
uint8_t SenseKey :4;
uint8_t Reserved :1;
uint8_t IncorrectLength :1;
uint8_t EndOfMedia :1;
uint8_t FileMark :1;
uint8_t Information[4];
uint8_t AdditionalSenseLength;
uint8_t CommandSpecificInformation[4];
uint8_t AdditionalSenseCode;
uint8_t AdditionalSenseCodeQualifier;
uint8_t FieldReplaceableUnitCode;
uint8_t SenseKeySpecific[3];
} __attribute__ ((packed)) SENSEDATA_t;
typedef struct {
uint32_t LBA;
uint32_t blocklen;
} __attribute__ ((packed)) CAPACITYDATA_t;
typedef struct {
uint8_t Reserved[3];
uint8_t Length;
uint32_t Blocks;
uint8_t DescriptorType :1;
uint8_t Reserved2 : 7;
uint8_t Blocklen[3];
} __attribute__ ((packed)) FORMATCAPACITYDATA_t;
static void clear_sense() {
sense.key = sense.asc = sense.ascq = 0;
}

View File

@@ -10,6 +10,7 @@
#include "data_io.h"
#include "archie.h"
#include "pcecd.h"
#include "hdd.h"
#include "cdc_control.h"
#include "usb.h"
#include "debug.h"
@@ -37,7 +38,6 @@ unsigned char key_remap_table[MAX_REMAP][2];
#define BREAK 0x8000
static char umounted; // 1st image is file or direct SD?
static char cue_valid = 0;
static char buffer[512];
static uint8_t buffer_drive_index = 0;
static uint32_t buffer_lba = 0xffffffff;
@@ -114,6 +114,9 @@ static uint32_t autofire_map;
static uint32_t autofire_mask;
static char autofire_joy;
// ATA drives
hardfileTYPE hardfiles[4];
char user_io_osd_is_visible() {
return osd_is_visible;
}
@@ -122,11 +125,15 @@ void user_io_reset() {
// no sd card image selected, SD card accesses will go directly
// to the card (first slot, and only until the first unmount)
umounted = 0;
cue_valid = 0;
toc.valid = 0;
sd_image[0].valid = 0;
sd_image[1].valid = 0;
sd_image[2].valid = 0;
sd_image[3].valid = 0;
hardfiles[0].enabled = HDF_DISABLED;
hardfiles[1].enabled = HDF_DISABLED;
hardfiles[2].enabled = HDF_DISABLED;
hardfiles[3].enabled = HDF_CDROM;
core_mod = 0;
core_features = 0;
ps2_kbd_state = PS2_KBD_IDLE;
@@ -376,6 +383,28 @@ void user_io_detect_core_type() {
user_io_file_mount(s, i);
}
}
// check for <core>.IDx files (IDE drives)
if(core_features & FEAT_IDE) {
for (int i = 0; i < SD_IMAGES; i++) {
hardfile[i] = &hardfiles[i];
}
if(!user_io_create_config_name(s, "ID0", CONFIG_ROOT | CONFIG_VHD)) {
for (int i = 0; i < HARDFILES-1; i++) {
if (!user_io_is_mounted(i)) {
s[strlen(s)-1] = '0'+i;
iprintf("Looking for %s\n", s);
hardfiles[i].enabled = HDF_FILE;
strncpy(hardfiles[i].name, s, sizeof(hardfiles[0].name));
hardfiles[i].name[sizeof(hardfiles[0].name)-1] = 0;
OpenHardfile(i);
}
}
}
OpenHardfile(3); // CDROM
}
}
}
@@ -706,23 +735,22 @@ static void kbd_fifo_poll() {
char user_io_is_cue_mounted() {
return cue_valid;
return toc.valid;
}
char user_io_cue_mount(const unsigned char *name) {
char res = CUE_RES_OK;
cue_valid = 0;
toc.valid = 0;
if (name) {
res = cue_parse(name, &sd_image[3]);
if (res == CUE_RES_OK) cue_valid = 1;
}
// send mounted image size first then notify about mounting
EnableIO();
SPI(UIO_SET_SDINFO);
// use LE version, so following BYTE(s) may be used for size extension in the future.
spi32le(cue_valid ? f_size(&toc.file->file) : 0);
spi32le(cue_valid ? f_size(&toc.file->file) >> 32 : 0);
spi32le(toc.valid ? f_size(&toc.file->file) : 0);
spi32le(toc.valid ? f_size(&toc.file->file) >> 32 : 0);
spi32le(0); // reserved for future expansion
spi32le(0); // reserved for future expansion
DisableIO();
@@ -1621,6 +1649,21 @@ void user_io_poll() {
if(core_type == CORE_TYPE_ARCHIE)
archie_poll();
if(core_features & FEAT_IDE)
{
unsigned char c1;
EnableFpga();
c1 = SPI(0); // cmd request
SPI(0);
SPI(0);
SPI(0);
SPI(0);
SPI(0);
DisableFpga();
HandleHDD(c1, 0, 1);
}
if((core_type == CORE_TYPE_MINIMIG2) ||
(core_type == CORE_TYPE_MIST2) ||
(core_type == CORE_TYPE_ARCHIE) ||

View File

@@ -80,6 +80,8 @@
#define FEAT_MENU 0x01 // menu core
#define FEAT_PCECD 0x02 // call pcecd_poll()
#define FEAT_QSPI 0x04 // QSPI connection to FPGA
#define FEAT_IDE 0x08 // call HandleHDD()
#define JOY_RIGHT 0x01
#define JOY_LEFT 0x02