ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sys_unix.cpp
Revision: 1.4
Committed: 1999-10-15T14:50:38Z (25 years, 1 month ago) by cebix
Branch: MAIN
CVS Tags: snapshot-21101999
Changes since 1.3: +28 -2 lines
Log Message:
- some fixes for NetBSD

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