~ubuntu-branches/ubuntu/feisty/basilisk2/feisty

« back to all changes in this revision

Viewing changes to src/Windows/sys_windows.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2005-07-30 20:42:20 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050730204220-1nl1cg2jkjvy63ry
Tags: 0.9.20050730-1
* New upstream CVS snapshot.
* Build-depend on virtual libsdl-dev (not libsdl1.2-dev).
* Invoke init rules also on clean (to separate better from official
  builds).
* Update URL of upstream source in debian/copyright.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  sys_windows.cpp - System dependent routines, Windows implementation
 
3
 *
 
4
 *  Basilisk II (C) 1997-2005 Christian Bauer
 
5
 *
 
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.
 
10
 *
 
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.
 
15
 *
 
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
 
19
 */
 
20
 
 
21
#include "sysdeps.h"
 
22
 
 
23
#define WIN32_LEAN_AND_MEAN
 
24
#include <windows.h>
 
25
#include <winioctl.h>
 
26
 
 
27
#include <string>
 
28
using std::string;
 
29
 
 
30
#include <algorithm>
 
31
using std::min;
 
32
 
 
33
#include "main.h"
 
34
#include "macos_util.h"
 
35
#include "prefs.h"
 
36
#include "user_strings.h"
 
37
#include "sys.h"
 
38
 
 
39
#include "cd_defs.h"
 
40
#include "cdenable/ntcd.h"
 
41
#include "cdenable/cache.h"
 
42
#include "cdenable/eject_nt.h"
 
43
 
 
44
#define DEBUG 0
 
45
#include "debug.h"
 
46
 
 
47
 
 
48
// File handles are pointers to these structures
 
49
struct file_handle {
 
50
        char *name;                     // Copy of device/file name
 
51
        HANDLE fh;
 
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)
 
58
        cachetype cache;
 
59
        bool is_media_present;
 
60
};
 
61
 
 
62
// File handle of first floppy drive (for SysMountFirstFloppy())
 
63
static file_handle *first_floppy = NULL;
 
64
 
 
65
// CD-ROM variables
 
66
static const int CD_READ_AHEAD_SECTORS = 16;
 
67
static char *sector_buffer = NULL;
 
68
 
 
69
 
 
70
/*
 
71
 *  Initialization
 
72
 */
 
73
 
 
74
void SysInit(void)
 
75
{
 
76
        // Initialize CD-ROM driver
 
77
        sector_buffer = (char *)VirtualAlloc(NULL, 8192, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
 
78
        CdenableSysInstallStart();
 
79
}
 
80
 
 
81
 
 
82
/*
 
83
 *  Deinitialization
 
84
 */
 
85
 
 
86
void SysExit(void)
 
87
{
 
88
        if (sector_buffer) {
 
89
                VirtualFree(sector_buffer, 0, MEM_RELEASE );
 
90
                sector_buffer = NULL;
 
91
        }
 
92
}
 
93
 
 
94
 
 
95
/*
 
96
 *  Mount first floppy disk
 
97
 */
 
98
 
 
99
void SysMountFirstFloppy(void)
 
100
{
 
101
        if (first_floppy)
 
102
                MountVolume(first_floppy);
 
103
}
 
104
 
 
105
 
 
106
/*
 
107
 *  This gets called when no "floppy" prefs items are found
 
108
 *  It scans for available floppy drives and adds appropriate prefs items
 
109
 */
 
110
 
 
111
void SysAddFloppyPrefs(void)
 
112
{
 
113
}
 
114
 
 
115
 
 
116
/*
 
117
 *  This gets called when no "disk" prefs items are found
 
118
 *  It scans for available HFS volumes and adds appropriate prefs items
 
119
 */
 
120
 
 
121
void SysAddDiskPrefs(void)
 
122
{
 
123
}
 
124
 
 
125
 
 
126
/*
 
127
 *  This gets called when no "cdrom" prefs items are found
 
128
 *  It scans for available CD-ROM drives and adds appropriate prefs items
 
129
 */
 
130
 
 
131
void SysAddCDROMPrefs(void)
 
132
{
 
133
        // Don't scan for drives if nocdrom option given
 
134
        if (PrefsFindBool("nocdrom"))
 
135
                return;
 
136
 
 
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());
 
142
        }
 
