ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sys_unix.cpp
Revision: 1.32
Committed: 2010-10-06T00:30:23Z (14 years, 1 month ago) by asvitkine
Branch: MAIN
Changes since 1.31: +109 -6 lines
Log Message:
[Geoffrey Brown]

Add bin/cue support. The following should work:

1) Basilisk and SheepShaver with sdl-audio and bincue on linux and os x
2) SheepShaver with bincue and core audio on os x

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * sys_unix.cpp - System dependent routines, Unix implementation
3     *
4 cebix 1.31 * Basilisk II (C) Christian Bauer
5 cebix 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     #include <sys/ioctl.h>
24     #include <sys/stat.h>
25     #include <errno.h>
26    
27 gbeauche 1.23 #ifdef HAVE_AVAILABILITYMACROS_H
28     #include <AvailabilityMacros.h>
29     #endif
30    
31 cebix 1.1 #ifdef __linux__
32 cebix 1.6 #include <sys/mount.h>
33 cebix 1.1 #include <linux/cdrom.h>
34     #include <linux/fd.h>
35     #include <linux/major.h>
36     #include <linux/kdev_t.h>
37 cebix 1.16 #include <dirent.h>
38 cebix 1.31 #include <limits.h>
39 cebix 1.1 #endif
40    
41 cebix 1.3 #if defined(__FreeBSD__) || defined(__NetBSD__)
42 cebix 1.1 #include <sys/cdio.h>
43     #endif
44    
45 gbeauche 1.29 #if defined __APPLE__ && defined __MACH__
46     #include <sys/disk.h>
47     #if (defined AQUA || defined HAVE_FRAMEWORK_COREFOUNDATION)
48     #ifndef __MACOSX__
49     #define __MACOSX__ MAC_OS_X_VERSION_MIN_REQUIRED
50     #endif
51     #endif
52     #endif
53    
54 cebix 1.1 #include "main.h"
55     #include "macos_util.h"
56     #include "prefs.h"
57     #include "user_strings.h"
58     #include "sys.h"
59    
60 asvitkine 1.32 #if defined(BINCUE)
61     #include "bincue_unix.h"
62     #endif
63    
64 cebix 1.1 #define DEBUG 0
65     #include "debug.h"
66    
67     // File handles are pointers to these structures
68     struct file_handle {
69 asvitkine 1.32 char *name; // Copy of device/file name
70 cebix 1.1 int fd;
71     bool is_file; // Flag: plain file or /dev/something?
72     bool is_floppy; // Flag: floppy device
73     bool is_cdrom; // Flag: CD-ROM device
74 asvitkine 1.32 #if defined(BINCUE)
75     bool is_bincue; // Flag: BIN CUE file
76     #endif
77 cebix 1.1 bool read_only; // Copy of Sys_open() flag
78 asvitkine 1.32 loff_t start_byte; // Size of file header (if any)
79 cebix 1.1 loff_t file_size; // Size of file data (only valid if is_file is true)
80 gbeauche 1.29 bool is_media_present; // Flag: media is inserted and available
81 cebix 1.1
82     #if defined(__linux__)
83     int cdrom_cap; // CD-ROM capability flags (only valid if is_cdrom is true)
84     #elif defined(__FreeBSD__)
85     struct ioc_capability cdrom_cap;
86 nigel 1.19 #elif defined(__APPLE__) && defined(__MACH__)
87 asvitkine 1.32 char *ioctl_name; // For CDs on OS X - a device for special ioctls
88     int ioctl_fd;
89     #endif
90    
91     #if defined(BINCUE)
92     void *bincue_fd;
93 cebix 1.1 #endif
94     };
95    
96 gbeauche 1.29 // Open file handles
97     struct open_file_handle {
98     file_handle *fh;
99     open_file_handle *next;
100     };
101     static open_file_handle *open_file_handles = NULL;
102    
103 cebix 1.1 // File handle of first floppy drive (for SysMountFirstFloppy())
104     static file_handle *first_floppy = NULL;
105    
106 gbeauche 1.29 // Prototypes
107     static void cdrom_close(file_handle *fh);
108     static bool cdrom_open(file_handle *fh, const char *path = NULL);
109    
110 cebix 1.1
111     /*
112     * Initialization
113     */
114    
115     void SysInit(void)
116     {
117 gbeauche 1.29 #if defined __MACOSX__
118     extern void DarwinSysInit(void);
119     DarwinSysInit();
120     #endif
121 cebix 1.1 }
122    
123    
124     /*
125     * Deinitialization
126     */
127    
128     void SysExit(void)
129     {
130 gbeauche 1.29 #if defined __MACOSX__
131     extern void DarwinSysExit(void);
132     DarwinSysExit();
133     #endif
134     }
135    
136    
137     /*
138     * Manage open file handles
139     */
140    
141     static void sys_add_file_handle(file_handle *fh)
142     {
143     open_file_handle *p = new open_file_handle;
144     p->fh = fh;
145     p->next = open_file_handles;
146     open_file_handles = p;
147     }
148    
149     static void sys_remove_file_handle(file_handle *fh)
150     {
151     open_file_handle *p = open_file_handles;
152     open_file_handle *q = NULL;
153    
154     while (p) {
155     if (p->fh == fh) {
156     if (q)
157     q->next = p->next;
158     else
159     open_file_handles = p->next;
160     delete p;
161     break;
162     }
163     q = p;
164     p = p->next;
165     }
166     }
167    
168    
169     /*
170     * Account for media that has just arrived
171     */
172    
173     void SysMediaArrived(const char *path, int type)
174     {
175     // Replace the "cdrom" entry (we are polling, it's unique)
176     if (type == MEDIA_CD && !PrefsFindBool("nocdrom"))
177     PrefsReplaceString("cdrom", path);
178    
179     // Wait for media to be available for reading
180     if (open_file_handles) {
181     const int MAX_WAIT = 5;
182     for (int i = 0; i < MAX_WAIT; i++) {
183     if (access(path, R_OK) == 0)
184     break;
185     switch (errno) {
186     case ENOENT: // Unlikely
187     case EACCES: // MacOS X is mounting the media
188     sleep(1);
189     continue;
190     }
191     printf("WARNING: Cannot access %s (%s)\n", path, strerror(errno));
192     return;
193     }
194     }
195    
196     for (open_file_handle *p = open_file_handles; p != NULL; p = p->next) {
197     file_handle * const fh = p->fh;
198    
199     // Re-open CD-ROM device
200     if (fh->is_cdrom && type == MEDIA_CD) {
201     cdrom_close(fh);
202     if (cdrom_open(fh, path)) {
203     fh->is_media_present = true;
204     MountVolume(fh);
205     }
206     }
207     }
208     }
209    
210    
211     /*
212     * Account for media that has just been removed
213     */
214    
215     void SysMediaRemoved(const char *path, int type)
216     {
217     if ((type & MEDIA_REMOVABLE) != MEDIA_CD)
218     return;
219    
220     for (open_file_handle *p = open_file_handles; p != NULL; p = p->next) {
221     file_handle * const fh = p->fh;
222    
223     // Mark media as not available
224     if (!fh->is_cdrom || !fh->is_media_present)
225     continue;
226     if (fh->name && strcmp(fh->name, path) == 0) {
227     fh->is_media_present = false;
228     break;
229     }
230     #if defined __MACOSX__
231     if (fh->ioctl_name && strcmp(fh->ioctl_name, path) == 0) {
232     fh->is_media_present = false;
233     break;
234     }
235     #endif
236     }
237 cebix 1.1 }
238    
239    
240     /*
241     * Mount first floppy disk
242     */
243    
244     void SysMountFirstFloppy(void)
245     {
246     if (first_floppy)
247     MountVolume(first_floppy);
248     }
249    
250    
251     /*
252     * This gets called when no "floppy" prefs items are found
253     * It scans for available floppy drives and adds appropriate prefs items
254     */
255    
256     void SysAddFloppyPrefs(void)
257     {
258     #if defined(__linux__)
259 cebix 1.27 DIR *fd_dir = opendir("/dev/floppy");
260     if (fd_dir) {
261     struct dirent *floppy_dev;
262     while ((floppy_dev = readdir(fd_dir)) != NULL) {
263     if (strstr(floppy_dev->d_name, "u1440") != NULL) {
264     char fd_dev[20];
265     sprintf(fd_dev, "/dev/floppy/%s", floppy_dev->d_name);
266     PrefsAddString("floppy", fd_dev);
267 cebix 1.16 }
268     }
269 cebix 1.27 closedir(fd_dir);
270     } else {
271     PrefsAddString("floppy", "/dev/fd0");
272     PrefsAddString("floppy", "/dev/fd1");
273 cebix 1.16 }
274 cebix 1.3 #elif defined(__NetBSD__)
275     PrefsAddString("floppy", "/dev/fd0a");
276     PrefsAddString("floppy", "/dev/fd1a");
277 nigel 1.19 #elif defined(__APPLE__) && defined(__MACH__)
278 gbeauche 1.25 #if defined(AQUA) || defined(HAVE_FRAMEWORK_COREFOUNDATION)
279 nigel 1.22 extern void DarwinAddFloppyPrefs(void);
280    
281     DarwinAddFloppyPrefs();
282     #else
283     // Until I can convince the other guys that my Darwin code is useful,
284     // we just add something safe (a non-existant device):
285     PrefsAddString("floppy", "/dev/null");
286     #endif
287 cebix 1.1 #else
288     PrefsAddString("floppy", "/dev/fd0");
289     PrefsAddString("floppy", "/dev/fd1");
290     #endif
291     }
292    
293    
294     /*
295     * This gets called when no "disk" prefs items are found
296     * It scans for available HFS volumes and adds appropriate prefs items
297 nigel 1.19 * On OS X, we could do the same, but on an OS X machine I think it is
298     * very unlikely that any mounted volumes would contain a system which
299     * is old enough to boot a 68k Mac, so we just do nothing here for now.
300 cebix 1.1 */
301    
302     void SysAddDiskPrefs(void)
303     {
304     #ifdef __linux__
305     FILE *f = fopen("/etc/fstab", "r");
306     if (f) {
307     char line[256];
308     while(fgets(line, 255, f)) {
309     // Read line
310     int len = strlen(line);
311 cebix 1.10 if (len == 0 || line[0] == '#')
312 cebix 1.1 continue;
313     line[len-1] = 0;
314    
315     // Parse line
316     char *dev, *mnt_point, *fstype;
317 cebix 1.3 if (sscanf(line, "%as %as %as", &dev, &mnt_point, &fstype) == 3) {
318 cebix 1.1 if (strcmp(fstype, "hfs") == 0)
319     PrefsAddString("disk", dev);
320     }
321 cebix 1.3 free(dev); free(mnt_point); free(fstype);
322 cebix 1.1 }
323     fclose(f);
324     }
325     #endif
326     }
327    
328    
329     /*
330     * This gets called when no "cdrom" prefs items are found
331     * It scans for available CD-ROM drives and adds appropriate prefs items
332     */
333    
334     void SysAddCDROMPrefs(void)
335     {
336     // Don't scan for drives if nocdrom option given
337     if (PrefsFindBool("nocdrom"))
338     return;
339    
340     #if defined(__linux__)
341 gbeauche 1.17 if (access("/dev/.devfsd", F_OK) < 0)
342 cebix 1.16 PrefsAddString("cdrom", "/dev/cdrom");
343     else {
344     DIR *cd_dir = opendir("/dev/cdroms");
345     if (cd_dir) {
346     struct dirent *cdrom_dev;
347     while ((cdrom_dev = readdir(cd_dir)) != NULL) {
348     if (strcmp(cdrom_dev->d_name, ".") != 0 && strcmp(cdrom_dev->d_name, "..") != 0) {
349 gbeauche 1.17 char cd_dev[20];
350     sprintf(cd_dev, "/dev/cdroms/%s", cdrom_dev->d_name);
351 cebix 1.16 PrefsAddString("cdrom", cd_dev);
352     }
353     }
354     closedir(cd_dir);
355     }
356     }
357 gbeauche 1.29 #elif defined __MACOSX__
358     // There is no predefined path for CD-ROMs on MacOS X. Rather, we
359     // define a single fake CD-ROM entry for the emulated MacOS.
360     // XXX this means we handle only CD-ROM drive at a time, wherever
361     // the disk is, the latest one is used.
362     PrefsAddString("cdrom", "/dev/poll/cdrom");
363 cebix 1.18 #elif defined(__FreeBSD__) || defined(__NetBSD__)
364 cebix 1.1 PrefsAddString("cdrom", "/dev/cd0c");
365     #endif
366     }
367    
368    
369     /*
370     * Add default serial prefs (must be added, even if no ports present)
371     */
372    
373     void SysAddSerialPrefs(void)
374     {
375     #if defined(__linux__)
376 gbeauche 1.17 if (access("/dev/.devfsd", F_OK) < 0) {
377 cebix 1.16 PrefsAddString("seriala", "/dev/ttyS0");
378     PrefsAddString("serialb", "/dev/ttyS1");
379     } else {
380     PrefsAddString("seriala", "/dev/tts/0");
381     PrefsAddString("serialb", "/dev/tts/1");
382     }
383 cebix 1.1 #elif defined(__FreeBSD__)
384     PrefsAddString("seriala", "/dev/cuaa0");
385     PrefsAddString("serialb", "/dev/cuaa1");
386 cebix 1.3 #elif defined(__NetBSD__)
387     PrefsAddString("seriala", "/dev/tty00");
388     PrefsAddString("serialb", "/dev/tty01");
389 nigel 1.19 #elif defined(__APPLE__) && defined(__MACH__)
390 gbeauche 1.25 #if defined(AQUA) || defined(HAVE_FRAMEWORK_COREFOUNDATION)
391 nigel 1.22 extern void DarwinAddSerialPrefs(void);
392    
393     DarwinAddSerialPrefs();
394     #else
395     // Until I can convince the other guys that my Darwin code is useful,
396     // we just add something safe (non-existant devices):
397     PrefsAddString("seriala", "/dev/null");
398     PrefsAddString("serialb", "/dev/null");
399     #endif
400 cebix 1.1 #endif
401     }
402    
403    
404     /*
405 gbeauche 1.29 * Open CD-ROM device and initialize internal data
406     */
407    
408     static bool cdrom_open_1(file_handle *fh)
409     {
410     #if defined __MACOSX__
411     // In OS X, the device name is OK for sending ioctls to,
412     // but not for reading raw CDROM data from.
413     // (it seems to have extra data padded in)
414     //
415     // So, we keep the already opened file handle,
416     // and open a slightly different file for CDROM data
417     //
418     fh->ioctl_fd = fh->fd;
419     fh->ioctl_name = fh->name;
420     fh->fd = -1;
421     fh->name = (char *)malloc(strlen(fh->ioctl_name) + 3);
422     if (fh->name) {
423     strcpy(fh->name, fh->ioctl_name);
424     strcat(fh->name, "s1");
425     fh->fd = open(fh->name, O_RDONLY, O_NONBLOCK);
426     }
427     if (fh->ioctl_fd < 0)
428     return false;
429     #endif
430     return true;
431     }
432    
433     bool cdrom_open(file_handle *fh, const char *path)
434     {
435     if (path)
436     fh->name = strdup(path);
437     fh->fd = open(fh->name, O_RDONLY, O_NONBLOCK);
438     fh->start_byte = 0;
439     if (!cdrom_open_1(fh))
440     return false;
441     return fh->fd >= 0;
442     }
443    
444    
445     /*
446     * Close a CD-ROM device
447     */
448    
449     void cdrom_close(file_handle *fh)
450     {
451 asvitkine 1.32
452 gbeauche 1.29 if (fh->fd >= 0) {
453     close(fh->fd);
454     fh->fd = -1;
455     }
456     if (fh->name) {
457     free(fh->name);
458     fh->name = NULL;
459     }
460     #if defined __MACOSX__
461     if (fh->ioctl_fd >= 0) {
462     close(fh->ioctl_fd);
463     fh->ioctl_fd = -1;
464     }
465     if (fh->ioctl_name) {
466     free(fh->ioctl_name);
467     fh->ioctl_name = NULL;
468     }
469     #endif
470     }
471    
472    
473     /*
474 cebix 1.1 * Check if device is a mounted HFS volume, get mount name
475     */
476    
477     static bool is_drive_mounted(const char *dev_name, char *mount_name)
478     {
479     #ifdef __linux__
480     FILE *f = fopen("/proc/mounts", "r");
481     if (f) {
482     char line[256];
483     while(fgets(line, 255, f)) {
484     // Read line
485     int len = strlen(line);
486     if (len == 0)
487     continue;
488     line[len-1] = 0;
489    
490     // Parse line
491     if (strncmp(line, dev_name, strlen(dev_name)) == 0) {
492     mount_name[0] = 0;
493 cebix 1.3 char *dummy;
494     sscanf(line, "%as %s", &dummy, mount_name);
495     free(dummy);
496 cebix 1.1 fclose(f);
497     return true;
498     }
499     }
500     fclose(f);
501     }
502     #endif
503     return false;
504     }
505    
506    
507     /*
508     * Open file/device, create new file handle (returns NULL on error)
509     */
510    
511     void *Sys_open(const char *name, bool read_only)
512     {
513     bool is_file = strncmp(name, "/dev/", 5) != 0;
514 cebix 1.3 #if defined(__FreeBSD__)
515 cebix 1.1 // SCSI IDE
516     bool is_cdrom = strncmp(name, "/dev/cd", 7) == 0 || strncmp(name, "/dev/acd", 8) == 0;
517     #else
518     bool is_cdrom = strncmp(name, "/dev/cd", 7) == 0;
519     #endif
520 cebix 1.28 bool is_floppy = strncmp(name, "/dev/fd", 7) == 0;
521 cebix 1.1
522 gbeauche 1.29 bool is_polled_media = strncmp(name, "/dev/poll/", 10) == 0;
523     if (is_floppy) // Floppy open fails if there's no disk inserted
524     is_polled_media = true;
525    
526     #if defined __MACOSX__
527 nigel 1.19 // There is no set filename in /dev which is the cdrom,
528     // so we have to see if it is any of the devices that we found earlier
529     {
530 gbeauche 1.29 int index = 0;
531     const char *str;
532     while ((str = PrefsFindString("cdrom", index++)) != NULL) {
533     if (is_polled_media || strcmp(str, name) == 0) {
534     is_cdrom = true;
535     read_only = true;
536     break;
537     }
538 nigel 1.19 }
539     }
540     #endif
541    
542 cebix 1.1 D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write"));
543    
544     // Check if write access is allowed, set read-only flag if not
545     if (!read_only && access(name, W_OK))
546     read_only = true;
547    
548     // Print warning message and eventually unmount drive when this is an HFS volume mounted under Linux (double mounting will corrupt the volume)
549     char mount_name[256];
550     if (!is_file && !read_only && is_drive_mounted(name, mount_name)) {
551     char str[512];
552     sprintf(str, GetString(STR_VOLUME_IS_MOUNTED_WARN), mount_name);
553     WarningAlert(str);
554     sprintf(str, "umount %s", mount_name);
555     if (system(str)) {
556     sprintf(str, GetString(STR_CANNOT_UNMOUNT_WARN), mount_name, strerror(errno));
557     WarningAlert(str);
558     return NULL;
559     }
560     }
561    
562     // Open file/device
563 asvitkine 1.32
564     #if defined(BINCUE)
565    
566     void *binfd = open_bincue(name);
567     if (binfd) {
568     file_handle *fh = new file_handle;
569     fh->fd = 0;
570     fh->is_file = false;
571     fh->name = strdup(name);
572     fh->bincue_fd = binfd;
573     fh->is_bincue = true;
574     fh->read_only = true;
575     fh->start_byte = 0;
576     fh->is_floppy = false;
577     fh->is_cdrom = false;
578     fh->is_media_present = true;
579     #if defined __MACOSX__
580     fh->ioctl_fd = -1;
581     fh->ioctl_name = NULL;
582     #endif
583     sys_add_file_handle(fh);
584     return fh;
585     }
586     #endif
587    
588 gbeauche 1.29 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__MACOSX__)
589 cebix 1.1 int fd = open(name, (read_only ? O_RDONLY : O_RDWR) | (is_cdrom ? O_NONBLOCK : 0));
590     #else
591     int fd = open(name, read_only ? O_RDONLY : O_RDWR);
592     #endif
593     if (fd < 0 && !read_only) {
594     // Read-write failed, try read-only
595     read_only = true;
596     fd = open(name, O_RDONLY);
597     }
598 gbeauche 1.29 if (fd >= 0 || is_polled_media) {
599 cebix 1.1 file_handle *fh = new file_handle;
600     fh->name = strdup(name);
601     fh->fd = fd;
602     fh->is_file = is_file;
603     fh->read_only = read_only;
604     fh->start_byte = 0;
605 cebix 1.28 fh->is_floppy = is_floppy;
606     fh->is_cdrom = is_cdrom;
607 gbeauche 1.29 fh->is_media_present = false;
608 asvitkine 1.32 #if defined __linux__
609     fh->cdrom_cap = 0;
610     #endif
611 gbeauche 1.29 #if defined __MACOSX__
612     fh->ioctl_fd = -1;
613     fh->ioctl_name = NULL;
614     #endif
615 asvitkine 1.32 #if defined(BINCUE)
616     fh->is_bincue = false;
617     fh->bincue_fd = NULL;
618     #endif
619 cebix 1.1 if (fh->is_file) {
620 gbeauche 1.29 fh->is_media_present = true;
621 cebix 1.1 // Detect disk image file layout
622     loff_t size = 0;
623     size = lseek(fd, 0, SEEK_END);
624     uint8 data[256];
625     lseek(fd, 0, SEEK_SET);
626     read(fd, data, 256);
627     FileDiskLayout(size, data, fh->start_byte, fh->file_size);
628     } else {
629     struct stat st;
630     if (fstat(fd, &st) == 0) {
631 gbeauche 1.29 fh->is_media_present = true;
632 cebix 1.1 if (S_ISBLK(st.st_mode)) {
633     fh->is_cdrom = is_cdrom;
634     #if defined(__linux__)
635     fh->is_floppy = (MAJOR(st.st_rdev) == FLOPPY_MAJOR);
636     #ifdef CDROM_GET_CAPABILITY
637     if (is_cdrom) {
638     fh->cdrom_cap = ioctl(fh->fd, CDROM_GET_CAPABILITY);
639     if (fh->cdrom_cap < 0)
640     fh->cdrom_cap = 0;
641     }
642     #else
643     fh->cdrom_cap = 0;
644     #endif
645 cebix 1.4 #elif defined(__FreeBSD__)
646 cebix 1.1 fh->is_floppy = ((st.st_rdev >> 16) == 2);
647     #ifdef CDIOCCAPABILITY
648     if (is_cdrom) {
649     if (ioctl(fh->fd, CDIOCCAPABILITY, &fh->cdrom_cap) < 0)
650     memset(&fh->cdrom_cap, 0, sizeof(fh->cdrom_cap));
651     }
652     #else
653     fh->cdrom_cap = 0;
654     #endif
655 cebix 1.4 #elif defined(__NetBSD__)
656     fh->is_floppy = ((st.st_rdev >> 16) == 2);
657 cebix 1.1 #endif
658     }
659 gbeauche 1.29 #if defined __MACOSX__
660     if (is_cdrom) {
661     fh->is_cdrom = true;
662     fh->is_floppy = false;
663     if (cdrom_open_1(fh))
664     fh->is_media_present = true;
665 nigel 1.19 }
666     #endif
667 cebix 1.1 }
668     }
669     if (fh->is_floppy && first_floppy == NULL)
670     first_floppy = fh;
671 gbeauche 1.29 sys_add_file_handle(fh);
672 cebix 1.1 return fh;
673     } else {
674     printf("WARNING: Cannot open %s (%s)\n", name, strerror(errno));
675     return NULL;
676     }
677     }
678    
679    
680     /*
681     * Close file/device, delete file handle
682     */
683    
684     void Sys_close(void *arg)
685     {
686     file_handle *fh = (file_handle *)arg;
687     if (!fh)
688     return;
689    
690 gbeauche 1.29 sys_remove_file_handle(fh);
691    
692 asvitkine 1.32 #if defined(BINCUE)
693     if (fh->is_bincue) {
694     close_bincue(fh->bincue_fd);
695     fh->bincue_fd = NULL;
696     }
697     #endif
698    
699 gbeauche 1.29 if (fh->is_cdrom)
700     cdrom_close(fh);
701 cebix 1.28 if (fh->fd >= 0)
702     close(fh->fd);
703 cebix 1.1 if (fh->name)
704     free(fh->name);
705     delete fh;
706     }
707    
708    
709     /*
710     * Read "length" bytes from file/device, starting at "offset", to "buffer",
711     * returns number of bytes read (or 0)
712     */
713    
714     size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
715     {
716     file_handle *fh = (file_handle *)arg;
717     if (!fh)
718     return 0;
719    
720 asvitkine 1.32 #if defined(BINCUE)
721     if (fh->is_bincue) {
722     return read_bincue(fh->bincue_fd, buffer, offset, length);
723     }
724     #endif
725    
726 cebix 1.1 // Seek to position
727     if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
728     return 0;
729    
730     // Read data
731     return read(fh->fd, buffer, length);
732     }
733    
734    
735     /*
736     * Write "length" bytes from "buffer" to file/device, starting at "offset",
737     * returns number of bytes written (or 0)
738     */
739    
740     size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
741     {
742     file_handle *fh = (file_handle *)arg;
743     if (!fh)
744     return 0;
745    
746     // Seek to position
747     if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
748     return 0;
749    
750     // Write data
751     return write(fh->fd, buffer, length);
752     }
753    
754    
755     /*
756     * Return size of file/device (minus header)
757     */
758    
759     loff_t SysGetFileSize(void *arg)
760     {
761     file_handle *fh = (file_handle *)arg;
762     if (!fh)
763     return true;
764    
765     if (fh->is_file)
766     return fh->file_size;
767     else {
768 asvitkine 1.32 long blocks;
769     #if defined(BINCUE)
770     if (fh->is_bincue) {
771     return size_bincue(fh->bincue_fd);
772     }
773     #endif
774 cebix 1.3 #if defined(__linux__)
775 asvitkine 1.32
776 cebix 1.5 if (ioctl(fh->fd, BLKGETSIZE, &blocks) < 0)
777     return 0;
778     D(bug(" BLKGETSIZE returns %d blocks\n", blocks));
779     return (loff_t)blocks * 512;
780 gbeauche 1.29 #elif defined __MACOSX__
781     uint32 block_size;
782     if (ioctl(fh->ioctl_fd, DKIOCGETBLOCKSIZE, &block_size) < 0)
783     return 0;
784     D(bug(" DKIOCGETBLOCKSIZE returns %lu bytes\n", (unsigned long)block_size));
785     uint64 block_count;
786     if (ioctl(fh->ioctl_fd, DKIOCGETBLOCKCOUNT, &block_count) < 0)
787     return 0;
788     D(bug(" DKIOCGETBLOCKCOUNT returns %llu blocks\n", (unsigned long long)block_count));
789     return block_count * block_size;
790 cebix 1.1 #else
791     return lseek(fh->fd, 0, SEEK_END) - fh->start_byte;
792     #endif
793     }
794     }
795    
796    
797     /*
798     * Eject volume (if applicable)
799     */
800    
801     void SysEject(void *arg)
802     {
803     file_handle *fh = (file_handle *)arg;
804     if (!fh)
805     return;
806    
807     #if defined(__linux__)
808     if (fh->is_floppy) {
809 cebix 1.28 if (fh->fd >= 0) {
810     fsync(fh->fd);
811     ioctl(fh->fd, FDFLUSH);
812     ioctl(fh->fd, FDEJECT);
813     close(fh->fd); // Close and reopen so the driver will see the media change
814     }
815 cebix 1.14 fh->fd = open(fh->name, fh->read_only ? O_RDONLY : O_RDWR);
816 cebix 1.1 } else if (fh->is_cdrom) {
817     ioctl(fh->fd, CDROMEJECT);
818     close(fh->fd); // Close and reopen so the driver will see the media change
819     fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK);
820     }
821 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
822 cebix 1.1 if (fh->is_floppy) {
823     fsync(fh->fd);
824     } else if (fh->is_cdrom) {
825     ioctl(fh->fd, CDIOCEJECT);
826     close(fh->fd); // Close and reopen so the driver will see the media change
827     fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK);
828     }
829 nigel 1.19 #elif defined(__APPLE__) && defined(__MACH__)
830 gbeauche 1.29 if (fh->is_cdrom && fh->is_media_present) {
831 nigel 1.19 close(fh->fd);
832 gbeauche 1.29 fh->fd = -1;
833     if (ioctl(fh->ioctl_fd, DKIOCEJECT) < 0) {
834     D(bug(" DKIOCEJECT failed on file %s: %s\n",
835     fh->ioctl_name, strerror(errno)));
836 nigel 1.19
837 gbeauche 1.29 // If we are running MacOS X, the device may be in busy
838     // state because the Finder has mounted the disk
839     close(fh->ioctl_fd);
840     fh->ioctl_fd = -1;
841 nigel 1.19
842 gbeauche 1.29 // Try to use "diskutil eject" but it can take up to 5
843     // seconds to complete
844     static const char eject_cmd[] = "/usr/sbin/diskutil eject %s 2>&1 >/dev/null";
845     char *cmd = (char *)alloca(strlen(eject_cmd) + strlen(fh->ioctl_name) + 1);
846     sprintf(cmd, eject_cmd, fh->ioctl_name);
847 nigel 1.19 system(cmd);
848     }
849 gbeauche 1.29 fh->is_media_present = false;
850 nigel 1.19 }
851 cebix 1.1 #endif
852     }
853    
854    
855     /*
856     * Format volume (if applicable)
857     */
858    
859     bool SysFormat(void *arg)
860     {
861     file_handle *fh = (file_handle *)arg;
862     if (!fh)
863     return false;
864    
865     //!!
866     return true;
867     }
868    
869    
870     /*
871     * Check if file/device is read-only (this includes the read-only flag on Sys_open())
872     */
873    
874     bool SysIsReadOnly(void *arg)
875     {
876     file_handle *fh = (file_handle *)arg;
877     if (!fh)
878     return true;
879    
880 cebix 1.3 #if defined(__linux__)
881 cebix 1.1 if (fh->is_floppy) {
882 cebix 1.28 if (fh->fd >= 0) {
883     struct floppy_drive_struct stat;
884     ioctl(fh->fd, FDGETDRVSTAT, &stat);
885     return !(stat.flags & FD_DISK_WRITABLE);
886     } else
887     return true;
888 cebix 1.1 } else
889     #endif
890     return fh->read_only;
891     }
892    
893    
894     /*
895     * Check if the given file handle refers to a fixed or a removable disk
896     */
897    
898     bool SysIsFixedDisk(void *arg)
899     {
900     file_handle *fh = (file_handle *)arg;
901     if (!fh)
902     return true;
903    
904     if (fh->is_file)
905     return true;
906     else if (fh->is_floppy || fh->is_cdrom)
907     return false;
908     else
909     return true;
910     }
911    
912    
913     /*
914     * Check if a disk is inserted in the drive (always true for files)
915     */
916    
917     bool SysIsDiskInserted(void *arg)
918     {
919     file_handle *fh = (file_handle *)arg;
920     if (!fh)
921     return false;
922    
923     if (fh->is_file) {
924     return true;
925    
926     #if defined(__linux__)
927     } else if (fh->is_floppy) {
928     char block[512];
929     lseek(fh->fd, 0, SEEK_SET);
930 cebix 1.14 ssize_t actual = read(fh->fd, block, 512);
931     if (actual < 0) {
932     close(fh->fd); // Close and reopen so the driver will see the media change
933     fh->fd = open(fh->name, fh->read_only ? O_RDONLY : O_RDWR);
934     actual = read(fh->fd, block, 512);
935     }
936     return actual == 512;
937 cebix 1.1 } else if (fh->is_cdrom) {
938 cebix 1.8 #ifdef CDROM_MEDIA_CHANGED
939     if (fh->cdrom_cap & CDC_MEDIA_CHANGED) {
940     // If we don't do this, all attempts to read from a disc fail
941 cebix 1.14 // once the tray has been opened (altough the TOC reads fine).
942 cebix 1.8 // Can somebody explain this to me?
943     if (ioctl(fh->fd, CDROM_MEDIA_CHANGED) == 1) {
944     close(fh->fd);
945     fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK);
946     }
947     }
948     #endif
949 cebix 1.1 #ifdef CDROM_DRIVE_STATUS
950     if (fh->cdrom_cap & CDC_DRIVE_STATUS) {
951     return ioctl(fh->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK;
952     }
953     #endif
954     cdrom_tochdr header;
955     return ioctl(fh->fd, CDROMREADTOCHDR, &header) == 0;
956 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
957 cebix 1.1 } else if (fh->is_floppy) {
958     return false; //!!
959     } else if (fh->is_cdrom) {
960     struct ioc_toc_header header;
961     return ioctl(fh->fd, CDIOREADTOCHEADER, &header) == 0;
962 gbeauche 1.29 #elif defined __MACOSX__
963     } else if (fh->is_cdrom || fh->is_floppy) {
964     return fh->is_media_present;
965 cebix 1.1 #endif
966    
967     } else
968     return true;
969     }
970    
971    
972     /*
973     * Prevent medium removal (if applicable)
974     */
975    
976     void SysPreventRemoval(void *arg)
977     {
978     file_handle *fh = (file_handle *)arg;
979     if (!fh)
980     return;
981    
982     #if defined(__linux__) && defined(CDROM_LOCKDOOR)
983     if (fh->is_cdrom)
984     ioctl(fh->fd, CDROM_LOCKDOOR, 1);
985     #endif
986     }
987    
988    
989     /*
990     * Allow medium removal (if applicable)
991     */
992    
993     void SysAllowRemoval(void *arg)
994     {
995     file_handle *fh = (file_handle *)arg;
996     if (!fh)
997     return;
998    
999 cebix 1.2 #if defined(__linux__) && defined(CDROM_LOCKDOOR)
1000 cebix 1.1 if (fh->is_cdrom)
1001     ioctl(fh->fd, CDROM_LOCKDOOR, 0);
1002     #endif
1003     }
1004    
1005    
1006     /*
1007     * Read CD-ROM TOC (binary MSF format, 804 bytes max.)
1008     */
1009    
1010     bool SysCDReadTOC(void *arg, uint8 *toc)
1011     {
1012     file_handle *fh = (file_handle *)arg;
1013     if (!fh)
1014     return false;
1015    
1016 asvitkine 1.32 #if defined(BINCUE)
1017     if (fh->is_bincue){
1018     return readtoc_bincue(fh->bincue_fd, toc);
1019     }
1020     #endif
1021    
1022 cebix 1.1 if (fh->is_cdrom) {
1023 asvitkine 1.32
1024 cebix 1.1 #if defined(__linux__)
1025     uint8 *p = toc + 2;
1026    
1027     // Header
1028     cdrom_tochdr header;
1029     if (ioctl(fh->fd, CDROMREADTOCHDR, &header) < 0)
1030     return false;
1031     *p++ = header.cdth_trk0;
1032     *p++ = header.cdth_trk1;
1033    
1034     // Tracks
1035     cdrom_tocentry entry;
1036     for (int i=header.cdth_trk0; i<=header.cdth_trk1; i++) {
1037     entry.cdte_track = i;
1038     entry.cdte_format = CDROM_MSF;
1039     if (ioctl(fh->fd, CDROMREADTOCENTRY, &entry) < 0)
1040     return false;
1041     *p++ = 0;
1042     *p++ = (entry.cdte_adr << 4) | entry.cdte_ctrl;
1043     *p++ = entry.cdte_track;
1044     *p++ = 0;
1045     *p++ = 0;
1046     *p++ = entry.cdte_addr.msf.minute;
1047     *p++ = entry.cdte_addr.msf.second;
1048     *p++ = entry.cdte_addr.msf.frame;
1049     }
1050    
1051     // Leadout track
1052     entry.cdte_track = CDROM_LEADOUT;
1053     entry.cdte_format = CDROM_MSF;
1054     if (ioctl(fh->fd, CDROMREADTOCENTRY, &entry) < 0)
1055     return false;
1056     *p++ = 0;
1057     *p++ = (entry.cdte_adr << 4) | entry.cdte_ctrl;
1058     *p++ = entry.cdte_track;
1059     *p++ = 0;
1060     *p++ = 0;
1061     *p++ = entry.cdte_addr.msf.minute;
1062     *p++ = entry.cdte_addr.msf.second;
1063     *p++ = entry.cdte_addr.msf.frame;
1064    
1065     // TOC size
1066     int toc_size = p - toc;
1067     *toc++ = toc_size >> 8;
1068     *toc++ = toc_size & 0xff;
1069     return true;
1070 gbeauche 1.29 #elif defined __MACOSX__ && defined MAC_OS_X_VERSION_10_2
1071     if (fh->is_media_present) {
1072     extern bool DarwinCDReadTOC(char *name, uint8 *toc);
1073     return DarwinCDReadTOC(fh->name, toc);
1074     }
1075     return false;
1076 cebix 1.4 #elif defined(__FreeBSD__)
1077 cebix 1.1 uint8 *p = toc + 2;
1078    
1079     // Header
1080     struct ioc_toc_header header;
1081     if (ioctl(fh->fd, CDIOREADTOCHEADER, &header) < 0)
1082     return false;
1083     *p++ = header.starting_track;
1084     *p++ = header.ending_track;
1085    
1086     // Tracks
1087     struct ioc_read_toc_single_entry entry;
1088     for (int i=header.starting_track; i<=header.ending_track; i++) {
1089     entry.track = i;
1090     entry.address_format = CD_MSF_FORMAT;
1091     if (ioctl(fh->fd, CDIOREADTOCENTRY, &entry) < 0)
1092     return false;
1093     *p++ = 0;
1094     *p++ = (entry.entry.addr_type << 4) | entry.entry.control;
1095     *p++ = entry.entry.track;
1096     *p++ = 0;
1097     *p++ = 0;
1098     *p++ = entry.entry.addr.msf.minute;
1099     *p++ = entry.entry.addr.msf.second;
1100     *p++ = entry.entry.addr.msf.frame;
1101     }
1102    
1103     // Leadout track
1104     entry.track = CD_TRACK_INFO;
1105     entry.address_format = CD_MSF_FORMAT;
1106     if (ioctl(fh->fd, CDIOREADTOCENTRY, &entry) < 0)
1107     return false;
1108     *p++ = 0;
1109     *p++ = (entry.entry.addr_type << 4) | entry.entry.control;
1110     *p++ = entry.entry.track;
1111     *p++ = 0;
1112     *p++ = 0;
1113     *p++ = entry.entry.addr.msf.minute;
1114     *p++ = entry.entry.addr.msf.second;
1115     *p++ = entry.entry.addr.msf.frame;
1116 cebix 1.4
1117     // TOC size
1118     int toc_size = p - toc;
1119     *toc++ = toc_size >> 8;
1120     *toc++ = toc_size & 0xff;
1121     return true;
1122     #elif defined(__NetBSD__)
1123     uint8 *p = toc + 2;
1124    
1125     // Header
1126     struct ioc_toc_header header;
1127     if (ioctl(fh->fd, CDIOREADTOCHEADER, &header) < 0)
1128     return false;
1129     *p++ = header.starting_track;
1130     *p++ = header.ending_track;
1131    
1132     // Tracks (this is nice... :-)
1133     struct ioc_read_toc_entry entries;
1134     entries.address_format = CD_MSF_FORMAT;
1135     entries.starting_track = 1;
1136     entries.data_len = 800;
1137     entries.data = (cd_toc_entry *)p;
1138     if (ioctl(fh->fd, CDIOREADTOCENTRIES, &entries) < 0)
1139     return false;
1140 cebix 1.1
1141     // TOC size
1142     int toc_size = p - toc;
1143     *toc++ = toc_size >> 8;
1144     *toc++ = toc_size & 0xff;
1145     return true;
1146 cebix 1.15 #else
1147     return false;
1148 cebix 1.1 #endif
1149     } else
1150     return false;
1151     }
1152    
1153    
1154     /*
1155     * Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
1156     */
1157    
1158     bool SysCDGetPosition(void *arg, uint8 *pos)
1159     {
1160     file_handle *fh = (file_handle *)arg;
1161     if (!fh)
1162     return false;
1163    
1164 asvitkine 1.32 #if defined(BINCUE)
1165     if (fh->is_bincue) {
1166    
1167     return GetPosition_bincue(fh->bincue_fd, pos);
1168     }
1169     #endif
1170    
1171 cebix 1.1 if (fh->is_cdrom) {
1172     #if defined(__linux__)
1173     cdrom_subchnl chan;
1174     chan.cdsc_format = CDROM_MSF;
1175     if (ioctl(fh->fd, CDROMSUBCHNL, &chan) < 0)
1176     return false;
1177     *pos++ = 0;
1178     *pos++ = chan.cdsc_audiostatus;
1179     *pos++ = 0;
1180     *pos++ = 12; // Sub-Q data length
1181     *pos++ = 0;
1182     *pos++ = (chan.cdsc_adr << 4) | chan.cdsc_ctrl;
1183     *pos++ = chan.cdsc_trk;
1184     *pos++ = chan.cdsc_ind;
1185     *pos++ = 0;
1186     *pos++ = chan.cdsc_absaddr.msf.minute;
1187     *pos++ = chan.cdsc_absaddr.msf.second;
1188     *pos++ = chan.cdsc_absaddr.msf.frame;
1189     *pos++ = 0;
1190     *pos++ = chan.cdsc_reladdr.msf.minute;
1191     *pos++ = chan.cdsc_reladdr.msf.second;
1192     *pos++ = chan.cdsc_reladdr.msf.frame;
1193     return true;
1194 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1195 cebix 1.1 struct ioc_read_subchannel chan;
1196     chan.data_format = CD_MSF_FORMAT;
1197     chan.address_format = CD_MSF_FORMAT;
1198     chan.track = CD_CURRENT_POSITION;
1199     if (ioctl(fh->fd, CDIOCREADSUBCHANNEL, &chan) < 0)
1200     return false;
1201     *pos++ = 0;
1202     *pos++ = chan.data->header.audio_status;
1203     *pos++ = 0;
1204     *pos++ = 12; // Sub-Q data length
1205     *pos++ = 0;
1206     *pos++ = (chan.data->what.position.addr_type << 4) | chan.data->what.position.control;
1207     *pos++ = chan.data->what.position.track_number;
1208     *pos++ = chan.data->what.position.index_number;
1209     *pos++ = 0;
1210     *pos++ = chan.data->what.position.absaddr.msf.minute;
1211     *pos++ = chan.data->what.position.absaddr.msf.second;
1212     *pos++ = chan.data->what.position.absaddr.msf.frame;
1213     *pos++ = 0;
1214     *pos++ = chan.data->what.position.reladdr.msf.minute;
1215     *pos++ = chan.data->what.position.reladdr.msf.second;
1216     *pos++ = chan.data->what.position.reladdr.msf.frame;
1217     return true;
1218 cebix 1.15 #else
1219     return false;
1220 cebix 1.1 #endif
1221     } else
1222     return false;
1223     }
1224    
1225    
1226     /*
1227     * Play CD audio
1228     */
1229    
1230     bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
1231     {
1232     file_handle *fh = (file_handle *)arg;
1233     if (!fh)
1234     return false;
1235    
1236 asvitkine 1.32 #if defined(BINCUE)
1237     if (fh->is_bincue) {
1238     return CDPlay_bincue(fh->bincue_fd, start_m, start_s,
1239     start_f, end_m, end_s, end_f);
1240     }
1241     #endif
1242    
1243 cebix 1.1 if (fh->is_cdrom) {
1244     #if defined(__linux__)
1245     cdrom_msf play;
1246     play.cdmsf_min0 = start_m;
1247     play.cdmsf_sec0 = start_s;
1248     play.cdmsf_frame0 = start_f;
1249     play.cdmsf_min1 = end_m;
1250     play.cdmsf_sec1 = end_s;
1251     play.cdmsf_frame1 = end_f;
1252     return ioctl(fh->fd, CDROMPLAYMSF, &play) == 0;
1253 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1254 cebix 1.1 struct ioc_play_msf play;
1255     play.start_m = start_m;
1256     play.start_s = start_s;
1257     play.start_f = start_f;
1258     play.end_m = end_m;
1259     play.end_s = end_s;
1260     play.end_f = end_f;
1261     return ioctl(fh->fd, CDIOCPLAYMSF, &play) == 0;
1262 cebix 1.15 #else
1263     return false;
1264 cebix 1.1 #endif
1265     } else
1266     return false;
1267     }
1268    
1269    
1270     /*
1271     * Pause CD audio
1272     */
1273    
1274     bool SysCDPause(void *arg)
1275     {
1276     file_handle *fh = (file_handle *)arg;
1277     if (!fh)
1278     return false;
1279    
1280 asvitkine 1.32 #if defined(BINCUE)
1281     if (fh->is_bincue){
1282     return CDPause_bincue(fh->bincue_fd);
1283     }
1284     #endif
1285    
1286 cebix 1.1 if (fh->is_cdrom) {
1287     #if defined(__linux__)
1288     return ioctl(fh->fd, CDROMPAUSE) == 0;
1289 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1290 cebix 1.1 return ioctl(fh->fd, CDIOCPAUSE) == 0;
1291 cebix 1.15 #else
1292     return false;
1293 cebix 1.1 #endif
1294     } else
1295     return false;
1296     }
1297    
1298    
1299     /*
1300     * Resume paused CD audio
1301     */
1302    
1303     bool SysCDResume(void *arg)
1304     {
1305     file_handle *fh = (file_handle *)arg;
1306     if (!fh)
1307     return false;
1308    
1309 asvitkine 1.32 #if defined(BINCUE)
1310     if (fh->is_bincue) {
1311     return CDResume_bincue(fh->bincue_fd);
1312     }
1313     #endif
1314    
1315    
1316 cebix 1.1 if (fh->is_cdrom) {
1317     #if defined(__linux__)
1318     return ioctl(fh->fd, CDROMRESUME) == 0;
1319 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1320 cebix 1.1 return ioctl(fh->fd, CDIOCRESUME) == 0;
1321 cebix 1.15 #else
1322     return false;
1323 cebix 1.1 #endif
1324     } else
1325     return false;
1326     }
1327    
1328    
1329     /*
1330     * Stop CD audio
1331     */
1332    
1333     bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
1334     {
1335     file_handle *fh = (file_handle *)arg;
1336     if (!fh)
1337     return false;
1338    
1339 asvitkine 1.32 #if defined(BINCUE)
1340     if (fh->is_bincue) {
1341     return CDStop_bincue(fh->bincue_fd);
1342     }
1343     #endif
1344    
1345    
1346 cebix 1.1 if (fh->is_cdrom) {
1347     #if defined(__linux__)
1348     return ioctl(fh->fd, CDROMSTOP) == 0;
1349 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1350 cebix 1.1 return ioctl(fh->fd, CDIOCSTOP) == 0;
1351 cebix 1.15 #else
1352     return false;
1353 cebix 1.1 #endif
1354     } else
1355     return false;
1356     }
1357    
1358    
1359     /*
1360     * Perform CD audio fast-forward/fast-reverse operation starting from specified address
1361     */
1362    
1363     bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
1364     {
1365     file_handle *fh = (file_handle *)arg;
1366     if (!fh)
1367     return false;
1368    
1369     // Not supported under Linux
1370     return false;
1371     }
1372    
1373    
1374     /*
1375     * Set CD audio volume (0..255 each channel)
1376     */
1377    
1378     void SysCDSetVolume(void *arg, uint8 left, uint8 right)
1379     {
1380     file_handle *fh = (file_handle *)arg;
1381     if (!fh)
1382     return;
1383    
1384     if (fh->is_cdrom) {
1385     #if defined(__linux__)
1386     cdrom_volctrl vol;
1387     vol.channel0 = vol.channel2 = left;
1388     vol.channel1 = vol.channel3 = right;
1389     ioctl(fh->fd, CDROMVOLCTRL, &vol);
1390 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1391 cebix 1.1 struct ioc_vol vol;
1392     vol.vol[0] = vol.vol[2] = left;
1393     vol.vol[1] = vol.vol[3] = right;
1394     ioctl(fh->fd, CDIOCSETVOL, &vol);
1395     #endif
1396     }
1397     }
1398    
1399    
1400     /*
1401     * Get CD audio volume (0..255 each channel)
1402     */
1403    
1404     void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
1405     {
1406     file_handle *fh = (file_handle *)arg;
1407     if (!fh)
1408     return;
1409    
1410     left = right = 0;
1411     if (fh->is_cdrom) {
1412     #if defined(__linux__)
1413     cdrom_volctrl vol;
1414     ioctl(fh->fd, CDROMVOLREAD, &vol);
1415     left = vol.channel0;
1416     right = vol.channel1;
1417 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1418 cebix 1.1 struct ioc_vol vol;
1419     ioctl(fh->fd, CDIOCGETVOL, &vol);
1420     left = vol.vol[0];
1421     right = vol.vol[1];
1422     #endif
1423     }
1424     }