2001-04-10 06:20:02 +04:00
|
|
|
// Copyright (C) 2001 MandrakeSoft S.A.
|
2001-04-10 05:04:59 +04:00
|
|
|
//
|
|
|
|
// MandrakeSoft S.A.
|
|
|
|
// 43, rue d'Aboukir
|
|
|
|
// 75002 Paris - France
|
|
|
|
// http://www.linux-mandrake.com/
|
|
|
|
// http://www.mandrakesoft.com/
|
|
|
|
//
|
|
|
|
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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"
|
|
|
|
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
#define LOG_THIS /* no SMF tricks here, not needed */
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
#ifdef __linux__
|
|
|
|
extern "C" {
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <linux/fs.h>
|
|
|
|
#include <linux/cdrom.h>
|
|
|
|
// I use the framesize in non OS specific code too
|
|
|
|
#define BX_CD_FRAMESIZE CD_FRAMESIZE
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2001-04-10 06:15:31 +04:00
|
|
|
#ifdef __sun
|
|
|
|
extern "C" {
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/cdio.h>
|
|
|
|
#define BX_CD_FRAMESIZE CDROM_BLK_2048
|
|
|
|
}
|
|
|
|
#endif /* __sun */
|
|
|
|
|
2001-05-16 21:39:07 +04:00
|
|
|
#if (defined(__OpenBSD__) || defined(__FreeBSD__))
|
2001-05-08 23:51:46 +04:00
|
|
|
// OpenBSD pre version 2.7 may require extern "C" { } structure around
|
2001-06-19 01:14:00 +04:00
|
|
|
// all the includes, because the i386 sys/disklabel.h contains code which
|
2001-05-08 23:51:46 +04:00
|
|
|
// c++ considers invalid.
|
2001-04-10 05:04:59 +04:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/cdio.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/disklabel.h>
|
|
|
|
|
|
|
|
// XXX
|
|
|
|
#define BX_CD_FRAMESIZE 2048
|
|
|
|
#define CD_FRAMESIZE 2048
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#include <winioctl.h>
|
2001-06-25 06:18:16 +04:00
|
|
|
#include "aspi-win32.h"
|
|
|
|
#include "scsidefs.h"
|
2001-06-25 16:56:54 +04:00
|
|
|
#ifndef __MINGW32__
|
2001-06-25 06:18:16 +04:00
|
|
|
#include "type.h"
|
2001-06-25 16:56:54 +04:00
|
|
|
#endif
|
2001-06-25 06:18:16 +04:00
|
|
|
|
|
|
|
DWORD (*GetASPI32SupportInfo)(void);
|
|
|
|
DWORD (*SendASPI32Command)(LPSRB);
|
|
|
|
BOOL (*GetASPI32Buffer)(PASPI32BUFF);
|
|
|
|
BOOL (*FreeASPI32Buffer)(PASPI32BUFF);
|
|
|
|
BOOL (*TranslateASPI32Address)(PDWORD,PDWORD);
|
|
|
|
DWORD (*GetASPI32DLLVersion)(void);
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL bUseASPI = FALSE;
|
|
|
|
static BOOL bHaveDev = FALSE;
|
|
|
|
static int hid = 0;
|
|
|
|
static int tid = 0;
|
|
|
|
static int lun = 0;
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
#define BX_CD_FRAMESIZE 2048
|
|
|
|
#define CD_FRAMESIZE 2048
|
|
|
|
HANDLE hFile = NULL;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2001-06-19 01:11:46 +04:00
|
|
|
#include <stdio.h>
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2001-06-25 06:18:16 +04:00
|
|
|
#ifdef WIN32
|
|
|
|
|
|
|
|
int ReadCDSector(unsigned int hid, unsigned int tid, unsigned int lun, unsigned long frame, unsigned char *buf, int bufsize)
|
|
|
|
{
|
|
|
|
HANDLE hEventSRB;
|
|
|
|
SRB_ExecSCSICmd srb;
|
|
|
|
DWORD dwStatus;
|
|
|
|
|
|
|
|
hEventSRB = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
|
|
|
|
memset(&srb,0,sizeof(SRB_ExecSCSICmd));
|
|
|
|
srb.SRB_Cmd = SC_EXEC_SCSI_CMD;
|
|
|
|
srb.SRB_HaId = hid;
|
|
|
|
srb.SRB_Target = tid;
|
|
|
|
srb.SRB_Lun = lun;
|
|
|
|
srb.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
|
|
|
|
srb.SRB_SenseLen = SENSE_LEN;
|
|
|
|
srb.SRB_PostProc = hEventSRB;
|
|
|
|
srb.SRB_BufPointer = buf;
|
|
|
|
srb.SRB_BufLen = bufsize;
|
|
|
|
srb.SRB_CDBLen = 10;
|
|
|
|
srb.CDBByte[0] = SCSI_READ10;
|
|
|
|
srb.CDBByte[2] = frame>>24;
|
|
|
|
srb.CDBByte[3] = frame>>16;
|
|
|
|
srb.CDBByte[4] = frame>>8;
|
|
|
|
srb.CDBByte[5] = frame;
|
|
|
|
srb.CDBByte[7] = 0;
|
|
|
|
srb.CDBByte[8] = 1; /* read 1 frames */
|
|
|
|
|
|
|
|
ResetEvent(hEventSRB);
|
|
|
|
dwStatus = SendASPI32Command((SRB *)&srb);
|
|
|
|
if(dwStatus == SS_PENDING) {
|
|
|
|
WaitForSingleObject(hEventSRB, 100000);
|
|
|
|
}
|
|
|
|
CloseHandle(hEventSRB);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetCDCapacity(unsigned int hid, unsigned int tid, unsigned int lun)
|
|
|
|
{
|
|
|
|
HANDLE hEventSRB;
|
|
|
|
SRB_ExecSCSICmd srb;
|
|
|
|
DWORD dwStatus;
|
|
|
|
char buf[8];
|
|
|
|
|
|
|
|
hEventSRB = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
|
|
|
|
memset(&buf, 0, sizeof(buf));
|
|
|
|
memset(&srb,0,sizeof(SRB_ExecSCSICmd));
|
|
|
|
srb.SRB_Cmd = SC_EXEC_SCSI_CMD;
|
|
|
|
srb.SRB_HaId = hid;
|
|
|
|
srb.SRB_Target = tid;
|
|
|
|
srb.SRB_Lun = lun;
|
|
|
|
srb.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
|
|
|
|
srb.SRB_SenseLen = SENSE_LEN;
|
|
|
|
srb.SRB_PostProc = hEventSRB;
|
|
|
|
srb.SRB_BufPointer = (unsigned char *)buf;
|
|
|
|
srb.SRB_BufLen = 8;
|
|
|
|
srb.SRB_CDBLen = 10;
|
|
|
|
srb.CDBByte[0] = SCSI_READCDCAP;
|
|
|
|
srb.CDBByte[2] = 0;
|
|
|
|
srb.CDBByte[3] = 0;
|
|
|
|
srb.CDBByte[4] = 0;
|
|
|
|
srb.CDBByte[5] = 0;
|
|
|
|
srb.CDBByte[8] = 0;
|
|
|
|
|
|
|
|
ResetEvent(hEventSRB);
|
|
|
|
dwStatus = SendASPI32Command((SRB *)&srb);
|
|
|
|
if(dwStatus == SS_PENDING) {
|
|
|
|
WaitForSingleObject(hEventSRB, 100000);
|
|
|
|
}
|
|
|
|
|
|
|
|
CloseHandle(hEventSRB);
|
|
|
|
return ((buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]) * ((buf[4] << 24) + (buf[5] << 16) + (buf[6] << 8) + buf[7]);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
cdrom_interface::cdrom_interface(char *dev)
|
|
|
|
{
|
2001-06-20 01:36:09 +04:00
|
|
|
setprefix("CD");
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
settype(CDLOG);
|
2001-04-10 05:04:59 +04:00
|
|
|
fd = -1; // File descriptor not yet allocated
|
|
|
|
|
|
|
|
if ( dev == NULL )
|
|
|
|
path = NULL;
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
else {
|
2001-04-10 05:04:59 +04:00
|
|
|
path = strdup(dev);
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("Init, file = '%s'",dev));
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
}
|
2001-06-19 01:11:46 +04:00
|
|
|
using_file=0;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
cdrom_interface::~cdrom_interface(void)
|
|
|
|
{
|
|
|
|
if (fd >= 0)
|
|
|
|
close(fd);
|
|
|
|
if (path)
|
|
|
|
free(path);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
cdrom_interface::insert_cdrom()
|
|
|
|
{
|
|
|
|
unsigned char buffer[BX_CD_FRAMESIZE];
|
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
// Load CD-ROM. Returns false if CD is not ready.
|
2001-06-23 07:23:41 +04:00
|
|
|
BX_INFO (("load cdrom with path=%s", path));
|
2001-04-10 05:04:59 +04:00
|
|
|
#ifdef WIN32
|
2001-04-10 06:17:10 +04:00
|
|
|
char drive[256];
|
2001-06-25 06:18:16 +04:00
|
|
|
OSVERSIONINFO osi;
|
2001-06-19 01:11:46 +04:00
|
|
|
if ( (path[1] == ':') && (strlen(path) == 2) )
|
|
|
|
{
|
2001-06-25 06:18:16 +04:00
|
|
|
osi.dwOSVersionInfoSize = sizeof(osi);
|
|
|
|
GetVersionEx(&osi);
|
|
|
|
if(osi.dwPlatformId == VER_PLATFORM_WIN32_NT) {
|
|
|
|
// Use direct device access under windows NT/2k
|
|
|
|
|
|
|
|
// With all the backslashes it's hard to see, but to open D: drive
|
|
|
|
// the name would be: \\.\d:
|
|
|
|
sprintf(drive, "\\\\.\\%s", path);
|
|
|
|
using_file = 0;
|
|
|
|
BX_INFO (("Using direct access for cdrom."));
|
|
|
|
// This trick only works for Win2k and WinNT, so warn the user of that.
|
|
|
|
} else {
|
|
|
|
BX_INFO(("Using ASPI for cdrom."));
|
|
|
|
bUseASPI = TRUE;
|
|
|
|
}
|
2001-06-19 01:11:46 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(drive,path);
|
|
|
|
using_file = 1;
|
2001-06-19 01:14:00 +04:00
|
|
|
BX_INFO (("opening image file as a cd"));
|
2001-06-19 01:11:46 +04:00
|
|
|
}
|
2001-06-25 06:18:16 +04:00
|
|
|
if(bUseASPI) {
|
|
|
|
DWORD d, cnt, max;
|
|
|
|
int i, j, k;
|
|
|
|
SRB_HAInquiry sh;
|
|
|
|
SRB_GDEVBlock sd;
|
|
|
|
HINSTANCE hASPI = LoadLibrary("WNASPI32.DLL");
|
|
|
|
if(hASPI) {
|
|
|
|
SendASPI32Command = (DWORD(*)(LPSRB))GetProcAddress( hASPI, "SendASPI32Command" );
|
|
|
|
GetASPI32DLLVersion = (DWORD(*)(void))GetProcAddress( hASPI, "GetASPI32DLLVersion" );
|
|
|
|
GetASPI32SupportInfo = (DWORD(*)(void))GetProcAddress( hASPI, "GetASPI32SupportInfo" );
|
|
|
|
BX_INFO(("Using first CDROM. Please upgrade your ASPI drivers to version 4.01 or later if you wish to specify a cdrom driver."));
|
|
|
|
|
|
|
|
d = GetASPI32SupportInfo();
|
|
|
|
cnt = LOBYTE(LOWORD(d));
|
|
|
|
for(i = 0; i < cnt; i++) {
|
|
|
|
memset(&sh, 0, sizeof(sh));
|
|
|
|
sh.SRB_Cmd = SC_HA_INQUIRY;
|
|
|
|
sh.SRB_HaId = i;
|
|
|
|
SendASPI32Command((LPSRB)&sh);
|
|
|
|
if(sh.SRB_Status != SS_COMP)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
max = (int)sh.HA_Unique[3];
|
|
|
|
for(j = 0; j < max; j++) {
|
|
|
|
for(k = 0; k < 8; k++) {
|
|
|
|
memset(&sd, 0, sizeof(sd));
|
|
|
|
sd.SRB_Cmd = SC_GET_DEV_TYPE;
|
|
|
|
sd.SRB_HaId = i;
|
|
|
|
sd.SRB_Target = j;
|
|
|
|
sd.SRB_Lun = k;
|
|
|
|
SendASPI32Command((LPSRB)&sd);
|
|
|
|
if(sd.SRB_Status == SS_COMP) {
|
|
|
|
if(sd.SRB_DeviceType == DTYPE_CDROM) {
|
|
|
|
hid = i;
|
|
|
|
tid = j;
|
|
|
|
lun = k;
|
|
|
|
bHaveDev = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(bHaveDev) break;
|
|
|
|
}
|
|
|
|
if(bHaveDev) break;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
BX_PANIC(("Could not load ASPI drivers."));
|
|
|
|
}
|
|
|
|
fd=1;
|
|
|
|
} else {
|
|
|
|
BX_INFO(("Using direct access for CDROM"));
|
|
|
|
hFile=CreateFile((char *)&drive, GENERIC_READ, 0 , NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
|
|
|
|
if (hFile !=(void *)0xFFFFFFFF)
|
|
|
|
fd=1;
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
2001-06-25 06:18:16 +04:00
|
|
|
fd = open(path, O_RDONLY);
|
2001-06-19 01:11:46 +04:00
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
if (fd < 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(( "::cdrom_interface: open failed on dev '%s'.", path));
|
2001-04-10 05:04:59 +04:00
|
|
|
return(false);
|
|
|
|
}
|
2001-06-19 01:11:46 +04:00
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
// I just see if I can read a sector to verify that a
|
|
|
|
// CD is in the drive and readable.
|
|
|
|
#ifdef WIN32
|
2001-06-25 06:18:16 +04:00
|
|
|
if(!bUseASPI) {
|
|
|
|
ReadFile(hFile, (void *) buffer, BX_CD_FRAMESIZE, (unsigned long *) &ret, NULL);
|
|
|
|
if (ret < 0) {
|
|
|
|
CloseHandle(hFile);
|
|
|
|
fd = -1;
|
|
|
|
BX_DEBUG(( "insert_cdrom: read returns error." ));
|
|
|
|
return(false);
|
2001-06-19 01:11:46 +04:00
|
|
|
}
|
2001-06-25 06:18:16 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
|
|
|
ret = read(fd, &buffer, BX_CD_FRAMESIZE);
|
|
|
|
if (ret < 0) {
|
|
|
|
close(fd);
|
|
|
|
fd = -1;
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_DEBUG(( "insert_cdrom: read returns error." ));
|
2001-04-10 05:04:59 +04:00
|
|
|
return(false);
|
2001-06-19 01:11:46 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
return(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
cdrom_interface::eject_cdrom()
|
|
|
|
{
|
|
|
|
// Logically eject the CD. I suppose we could stick in
|
|
|
|
// some ioctl() calls to really eject the CD as well.
|
|
|
|
|
|
|
|
if (fd >= 0) {
|
2001-05-16 21:39:07 +04:00
|
|
|
#if (defined(__OpenBSD__) || defined(__FreeBSD__))
|
2001-04-10 05:04:59 +04:00
|
|
|
(void) ioctl (fd, CDIOCALLOW);
|
|
|
|
if (ioctl (fd, CDIOCEJECT) < 0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_DEBUG(( "eject_cdrom: eject returns error." ));
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef WIN32
|
2001-06-19 01:11:46 +04:00
|
|
|
if (using_file == 0)
|
|
|
|
{
|
2001-06-25 06:18:16 +04:00
|
|
|
if(bUseASPI) {
|
|
|
|
} else {
|
|
|
|
DWORD lpBytesReturned;
|
|
|
|
DeviceIoControl(hFile, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &lpBytesReturned, NULL);
|
|
|
|
}
|
2001-06-19 01:11:46 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#endif
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
fd = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
2001-06-19 01:14:00 +04:00
|
|
|
cdrom_interface::read_toc(uint8* buf, int* length, bool msf, int start_track)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
// Read CD TOC. Returns false if start track is out of bounds.
|
|
|
|
|
|
|
|
if (fd < 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: read_toc: file not open."));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
{
|
|
|
|
/* #define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
|
2001-06-19 01:14:00 +04:00
|
|
|
#define IOCTL_CDROM_READ_TOC CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
|
2001-04-10 05:04:59 +04:00
|
|
|
unsigned long iBytesReturned;
|
2001-06-19 01:14:00 +04:00
|
|
|
DeviceIoControl(hFile, IOCTL_CDROM_READ_TOC, NULL, 0, NULL, 0, &iBytesReturned, NULL); */
|
2001-06-19 01:11:46 +04:00
|
|
|
return true;
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
2001-04-10 06:15:31 +04:00
|
|
|
#elif __linux__ || defined(__sun)
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
struct cdrom_tochdr tochdr;
|
|
|
|
if (ioctl(fd, CDROMREADTOCHDR, &tochdr))
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: read_toc: READTOCHDR failed."));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (start_track > tochdr.cdth_trk1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
buf[2] = tochdr.cdth_trk0;
|
|
|
|
buf[3] = tochdr.cdth_trk1;
|
|
|
|
|
|
|
|
if (start_track < tochdr.cdth_trk0)
|
|
|
|
start_track = tochdr.cdth_trk0;
|
|
|
|
|
|
|
|
int len = 4;
|
|
|
|
for (int i = start_track; i <= tochdr.cdth_trk1; i++) {
|
|
|
|
struct cdrom_tocentry tocentry;
|
|
|
|
tocentry.cdte_format = (msf) ? CDROM_MSF : CDROM_LBA;
|
|
|
|
tocentry.cdte_track = i;
|
|
|
|
if (ioctl(fd, CDROMREADTOCENTRY, &tocentry))
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: read_toc: READTOCENTRY failed."));
|
2001-04-10 05:04:59 +04:00
|
|
|
buf[len++] = 0; // Reserved
|
2001-06-19 01:14:00 +04:00
|
|
|
buf[len++] = (tocentry.cdte_adr << 4) | tocentry.cdte_ctrl ; // ADR, control
|
2001-04-10 05:04:59 +04:00
|
|
|
buf[len++] = i; // Track number
|
|
|
|
buf[len++] = 0; // Reserved
|
|
|
|
|
|
|
|
// Start address
|
|
|
|
if (msf) {
|
|
|
|
buf[len++] = 0; // reserved
|
|
|
|
buf[len++] = tocentry.cdte_addr.msf.minute;
|
|
|
|
buf[len++] = tocentry.cdte_addr.msf.second;
|
|
|
|
buf[len++] = tocentry.cdte_addr.msf.frame;
|
|
|
|
} else {
|
|
|
|
buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 24) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 16) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 8) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 0) & 0xff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lead out track
|
|
|
|
struct cdrom_tocentry tocentry;
|
|
|
|
tocentry.cdte_format = (msf) ? CDROM_MSF : CDROM_LBA;
|
2001-06-19 01:11:46 +04:00
|
|
|
#ifdef CDROM_LEADOUT
|
2001-04-10 06:15:31 +04:00
|
|
|
tocentry.cdte_track = CDROM_LEADOUT;
|
|
|
|
#else
|
2001-04-10 05:04:59 +04:00
|
|
|
tocentry.cdte_track = 0xaa;
|
2001-04-10 06:15:31 +04:00
|
|
|
#endif
|
2001-04-10 05:04:59 +04:00
|
|
|
if (ioctl(fd, CDROMREADTOCENTRY, &tocentry))
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: read_toc: READTOCENTRY lead-out failed."));
|
2001-04-10 05:04:59 +04:00
|
|
|
buf[len++] = 0; // Reserved
|
2001-06-19 01:14:00 +04:00
|
|
|
buf[len++] = (tocentry.cdte_adr << 4) | tocentry.cdte_ctrl ; // ADR, control
|
2001-04-10 05:04:59 +04:00
|
|
|
buf[len++] = 0xaa; // Track number
|
|
|
|
buf[len++] = 0; // Reserved
|
|
|
|
|
|
|
|
// Start address
|
|
|
|
if (msf) {
|
|
|
|
buf[len++] = 0; // reserved
|
|
|
|
buf[len++] = tocentry.cdte_addr.msf.minute;
|
|
|
|
buf[len++] = tocentry.cdte_addr.msf.second;
|
|
|
|
buf[len++] = tocentry.cdte_addr.msf.frame;
|
|
|
|
} else {
|
|
|
|
buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 24) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 16) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 8) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.cdte_addr.lba) >> 0) & 0xff;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[0] = ((len-2) >> 8) & 0xff;
|
|
|
|
buf[1] = (len-2) & 0xff;
|
|
|
|
|
|
|
|
*length = len;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2001-05-16 21:39:07 +04:00
|
|
|
#elif (defined(__OpenBSD__) || defined(__FreeBSD__))
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
struct ioc_toc_header h;
|
|
|
|
struct ioc_read_toc_entry t;
|
|
|
|
|
|
|
|
if (ioctl (fd, CDIOREADTOCHEADER, &h) < 0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: read_toc: READTOCHDR failed."));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (start_track > h.ending_track)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
buf[2] = h.starting_track;
|
|
|
|
buf[3] = h.ending_track;
|
|
|
|
|
|
|
|
if (start_track < h.starting_track)
|
|
|
|
start_track = h.starting_track;
|
2001-06-19 01:11:46 +04:00
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
int len = 4;
|
|
|
|
for (int i = start_track; i <= h.ending_track; i++) {
|
|
|
|
struct cd_toc_entry tocentry;
|
|
|
|
t.address_format = (msf) ? CD_MSF_FORMAT : CD_LBA_FORMAT;
|
|
|
|
t.starting_track = i;
|
|
|
|
t.data_len = sizeof(tocentry);
|
|
|
|
t.data = &tocentry;
|
|
|
|
|
|
|
|
if (ioctl (fd, CDIOREADTOCENTRYS, &tocentry) < 0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: read_toc: READTOCENTRY failed."));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
buf[len++] = 0; // Reserved
|
2001-06-19 01:14:00 +04:00
|
|
|
buf[len++] = (tocentry.addr_type << 4) | tocentry.control ; // ADR, control
|
2001-04-10 05:04:59 +04:00
|
|
|
buf[len++] = i; // Track number
|
|
|
|
buf[len++] = 0; // Reserved
|
|
|
|
|
|
|
|
// Start address
|
|
|
|
if (msf) {
|
|
|
|
buf[len++] = 0; // reserved
|
|
|
|
buf[len++] = tocentry.addr.msf.minute;
|
|
|
|
buf[len++] = tocentry.addr.msf.second;
|
|
|
|
buf[len++] = tocentry.addr.msf.frame;
|
|
|
|
} else {
|
|
|
|
buf[len++] = (((unsigned)tocentry.addr.lba) >> 24) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.addr.lba) >> 16) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.addr.lba) >> 8) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.addr.lba) >> 0) & 0xff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lead out track
|
|
|
|
struct cd_toc_entry tocentry;
|
|
|
|
t.address_format = (msf) ? CD_MSF_FORMAT : CD_LBA_FORMAT;
|
|
|
|
t.starting_track = 0xaa;
|
|
|
|
t.data_len = sizeof(tocentry);
|
|
|
|
t.data = &tocentry;
|
|
|
|
|
|
|
|
if (ioctl (fd, CDIOREADTOCENTRYS, &tocentry) < 0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: read_toc: READTOCENTRY lead-out failed."));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
buf[len++] = 0; // Reserved
|
2001-06-19 01:14:00 +04:00
|
|
|
buf[len++] = (tocentry.addr_type << 4) | tocentry.control ; // ADR, control
|
2001-04-10 05:04:59 +04:00
|
|
|
buf[len++] = 0xaa; // Track number
|
|
|
|
buf[len++] = 0; // Reserved
|
|
|
|
|
|
|
|
// Start address
|
|
|
|
if (msf) {
|
|
|
|
buf[len++] = 0; // reserved
|
|
|
|
buf[len++] = tocentry.addr.msf.minute;
|
|
|
|
buf[len++] = tocentry.addr.msf.second;
|
|
|
|
buf[len++] = tocentry.addr.msf.frame;
|
|
|
|
} else {
|
|
|
|
buf[len++] = (((unsigned)tocentry.addr.lba) >> 24) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.addr.lba) >> 16) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.addr.lba) >> 8) & 0xff;
|
|
|
|
buf[len++] = (((unsigned)tocentry.addr.lba) >> 0) & 0xff;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[0] = ((len-2) >> 8) & 0xff;
|
|
|
|
buf[1] = (len-2) & 0xff;
|
|
|
|
|
|
|
|
*length = len;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
#else
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(("read_toc: your OS is not supported yet."));
|
2001-04-10 05:04:59 +04:00
|
|
|
return(false); // OS not supported yet, return false always.
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uint32
|
|
|
|
cdrom_interface::capacity()
|
|
|
|
{
|
|
|
|
// Return CD-ROM capacity. I believe you want to return
|
|
|
|
// the number of bytes of capacity the actual media has.
|
2001-04-10 06:15:31 +04:00
|
|
|
#ifdef __sun
|
|
|
|
{
|
|
|
|
struct stat buf = {0};
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2001-04-10 06:15:31 +04:00
|
|
|
if (fd < 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: capacity: file not open."));
|
2001-04-10 06:15:31 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if( fstat(fd, &buf) != 0 )
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: capacity: stat() failed."));
|
2001-04-10 06:15:31 +04:00
|
|
|
|
|
|
|
return(buf.st_size);
|
2001-06-19 01:11:46 +04:00
|
|
|
}
|
2001-04-10 06:15:31 +04:00
|
|
|
#elif __linux__
|
2001-04-10 05:04:59 +04:00
|
|
|
{
|
|
|
|
// I just looked through the Linux kernel source to see
|
|
|
|
// what it does with the ATAPI capacity command, and reversed
|
|
|
|
// that process here.
|
|
|
|
uint32 nr_sects;
|
|
|
|
|
|
|
|
if (fd < 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: capacity: file not open."));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
if (ioctl(fd, BLKGETSIZE, &nr_sects) != 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: ioctl(BLKGETSIZE) failed"));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
nr_sects /= (CD_FRAMESIZE / 512);
|
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_DEBUG(( "capacity: %u", nr_sects));
|
2001-04-10 05:04:59 +04:00
|
|
|
return(nr_sects);
|
|
|
|
}
|
|
|
|
#elif defined(__OpenBSD__)
|
|
|
|
{
|
|
|
|
// We just read the disklabel, imagine that...
|
|
|
|
struct disklabel lp;
|
|
|
|
|
|
|
|
if (fd < 0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: capacity: file not open."));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
|
|
|
if (ioctl(fd, DIOCGDINFO, &lp) < 0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: ioctl(DIOCGDINFO) failed"));
|
2001-04-10 05:04:59 +04:00
|
|
|
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_DEBUG(( "capacity: %u", lp.d_secperunit ));
|
2001-04-10 05:04:59 +04:00
|
|
|
return(lp.d_secperunit);
|
2001-05-16 21:39:07 +04:00
|
|
|
}
|
|
|
|
#elif defined(__FreeBSD__)
|
|
|
|
{
|
|
|
|
// Read the TOC to get the data size, since disklabel doesn't appear
|
|
|
|
// to work, sadly.
|
|
|
|
// Keith Jones, 16 January 2000
|
|
|
|
|
|
|
|
#define MAX_TRACKS 100
|
|
|
|
|
|
|
|
int i, num_tracks, num_sectors;
|
|
|
|
struct ioc_toc_header td;
|
|
|
|
struct ioc_read_toc_entry rte;
|
|
|
|
struct cd_toc_entry toc_buffer[MAX_TRACKS + 1];
|
|
|
|
|
|
|
|
if (fd < 0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: capacity: file not open."));
|
2001-05-16 21:39:07 +04:00
|
|
|
|
|
|
|
if (ioctl(fd, CDIOREADTOCHEADER, &td) < 0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: ioctl(CDIOREADTOCHEADER) failed"));
|
2001-05-16 21:39:07 +04:00
|
|
|
|
|
|
|
num_tracks = (td.ending_track - td.starting_track) + 1;
|
|
|
|
if (num_tracks > MAX_TRACKS)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: TOC is too large"));
|
2001-05-16 21:39:07 +04:00
|
|
|
|
|
|
|
rte.address_format = CD_LBA_FORMAT;
|
|
|
|
rte.starting_track = td.starting_track;
|
|
|
|
rte.data_len = (num_tracks + 1) * sizeof(struct cd_toc_entry);
|
|
|
|
rte.data = toc_buffer;
|
|
|
|
if (ioctl(fd, CDIOREADTOCENTRYS, &rte) < 0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: ioctl(CDIOREADTOCENTRYS) failed"));
|
2001-05-16 21:39:07 +04:00
|
|
|
|
|
|
|
num_sectors = -1;
|
|
|
|
for (i = 0; i < num_tracks; i++) {
|
|
|
|
if (rte.data[i].control & 4) { /* data track */
|
|
|
|
num_sectors = ntohl(rte.data[i + 1].addr.lba)
|
|
|
|
- ntohl(rte.data[i].addr.lba);
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_ERROR(( "cdrom: Data track %d, length %d",
|
|
|
|
rte.data[i].track, num_sectors));
|
2001-05-16 21:39:07 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_sectors < 0)
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: no data track found"));
|
2001-05-16 21:39:07 +04:00
|
|
|
|
|
|
|
return(num_sectors);
|
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
#elif defined WIN32
|
|
|
|
{
|
2001-06-25 06:18:16 +04:00
|
|
|
if(bUseASPI) {
|
|
|
|
return GetCDCapacity(hid, tid, lun);
|
|
|
|
} else {
|
|
|
|
unsigned long FileSize;
|
|
|
|
return (GetFileSize(hFile, &FileSize));
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
#else
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_INFO(( "capacity: your OS is not supported yet." ));
|
2001-04-10 05:04:59 +04:00
|
|
|
return(0);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
cdrom_interface::read_block(uint8* buf, int lba)
|
|
|
|
{
|
|
|
|
// Read a single block from the CD
|
|
|
|
|
|
|
|
off_t pos;
|
|
|
|
ssize_t n;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
2001-06-25 06:18:16 +04:00
|
|
|
if(bUseASPI) {
|
|
|
|
ReadCDSector(hid, tid, lun, lba, buf, BX_CD_FRAMESIZE);
|
|
|
|
n = BX_CD_FRAMESIZE;
|
|
|
|
} else {
|
|
|
|
pos = SetFilePointer(hFile, lba*BX_CD_FRAMESIZE, NULL, SEEK_SET);
|
|
|
|
if (pos == 0xffffffff) {
|
|
|
|
BX_PANIC(("cdrom: read_block: lseek returned error."));
|
|
|
|
}
|
|
|
|
ReadFile(hFile, (void *) buf, BX_CD_FRAMESIZE, (unsigned long *) &n, NULL);
|
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
#else
|
|
|
|
pos = lseek(fd, lba*BX_CD_FRAMESIZE, SEEK_SET);
|
|
|
|
if (pos < 0) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: read_block: lseek returned error."));
|
2001-06-25 06:18:16 +04:00
|
|
|
}
|
2001-04-10 05:04:59 +04:00
|
|
|
n = read(fd, buf, BX_CD_FRAMESIZE);
|
|
|
|
#endif
|
2001-06-19 01:11:46 +04:00
|
|
|
|
2001-04-10 05:04:59 +04:00
|
|
|
if (n != BX_CD_FRAMESIZE) {
|
2001-05-30 22:56:02 +04:00
|
|
|
BX_PANIC(("cdrom: read_block: read returned %d",
|
merge in BRANCH-io-cleanup.
To see the commit logs for this use either cvsweb or
cvs update -r BRANCH-io-cleanup and then 'cvs log' the various files.
In general this provides a generic interface for logging.
logfunctions:: is a class that is inherited by some classes, and also
. allocated as a standalone global called 'genlog'. All logging uses
. one of the ::info(), ::error(), ::ldebug(), ::panic() methods of this
. class through 'BX_INFO(), BX_ERROR(), BX_DEBUG(), BX_PANIC()' macros
. respectively.
.
. An example usage:
. BX_INFO(("Hello, World!\n"));
iofunctions:: is a class that is allocated once by default, and assigned
as the iofunction of each logfunctions instance. It is this class that
maintains the file descriptor and other output related code, at this
point using vfprintf(). At some future point, someone may choose to
write a gui 'console' for bochs to which messages would be redirected
simply by assigning a different iofunction class to the various logfunctions
objects.
More cleanup is coming, but this works for now. If you want to see alot
of debugging output, in main.cc, change onoff[LOGLEV_DEBUG]=0 to =1.
Comments, bugs, flames, to me: todd@fries.net
2001-05-15 18:49:57 +04:00
|
|
|
(int) n));
|
2001-04-10 05:04:59 +04:00
|
|
|
}
|
|
|
|
}
|
2001-06-19 01:11:46 +04:00
|
|
|
|