143
}
 
144
 
 
145
 
 
146
/*
 
147
 *  Add default serial prefs (must be added, even if no ports present)
 
148
 */
 
149
 
 
150
void SysAddSerialPrefs(void)
 
151
{
 
152
        PrefsAddString("seriala", "COM1");
 
153
        PrefsAddString("serialb", "COM2");
 
154
}
 
155
 
 
156
 
 
157
/*
 
158
 *  Read CD-ROM
 
159
 *  Must give cd some time to settle
 
160
 *  Can't give too much however, would be annoying, this is difficult..
 
161
 */
 
162
 
 
163
static inline int cd_read_with_retry(file_handle *fh, ULONG LBA, int count, char *buf )
 
164
{
 
165
        if (!fh || !fh->fh)
 
166
                return 0;
 
167
 
 
168
        return CdenableSysReadCdBytes(fh->fh, LBA, count, buf);
 
169
}
 
170
 
 
171
static int cd_read(file_handle *fh, cachetype *cptr, ULONG LBA, int count, char *buf)
 
172
{
 
173
        ULONG l1, l2, cc;
 
174
        int i, c_count, got_bytes = 0, nblocks, s_inx, ss, first_block;
 
175
        int ok_bytes = 0;
 
176
        char *ptr, *ttptr = 0, *tmpbuf;
 
177
 
 
178
        if (count <= 0)
 
179
                return 0;
 
180
 
 
181
        if (!fh || !fh->fh)
 
182
                return 0;
 
183
 
 
184
        ss = 2048;
 
185
        l1 = (LBA / ss) * ss;
 
186
        l2 = ((LBA + count - 1 + ss) / ss) * ss;
 
187
        cc = l2 - l1;
 
188
        nblocks = cc / ss;
 
189
        first_block = LBA / ss;
 
190
 
 
191
        ptr = buf;
 
192
        s_inx = LBA - l1;
 
193
        c_count = ss - s_inx;
 
194
        if (c_count > count)
 
195
                c_count = count;
 
196
 
 
197
        for (i = 0; i < nblocks; i++) {
 
198
                if (!cache_get(cptr, first_block + i, sector_buffer))
 
199
                        break;
 
200
 
 
201
                memcpy(ptr, sector_buffer + s_inx, c_count);
 
202
                ok_bytes += c_count;
 
203
                ptr += c_count;
 
204
                s_inx = 0;
 
205
                c_count = ss;
 
206
                if (c_count > count - ok_bytes)
 
207
                        c_count = count - ok_bytes;
 
208
        }
 
209
 
 
210
        if (i != nblocks && count != ok_bytes) {
 
211
                int bytes_left = count - ok_bytes;
 
212
                int blocks_left = nblocks - i;
 
213
                int alignedleft;
 
214
 
 
215
                // NEW read ahead code:
 
216
                int ahead = CD_READ_AHEAD_SECTORS;
 
217
                if (blocks_left < ahead) {
 
218
                        nblocks += (ahead - blocks_left);
 
219
                        blocks_left = ahead;
 
220
                }
 
221
 
 
222
                alignedleft = blocks_left*ss;
 
223
 
 
224
                tmpbuf = (char *)VirtualAlloc(
 
225
                        NULL, alignedleft,
 
226
                        MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
 
227
                if (tmpbuf) {
 
228
                        got_bytes = cd_read_with_retry(fh, (first_block + i) * ss, alignedleft, tmpbuf);
 
229
                        if (got_bytes != alignedleft) {
 
230
                                // should never happen
 
231
                                // Yes it does ...
 
232
                                if (got_bytes < 0)
 
233
                                        got_bytes = 0;
 
234
                                if (c_count > got_bytes)
 
235
                                        c_count = got_bytes;
 
236
                                if (c_count > 0) {
 
237
                                        ttptr = tmpbuf;
 
238
                                        memcpy(ptr, ttptr + s_inx, c_count);
 
239
                                        ok_bytes += c_count;
 
240
                                }
 
241
                                VirtualFree(tmpbuf, 0, MEM_RELEASE );
 
242
                                return ok_bytes;
 
243
                        }
 
244
                        ttptr = tmpbuf;
 
245
                        for ( ; i < nblocks; i++) {
 
246
                                if (c_count > 0) {
 
247
                                        memcpy(ptr, ttptr + s_inx, c_count);
 
248
                                        ok_bytes += c_count;
 
249
                                        ptr += c_count;
 
250
                                }
 
251
                                s_inx = 0;
 
252
                                c_count = ss;
 
253
                                if (c_count > count - ok_bytes)
 
254
                                        c_count = count - ok_bytes;
 
255
                                cache_put(cptr, first_block + i, ttptr, ss);
 
256
                                ttptr += ss;
 
257
                        }
 
258
                        VirtualFree(tmpbuf, 0, MEM_RELEASE );
 
259
                }
 
260
        }
 
261
 
 
262
        return ok_bytes;
 
263
}
 
264
 
 
265
 
 
266
/*
 
267
 *  Check if file handle FH represents a readable CD-ROM
 
268
 */
 
269
 
 
270
static bool is_cdrom_readable(file_handle *fh)
 
271
{
 
272
        if (!fh || !fh->fh)
 
273
                return false;
 
274
 
 
275
        cache_clear(&fh->cache);
 
276
 
 
277
        DWORD dummy;
 
278
        bool result = (0 != DeviceIoControl(
 
279
                fh->fh,
 
280
                IOCTL_STORAGE_CHECK_VERIFY,
 
281
                NULL, 0,
 
282
                NULL, 0,
 
283
                &dummy,
 
284
                NULL));
 
285
        if (!result) {
 
286
                const size_t n_bytes = 2048;
 
287
                char *buffer = (char *)VirtualAlloc(NULL, n_bytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
 
288
                if (buffer) {
 
289
                        result = (cd_read_with_retry(fh, 0, n_bytes, buffer) == n_bytes);
 
290
                        VirtualFree(buffer, 0, MEM_RELEASE);
 
291
                }
 
292
        }
 
293
 
 
294
        return result;
 
295
}
 
296
 
 
297
 
 
298
/*
 
299
 *  Check if NAME represents a read-only file
 
300
 */
 
301
 
 
302
static bool is_read_only_path(const char *name)
 
303
{
 
304
        DWORD attrib = GetFileAttributes((char *)name);
 
305
        return (attrib != INVALID_FILE_ATTRIBUTES && ((attrib & FILE_ATTRIBUTE_READONLY) != 0));
 
306
}
 
307
 
 
308
 
 
309
/*
 
310
 *  Open file/device, create new file handle (returns NULL on error)
 
311
 */
 
312
 
 
313
void *Sys_open(const char *path_name, bool read_only)
 
314
{
 
315
        file_handle * fh = NULL;
 
316
 
 
317
        // Parse path name and options
 
318
        char name[MAX_PATH];
 
319
        strcpy(name, path_name);
 
320
 
 
321
        // Normalize floppy / cd path
 
322
        int name_len = strlen(name);
 
323
        if (name_len == 1 && isalpha(name[0]))
 
324
                strcat(name, ":\\");
 
325
        if (name_len > 0 && name[name_len - 1] == ':')
 
326
                strcat(name, "\\");
 
327
        name_len = strlen(name);
 
328
 
 
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);
 
332
 
 
333
                if (type == DRIVE_CDROM) {
 
334
                        read_only = true;
 
335
                        char device_name[MAX_PATH];
 
336
                        sprintf(device_name, "\\\\.\\%c:", name[0]);
 
337
 
 
338
                        // Open device
 
339
                        HANDLE h = CreateFile(
 
340
                                device_name,
 
341
                                GENERIC_READ,
 
342
                                0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 
343
 
 
344
                        if (h != INVALID_HANDLE_VALUE) {
 
345
                                fh = new file_handle;
 
346
                                fh->name = strdup(name);
 
347
                                fh->fh = h;
 
348
                                fh->is_file = false;
 
349
                                fh->read_only = read_only;
 
350
                                fh->start_byte = 0;
 
351
                                fh->is_floppy = false;
 
352
                                fh->is_cdrom = true;
 
353
                                if (!PrefsFindBool("nocdrom"))
 
354
                                        fh->is_media_present = is_cdrom_readable(fh);
 
355
                        }
 
356
                }
 
357
        }
 
358
 
 
359
        else { // Hard file
 
360
 
 
361
                // Check if write access is allowed, set read-only flag if not
 
362
                if (!read_only && is_read_only_path(name))
 
363
                        read_only = true;
 
364
 
 
365
                // Open file
 
366
                HANDLE h = CreateFile(
 
367
                        name,
 
368
                        read_only ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
 
369
                        0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 
370
 
 
371
                if (h == INVALID_HANDLE_VALUE && !read_only) {
 
372
                        // Read-write failed, try read-only
 
373
                        read_only = true;
 
374
                        h = CreateFile(
 
375
                                name,
 
376
                                GENERIC_READ,
 
377
                                0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 
378
                }
 
379
 
 
380
                if (h != INVALID_HANDLE_VALUE) {
 
381
                        fh = new file_handle;
 
382
                        fh->name = strdup(name);
 
383
                        fh->fh = h;
 
384
                        fh->is_file = true;
 
385
                        fh->read_only = read_only;
 
386
                        fh->start_byte = 0;
 
387
                        fh->is_floppy = false;
 
388
                        fh->is_cdrom = false;
 
389
 
 
390
                        // Detect disk image file layout
 
391
                        loff_t size = GetFileSize(h, NULL);
 
392
                        DWORD bytes_read;
 
393
                        uint8 data[256];
 
394
                        ReadFile(h, data, sizeof(data), &bytes_read, NULL);
 
395
                        FileDiskLayout(size, data, fh->start_byte, fh->file_size);
 
396
                }
 
397
        }
 
398
 
 
399
        if (fh->is_floppy && first_floppy == NULL)
 
400
                first_floppy = fh;
 
401
 
 
402
        return fh;
 
403
}
 
404
 
 
405
 
 
406
/*
 
407
 *  Close file/device, delete file handle
 
408
 */
 
409
 
 
410
void Sys_close(void *arg)
 
411
{
 
412
        file_handle *fh = (file_handle *)arg;
 
413
        if (!fh)
 
414
                return;
 
415
 
 
416
        if (fh->is_cdrom) {
 
417
                cache_final(&fh->cache);
 
418
                SysAllowRemoval((void *)fh);
 
419
        }
 
420
        if (fh->fh != NULL) {
 
421
                CloseHandle(fh->fh);
 
422
                fh->fh = NULL;
 
423
        }
 
424
        if (fh->name)
 
425
                free(fh->name);
 
426
 
 
427
        delete fh;
 
428
}
 
429
 
 
430
 
 
431
/*
 
432
 *  Read "length" bytes from file/device, starting at "offset", to "buffer",
 
433
 *  returns number of bytes read (or 0)
 
434
 */
 
435
 
 
436
size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
 
437
{
 
438
        file_handle *fh = (file_handle *)arg;
 
439
        if (!fh)
 
440
                return 0;
 
441
 
 
442
        DWORD bytes_read = 0;
 
443
 
 
444
        if (fh->is_file) {
 
445
                // Seek to position
 
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)
 
450
                        return 0;
 
451
 
 
452
                // Read data
 
453
                if (ReadFile(fh->fh, buffer, length, &bytes_read, NULL) == 0)
 
454
                        bytes_read = 0;
 
455
        }
 
456
        else if (fh->is_cdrom) {
 
457
                int bytes_left, try_bytes, got_bytes;
 
458
                char *b = (char *)buffer;
 
459
                bytes_left = length;
 
460
                while (bytes_left) {
 
461
                        try_bytes = min(bytes_left, 32768);
 
462
                        if (fh->is_cdrom) {
 
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);
 
466
                        }
 
467
                        b += got_bytes;
 
468
                        offset += got_bytes;
 
469
                        bytes_read += got_bytes;
 
470
                        bytes_left -= got_bytes;
 
471
                        if (got_bytes != try_bytes)
 
472
                                bytes_left = 0;
 
473
                }
 
474
        }
 
475
        // TODO: other media
 
476
 
 
477
        return bytes_read;
 
478
}
 
479
 
 
480
 
 
481
/*
 
482
 *  Write "length" bytes from "buffer" to file/device, starting at "offset",
 
483
 *  returns number of bytes written (or 0)
 
484
 */
 
485
 
 
486
size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
 
487
{
 
488
        file_handle *fh = (file_handle *)arg;
 
489
        if (!fh)
 
490
                return 0;
 
491
 
 
492
        DWORD bytes_written = 0;
 
493
 
 
494
        if (fh->is_file) {
 
495
                // Seek to position
 
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)
 
500
                        return 0;
 
501
 
 
502
                // Write data
 
503
                if (WriteFile(fh->fh, buffer, length, &bytes_written, NULL) == 0)
 
504
                        bytes_written = 0;
 
505
        }
 
506
        // TODO: other media
 
507
 
 
508
        return bytes_written;
 
509
}
 
