ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sys_unix.cpp
Revision: 1.1.1.1 (vendor branch)
Committed: 1999-10-03T14:16:25Z (24 years, 9 months ago) by cebix
Branch: cebix
CVS Tags: start
Changes since 1.1: +0 -0 lines
Log Message:
Imported sources

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * sys_unix.cpp - System dependent routines, Unix implementation
3     *
4     * Basilisk II (C) 1997-1999 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     #include <sys/ioctl.h>
24     #include <sys/stat.h>
25     #include <errno.h>
26    
27     #ifdef __linux__
28     #include <linux/cdrom.h>
29     #include <linux/fd.h>
30     #include <linux/major.h>
31     #include <linux/kdev_t.h>
32     #include <linux/unistd.h>
33    
34     #ifdef __NR__llseek
35     _syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo, loff_t *, res, uint, wh);
36     #else
37     static int _llseek(uint fd, ulong hi, ulong lo, loff_t *res, uint wh)
38     {
39     if (hi)
40     return -1;
41     *res = lseek(fd, lo, wh);
42     if (*res == -1)
43     return -1;
44     return 0;
45     }
46     #endif
47     #endif
48    
49     #ifdef __FreeBSD__
50     #include <sys/cdio.h>
51     #endif
52    
53     #include "main.h"
54     #include "macos_util.h"
55     #include "prefs.h"
56     #include "user_strings.h"
57     #include "sys.h"
58    
59     #define DEBUG 0
60     #include "debug.h"
61    
62    
63     // File handles are pointers to these structures
64     struct file_handle {
65     char *name; // Copy of device/file name
66     int fd;
67     bool is_file; // Flag: plain file or /dev/something?
68     bool is_floppy; // Flag: floppy device
69     bool is_cdrom; // Flag: CD-ROM device
70     bool read_only; // Copy of Sys_open() flag
71     loff_t start_byte; // Size of file header (if any)
72     loff_t file_size; // Size of file data (only valid if is_file is true)
73    
74     #if defined(__linux__)
75     int cdrom_cap; // CD-ROM capability flags (only valid if is_cdrom is true)
76     #elif defined(__FreeBSD__)
77     struct ioc_capability cdrom_cap;
78     #endif
79     };
80    
81     // File handle of first floppy drive (for SysMountFirstFloppy())
82     static file_handle *first_floppy = NULL;
83    
84    
85     /*
86     * Initialization
87     */
88    
89     void SysInit(void)
90     {
91     }
92    
93    
94     /*
95     * Deinitialization
96     */
97    
98     void SysExit(void)
99     {
100     }
101    
102    
103     /*
104     * Mount first floppy disk
105     */
106    
107     void SysMountFirstFloppy(void)
108     {
109     if (first_floppy)
110     MountVolume(first_floppy);
111     }
112    
113    
114     /*
115     * This gets called when no "floppy" prefs items are found
116     * It scans for available floppy drives and adds appropriate prefs items
117     */
118    
119     void SysAddFloppyPrefs(void)
120     {
121     #if defined(__linux__)
122     PrefsAddString("floppy", "/dev/fd0H1440");
123     PrefsAddString("floppy", "/dev/fd1H1440");
124     #else
125     PrefsAddString("floppy", "/dev/fd0");
126     PrefsAddString("floppy", "/dev/fd1");
127     #endif
128     }
129    
130    
131     /*
132     * This gets called when no "disk" prefs items are found
133     * It scans for available HFS volumes and adds appropriate prefs items
134     */
135    
136     void SysAddDiskPrefs(void)
137     {
138     #ifdef __linux__
139     FILE *f = fopen("/etc/fstab", "r");
140     if (f) {
141     char line[256];
142     while(fgets(line, 255, f)) {
143     // Read line
144     int len = strlen(line);
145     if (len == 0)
146     continue;
147     line[len-1] = 0;
148    
149     // Parse line
150     char *dev, *mnt_point, *fstype;
151     if (sscanf(line, "%s %s %s", &dev, &mnt_point, &fstype) == 3) {
152     if (strcmp(fstype, "hfs") == 0)
153     PrefsAddString("disk", dev);
154     }
155     }
156     fclose(f);
157     }
158     #endif
159     }
160    
161    
162     /*
163     * This gets called when no "cdrom" prefs items are found
164     * It scans for available CD-ROM drives and adds appropriate prefs items
165     */
166    
167     void SysAddCDROMPrefs(void)
168     {
169     // Don't scan for drives if nocdrom option given
170     if (PrefsFindBool("nocdrom"))
171     return;
172    
173     #if defined(__linux__)
174     PrefsAddString("cdrom", "/dev/cdrom");
175     #elif defined(__FreeBSD__)
176     PrefsAddString("cdrom", "/dev/cd0c");
177     #endif
178     }
179    
180    
181     /*
182     * Add default serial prefs (must be added, even if no ports present)
183     */
184    
185     void SysAddSerialPrefs(void)
186     {
187     #if defined(__linux__)
188     PrefsAddString("seriala", "/dev/ttyS0");
189     PrefsAddString("serialb", "/dev/ttyS1");
190     #elif defined(__FreeBSD__)
191     PrefsAddString("seriala", "/dev/cuaa0");
192     PrefsAddString("serialb", "/dev/cuaa1");
193     #endif
194     }
195    
196    
197     /*
198     * Check if device is a mounted HFS volume, get mount name
199     */
200    
201     static bool is_drive_mounted(const char *dev_name, char *mount_name)
202     {
203     #ifdef __linux__
204     FILE *f = fopen("/proc/mounts", "r");
205     if (f) {
206     char line[256];
207     while(fgets(line, 255, f)) {
208     // Read line
209     int len = strlen(line);
210     if (len == 0)
211     continue;
212     line[len-1] = 0;
213    
214     // Parse line
215     if (strncmp(line, dev_name, strlen(dev_name)) == 0) {
216     mount_name[0] = 0;
217     char dummy[256];
218     sscanf(line, "%s %s", dummy, mount_name);
219     fclose(f);
220     return true;
221     }
222     }
223     fclose(f);
224     }
225     #endif
226     return false;
227     }
228    
229    
230     /*
231     * Open file/device, create new file handle (returns NULL on error)
232     */
233    
234     void *Sys_open(const char *name, bool read_only)
235     {
236     bool is_file = strncmp(name, "/dev/", 5) != 0;
237     #ifdef __FreeBSD__
238     // SCSI IDE
239     bool is_cdrom = strncmp(name, "/dev/cd", 7) == 0 || strncmp(name, "/dev/acd", 8) == 0;
240     #else
241     bool is_cdrom = strncmp(name, "/dev/cd", 7) == 0;
242     #endif
243    
244     D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write"));
245    
246     // Check if write access is allowed, set read-only flag if not
247     if (!read_only && access(name, W_OK))
248     read_only = true;
249    
250     // Print warning message and eventually unmount drive when this is an HFS volume mounted under Linux (double mounting will corrupt the volume)
251     char mount_name[256];
252     if (!is_file && !read_only && is_drive_mounted(name, mount_name)) {
253     char str[512];
254     sprintf(str, GetString(STR_VOLUME_IS_MOUNTED_WARN), mount_name);
255     WarningAlert(str);
256     sprintf(str, "umount %s", mount_name);
257     if (system(str)) {
258     sprintf(str, GetString(STR_CANNOT_UNMOUNT_WARN), mount_name, strerror(errno));
259     WarningAlert(str);
260     return NULL;
261     }
262     }
263    
264     // Open file/device
265     #ifdef __linux__
266     int fd = open(name, (read_only ? O_RDONLY : O_RDWR) | (is_cdrom ? O_NONBLOCK : 0));
267     #else
268     int fd = open(name, read_only ? O_RDONLY : O_RDWR);
269     #endif
270     if (fd < 0 && !read_only) {
271     // Read-write failed, try read-only
272     read_only = true;
273     fd = open(name, O_RDONLY);
274     }
275     if (fd >= 0) {
276     file_handle *fh = new file_handle;
277     fh->name = strdup(name);
278     fh->fd = fd;
279     fh->is_file = is_file;
280     fh->read_only = read_only;
281     fh->start_byte = 0;
282     fh->is_floppy = false;
283     fh->is_cdrom = false;
284     if (fh->is_file) {
285     // Detect disk image file layout
286     loff_t size = 0;
287     #ifdef __linux__
288     _llseek(fh->fd, 0, 0, &size, SEEK_END);
289     #else
290     size = lseek(fd, 0, SEEK_END);
291     #endif
292     uint8 data[256];
293     lseek(fd, 0, SEEK_SET);
294     read(fd, data, 256);
295     FileDiskLayout(size, data, fh->start_byte, fh->file_size);
296     } else {
297     struct stat st;
298     if (fstat(fd, &st) == 0) {
299     if (S_ISBLK(st.st_mode)) {
300     fh->is_cdrom = is_cdrom;
301     #if defined(__linux__)
302     fh->is_floppy = (MAJOR(st.st_rdev) == FLOPPY_MAJOR);
303     #ifdef CDROM_GET_CAPABILITY
304     if (is_cdrom) {
305     fh->cdrom_cap = ioctl(fh->fd, CDROM_GET_CAPABILITY);
306     if (fh->cdrom_cap < 0)
307     fh->cdrom_cap = 0;
308     }
309     #else
310     fh->cdrom_cap = 0;
311     #endif
312     #elif defined(__FreeBSD__)
313     fh->is_floppy = ((st.st_rdev >> 16) == 2);
314     #ifdef CDIOCCAPABILITY
315     if (is_cdrom) {
316     if (ioctl(fh->fd, CDIOCCAPABILITY, &fh->cdrom_cap) < 0)
317     memset(&fh->cdrom_cap, 0, sizeof(fh->cdrom_cap));
318     }
319     #else
320     fh->cdrom_cap = 0;
321     #endif
322     #endif
323     }
324     }
325     }
326     if (fh->is_floppy && first_floppy == NULL)
327     first_floppy = fh;
328     return fh;
329     } else {
330     printf("WARNING: Cannot open %s (%s)\n", name, strerror(errno));
331     return NULL;
332     }
333     }
334    
335    
336     /*
337     * Close file/device, delete file handle
338     */
339    
340     void Sys_close(void *arg)
341     {
342     file_handle *fh = (file_handle *)arg;
343     if (!fh)
344     return;
345    
346     close(fh->fd);
347     if (fh->name)
348     free(fh->name);
349     delete fh;
350     }
351    
352    
353     /*
354     * Read "length" bytes from file/device, starting at "offset", to "buffer",
355     * returns number of bytes read (or 0)
356     */
357    
358     size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
359     {
360     file_handle *fh = (file_handle *)arg;
361     if (!fh)
362     return 0;
363    
364     // Seek to position
365     #ifdef __linux__
366     loff_t pos = offset + fh->start_byte, res;
367     if (_llseek(fh->fd, pos >> 32, pos, &res, SEEK_SET) < 0)
368     return 0;
369     #else
370     if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
371     return 0;
372     #endif
373    
374     // Read data
375     return read(fh->fd, buffer, length);
376     }
377    
378    
379     /*
380     * Write "length" bytes from "buffer" to file/device, starting at "offset",
381     * returns number of bytes written (or 0)
382     */
383    
384     size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
385     {
386     file_handle *fh = (file_handle *)arg;
387     if (!fh)
388     return 0;
389    
390     // Seek to position
391     #ifdef __linux__
392     loff_t pos = offset + fh->start_byte, res;
393     if (_llseek(fh->fd, pos >> 32, pos, &res, SEEK_SET) < 0)
394     return 0;
395     #else
396     if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
397     return 0;
398     #endif
399    
400     // Write data
401     return write(fh->fd, buffer, length);
402     }
403    
404    
405     /*
406     * Return size of file/device (minus header)
407     */
408    
409     loff_t SysGetFileSize(void *arg)
410     {
411     file_handle *fh = (file_handle *)arg;
412     if (!fh)
413     return true;
414    
415     if (fh->is_file)
416     return fh->file_size;
417     else {
418     #ifdef __linux__
419     loff_t pos = 0;
420     _llseek(fh->fd, 0, 0, &pos, SEEK_END);
421     return pos - fh->start_byte;
422     #else
423     return lseek(fh->fd, 0, SEEK_END) - fh->start_byte;
424     #endif
425     }
426     }
427    
428    
429     /*
430     * Eject volume (if applicable)
431     */
432    
433     void SysEject(void *arg)
434     {
435     file_handle *fh = (file_handle *)arg;
436     if (!fh)
437     return;
438    
439     #if defined(__linux__)
440     if (fh->is_floppy) {
441     fsync(fh->fd);
442     ioctl(fh->fd, FDFLUSH);
443     ioctl(fh->fd, FDEJECT);
444     } else if (fh->is_cdrom) {
445     ioctl(fh->fd, CDROMEJECT);
446     close(fh->fd); // Close and reopen so the driver will see the media change
447     fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK);
448     }
449     #elif defined(__FreeBSD__)
450     if (fh->is_floppy) {
451     fsync(fh->fd);
452     //ioctl(fh->fd, FDFLUSH);
453     //ioctl(fh->fd, FDEJECT);
454     } else if (fh->is_cdrom) {
455     ioctl(fh->fd, CDIOCEJECT);
456     close(fh->fd); // Close and reopen so the driver will see the media change
457     fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK);
458     }
459     #endif
460     }
461    
462    
463     /*
464     * Format volume (if applicable)
465     */
466    
467     bool SysFormat(void *arg)
468     {
469     file_handle *fh = (file_handle *)arg;
470     if (!fh)
471     return false;
472    
473     //!!
474     return true;
475     }
476    
477    
478     /*
479     * Check if file/device is read-only (this includes the read-only flag on Sys_open())
480     */
481    
482     bool SysIsReadOnly(void *arg)
483     {
484     file_handle *fh = (file_handle *)arg;
485     if (!fh)
486     return true;
487    
488     #ifdef __linux__
489     if (fh->is_floppy) {
490     struct floppy_drive_struct stat;
491     ioctl(fh->fd, FDGETDRVSTAT, &stat);
492     return !(stat.flags & FD_DISK_WRITABLE);
493     } else
494     #endif
495     return fh->read_only;
496     }
497    
498    
499     /*
500     * Check if the given file handle refers to a fixed or a removable disk
501     */
502    
503     bool SysIsFixedDisk(void *arg)
504     {
505     file_handle *fh = (file_handle *)arg;
506     if (!fh)
507     return true;
508    
509     if (fh->is_file)
510     return true;
511     else if (fh->is_floppy || fh->is_cdrom)
512     return false;
513     else
514     return true;
515     }
516    
517    
518     /*
519     * Check if a disk is inserted in the drive (always true for files)
520     */
521    
522     bool SysIsDiskInserted(void *arg)
523     {
524     file_handle *fh = (file_handle *)arg;
525     if (!fh)
526     return false;
527    
528     if (fh->is_file) {
529     return true;
530    
531     #if defined(__linux__)
532     } else if (fh->is_floppy) {
533     char block[512];
534     lseek(fh->fd, 0, SEEK_SET);
535     return read(fh->fd, block, 512) == 512;
536     } else if (fh->is_cdrom) {
537     #ifdef CDROM_DRIVE_STATUS
538     if (fh->cdrom_cap & CDC_DRIVE_STATUS) {
539     return ioctl(fh->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK;
540     }
541     #endif
542     cdrom_tochdr header;
543     return ioctl(fh->fd, CDROMREADTOCHDR, &header) == 0;
544     #elif defined(__FreeBSD__)
545     } else if (fh->is_floppy) {
546     return false; //!!
547     } else if (fh->is_cdrom) {
548     struct ioc_toc_header header;
549     return ioctl(fh->fd, CDIOREADTOCHEADER, &header) == 0;
550     #endif
551    
552     } else
553     return true;
554     }
555    
556    
557     /*
558     * Prevent medium removal (if applicable)
559     */
560    
561     void SysPreventRemoval(void *arg)
562     {
563     file_handle *fh = (file_handle *)arg;
564     if (!fh)
565     return;
566    
567     #if defined(__linux__) && defined(CDROM_LOCKDOOR)
568     if (fh->is_cdrom)
569     ioctl(fh->fd, CDROM_LOCKDOOR, 1);
570     #endif
571     }
572    
573    
574     /*
575     * Allow medium removal (if applicable)
576     */
577    
578     void SysAllowRemoval(void *arg)
579     {
580     file_handle *fh = (file_handle *)arg;
581     if (!fh)
582     return;
583    
584     #ifdef defined(__linux__) && defined(CDROM_LOCKDOOR)
585     if (fh->is_cdrom)
586     ioctl(fh->fd, CDROM_LOCKDOOR, 0);
587     #endif
588     }
589    
590    
591     /*
592     * Read CD-ROM TOC (binary MSF format, 804 bytes max.)
593     */
594    
595     bool SysCDReadTOC(void *arg, uint8 *toc)
596     {
597     file_handle *fh = (file_handle *)arg;
598     if (!fh)
599     return false;
600    
601     if (fh->is_cdrom) {
602     #if defined(__linux__)
603     uint8 *p = toc + 2;
604    
605     // Header
606     cdrom_tochdr header;
607     if (ioctl(fh->fd, CDROMREADTOCHDR, &header) < 0)
608     return false;
609     *p++ = header.cdth_trk0;
610     *p++ = header.cdth_trk1;
611    
612     // Tracks
613     cdrom_tocentry entry;
614     for (int i=header.cdth_trk0; i<=header.cdth_trk1; i++) {
615     entry.cdte_track = i;
616     entry.cdte_format = CDROM_MSF;
617     if (ioctl(fh->fd, CDROMREADTOCENTRY, &entry) < 0)
618     return false;
619     *p++ = 0;
620     *p++ = (entry.cdte_adr << 4) | entry.cdte_ctrl;
621     *p++ = entry.cdte_track;
622     *p++ = 0;
623     *p++ = 0;
624     *p++ = entry.cdte_addr.msf.minute;
625     *p++ = entry.cdte_addr.msf.second;
626     *p++ = entry.cdte_addr.msf.frame;
627     }
628    
629     // Leadout track
630     entry.cdte_track = CDROM_LEADOUT;
631     entry.cdte_format = CDROM_MSF;
632     if (ioctl(fh->fd, CDROMREADTOCENTRY, &entry) < 0)
633     return false;
634     *p++ = 0;
635     *p++ = (entry.cdte_adr << 4) | entry.cdte_ctrl;
636     *p++ = entry.cdte_track;
637     *p++ = 0;
638     *p++ = 0;
639     *p++ = entry.cdte_addr.msf.minute;
640     *p++ = entry.cdte_addr.msf.second;
641     *p++ = entry.cdte_addr.msf.frame;
642    
643     // TOC size
644     int toc_size = p - toc;
645     *toc++ = toc_size >> 8;
646     *toc++ = toc_size & 0xff;
647     return true;
648     #elif defined(__FreeBSD__)
649     uint8 *p = toc + 2;
650    
651     // Header
652     struct ioc_toc_header header;
653     if (ioctl(fh->fd, CDIOREADTOCHEADER, &header) < 0)
654     return false;
655     *p++ = header.starting_track;
656     *p++ = header.ending_track;
657    
658     // Tracks
659     struct ioc_read_toc_single_entry entry;
660     for (int i=header.starting_track; i<=header.ending_track; i++) {
661     entry.track = i;
662     entry.address_format = CD_MSF_FORMAT;
663     if (ioctl(fh->fd, CDIOREADTOCENTRY, &entry) < 0)
664     return false;
665     *p++ = 0;
666     *p++ = (entry.entry.addr_type << 4) | entry.entry.control;
667     *p++ = entry.entry.track;
668     *p++ = 0;
669     *p++ = 0;
670     *p++ = entry.entry.addr.msf.minute;
671     *p++ = entry.entry.addr.msf.second;
672     *p++ = entry.entry.addr.msf.frame;
673     }
674    
675     // Leadout track
676     entry.track = CD_TRACK_INFO;
677     entry.address_format = CD_MSF_FORMAT;
678     if (ioctl(fh->fd, CDIOREADTOCENTRY, &entry) < 0)
679     return false;
680     *p++ = 0;
681     *p++ = (entry.entry.addr_type << 4) | entry.entry.control;
682     *p++ = entry.entry.track;
683     *p++ = 0;
684     *p++ = 0;
685     *p++ = entry.entry.addr.msf.minute;
686     *p++ = entry.entry.addr.msf.second;
687     *p++ = entry.entry.addr.msf.frame;
688    
689     // TOC size
690     int toc_size = p - toc;
691     *toc++ = toc_size >> 8;
692     *toc++ = toc_size & 0xff;
693     return true;
694     #endif
695     } else
696     return false;
697     }
698    
699    
700     /*
701     * Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
702     */
703    
704     bool SysCDGetPosition(void *arg, uint8 *pos)
705     {
706     file_handle *fh = (file_handle *)arg;
707     if (!fh)
708     return false;
709    
710     if (fh->is_cdrom) {
711     #if defined(__linux__)
712     cdrom_subchnl chan;
713     chan.cdsc_format = CDROM_MSF;
714     if (ioctl(fh->fd, CDROMSUBCHNL, &chan) < 0)
715     return false;
716     *pos++ = 0;
717     *pos++ = chan.cdsc_audiostatus;
718     *pos++ = 0;
719     *pos++ = 12; // Sub-Q data length
720     *pos++ = 0;
721     *pos++ = (chan.cdsc_adr << 4) | chan.cdsc_ctrl;
722     *pos++ = chan.cdsc_trk;
723     *pos++ = chan.cdsc_ind;
724     *pos++ = 0;
725     *pos++ = chan.cdsc_absaddr.msf.minute;
726     *pos++ = chan.cdsc_absaddr.msf.second;
727     *pos++ = chan.cdsc_absaddr.msf.frame;
728     *pos++ = 0;
729     *pos++ = chan.cdsc_reladdr.msf.minute;
730     *pos++ = chan.cdsc_reladdr.msf.second;
731     *pos++ = chan.cdsc_reladdr.msf.frame;
732     return true;
733     #elif defined(__FreeBSD__)
734     struct ioc_read_subchannel chan;
735     chan.data_format = CD_MSF_FORMAT;
736     chan.address_format = CD_MSF_FORMAT;
737     chan.track = CD_CURRENT_POSITION;
738     if (ioctl(fh->fd, CDIOCREADSUBCHANNEL, &chan) < 0)
739     return false;
740     *pos++ = 0;
741     *pos++ = chan.data->header.audio_status;
742     *pos++ = 0;
743     *pos++ = 12; // Sub-Q data length
744     *pos++ = 0;
745     *pos++ = (chan.data->what.position.addr_type << 4) | chan.data->what.position.control;
746     *pos++ = chan.data->what.position.track_number;
747     *pos++ = chan.data->what.position.index_number;
748     *pos++ = 0;
749     *pos++ = chan.data->what.position.absaddr.msf.minute;
750     *pos++ = chan.data->what.position.absaddr.msf.second;
751     *pos++ = chan.data->what.position.absaddr.msf.frame;
752     *pos++ = 0;
753     *pos++ = chan.data->what.position.reladdr.msf.minute;
754     *pos++ = chan.data->what.position.reladdr.msf.second;
755     *pos++ = chan.data->what.position.reladdr.msf.frame;
756     return true;
757     #endif
758     } else
759     return false;
760     }
761    
762    
763     /*
764     * Play CD audio
765     */
766    
767     bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
768     {
769     file_handle *fh = (file_handle *)arg;
770     if (!fh)
771     return false;
772    
773     if (fh->is_cdrom) {
774     #if defined(__linux__)
775     cdrom_msf play;
776     play.cdmsf_min0 = start_m;
777     play.cdmsf_sec0 = start_s;
778     play.cdmsf_frame0 = start_f;
779     play.cdmsf_min1 = end_m;
780     play.cdmsf_sec1 = end_s;
781     play.cdmsf_frame1 = end_f;
782     return ioctl(fh->fd, CDROMPLAYMSF, &play) == 0;
783     #elif defined(__FreeBSD__)
784     struct ioc_play_msf play;
785     play.start_m = start_m;
786     play.start_s = start_s;
787     play.start_f = start_f;
788     play.end_m = end_m;
789     play.end_s = end_s;
790     play.end_f = end_f;
791     return ioctl(fh->fd, CDIOCPLAYMSF, &play) == 0;
792     #endif
793     } else
794     return false;
795     }
796    
797    
798     /*
799     * Pause CD audio
800     */
801    
802     bool SysCDPause(void *arg)
803     {
804     file_handle *fh = (file_handle *)arg;
805     if (!fh)
806     return false;
807    
808     if (fh->is_cdrom) {
809     #if defined(__linux__)
810     return ioctl(fh->fd, CDROMPAUSE) == 0;
811     #elif defined(__FreeBSD__)
812     return ioctl(fh->fd, CDIOCPAUSE) == 0;
813     #endif
814     } else
815     return false;
816     }
817    
818    
819     /*
820     * Resume paused CD audio
821     */
822    
823     bool SysCDResume(void *arg)
824     {
825     file_handle *fh = (file_handle *)arg;
826     if (!fh)
827     return false;
828    
829     if (fh->is_cdrom) {
830     #if defined(__linux__)
831     return ioctl(fh->fd, CDROMRESUME) == 0;
832     #elif defined(__FreeBSD__)
833     return ioctl(fh->fd, CDIOCRESUME) == 0;
834     #endif
835     } else
836     return false;
837     }
838    
839    
840     /*
841     * Stop CD audio
842     */
843    
844     bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
845     {
846     file_handle *fh = (file_handle *)arg;
847     if (!fh)
848     return false;
849    
850     if (fh->is_cdrom) {
851     #if defined(__linux__)
852     return ioctl(fh->fd, CDROMSTOP) == 0;
853     #elif defined(__FreeBSD__)
854     return ioctl(fh->fd, CDIOCSTOP) == 0;
855     #endif
856     } else
857     return false;
858     }
859    
860    
861     /*
862     * Perform CD audio fast-forward/fast-reverse operation starting from specified address
863     */
864    
865     bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
866     {
867     file_handle *fh = (file_handle *)arg;
868     if (!fh)
869     return false;
870    
871     // Not supported under Linux
872     return false;
873     }
874    
875    
876     /*
877     * Set CD audio volume (0..255 each channel)
878     */
879    
880     void SysCDSetVolume(void *arg, uint8 left, uint8 right)
881     {
882     file_handle *fh = (file_handle *)arg;
883     if (!fh)
884     return;
885    
886     if (fh->is_cdrom) {
887     #if defined(__linux__)
888     cdrom_volctrl vol;
889     vol.channel0 = vol.channel2 = left;
890     vol.channel1 = vol.channel3 = right;
891     ioctl(fh->fd, CDROMVOLCTRL, &vol);
892     #elif defined(__FreeBSD__)
893     struct ioc_vol vol;
894     vol.vol[0] = vol.vol[2] = left;
895     vol.vol[1] = vol.vol[3] = right;
896     ioctl(fh->fd, CDIOCSETVOL, &vol);
897     #endif
898     }
899     }
900    
901    
902     /*
903     * Get CD audio volume (0..255 each channel)
904     */
905    
906     void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
907     {
908     file_handle *fh = (file_handle *)arg;
909     if (!fh)
910     return;
911    
912     left = right = 0;
913     if (fh->is_cdrom) {
914     #if defined(__linux__)
915     cdrom_volctrl vol;
916     ioctl(fh->fd, CDROMVOLREAD, &vol);
917     left = vol.channel0;
918     right = vol.channel1;
919     #elif defined(__FreeBSD__)
920     struct ioc_vol vol;
921     ioctl(fh->fd, CDIOCGETVOL, &vol);
922     left = vol.vol[0];
923     right = vol.vol[1];
924     #endif
925     }
926     }