ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/sys_windows.cpp
Revision: 1.4
Committed: 2006-05-08T12:15:58Z (18 years, 1 month ago) by gbeauche
Branch: MAIN
CVS Tags: nigel-build-19
Changes since 1.3: +0 -8 lines
Log Message:
Rewrite MacOS X CD-ROM support.

Other bugs fixed:
- CD-ROM media are polled and now can be changed without rebooting
- Buffer overflow, memory leak and extra wait in CD-ROM ejection code

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 // 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 // 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 // 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 // Prototypes
77 static bool is_cdrom_readable(file_handle *fh);
78
79
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 * 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 * 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 memset(&fh->cache, 0, sizeof(cachetype));
452 cache_init(&fh->cache);
453 cache_clear(&fh->cache);
454 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 if (fh)
504 sys_add_file_handle(fh);
505
506 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 sys_remove_file_handle(fh);
521
522 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 }