510
 
 
511
 
 
512
/*
 
513
 *  Return size of file/device (minus header)
 
514
 */
 
515
 
 
516
loff_t SysGetFileSize(void *arg)
 
517
{
 
518
        file_handle *fh = (file_handle *)arg;
 
519
        if (!fh)
 
520
                return true;
 
521
 
 
522
        if (fh->is_file)
 
523
                return fh->file_size;
 
524
        else if (fh->is_cdrom)
 
525
                return 0x28A00000; // FIXME: get real CD-ROM size
 
526
        else {
 
527
                // TODO: other media
 
528
                return 0;
 
529
        }
 
530
}
 
531
 
 
532
 
 
533
/*
 
534
 *  Eject volume (if applicable)
 
535
 */
 
536
 
 
537
void SysEject(void *arg)
 
538
{
 
539
        file_handle *fh = (file_handle *)arg;
 
540
        if (!fh)
 
541
                return;
 
542
 
 
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);
 
548
 
 
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);
 
552
 
 
553
                if (!PrefsFindBool("nocdrom")) {
 
554
                        DWORD dummy;
 
555
                        DeviceIoControl(
 
556
                                fh->fh,
 
557
                                IOCTL_STORAGE_EJECT_MEDIA,
 
558
                                NULL, 0,
 
559
                                NULL, 0,
 
560
                                &dummy,
 
561
                                NULL
 
562
                                );
 
563
                }
 
