///////////////////////////////////////////////////////////////////////// // $Id: cdrom_amigaos.cc,v 1.17 2009-12-04 19:50:26 sshwarts Exp $ ///////////////////////////////////////////////////////////////////////// // // Copyright (C) 2000-2009 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" #include "scsi_commands.h" #include "cdrom.h" #include #include #include #include #include #include #include #include #include #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]; 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_interface::cdrom_interface(char *dev) { char buf[256]; 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_interface::~cdrom_interface(void) { if (cd_error == 0) { CloseDevice((struct IORequest *)CDIO); } if (CDIO != NULL) { DeleteIORequest((struct IORequest *)CDIO); } if (CDMP != NULL) { DeleteMsgPort(CDMP); } } bx_bool cdrom_interface::insert_cdrom(char *dev) { Bit8u cdb[6]; Bit8u buf[2*BX_CD_FRAMESIZE]; Bit8u i = 0; 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; for(i = 0; i < 200; i++) /*it takes a while for the cdrom to validate*/ { DoIO((struct IORequest *)CDIO); if (CDIO->iotd_Req.io_Error == 0) break; Delay (10); } if (CDIO->iotd_Req.io_Error != 0) return false; else return true; } void cdrom_interface::eject_cdrom() { Bit8u cdb[6]; memset(cdb,0,sizeof(cdb)); cdb[0] = SCSI_DA_START_STOP_UNIT; cdb[4] = 0 | 2; DoSCSI(0, 0,cdb,sizeof(cdb),SCSIF_READ); } bx_bool cdrom_interface::read_toc(Bit8u* buf, int* length, bx_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)); 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_interface::capacity() { CAPACITY cap; Bit8u cdb[10]; 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")); } bx_bool cdrom_interface::read_block(Bit8u* buf, int lba, int blocksize) { 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; } bx_bool cdrom_interface::start_cdrom() { // Spin up the cdrom drive. if (fd >= 0) { BX_INFO(("start_cdrom: your OS is not supported yet.")); return 0; // OS not supported yet, return 0 always. } return 0; } 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; } void cdrom_interface::seek(int lba) { unsigned char buffer[BX_CD_FRAMESIZE]; read_block(buffer, lba, BX_CD_FRAMESIZE); }