ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/sys_windows.cpp
Revision: 1.5
Committed: 2008-01-01T09:40:34Z (16 years, 5 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +1 -1 lines
Log Message:
Happy New Year!

File Contents

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