564
                cache_clear(&fh->cache);
 
565
                fh->start_byte = 0;
 
566
        }
 
567
        // TODO: handle floppies
 
568
}
 
569
 
 
570
 
 
571
/*
 
572
 *  Format volume (if applicable)
 
573
 */
 
574
 
 
575
bool SysFormat(void *arg)
 
576
{
 
577
        file_handle *fh = (file_handle *)arg;
 
578
        if (!fh)
 
579
                return false;
 
580
 
 
581
        //!!
 
582
        return true;
 
583
}
 
584
 
 
585
 
 
586
/*
 
587
 *  Check if file/device is read-only (this includes the read-only flag on Sys_open())
 
588
 */
 
589
 
 
590
bool SysIsReadOnly(void *arg)
 
591
{
 
592
        file_handle *fh = (file_handle *)arg;
 
593
        if (!fh)
 
594
                return true;
 
595
 
 
596
        return fh->read_only;
 
597
}
 
598
 
 
599
 
 
600
/*
 
601
 *  Check if the given file handle refers to a fixed or a removable disk
 
602
 */
 
603
 
 
604
bool SysIsFixedDisk(void *arg)
 
605
{
 
606
        file_handle *fh = (file_handle *)arg;
 
607
        if (!fh)
 
608
                return true;
 
609
 
 
610
        if (fh->is_file)
 
611
                return true;
 
612
        else if (fh->is_floppy || fh->is_cdrom)
 
613
                return false;
 
614
        else
 
615
                return true;
 
616
}
 
