///////////////////////////////////////////////////////////////////////// // $Id$ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2000-2021 The Bochs Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // // These are the low-level CDROM functions which are called // from 'harddrv.cc'. They effect the OS specific functionality // needed by the CDROM emulation in 'harddrv.cc'. Mostly, just // ioctl() calls and such. Should be fairly easy to add support // for your OS if it is not supported yet. #include "bochs.h" #if BX_SUPPORT_CDROM #include "scsi_commands.h" #include "cdrom.h" #include "cdrom_amigaos.h" #include #include #include #include #include #include #include #include #include #if BX_WITH_AMIGAOS #include #endif #define LOG_THIS /* no SMF tricks here, not needed */ #define BX_CD_FRAMESIZE 2048 #define CD_FRAMESIZE 2048 #define SENSELEN 32 #define MAX_DATA_LEN 252 int amiga_cd_unit; char amiga_cd_device[256]; int oldpos = 0; struct MsgPort *CDMP; /* Pointer for message port */ struct IOExtTD *CDIO; /* Pointer for IORequest */ int cd_error; typedef struct { UBYTE pad0; UBYTE trackType; UBYTE trackNum; UBYTE pad1; ULONG startFrame; } TOCENTRY; typedef struct { UWORD length; UBYTE firstTrack; UBYTE lastTrack; TOCENTRY tocs[100]; } TOC; typedef struct { ULONG sectors; ULONG blocksize; } CAPACITY; unsigned char sensebuf[SENSELEN]; int DoSCSI(UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags); cdrom_amigaos_c::cdrom_amigaos_c(const char *dev) { char buf[256], prefix[6]; sprintf(prefix, "CD%d", ++bx_cdrom_count); put(prefix); fd = -1; fda = NULL; if (dev == NULL) { path = NULL; } else { path = strdup(dev); } if (strstr(path, ".device ") == 0) { BX_INFO(("Amiga: Using CD ROM as Image")); using_file=1; if (fda) Close(fda); fda = Open(path, MODE_OLDFILE); } else { using_file=0; sscanf(dev, "%s%s", amiga_cd_device, buf); amiga_cd_unit = atoi(buf); CDMP = CreateMsgPort(); if (CDMP != NULL) { CDIO = (struct IOExtTD *)CreateIORequest(CDMP, sizeof(struct IOExtTD)); if (CDIO != NULL) { cd_error = OpenDevice(amiga_cd_device, amiga_cd_unit, (struct IORequest *)CDIO, 0); if (cd_error != 0) BX_PANIC(("CD_Open: could not open device %s unit %d\n", amiga_cd_device, amiga_cd_unit)); } } } } cdrom_amigaos_c::~cdrom_amigaos_c(void) { if(fda) Close(fda); fda = NULL; if (cd_error == 0) { CloseDevice((struct IORequest *)CDIO); } if (CDIO != NULL) { DeleteIORequest((struct IORequest *)CDIO); } if (CDMP != NULL) { DeleteMsgPort(CDMP); } } bool cdrom_amigaos_c::insert_cdrom(const char *dev) { Bit8u cdb[6]; Bit8u buf[2*BX_CD_FRAMESIZE]; Bit8u i = 0; BX_INFO(("dev = %s", dev)); if (dev != NULL) path = strdup(dev); if (strstr(path, ".device ") == 0) { BX_INFO(("Amiga: Using CD ROM as Image")); using_file=1; if(fda) Close(fda); fda = Open(path, MODE_OLDFILE); if(fda){ return true; } else return false; } else { using_file=0; BX_INFO(("Amiga: Using CD ROM as physical drive")); memset(cdb,0,sizeof(cdb)); cdb[0] = SCSI_DA_START_STOP_UNIT; cdb[4] = 1 | 2; DoSCSI(0, 0,cdb,sizeof(cdb),SCSIF_READ); /*Check if there's a valid media present in the drive*/ CDIO->iotd_Req.io_Data = buf; CDIO->iotd_Req.io_Command = CMD_READ; CDIO->iotd_Req.io_Length = BX_CD_FRAMESIZE; CDIO->iotd_Req.io_Offset = BX_CD_FRAMESIZE; if (CDIO->iotd_Req.io_Error != 0) return false; else return true; } } void cdrom_amigaos_c::eject_cdrom() { Bit8u cdb[6]; if(fda) { Close(fda); fda = NULL; } else { memset(cdb,0,sizeof(cdb)); cdb[0] = SCSI_DA_START_STOP_UNIT; cdb[4] = 0 | 2; DoSCSI(0, 0,cdb,sizeof(cdb),SCSIF_READ); } } bool cdrom_amigaos_c::read_toc(Bit8u* buf, int* length, bool msf, int start_track, int format) { Bit8u cdb[10]; TOC *toc; toc = (TOC*) buf; if (format != 0) return false; memset(cdb,0,sizeof(cdb)); if(using_file){ return create_toc(buf, length, msf, start_track, format); } else { cdb[0] = SCSI_CD_READ_TOC; if (msf) cdb[1] = 2; else cdb[1] = 0; cdb[6] = start_track; cdb[7] = sizeof(TOC)>>8; cdb[8] = sizeof(TOC)&0xFF; DoSCSI((UBYTE *)buf, sizeof(TOC), cdb, sizeof(cdb), SCSIF_READ); *length = toc->length + 4; return true; } } Bit32u cdrom_amigaos_c::capacity() { CAPACITY cap; Bit8u cdb[10]; if (using_file) { int len; Seek(fda, 0, OFFSET_END); len = Seek(fda, 0, OFFSET_BEGINNING); if ((len % 2048) != 0) { BX_ERROR (("expected cdrom image to be a multiple of 2048 bytes")); } return (len/2048); } else { memset(cdb,0,sizeof(cdb)); cdb[0] = SCSI_DA_READ_CAPACITY; int err; if ((err = DoSCSI((UBYTE *)&cap, sizeof(cap), cdb, sizeof (cdb), (SCSIF_READ | SCSIF_AUTOSENSE))) == 0) return(cap.sectors); else BX_PANIC (("Couldn't get media capacity")); } } bool cdrom_amigaos_c::read_block(Bit8u* buf, Bit32u lba, int blocksize) { int n; Bit8u try_count = 3; if (using_file) { do { if(oldpos != lba*BX_CD_FRAMESIZE) Seek(fda, lba*BX_CD_FRAMESIZE, OFFSET_BEGINNING); oldpos = lba*BX_CD_FRAMESIZE+BX_CD_FRAMESIZE; n = Read(fda, buf, BX_CD_FRAMESIZE); } while ((n != BX_CD_FRAMESIZE) && (--try_count > 0)); if(try_count <=0) { BX_PANIC(("Error reading CD image sector: %ld", lba)); return(0); } return 1; } else { CDIO->iotd_Req.io_Data = buf; CDIO->iotd_Req.io_Command = CMD_READ; CDIO->iotd_Req.io_Length = BX_CD_FRAMESIZE; CDIO->iotd_Req.io_Offset = lba * BX_CD_FRAMESIZE; DoIO((struct IORequest *)CDIO); if (CDIO->iotd_Req.io_Error != 0) { BX_PANIC(("Error %d reading CD data sector: %ld", CDIO->iotd_Req.io_Error, lba)); return 0; } return 1; } } int DoSCSI(UBYTE *data, int datasize, Bit8u *cmd,int cmdsize, UBYTE direction) { struct SCSICmd scmd; CDIO->iotd_Req.io_Command = HD_SCSICMD; CDIO->iotd_Req.io_Data = &scmd; CDIO->iotd_Req.io_Length = sizeof(scmd); scmd.scsi_Data = (UWORD *)data; scmd.scsi_Length = datasize; scmd.scsi_SenseActual = 0; scmd.scsi_SenseData = sensebuf; scmd.scsi_SenseLength = SENSELEN; scmd.scsi_Command = cmd; scmd.scsi_CmdLength = cmdsize; scmd.scsi_Flags = SCSIF_AUTOSENSE | direction; DoIO((struct IORequest *)CDIO); if (CDIO->iotd_Req.io_Error != 0) { // BX_PANIC(("DoSCSI: error %d", CDIO->iotd_Req.io_Error)); } return CDIO->iotd_Req.io_Error; } #endif /* if BX_SUPPORT_CDROM */