mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-09-28 15:54:44 +00:00
1136 lines
22 KiB
C++
Executable File
1136 lines
22 KiB
C++
Executable File
/*
|
|
* sys_windows.cpp - System dependent routines, Windows implementation
|
|
*
|
|
* Basilisk II (C) 1997-2008 Christian Bauer
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#include "sysdeps.h"
|
|
|
|
#include <winioctl.h>
|
|
|
|
#include <string>
|
|
typedef std::basic_string<TCHAR> tstring;
|
|
|
|
#include <algorithm>
|
|
using std::min;
|
|
|
|
#include "main.h"
|
|
#include "util_windows.h"
|
|
#include "macos_util.h"
|
|
#include "prefs.h"
|
|
#include "user_strings.h"
|
|
#include "sys.h"
|
|
|
|
#include "cd_defs.h"
|
|
#include "cdenable/ntcd.h"
|
|
#include "cdenable/cache.h"
|
|
#include "cdenable/eject_nt.h"
|
|
|
|
#if defined(BINCUE)
|
|
#include "bincue.h"
|
|
#endif
|
|
|
|
#define DEBUG 0
|
|
#include "debug.h"
|
|
|
|
|
|
// File handles are pointers to these structures
|
|
struct file_handle {
|
|
TCHAR *name; // Copy of device/file name
|
|
HANDLE fh;
|
|
bool is_file; // Flag: plain file or physical device?
|
|
bool is_floppy; // Flag: floppy device
|
|
bool is_cdrom; // Flag: CD-ROM device
|
|
bool read_only; // Copy of Sys_open() flag
|
|
loff_t start_byte; // Size of file header (if any)
|
|
loff_t file_size; // Size of file data (only valid if is_file is true)
|
|
cachetype cache;
|
|
bool is_media_present;
|
|
|
|
#if defined(BINCUE)
|
|
bool is_bincue; // Flag: BIN CUE file
|
|
void *bincue_fd;
|
|
file_handle() {is_bincue = false;} // default bincue false
|
|
#endif
|
|
};
|
|
|
|
// Open file handles
|
|
struct open_file_handle {
|
|
file_handle *fh;
|
|
open_file_handle *next;
|
|
};
|
|
static open_file_handle *open_file_handles = NULL;
|
|
|
|
// File handle of first floppy drive (for SysMountFirstFloppy())
|
|
static file_handle *first_floppy = NULL;
|
|
|
|
// CD-ROM variables
|
|
static const int CD_READ_AHEAD_SECTORS = 16;
|
|
static char *sector_buffer = NULL;
|
|
|
|
// Prototypes
|
|
static bool is_cdrom_readable(file_handle *fh);
|
|
static DWORD file_offset_read(HANDLE fh, loff_t offset, int count, char *buf);
|
|
|
|
/*
|
|
* Initialization
|
|
*/
|
|
|
|
void SysInit(void)
|
|
{
|
|
// Initialize CD-ROM driver
|
|
sector_buffer = (char *)VirtualAlloc(NULL, 8192, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
CdenableSysInstallStart();
|
|
}
|
|
|
|
|
|
/*
|
|
* Deinitialization
|
|
*/
|
|
|
|
void SysExit(void)
|
|
{
|
|
if (sector_buffer) {
|
|
VirtualFree(sector_buffer, 0, MEM_RELEASE );
|
|
sector_buffer = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Manage open file handles
|
|
*/
|
|
|
|
static void sys_add_file_handle(file_handle *fh)
|
|
{
|
|
open_file_handle *p = new open_file_handle;
|
|
p->fh = fh;
|
|
p->next = open_file_handles;
|
|
open_file_handles = p;
|
|
}
|
|
|
|
static void sys_remove_file_handle(file_handle *fh)
|
|
{
|
|
open_file_handle *p = open_file_handles;
|
|
open_file_handle *q = NULL;
|
|
|
|
while (p) {
|
|
if (p->fh == fh) {
|
|
if (q)
|
|
q->next = p->next;
|
|
else
|
|
open_file_handles = p->next;
|
|
delete p;
|
|
break;
|
|
}
|
|
q = p;
|
|
p = p->next;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Mount removable media now
|
|
*/
|
|
|
|
void mount_removable_media(int media)
|
|
{
|
|
for (open_file_handle *p = open_file_handles; p != NULL; p = p->next) {
|
|
file_handle * const fh = p->fh;
|
|
|
|
if (fh->is_cdrom && (media & MEDIA_CD)) {
|
|
cache_clear(&fh->cache);
|
|
fh->start_byte = 0;
|
|
|
|
if (fh->fh && fh->fh != INVALID_HANDLE_VALUE)
|
|
CloseHandle(fh->fh);
|
|
|
|
// Re-open device
|
|
TCHAR device_name[MAX_PATH];
|
|
_sntprintf(device_name, lengthof(device_name), TEXT("\\\\.\\%c:"), fh->name[0]);
|
|
fh->fh = CreateFile(
|
|
device_name,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (fh->fh != INVALID_HANDLE_VALUE) {
|
|
fh->is_media_present = is_cdrom_readable(fh);
|
|
if (fh->is_media_present)
|
|
MountVolume(fh);
|
|
} else {
|
|
fh->is_media_present = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Account for media that has just arrived
|
|
*/
|
|
|
|
void SysMediaArrived(void)
|
|
{
|
|
mount_removable_media(MEDIA_REMOVABLE);
|
|
}
|
|
|
|
|
|
/*
|
|
* Account for media that has just been removed
|
|
*/
|
|
|
|
void SysMediaRemoved(void)
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
* Mount first floppy disk
|
|
*/
|
|
|
|
void SysMountFirstFloppy(void)
|
|
{
|
|
if (first_floppy)
|
|
MountVolume(first_floppy);
|
|
}
|
|
|
|
|
|
/*
|
|
* This gets called when no "floppy" prefs items are found
|
|
* It scans for available floppy drives and adds appropriate prefs items
|
|
*/
|
|
|
|
void SysAddFloppyPrefs(void)
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
* This gets called when no "disk" prefs items are found
|
|
* It scans for available HFS volumes and adds appropriate prefs items
|
|
*/
|
|
|
|
void SysAddDiskPrefs(void)
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
* This gets called when no "cdrom" prefs items are found
|
|
* It scans for available CD-ROM drives and adds appropriate prefs items
|
|
*/
|
|
|
|
void SysAddCDROMPrefs(void)
|
|
{
|
|
// Don't scan for drives if nocdrom option given
|
|
if (PrefsFindBool("nocdrom"))
|
|
return;
|
|
|
|
char rootdir[] = "C:\\";
|
|
for (; rootdir[0] <= 'Z'; rootdir[0]++) {
|
|
if (GetDriveTypeA(rootdir) == DRIVE_CDROM)
|
|
PrefsAddString("cdrom", rootdir);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Add default serial prefs (must be added, even if no ports present)
|
|
*/
|
|
|
|
void SysAddSerialPrefs(void)
|
|
{
|
|
PrefsAddString("seriala", "COM1");
|
|
PrefsAddString("serialb", "COM2");
|
|
}
|
|
|
|
|
|
/*
|
|
* Read CD-ROM
|
|
* Must give cd some time to settle
|
|
* Can't give too much however, would be annoying, this is difficult..
|
|
*/
|
|
|
|
static inline int cd_read_with_retry(file_handle *fh, ULONG offset, int count, char *buf )
|
|
{
|
|
if (!fh || !fh->fh)
|
|
return 0;
|
|
|
|
DWORD bytes_read = CdenableSysReadCdBytes(fh->fh, offset, count, buf);
|
|
|
|
if (bytes_read == 0) {
|
|
// fall back to logical volume handle read in the case where there's no cdenable
|
|
bytes_read = file_offset_read(fh->fh, offset, count, buf);
|
|
}
|
|
|
|
return bytes_read;
|
|
}
|
|
|
|
/*
|
|
* Generic offset read function for a file or a device that behaves like one
|
|
*/
|
|
|
|
static DWORD file_offset_read(HANDLE fh, loff_t offset, int count, char *buf)
|
|
{
|
|
// Seek to position
|
|
LONG lo = (LONG)offset;
|
|
LONG hi = (LONG)(offset >> 32);
|
|
DWORD r = SetFilePointer(fh, lo, &hi, FILE_BEGIN);
|
|
if (r == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
|
|
return 0;
|
|
}
|
|
|
|
DWORD bytes_read;
|
|
|
|
// Read data
|
|
if (ReadFile(fh, buf, count, &bytes_read, NULL) == 0)
|
|
bytes_read = 0;
|
|
|
|
return bytes_read;
|
|
}
|
|
|
|
static int cd_read(file_handle *fh, cachetype *cptr, ULONG LBA, int count, char *buf)
|
|
{
|
|
ULONG l1, l2, cc;
|
|
int i, c_count, got_bytes = 0, nblocks, s_inx, ss, first_block;
|
|
int ok_bytes = 0;
|
|
char *ptr, *ttptr = 0, *tmpbuf;
|
|
|
|
if (count <= 0)
|
|
return 0;
|
|
|
|
if (!fh || !fh->fh)
|
|
return 0;
|
|
|
|
ss = 2048;
|
|
l1 = (LBA / ss) * ss;
|
|
l2 = ((LBA + count - 1 + ss) / ss) * ss;
|
|
cc = l2 - l1;
|
|
nblocks = cc / ss;
|
|
first_block = LBA / ss;
|
|
|
|
ptr = buf;
|
|
s_inx = LBA - l1;
|
|
c_count = ss - s_inx;
|
|
if (c_count > count)
|
|
c_count = count;
|
|
|
|
for (i = 0; i < nblocks; i++) {
|
|
if (!cache_get(cptr, first_block + i, sector_buffer))
|
|
break;
|
|
|
|
memcpy(ptr, sector_buffer + s_inx, c_count);
|
|
ok_bytes += c_count;
|
|
ptr += c_count;
|
|
s_inx = 0;
|
|
c_count = ss;
|
|
if (c_count > count - ok_bytes)
|
|
c_count = count - ok_bytes;
|
|
}
|
|
|
|
if (i != nblocks && count != ok_bytes) {
|
|
int bytes_left = count - ok_bytes;
|
|
int blocks_left = nblocks - i;
|
|
int alignedleft;
|
|
|
|
// NEW read ahead code:
|
|
int ahead = CD_READ_AHEAD_SECTORS;
|
|
if (blocks_left < ahead) {
|
|
nblocks += (ahead - blocks_left);
|
|
blocks_left = ahead;
|
|
}
|
|
|
|
alignedleft = blocks_left*ss;
|
|
|
|
tmpbuf = (char *)VirtualAlloc(
|
|
NULL, alignedleft,
|
|
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
if (tmpbuf) {
|
|
got_bytes = cd_read_with_retry(fh, (first_block + i) * ss, alignedleft, tmpbuf);
|
|
if (got_bytes != alignedleft) {
|
|
// should never happen
|
|
// Yes it does ...
|
|
if (got_bytes < 0)
|
|
got_bytes = 0;
|
|
if (c_count > got_bytes)
|
|
c_count = got_bytes;
|
|
if (c_count > 0) {
|
|
ttptr = tmpbuf;
|
|
memcpy(ptr, ttptr + s_inx, c_count);
|
|
ok_bytes += c_count;
|
|
}
|
|
VirtualFree(tmpbuf, 0, MEM_RELEASE );
|
|
return ok_bytes;
|
|
}
|
|
ttptr = tmpbuf;
|
|
for ( ; i < nblocks; i++) {
|
|
if (c_count > 0) {
|
|
memcpy(ptr, ttptr + s_inx, c_count);
|
|
ok_bytes += c_count;
|
|
ptr += c_count;
|
|
}
|
|
s_inx = 0;
|
|
c_count = ss;
|
|
if (c_count > count - ok_bytes)
|
|
c_count = count - ok_bytes;
|
|
cache_put(cptr, first_block + i, ttptr, ss);
|
|
ttptr += ss;
|
|
}
|
|
VirtualFree(tmpbuf, 0, MEM_RELEASE );
|
|
}
|
|
}
|
|
|
|
return ok_bytes;
|
|
}
|
|
|
|
|
|
/*
|
|
* Check if file handle FH represents a readable CD-ROM
|
|
*/
|
|
|
|
static bool is_cdrom_readable(file_handle *fh)
|
|
{
|
|
if (!fh || !fh->fh)
|
|
return false;
|
|
|
|
cache_clear(&fh->cache);
|
|
|
|
DWORD dummy;
|
|
bool result = (0 != DeviceIoControl(
|
|
fh->fh,
|
|
IOCTL_STORAGE_CHECK_VERIFY,
|
|
NULL, 0,
|
|
NULL, 0,
|
|
&dummy,
|
|
NULL));
|
|
if (!result) {
|
|
const size_t n_bytes = 2048;
|
|
char *buffer = (char *)VirtualAlloc(NULL, n_bytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
if (buffer) {
|
|
result = (cd_read_with_retry(fh, 0, n_bytes, buffer) == n_bytes);
|
|
VirtualFree(buffer, 0, MEM_RELEASE);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
* Check if NAME represents a read-only file
|
|
*/
|
|
|
|
static bool is_read_only_path(const TCHAR *name)
|
|
{
|
|
DWORD attrib = GetFileAttributes(name);
|
|
return (attrib != INVALID_FILE_ATTRIBUTES && ((attrib & FILE_ATTRIBUTE_READONLY) != 0));
|
|
}
|
|
|
|
|
|
/*
|
|
* Open file/device, create new file handle (returns NULL on error)
|
|
*/
|
|
|
|
void *Sys_open(const char *path_name, bool read_only)
|
|
{
|
|
file_handle * fh = NULL;
|
|
|
|
// Parse path name and options
|
|
TCHAR name[MAX_PATH];
|
|
tcslcpy(name, path_name, lengthof(name));
|
|
|
|
// Normalize floppy / cd path
|
|
int name_len = _tcslen(name);
|
|
if (name_len == 1 && _istalpha(name[0]))
|
|
_tcscat(name, TEXT(":\\"));
|
|
if (name_len > 0 && name[name_len - 1] == TEXT(':'))
|
|
_tcscat(name, TEXT("\\"));
|
|
name_len = _tcslen(name);
|
|
|
|
D(bug(TEXT("Sys_open(%s, %s)\n"), name, read_only ? TEXT("read-only") : TEXT("read/write")));
|
|
if (name_len > 0 && name[name_len - 1] == TEXT('\\')) {
|
|
int type = GetDriveType(name);
|
|
|
|
if (type == DRIVE_CDROM) {
|
|
read_only = true;
|
|
TCHAR device_name[MAX_PATH];
|
|
_sntprintf(device_name, lengthof(device_name), TEXT("\\\\.\\%c:"), name[0]);
|
|
|
|
// Open device
|
|
HANDLE h = CreateFile(
|
|
device_name,
|
|
GENERIC_READ,
|
|
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (h != INVALID_HANDLE_VALUE) {
|
|
fh = new file_handle;
|
|
fh->name = _tcsdup(name);
|
|
fh->fh = h;
|
|
fh->is_file = false;
|
|
fh->read_only = read_only;
|
|
fh->start_byte = 0;
|
|
fh->is_floppy = false;
|
|
fh->is_cdrom = true;
|
|
memset(&fh->cache, 0, sizeof(cachetype));
|
|
cache_init(&fh->cache);
|
|
cache_clear(&fh->cache);
|
|
if (!PrefsFindBool("nocdrom"))
|
|
fh->is_media_present = is_cdrom_readable(fh);
|
|
}
|
|
}
|
|
}
|
|
|
|
else { // Hard file
|
|
|
|
// Check if write access is allowed, set read-only flag if not
|
|
if (!read_only && is_read_only_path(name))
|
|
read_only = true;
|
|
|
|
// Open file
|
|
|
|
#if defined(BINCUE)
|
|
void *binfd = open_bincue(name); // check if bincue
|
|
#endif
|
|
|
|
HANDLE h = CreateFile(
|
|
name,
|
|
read_only ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
|
|
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if (h == INVALID_HANDLE_VALUE && !read_only) {
|
|
// Read-write failed, try read-only
|
|
read_only = true;
|
|
h = CreateFile(
|
|
name,
|
|
GENERIC_READ,
|
|
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
}
|
|
|
|
if (h != INVALID_HANDLE_VALUE) {
|
|
fh = new file_handle;
|
|
fh->name = _tcsdup(name);
|
|
fh->fh = h;
|
|
fh->is_file = true;
|
|
fh->read_only = read_only;
|
|
fh->start_byte = 0;
|
|
fh->is_floppy = false;
|
|
fh->is_cdrom = false;
|
|
|
|
#if defined(BINCUE)
|
|
if (binfd) {
|
|
fh->bincue_fd = binfd;
|
|
fh->is_bincue = true;
|
|
fh->is_media_present = true;
|
|
sys_add_file_handle(fh);
|
|
return fh;
|
|
}
|
|
#endif
|
|
|
|
// Detect disk image file layout
|
|
loff_t size = GetFileSize(h, NULL);
|
|
DWORD bytes_read;
|
|
uint8 data[256];
|
|
ReadFile(h, data, sizeof(data), &bytes_read, NULL);
|
|
FileDiskLayout(size, data, fh->start_byte, fh->file_size);
|
|
}
|
|
}
|
|
|
|
if (fh) {
|
|
if (fh->is_floppy && first_floppy == NULL)
|
|
first_floppy = fh;
|
|
sys_add_file_handle(fh);
|
|
}
|
|
|
|
return fh;
|
|
}
|
|
|
|
|
|
/*
|
|
* Close file/device, delete file handle
|
|
*/
|
|
|
|
void Sys_close(void *arg)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return;
|
|
|
|
sys_remove_file_handle(fh);
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
close_bincue(fh->bincue_fd);
|
|
#endif
|
|
|
|
if (fh->is_cdrom) {
|
|
cache_final(&fh->cache);
|
|
SysAllowRemoval((void *)fh);
|
|
}
|
|
if (fh->fh != NULL) {
|
|
CloseHandle(fh->fh);
|
|
fh->fh = NULL;
|
|
}
|
|
if (fh->name)
|
|
free(fh->name);
|
|
|
|
delete fh;
|
|
}
|
|
|
|
|
|
/*
|
|
* Read "length" bytes from file/device, starting at "offset", to "buffer",
|
|
* returns number of bytes read (or 0)
|
|
*/
|
|
|
|
size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return 0;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
return read_bincue(fh->bincue_fd, buffer, offset, length);
|
|
#endif
|
|
|
|
DWORD bytes_read = 0;
|
|
|
|
if (fh->is_file) {
|
|
bytes_read = file_offset_read(fh->fh, offset, length, (char *)buffer);
|
|
}
|
|
else if (fh->is_cdrom) {
|
|
int bytes_left, try_bytes, got_bytes;
|
|
char *b = (char *)buffer;
|
|
bytes_left = length;
|
|
while (bytes_left) {
|
|
try_bytes = min(bytes_left, 32768);
|
|
if (fh->is_cdrom) {
|
|
got_bytes = cd_read(fh, &fh->cache, (DWORD)offset, try_bytes, b);
|
|
if (got_bytes != try_bytes && !PrefsFindBool("nocdrom"))
|
|
fh->is_media_present = is_cdrom_readable(fh);
|
|
}
|
|
b += got_bytes;
|
|
offset += got_bytes;
|
|
bytes_read += got_bytes;
|
|
bytes_left -= got_bytes;
|
|
if (got_bytes != try_bytes)
|
|
bytes_left = 0;
|
|
}
|
|
}
|
|
// TODO: other media
|
|
|
|
return bytes_read;
|
|
}
|
|
|
|
|
|
/*
|
|
* Write "length" bytes from "buffer" to file/device, starting at "offset",
|
|
* returns number of bytes written (or 0)
|
|
*/
|
|
|
|
size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return 0;
|
|
|
|
DWORD bytes_written = 0;
|
|
|
|
if (fh->is_file) {
|
|
// Seek to position
|
|
LONG lo = (LONG)offset;
|
|
LONG hi = (LONG)(offset >> 32);
|
|
DWORD r = SetFilePointer(fh->fh, lo, &hi, FILE_BEGIN);
|
|
if (r == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
|
|
return 0;
|
|
|
|
// Write data
|
|
if (WriteFile(fh->fh, buffer, length, &bytes_written, NULL) == 0)
|
|
bytes_written = 0;
|
|
}
|
|
// TODO: other media
|
|
|
|
return bytes_written;
|
|
}
|
|
|
|
|
|
/*
|
|
* Return size of file/device (minus header)
|
|
*/
|
|
|
|
loff_t SysGetFileSize(void *arg)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return true;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
return size_bincue(fh->bincue_fd);
|
|
#endif
|
|
|
|
if (fh->is_file)
|
|
return fh->file_size;
|
|
else if (fh->is_cdrom)
|
|
return 0x28A00000; // FIXME: get real CD-ROM size
|
|
else {
|
|
// TODO: other media
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Eject volume (if applicable)
|
|
*/
|
|
|
|
void SysEject(void *arg)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue) {
|
|
fh->is_media_present = false;
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
if (fh->is_cdrom && fh->fh) {
|
|
fh->is_media_present = false;
|
|
// Commented out because there was some problems, but can't remember
|
|
// exactly ... need to find out
|
|
// EjectVolume(toupper(*fh->name),false);
|
|
|
|
// Preventing is cumulative, try to make sure it's indeed released now
|
|
for (int i = 0; i < 10; i++)
|
|
PreventRemovalOfVolume(fh->fh, false);
|
|
|
|
if (!PrefsFindBool("nocdrom")) {
|
|
DWORD dummy;
|
|
DeviceIoControl(
|
|
fh->fh,
|
|
IOCTL_STORAGE_EJECT_MEDIA,
|
|
NULL, 0,
|
|
NULL, 0,
|
|
&dummy,
|
|
NULL
|
|
);
|
|
}
|
|
cache_clear(&fh->cache);
|
|
fh->start_byte = 0;
|
|
}
|
|
// TODO: handle floppies
|
|
}
|
|
|
|
|
|
/*
|
|
* Format volume (if applicable)
|
|
*/
|
|
|
|
bool SysFormat(void *arg)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return false;
|
|
|
|
//!!
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
* Check if file/device is read-only (this includes the read-only flag on Sys_open())
|
|
*/
|
|
|
|
bool SysIsReadOnly(void *arg)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return true;
|
|
|
|
return fh->read_only;
|
|
}
|
|
|
|
|
|
/*
|
|
* Check if the given file handle refers to a fixed or a removable disk
|
|
*/
|
|
|
|
bool SysIsFixedDisk(void *arg)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return true;
|
|
|
|
if (fh->is_file)
|
|
return true;
|
|
else if (fh->is_floppy || fh->is_cdrom)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
* Check if a disk is inserted in the drive (always true for files)
|
|
*/
|
|
|
|
bool SysIsDiskInserted(void *arg)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return false;
|
|
|
|
if (fh->is_file)
|
|
return true;
|
|
else if (fh->is_cdrom && !PrefsFindBool("nocdrom")) {
|
|
if (PrefsFindBool("pollmedia"))
|
|
fh->is_media_present = is_cdrom_readable(fh);
|
|
return fh->is_media_present;
|
|
}
|
|
else {
|
|
// TODO: other media
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
* Prevent medium removal (if applicable)
|
|
*/
|
|
|
|
void SysPreventRemoval(void *arg)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return;
|
|
|
|
if (fh->is_cdrom && fh->fh)
|
|
PreventRemovalOfVolume(fh->fh, true);
|
|
}
|
|
|
|
|
|
/*
|
|
* Allow medium removal (if applicable)
|
|
*/
|
|
|
|
void SysAllowRemoval(void *arg)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return;
|
|
|
|
if (fh->is_cdrom && fh->fh)
|
|
PreventRemovalOfVolume(fh->fh, false);
|
|
}
|
|
|
|
|
|
/*
|
|
* Read CD-ROM TOC (binary MSF format, 804 bytes max.)
|
|
*/
|
|
|
|
bool SysCDReadTOC(void *arg, uint8 *toc)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return false;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
return readtoc_bincue(fh->bincue_fd, toc);
|
|
#endif
|
|
|
|
if (fh->is_cdrom) {
|
|
|
|
DWORD dummy;
|
|
return DeviceIoControl(fh->fh,
|
|
IOCTL_CDROM_READ_TOC,
|
|
NULL, 0,
|
|
toc, min((int)sizeof(CDROM_TOC), 804),
|
|
&dummy,
|
|
NULL) != FALSE;
|
|
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
* Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
|
|
*/
|
|
|
|
bool SysCDGetPosition(void *arg, uint8 *pos)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return false;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
return GetPosition_bincue(fh->bincue_fd, pos);
|
|
#endif
|
|
|
|
if (fh->is_cdrom) {
|
|
SUB_Q_CHANNEL_DATA q_data;
|
|
|
|
CDROM_SUB_Q_DATA_FORMAT q_format;
|
|
q_format.Format = IOCTL_CDROM_CURRENT_POSITION;
|
|
q_format.Track = 0; // used only by ISRC reads
|
|
|
|
DWORD dwBytesReturned = 0;
|
|
bool ok = DeviceIoControl(fh->fh,
|
|
IOCTL_CDROM_READ_Q_CHANNEL,
|
|
&q_format, sizeof(CDROM_SUB_Q_DATA_FORMAT),
|
|
&q_data, sizeof(SUB_Q_CHANNEL_DATA),
|
|
&dwBytesReturned,
|
|
NULL) != FALSE;
|
|
if (ok)
|
|
memcpy(pos, &q_data.CurrentPosition, sizeof(SUB_Q_CURRENT_POSITION));
|
|
|
|
return ok;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
* Play CD audio
|
|
*/
|
|
|
|
bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return false;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
return CDPlay_bincue(fh->bincue_fd, start_m, start_s, start_f, end_m, end_s, end_f);
|
|
#endif
|
|
|
|
if (fh->is_cdrom) {
|
|
CDROM_PLAY_AUDIO_MSF msf;
|
|
msf.StartingM = start_m;
|
|
msf.StartingS = start_s;
|
|
msf.StartingF = start_f;
|
|
msf.EndingM = end_m;
|
|
msf.EndingS = end_s;
|
|
msf.EndingF = end_f;
|
|
|
|
DWORD dwBytesReturned = 0;
|
|
return DeviceIoControl(fh->fh,
|
|
IOCTL_CDROM_PLAY_AUDIO_MSF,
|
|
&msf, sizeof(CDROM_PLAY_AUDIO_MSF),
|
|
NULL, 0,
|
|
&dwBytesReturned,
|
|
NULL) != FALSE;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
* Pause CD audio
|
|
*/
|
|
|
|
bool SysCDPause(void *arg)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return false;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
return CDPause_bincue(fh->bincue_fd);
|
|
#endif
|
|
|
|
if (fh->is_cdrom) {
|
|
DWORD dwBytesReturned = 0;
|
|
return DeviceIoControl(fh->fh,
|
|
IOCTL_CDROM_PAUSE_AUDIO,
|
|
NULL, 0,
|
|
NULL, 0,
|
|
&dwBytesReturned,
|
|
NULL) != FALSE;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
* Resume paused CD audio
|
|
*/
|
|
|
|
bool SysCDResume(void *arg)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return false;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
return CDResume_bincue(fh->bincue_fd);
|
|
#endif
|
|
|
|
if (fh->is_cdrom) {
|
|
DWORD dwBytesReturned = 0;
|
|
return DeviceIoControl(fh->fh,
|
|
IOCTL_CDROM_RESUME_AUDIO,
|
|
NULL, 0,
|
|
NULL, 0,
|
|
&dwBytesReturned, NULL) != FALSE;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
* Stop CD audio
|
|
*/
|
|
|
|
bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return false;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
return CDStop_bincue(fh->bincue_fd);
|
|
#endif
|
|
|
|
if (fh->is_cdrom) {
|
|
DWORD dwBytesReturned = 0;
|
|
return DeviceIoControl(fh->fh,
|
|
IOCTL_CDROM_STOP_AUDIO,
|
|
NULL, 0,
|
|
NULL, 0,
|
|
&dwBytesReturned,
|
|
NULL) != FALSE;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
* Perform CD audio fast-forward/fast-reverse operation starting from specified address
|
|
*/
|
|
|
|
bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return false;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
return CDScan_bincue(fh->bincue_fd,start_m,start_s,start_f,reverse);
|
|
#endif
|
|
|
|
if (fh->is_cdrom) {
|
|
|
|
CDROM_SEEK_AUDIO_MSF msf;
|
|
msf.M = start_m;
|
|
msf.S = start_s;
|
|
msf.F = start_f;
|
|
|
|
DWORD dwBytesReturned = 0;
|
|
return DeviceIoControl(fh->fh,
|
|
IOCTL_CDROM_SEEK_AUDIO_MSF,
|
|
&msf, sizeof(CDROM_SEEK_AUDIO_MSF),
|
|
NULL, 0,
|
|
&dwBytesReturned,
|
|
NULL) != FALSE;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
* Set CD audio volume (0..255 each channel)
|
|
*/
|
|
|
|
void SysCDSetVolume(void *arg, uint8 left, uint8 right)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
CDSetVol_bincue(fh->bincue_fd,left,right);
|
|
#endif
|
|
|
|
if (fh->is_cdrom) {
|
|
|
|
VOLUME_CONTROL vc;
|
|
vc.PortVolume[0] = left;
|
|
vc.PortVolume[1] = right;
|
|
vc.PortVolume[2] = left;
|
|
vc.PortVolume[3] = right;
|
|
|
|
DWORD dwBytesReturned = 0;
|
|
DeviceIoControl(fh->fh,
|
|
IOCTL_CDROM_SET_VOLUME,
|
|
&vc, sizeof(VOLUME_CONTROL),
|
|
NULL, 0,
|
|
&dwBytesReturned,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Get CD audio volume (0..255 each channel)
|
|
*/
|
|
|
|
void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
|
|
{
|
|
file_handle *fh = (file_handle *)arg;
|
|
if (!fh)
|
|
return;
|
|
|
|
left = right = 0;
|
|
|
|
#if defined(BINCUE)
|
|
if (fh->is_bincue)
|
|
CDGetVol_bincue(fh->bincue_fd,&left,&right);
|
|
#endif
|
|
|
|
if (fh->is_cdrom) {
|
|
|
|
VOLUME_CONTROL vc;
|
|
memset(&vc, 0, sizeof(vc));
|
|
|
|
DWORD dwBytesReturned = 0;
|
|
if (DeviceIoControl(fh->fh,
|
|
IOCTL_CDROM_GET_VOLUME,
|
|
NULL, 0,
|
|
&vc, sizeof(VOLUME_CONTROL),
|
|
&dwBytesReturned,
|
|
NULL))
|
|
{
|
|
left = vc.PortVolume[0];
|
|
right = vc.PortVolume[1];
|
|
}
|
|
}
|
|
}
|