617
 
 
618
 
 
619
/*
 
620
 *  Check if a disk is inserted in the drive (always true for files)
 
621
 */
 
622
 
 
623
bool SysIsDiskInserted(void *arg)
 
624
{
 
625
        file_handle *fh = (file_handle *)arg;
 
626
        if (!fh)
 
627
                return false;
 
628
 
 
629
        if (fh->is_file)
 
630
                return true;
 
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;
 
635
        }
 
636
        else {
 
637
                // TODO: other media
 
638
        }
 
639
 
 
640
        return false;
 
641
}
 
642
 
 
643
 
 
644
/*
 
645
 *  Prevent medium removal (if applicable)
 
646
 */
 
647
 
 
648
void SysPreventRemoval(void *arg)
 
649
{
 
650
        file_handle *fh = (file_handle *)arg;
 
651
        if (!fh)
 
652
                return;
 
653
 
 
654
        if (fh->is_cdrom && fh->fh)
 
655
                PreventRemovalOfVolume(fh->fh, true);
 
656
}
 
657
 
 
658
 
 
659
/*
 
660
 *  Allow medium removal (if applicable)
 
661
 */
 
662
 
 
663
void SysAllowRemoval(void *arg)
 
664
{
 
665
        file_handle *fh = (file_handle *)arg;
 
666
        if (!fh)
 
667
                return;
 
668
 
 
669
        if (fh->is_cdrom && fh->fh)
 
670
                PreventRemovalOfVolume(fh->fh, false);
 
671
}
 
