ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/sys_windows.cpp
Revision: 1.3
Committed: 2006-03-28T07:01:19Z (18 years, 3 months ago) by gbeauche
Branch: MAIN
Changes since 1.2: +114 -0 lines
Log Message:
Fix pollmedia on Windows, it's no longer necessary to boot with a CD-ROM in
the drive to use it. Side effect: media can be changed without problems now

File Contents

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