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

# Content
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 // 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 // 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 // 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 // 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 // Prototypes
85 static bool is_cdrom_readable(file_handle *fh);
86
87
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 * 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 * 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 memset(&fh->cache, 0, sizeof(cachetype));
460 cache_init(&fh->cache);
461 cache_clear(&fh->cache);
462 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 if (fh)
512 sys_add_file_handle(fh);
513
514 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 sys_remove_file_handle(fh);
529
530 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 }