672
 
 
673
 
 
674
/*
 
675
 *  Read CD-ROM TOC (binary MSF format, 804 bytes max.)
 
676
 */
 
677
 
 
678
bool SysCDReadTOC(void *arg, uint8 *toc)
 
679
{
 
680
        file_handle *fh = (file_handle *)arg;
 
681
        if (!fh || !fh->fh || !fh->is_cdrom)
 
682
                return false;
 
683
 
 
684
        DWORD dummy;
 
685
        return DeviceIoControl(fh->fh,
 
686
                                                   IOCTL_CDROM_READ_TOC,
 
687
                                                   NULL, 0,
 
688
                                                   toc, min((int)sizeof(CDROM_TOC), 804),
 
689
                                                   &dummy,
 
690
                                                   NULL);
 
691
}
 
692
 
 
693
 
 
694
/*
 
695
 *  Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
 
696
 */
 
697
 
 
698
bool SysCDGetPosition(void *arg, uint8 *pos)
 
699
{
 
700
        file_handle *fh = (file_handle *)arg;
 
701
        if (!fh || !fh->fh || !fh->is_cdrom)
 
702
                return false;
 
703
 
 
704
        SUB_Q_CHANNEL_DATA q_data;
 
705
 
 
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
 
709
 
 
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),
 
715
                                                          &dwBytesReturned,
 
716
                                                          NULL);
 
717
        if (ok)
 
718
                memcpy(pos, &q_data.CurrentPosition, sizeof(SUB_Q_CURRENT_POSITION));
 
719
 
 
720
        return ok;
 
721
}
 
722
 
 
723
 
 
724
/*
 
725
 *  Play CD audio
 
726
 */
 
727
 
 
728
bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
 
729
{
 
730
        file_handle *fh = (file_handle *)arg;
 
731
        if (!fh || !fh->fh || !fh->is_cdrom)
 
732
                return false;
 
733
 
 
734
        CDROM_PLAY_AUDIO_MSF msf;
 
735
        msf.StartingM = start_m;
 
736
        msf.StartingS = start_s;
 
737
        msf.StartingF = start_f;
 
738
        msf.EndingM = end_m;
 
739
        msf.EndingS = end_s;
 
740
        msf.EndingF = end_f;
 
741
 
 
742
        DWORD dwBytesReturned = 0;
 
743
        return DeviceIoControl(fh->fh,
 
744
                                                   IOCTL_CDROM_PLAY_AUDIO_MSF,
 
745
                                                   &msf, sizeof(CDROM_PLAY_AUDIO_MSF),
 
746
                                                   NULL, 0,
 
747
                                                   &dwBytesReturned,
 
748
                                                   NULL);
 
749
}
 
750
 
 
751
 
 
752
/*
 
753
 *  Pause CD audio
 
754
 */
 
755
 
 
756
bool SysCDPause(void *arg)
 
757
{
 
758
        file_handle *fh = (file_handle *)arg;
 
759
        if (!fh || !fh->fh || !fh->is_cdrom)
 
760
                return false;
 
761
 
 
762
        DWORD dwBytesReturned = 0;
 
763
        return DeviceIoControl(fh->fh,
 
764
                                                   IOCTL_CDROM_PAUSE_AUDIO,
 
765
                                                   NULL, 0,
 
766
                                                   NULL, 0,
 
767
                                                   &dwBytesReturned,
 
768
                                                   NULL);
 
769
}
 
770
 
 
771
 
 
772
/*
 
773
 *  Resume paused CD audio
 
774
 */
 
775
 
 
776
bool SysCDResume(void *arg)
 
