ATAPI: Translate PLAY AUDIO TRACK INDEX

This command is not supported by ATAPI devices, so translate it
This commit is contained in:
Matt Harlum 2024-04-03 05:12:46 +00:00 committed by Matt Harlum
parent 43bb237676
commit 6b5dc2fb5e
4 changed files with 215 additions and 2 deletions

166
atapi.c
View File

@ -993,6 +993,9 @@ bool atapi_update_presence(struct IDEUnit *unit, bool present) {
*
* If an access to the medium was successful then we know that it is present.
* The diskchange task can then skip the next "Test Unit Ready" so it won't interrupt a transfer
*
* @param unit Pointer to an IDEUnit struct
* @param cmd SCSI Command
*/
void atapi_do_defer_tur(struct IDEUnit *unit, UBYTE cmd) {
@ -1002,4 +1005,167 @@ void atapi_do_defer_tur(struct IDEUnit *unit, UBYTE cmd) {
unit->deferTUR = true;
}
}
/**
* atapi_read_toc
*
* Reads the CD TOC into the supplied buffer
*
* @param unit Pointer to an IDEUnit struct
* @param buf Pointer to the buffer
* @param bufSize Size of buffer
* @returns non-zero on error
*/
BYTE atapi_read_toc(struct IDEUnit *unit, BYTE *buf, ULONG bufSize) {
BYTE ret = 0;
if (buf == NULL || bufSize == 0) {
return IOERR_BADADDRESS;
}
struct SCSICmd *cmd = MakeSCSICmd(SZ_CDB_10);
cmd->scsi_Data = (UWORD *)buf;
cmd->scsi_Length = bufSize;
cmd->scsi_Flags = SCSIF_READ;
cmd->scsi_Command[0] = SCSI_CMD_READ_TOC;
cmd->scsi_Command[1] = 0x02; // MSF Flag
cmd->scsi_Command[7] = bufSize >> 8;
cmd->scsi_Command[8] = bufSize & 0xFF;
ret = atapi_packet(cmd,unit) != 0;
DeleteSCSICmd(cmd);
return ret;
}
/**
* atapi_get_track_msf
*
* Find the M/S/F of a Track
*
* @param toc pointer to a SCSI_CD_TOC struct
* @param trackNum track number to find
* @param msf Pointer to a SCSI_TRACK_MSF struct
* @returns true if track found
*/
BOOL atapi_get_track_msf(struct SCSI_CD_TOC *toc, int trackNum, struct SCSI_TRACK_MSF *msf) {
if (toc == NULL || msf == NULL) {
return false;
}
int numTracks = (toc->lastTrack - toc->firstTrack) + 1;
for (int t=0; t<=numTracks; t++) {
if (toc->td[t].trackNumber == trackNum) {
msf->minute = toc->td[t].minute;
msf->second = toc->td[t].second;
msf->frame = toc->td[t].frame;
return true;
}
}
return false;
}
/**
* atapi_play_track_index
*
* Find tracks <start> and <end> in TOC and issue a PLAY AUDIO MSF command
*
* @param unit Pointer to an IDEUnit struct
* @param start Start track number
* @param end End track number
* @returns non-zero on error
*/
BYTE atapi_play_track_index(struct IDEUnit *unit, UBYTE start, UBYTE end) {
BYTE ret = 0;
struct SCSI_TRACK_MSF startmsf, endmsf;
struct SCSI_CD_TOC *toc = AllocMem(SCSI_TOC_SIZE,MEMF_ANY|MEMF_CLEAR);
if (toc == NULL) return TDERR_NoMem;
ret = atapi_read_toc(unit,(BYTE *)toc,SCSI_TOC_SIZE);
if (ret == 0) {
if (end > toc->lastTrack) end = 0xAA; // Lead out
if (atapi_get_track_msf(toc,start,&startmsf) &&
atapi_get_track_msf(toc,end,&endmsf))
{
ret = atapi_play_audio_msf(unit,&startmsf,&endmsf);
} else {
ret = IOERR_BADADDRESS;
}
}
FreeMem(toc,SCSI_TOC_SIZE);
return ret;
}
/**
* atapi_play_audio_msf
*
* Issue a PLAY AUDIO MSF command to the drive
*
* @param unit Pointer to an IDEUnit struct
* @param start Pointer to a SCSI_TRACK_MSF struct for the starting position
* @param end Pointer to a SCSI_TRACK_MSF struct for the ending position
* @returns non-zero on error
*/
BYTE atapi_play_audio_msf(struct IDEUnit *unit, struct SCSI_TRACK_MSF *start, struct SCSI_TRACK_MSF *end) {
BYTE ret = 0;
struct SCSICmd *cmd = MakeSCSICmd(SZ_CDB_10);
if (cmd == NULL) return TDERR_NoMem;
cmd->scsi_Command[0] = SCSI_CMD_PLAY_AUDIO_MSF;
cmd->scsi_Command[3] = start->minute;
cmd->scsi_Command[4] = start->second;
cmd->scsi_Command[5] = start->frame;
cmd->scsi_Command[6] = end->minute;
cmd->scsi_Command[7] = end->second;
cmd->scsi_Command[8] = end->frame;
cmd->scsi_Flags = SCSIF_READ;
cmd->scsi_Data = NULL;
cmd->scsi_Length = 0;
ret = atapi_packet(cmd,unit);
DeleteSCSICmd(cmd);
return ret;
}
/**
* atapi_translate_play_audio_index
*
* PLAY AUDIO INDEX was deprecated with SCSI-3 and is not supported by ATAPI drives
* Some software makes use of this, so we translate it to a PLAY AUDIO MSF command
*
* @param cmd Pointer to a SCSICmd struct for a PLAY AUDIO INDEX command
* @param unit Pointer to an IDEUnit struct
* @returns non-zero on error
*/
BYTE atapi_translate_play_audio_index(struct SCSICmd *cmd, struct IDEUnit *unit) {
UBYTE start = cmd->scsi_Command[4];
UBYTE end = cmd->scsi_Command[7];
BYTE ret = 0;
ret = atapi_play_track_index(unit,start,end);
cmd->scsi_CmdActual = cmd->scsi_CmdLength;
cmd->scsi_Status = (ret == 0) ? 0 : SCSI_CHECK_CONDITION;
return ret;
}

View File

@ -7,6 +7,7 @@
#include <stdbool.h>
#include "device.h"
#include "scsi.h"
#include <exec/types.h>
#define atapi_flag_cd (1<<0)
@ -49,4 +50,9 @@ BYTE atapi_start_stop_unit(struct IDEUnit *unit, bool start, bool loej);
BYTE atapi_check_wp(struct IDEUnit *unit);
bool atapi_update_presence(struct IDEUnit *unit, bool present);
void atapi_do_defer_tur(struct IDEUnit *unit, UBYTE cmd);
BYTE atapi_read_toc(struct IDEUnit *unit, BYTE *buf, ULONG bufSize);
BOOL atapi_get_track_msf(struct SCSI_CD_TOC *toc, int trackNum, struct SCSI_TRACK_MSF *msf);
BYTE atapi_play_track_index(struct IDEUnit *unit, UBYTE start, UBYTE end);
BYTE atapi_play_audio_msf(struct IDEUnit *unit, struct SCSI_TRACK_MSF *start, struct SCSI_TRACK_MSF *end);
BYTE atapi_translate_play_audio_index(struct SCSICmd *cmd, struct IDEUnit *unit);
#endif

View File

@ -184,7 +184,7 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
enum xfer_dir direction = WRITE;
Trace("SCSI: Command %ld\n",*scsi_command->scsi_Command);
Trace("SCSI: Command %lx\n",*scsi_command->scsi_Command);
if (unit->atapi == false)
{
@ -270,6 +270,10 @@ static BYTE handle_scsi_command(struct IOStdReq *ioreq) {
error = atapi_scsi_mode_select_6(scsi_command,unit);
break;
case SCSI_CMD_PLAY_TRACK_INDEX:
error = atapi_translate_play_audio_index(scsi_command,unit);
break;
case SCSI_CMD_READ_CAPACITY_10:
// CDROMs don't support parameters for READ_CAPACITY_10 so clear them all
for (int i=1; i < scsi_command->scsi_CmdLength; i++) {

39
scsi.h
View File

@ -2,6 +2,9 @@
/* This file is part of lide.device
* Copyright (C) 2023 Matthew Harlum <matt@harlum.net>
*/
#ifndef _SCSI_H
#define _SCSI_H
#define SCSI_CMD_TEST_UNIT_READY 0x00
#define SCSI_CMD_REQUEST_SENSE 0x03
#define SCSI_CMD_READ_6 0x08
@ -12,6 +15,9 @@
#define SCSI_CMD_READ_CAPACITY_10 0x25
#define SCSI_CMD_READ_10 0x28
#define SCSI_CMD_WRITE_10 0x2A
#define SCSI_CMD_READ_TOC 0x43
#define SCSI_CMD_PLAY_AUDIO_MSF 0x47
#define SCSI_CMD_PLAY_TRACK_INDEX 0x48
#define SCSI_CMD_MODE_SELECT_10 0x55
#define SCSI_CMD_MODE_SENSE_10 0x5A
#define SCSI_CMD_START_STOP_UNIT 0x1B
@ -21,6 +27,10 @@
#define SZ_CDB_10 10
#define SZ_CDB_12 12
#define SCSI_CD_MAX_TRACKS 100
#define SCSI_TOC_SIZE (SCSI_CD_MAX_TRACKS * 8) + 4 // SCSI_CD_MAX_TRACKS track descriptors + the toc header
struct __attribute__((packed)) SCSI_Inquiry {
UBYTE peripheral_type;
UBYTE removable_media;
@ -79,6 +89,33 @@ struct __attribute__((packed)) SCSI_FIXED_SENSE {
UBYTE sks[3];
};
struct __attribute__((packed)) SCSI_TOC_TRACK_DESCRIPTOR {
UBYTE reserved1;
UBYTE adrControl;
UBYTE trackNumber;
UBYTE reserved2;
UBYTE reserved3;
UBYTE minute;
UBYTE second;
UBYTE frame;
};
struct __attribute__((packed)) SCSI_CD_TOC {
UWORD length;
UBYTE firstTrack;
UBYTE lastTrack;
struct SCSI_TOC_TRACK_DESCRIPTOR td[SCSI_CD_MAX_TRACKS];
};
struct __attribute__((packed)) SCSI_TRACK_MSF {
UBYTE minute;
UBYTE second;
UBYTE frame;
};
void scsi_sense(struct SCSICmd* command, ULONG info, ULONG specific, BYTE error);
struct SCSICmd * MakeSCSICmd(ULONG cdbSize);
void DeleteSCSICmd(struct SCSICmd *cmd);
void DeleteSCSICmd(struct SCSICmd *cmd);
#endif