2
* sys_windows.cpp - System dependent routines, Windows implementation
4
* Basilisk II (C) 1997-2005 Christian Bauer
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
#define WIN32_LEAN_AND_MEAN
34
#include "macos_util.h"
36
#include "user_strings.h"
40
#include "cdenable/ntcd.h"
41
#include "cdenable/cache.h"
42
#include "cdenable/eject_nt.h"
48
// File handles are pointers to these structures
50
char *name; // Copy of device/file name
52
bool is_file; // Flag: plain file or physical device?
53
bool is_floppy; // Flag: floppy device
54
bool is_cdrom; // Flag: CD-ROM device
55
bool read_only; // Copy of Sys_open() flag
56
loff_t start_byte; // Size of file header (if any)
57
loff_t file_size; // Size of file data (only valid if is_file is true)
59
bool is_media_present;
62
// File handle of first floppy drive (for SysMountFirstFloppy())
63
static file_handle *first_floppy = NULL;
66
static const int CD_READ_AHEAD_SECTORS = 16;
67
static char *sector_buffer = NULL;
76
// Initialize CD-ROM driver
77
sector_buffer = (char *)VirtualAlloc(NULL, 8192, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
78
CdenableSysInstallStart();
89
VirtualFree(sector_buffer, 0, MEM_RELEASE );
96
* Mount first floppy disk
99
void SysMountFirstFloppy(void)
102
MountVolume(first_floppy);
107
* This gets called when no "floppy" prefs items are found
108
* It scans for available floppy drives and adds appropriate prefs items
111
void SysAddFloppyPrefs(void)
117
* This gets called when no "disk" prefs items are found
118
* It scans for available HFS volumes and adds appropriate prefs items
121
void SysAddDiskPrefs(void)
127
* This gets called when no "cdrom" prefs items are found
128
* It scans for available CD-ROM drives and adds appropriate prefs items
131
void SysAddCDROMPrefs(void)
133
// Don't scan for drives if nocdrom option given
134
if (PrefsFindBool("nocdrom"))
137
for (char letter = 'C'; letter <= 'Z'; letter++) {
138
int i = (int)(letter - 'A');
139
string rootdir = letter + ":\\";
140
if (GetDriveType(rootdir.c_str()) == DRIVE_CDROM)
141
PrefsAddString("cdrom", rootdir.c_str());
147
* Add default serial prefs (must be added, even if no ports present)
150
void SysAddSerialPrefs(void)
152
PrefsAddString("seriala", "COM1");
153
PrefsAddString("serialb", "COM2");
159
* Must give cd some time to settle
160
* Can't give too much however, would be annoying, this is difficult..
163
static inline int cd_read_with_retry(file_handle *fh, ULONG LBA, int count, char *buf )
168
return CdenableSysReadCdBytes(fh->fh, LBA, count, buf);
171
static int cd_read(file_handle *fh, cachetype *cptr, ULONG LBA, int count, char *buf)
174
int i, c_count, got_bytes = 0, nblocks, s_inx, ss, first_block;
176
char *ptr, *ttptr = 0, *tmpbuf;
185
l1 = (LBA / ss) * ss;
186
l2 = ((LBA + count - 1 + ss) / ss) * ss;
189
first_block = LBA / ss;
193
c_count = ss - s_inx;
197
for (i = 0; i < nblocks; i++) {
198
if (!cache_get(cptr, first_block + i, sector_buffer))
201
memcpy(ptr, sector_buffer + s_inx, c_count);
206
if (c_count > count - ok_bytes)
207
c_count = count - ok_bytes;
210
if (i != nblocks && count != ok_bytes) {
211
int bytes_left = count - ok_bytes;
212
int blocks_left = nblocks - i;
215
// NEW read ahead code:
216
int ahead = CD_READ_AHEAD_SECTORS;
217
if (blocks_left < ahead) {
218
nblocks += (ahead - blocks_left);
222
alignedleft = blocks_left*ss;
224
tmpbuf = (char *)VirtualAlloc(
226
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
228
got_bytes = cd_read_with_retry(fh, (first_block + i) * ss, alignedleft, tmpbuf);
229
if (got_bytes != alignedleft) {
230
// should never happen
234
if (c_count > got_bytes)
238
memcpy(ptr, ttptr + s_inx, c_count);
241
VirtualFree(tmpbuf, 0, MEM_RELEASE );
245
for ( ; i < nblocks; i++) {
247
memcpy(ptr, ttptr + s_inx, c_count);
253
if (c_count > count - ok_bytes)
254
c_count = count - ok_bytes;
255
cache_put(cptr, first_block + i, ttptr, ss);
258
VirtualFree(tmpbuf, 0, MEM_RELEASE );
267
* Check if file handle FH represents a readable CD-ROM
270
static bool is_cdrom_readable(file_handle *fh)
275
cache_clear(&fh->cache);
278
bool result = (0 != DeviceIoControl(
280
IOCTL_STORAGE_CHECK_VERIFY,
286
const size_t n_bytes = 2048;
287
char *buffer = (char *)VirtualAlloc(NULL, n_bytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
289
result = (cd_read_with_retry(fh, 0, n_bytes, buffer) == n_bytes);
290
VirtualFree(buffer, 0, MEM_RELEASE);
299
* Check if NAME represents a read-only file
302
static bool is_read_only_path(const char *name)
304
DWORD attrib = GetFileAttributes((char *)name);
305
return (attrib != INVALID_FILE_ATTRIBUTES && ((attrib & FILE_ATTRIBUTE_READONLY) != 0));
310
* Open file/device, create new file handle (returns NULL on error)
313
void *Sys_open(const char *path_name, bool read_only)
315
file_handle * fh = NULL;
317
// Parse path name and options
319
strcpy(name, path_name);
321
// Normalize floppy / cd path
322
int name_len = strlen(name);
323
if (name_len == 1 && isalpha(name[0]))
325
if (name_len > 0 && name[name_len - 1] == ':')
327
name_len = strlen(name);
329
D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write"));
330
if (name_len > 0 && name[name_len - 1] == '\\') {
331
int type = GetDriveType(name);
333
if (type == DRIVE_CDROM) {
335
char device_name[MAX_PATH];
336
sprintf(device_name, "\\\\.\\%c:", name[0]);
339
HANDLE h = CreateFile(
342
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
344
if (h != INVALID_HANDLE_VALUE) {
345
fh = new file_handle;
346
fh->name = strdup(name);
349
fh->read_only = read_only;
351
fh->is_floppy = false;
353
if (!PrefsFindBool("nocdrom"))
354
fh->is_media_present = is_cdrom_readable(fh);
361
// Check if write access is allowed, set read-only flag if not
362
if (!read_only && is_read_only_path(name))
366
HANDLE h = CreateFile(
368
read_only ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
369
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
371
if (h == INVALID_HANDLE_VALUE && !read_only) {
372
// Read-write failed, try read-only
377
0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
380
if (h != INVALID_HANDLE_VALUE) {
381
fh = new file_handle;
382
fh->name = strdup(name);
385
fh->read_only = read_only;
387
fh->is_floppy = false;
388
fh->is_cdrom = false;
390
// Detect disk image file layout
391
loff_t size = GetFileSize(h, NULL);
394
ReadFile(h, data, sizeof(data), &bytes_read, NULL);
395
FileDiskLayout(size, data, fh->start_byte, fh->file_size);
399
if (fh->is_floppy && first_floppy == NULL)
407
* Close file/device, delete file handle
410
void Sys_close(void *arg)
412
file_handle *fh = (file_handle *)arg;
417
cache_final(&fh->cache);
418
SysAllowRemoval((void *)fh);
420
if (fh->fh != NULL) {
432
* Read "length" bytes from file/device, starting at "offset", to "buffer",
433
* returns number of bytes read (or 0)
436
size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
438
file_handle *fh = (file_handle *)arg;
442
DWORD bytes_read = 0;
446
LONG lo = (LONG)offset;
447
LONG hi = (LONG)(offset >> 32);
448
DWORD r = SetFilePointer(fh->fh, lo, &hi, FILE_BEGIN);
449
if (r == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
453
if (ReadFile(fh->fh, buffer, length, &bytes_read, NULL) == 0)
456
else if (fh->is_cdrom) {
457
int bytes_left, try_bytes, got_bytes;
458
char *b = (char *)buffer;
461
try_bytes = min(bytes_left, 32768);
463
got_bytes = cd_read(fh, &fh->cache, (DWORD)offset, try_bytes, b);
464
if (got_bytes != try_bytes && !PrefsFindBool("nocdrom"))
465
fh->is_media_present = is_cdrom_readable(fh);
469
bytes_read += got_bytes;
470
bytes_left -= got_bytes;
471
if (got_bytes != try_bytes)
482
* Write "length" bytes from "buffer" to file/device, starting at "offset",
483
* returns number of bytes written (or 0)
486
size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
488
file_handle *fh = (file_handle *)arg;
492
DWORD bytes_written = 0;
496
LONG lo = (LONG)offset;
497
LONG hi = (LONG)(offset >> 32);
498
DWORD r = SetFilePointer(fh->fh, lo, &hi, FILE_BEGIN);
499
if (r == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
503
if (WriteFile(fh->fh, buffer, length, &bytes_written, NULL) == 0)
508
return bytes_written;
513
* Return size of file/device (minus header)
516
loff_t SysGetFileSize(void *arg)
518
file_handle *fh = (file_handle *)arg;
523
return fh->file_size;
524
else if (fh->is_cdrom)
525
return 0x28A00000; // FIXME: get real CD-ROM size
534
* Eject volume (if applicable)
537
void SysEject(void *arg)
539
file_handle *fh = (file_handle *)arg;
543
if (fh->is_cdrom && fh->fh) {
544
fh->is_media_present = false;
545
// Commented out because there was some problems, but can't remember
546
// exactly ... need to find out
547
// EjectVolume(toupper(*fh->name),false);
549
// Preventing is cumulative, try to make sure it's indeed released now
550
for (int i = 0; i < 10; i++)
551
PreventRemovalOfVolume(fh->fh, false);
553
if (!PrefsFindBool("nocdrom")) {
557
IOCTL_STORAGE_EJECT_MEDIA,
564
cache_clear(&fh->cache);
567
// TODO: handle floppies
572
* Format volume (if applicable)
575
bool SysFormat(void *arg)
577
file_handle *fh = (file_handle *)arg;
587
* Check if file/device is read-only (this includes the read-only flag on Sys_open())
590
bool SysIsReadOnly(void *arg)
592
file_handle *fh = (file_handle *)arg;
596
return fh->read_only;
601
* Check if the given file handle refers to a fixed or a removable disk
604
bool SysIsFixedDisk(void *arg)
606
file_handle *fh = (file_handle *)arg;
612
else if (fh->is_floppy || fh->is_cdrom)
620
* Check if a disk is inserted in the drive (always true for files)
623
bool SysIsDiskInserted(void *arg)
625
file_handle *fh = (file_handle *)arg;
631
else if (fh->is_cdrom && !PrefsFindBool("nocdrom")) {
632
if (PrefsFindBool("pollmedia"))
633
fh->is_media_present = is_cdrom_readable(fh);
634
return fh->is_media_present;
645
* Prevent medium removal (if applicable)
648
void SysPreventRemoval(void *arg)
650
file_handle *fh = (file_handle *)arg;
654
if (fh->is_cdrom && fh->fh)
655
PreventRemovalOfVolume(fh->fh, true);
660
* Allow medium removal (if applicable)
663
void SysAllowRemoval(void *arg)
665
file_handle *fh = (file_handle *)arg;
669
if (fh->is_cdrom && fh->fh)
670
PreventRemovalOfVolume(fh->fh, false);
675
* Read CD-ROM TOC (binary MSF format, 804 bytes max.)
678
bool SysCDReadTOC(void *arg, uint8 *toc)
680
file_handle *fh = (file_handle *)arg;
681
if (!fh || !fh->fh || !fh->is_cdrom)
685
return DeviceIoControl(fh->fh,
686
IOCTL_CDROM_READ_TOC,
688
toc, min((int)sizeof(CDROM_TOC), 804),
695
* Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
698
bool SysCDGetPosition(void *arg, uint8 *pos)
700
file_handle *fh = (file_handle *)arg;
701
if (!fh || !fh->fh || !fh->is_cdrom)
704
SUB_Q_CHANNEL_DATA q_data;
706
CDROM_SUB_Q_DATA_FORMAT q_format;
707
q_format.Format = IOCTL_CDROM_CURRENT_POSITION;
708
q_format.Track = 0; // used only by ISRC reads
710
DWORD dwBytesReturned = 0;
711
bool ok = DeviceIoControl(fh->fh,
712
IOCTL_CDROM_READ_Q_CHANNEL,
713
&q_format, sizeof(CDROM_SUB_Q_DATA_FORMAT),
714
&q_data, sizeof(SUB_Q_CHANNEL_DATA),
718
memcpy(pos, &q_data.CurrentPosition, sizeof(SUB_Q_CURRENT_POSITION));
728
bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
730
file_handle *fh = (file_handle *)arg;
731
if (!fh || !fh->fh || !fh->is_cdrom)
734
CDROM_PLAY_AUDIO_MSF msf;
735
msf.StartingM = start_m;
736
msf.StartingS = start_s;
737
msf.StartingF = start_f;
742
DWORD dwBytesReturned = 0;
743
return DeviceIoControl(fh->fh,
744
IOCTL_CDROM_PLAY_AUDIO_MSF,
745
&msf, sizeof(CDROM_PLAY_AUDIO_MSF),
756
bool SysCDPause(void *arg)
758
file_handle *fh = (file_handle *)arg;
759
if (!fh || !fh->fh || !fh->is_cdrom)
762
DWORD dwBytesReturned = 0;
763
return DeviceIoControl(fh->fh,
764
IOCTL_CDROM_PAUSE_AUDIO,
773
* Resume paused CD audio
776
bool SysCDResume(void *arg)
778
file_handle *fh = (file_handle *)arg;
779
if (!fh || !fh->fh || !fh->is_cdrom)
782
DWORD dwBytesReturned = 0;
783
return DeviceIoControl(fh->fh,
784
IOCTL_CDROM_RESUME_AUDIO,
787
&dwBytesReturned, NULL);
795
bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
797
file_handle *fh = (file_handle *)arg;
798
if (!fh || !fh->fh || !fh->is_cdrom)
801
DWORD dwBytesReturned = 0;
802
return DeviceIoControl(fh->fh,
803
IOCTL_CDROM_STOP_AUDIO,
812
* Perform CD audio fast-forward/fast-reverse operation starting from specified address
815
bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
817
file_handle *fh = (file_handle *)arg;
818
if (!fh || !fh->fh || !fh->is_cdrom)
821
CDROM_SEEK_AUDIO_MSF msf;
826
DWORD dwBytesReturned = 0;
827
return DeviceIoControl(fh->fh,
828
IOCTL_CDROM_SEEK_AUDIO_MSF,
829
&msf, sizeof(CDROM_SEEK_AUDIO_MSF),
837
* Set CD audio volume (0..255 each channel)
840
void SysCDSetVolume(void *arg, uint8 left, uint8 right)
842
file_handle *fh = (file_handle *)arg;
843
if (!fh || !fh->fh || !fh->is_cdrom)
847
vc.PortVolume[0] = left;
848
vc.PortVolume[1] = right;
849
vc.PortVolume[2] = left;
850
vc.PortVolume[3] = right;
852
DWORD dwBytesReturned = 0;
853
DeviceIoControl(fh->fh,
854
IOCTL_CDROM_SET_VOLUME,
855
&vc, sizeof(VOLUME_CONTROL),
863
* Get CD audio volume (0..255 each channel)
866
void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
868
file_handle *fh = (file_handle *)arg;
873
if (!fh->fh || !fh->is_cdrom)
877
memset(&vc, 0, sizeof(vc));
879
DWORD dwBytesReturned = 0;
880
if (DeviceIoControl(fh->fh,
881
IOCTL_CDROM_GET_VOLUME,
883
&vc, sizeof(VOLUME_CONTROL),
887
left = vc.PortVolume[0];
888
right = vc.PortVolume[1];