777
{
 
778
        file_handle *fh = (file_handle *)arg;
 
779
        if (!fh || !fh->fh || !fh->is_cdrom)
 
780
                return false;
 
781
 
 
782
        DWORD dwBytesReturned = 0;
 
783
        return DeviceIoControl(fh->fh,
 
784
                                                   IOCTL_CDROM_RESUME_AUDIO,
 
785
                                                   NULL, 0,
 
786
                                                   NULL, 0,
 
787
                                                   &dwBytesReturned, NULL);
 
788
}
 
789
 
 
790
 
 
791
/*
 
792
 *  Stop CD audio
 
793
 */
 
794
 
 
795
bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
 
796
{
 
797
        file_handle *fh = (file_handle *)arg;
 
798
        if (!fh || !fh->fh || !fh->is_cdrom)
 
799
                return false;
 
800
 
 
801
        DWORD dwBytesReturned = 0;
 
802
        return DeviceIoControl(fh->fh,
 
803
                                                   IOCTL_CDROM_STOP_AUDIO,
 
804
                                                   NULL, 0,
 
805
                                                   NULL, 0,
 
806
                                                   &dwBytesReturned,
 
807
                                                   NULL);
 
808
}
 
809
 
 
810
 
 
811
/*
 
812
 *  Perform CD audio fast-forward/fast-reverse operation starting from specified address
 
813
 */
 
814
 
 
815
bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
 
816
{
 
817
        file_handle *fh = (file_handle *)arg;
 
818
        if (!fh || !fh->fh || !fh->is_cdrom)
 
819
                return false;
 
820
 
 
821
        CDROM_SEEK_AUDIO_MSF msf;
 
822
        msf.M = start_m;
 
823
        msf.S = start_s;
 
824
        msf.F = start_f;
 
825
 
 
826
        DWORD dwBytesReturned = 0;
 
827
        return DeviceIoControl(fh->fh,
 
828
                                                   IOCTL_CDROM_SEEK_AUDIO_MSF,
 
829
                                                   &msf, sizeof(CDROM_SEEK_AUDIO_MSF),
 
830
                                                   NULL, 0,
 
831
                                                   &dwBytesReturned,
 
832
                                                   NULL);
 
833
}
 
834
 
 
835
 
 
836
/*
 
837
 *  Set CD audio volume (0..255 each channel)
 
838
 */
 
839
 
 
840
void SysCDSetVolume(void *arg, uint8 left, uint8 right)
 
841
{
 
842
        file_handle *fh = (file_handle *)arg;
 
843
        if (!fh || !fh->fh || !fh->is_cdrom)
 
844
                return;
 
845
 
 
846
        VOLUME_CONTROL vc;
 
847
        vc.PortVolume[0] = left;
 
848
        vc.PortVolume[1] = right;
 
849
        vc.PortVolume[2] = left;
 
850
        vc.PortVolume[3] = right;
 
851
 
 
852
        DWORD dwBytesReturned = 0;
 
853
        DeviceIoControl(fh->fh,
 
854
                                        IOCTL_CDROM_SET_VOLUME,
 
855
                                        &vc, sizeof(VOLUME_CONTROL),
 
856
                                        NULL, 0,
 
857
                                        &dwBytesReturned,
 
858
                                        NULL);
 
859
}
 
860
 
 
861
 
 
862
/*
 
863
 *  Get CD audio volume (0..255 each channel)
 
864
 */
 
865
 
 
866
void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
 
867
{
 
868
        file_handle *fh = (file_handle *)arg;
 
869
        if (!fh)
 
870
                return;
 
871
 
 
872
        left = right = 0;
 
873
        if (!fh->fh || !fh->is_cdrom)
 
874
                return;
 
875
 
 
876
        VOLUME_CONTROL vc;
 
877
        memset(&vc, 0, sizeof(vc));
 
878
 
 
879
        DWORD dwBytesReturned = 0;
 
880
        if (DeviceIoControl(fh->fh,
 
881
                                                IOCTL_CDROM_GET_VOLUME,
 
882
                                                NULL, 0,
 
883
                                                &vc, sizeof(VOLUME_CONTROL),
 
884
                                                &dwBytesReturned,
 
885
                                                NULL))
 
886
        {
 
887
                left = vc.PortVolume[0];
 
888
                right = vc.PortVolume[1];
 
889
        }
 
890
}