ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sys_unix.cpp
Revision: 1.3
Committed: 1999-10-14T11:37:47Z (24 years, 10 months ago) by cebix
Branch: MAIN
Changes since 1.2: +32 -22 lines
Log Message:
- integrated patches 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.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
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     #endif
333     }
334     }
335     }
336     if (fh->is_floppy && first_floppy == NULL)
337     first_floppy = fh;
338     return fh;
339     } else {
340     printf("WARNING: Cannot open %s (%s)\n", name, strerror(errno));
341     return NULL;
342     }
343     }
344    
345    
346     /*
347     * Close file/device, delete file handle
348     */
349    
350     void Sys_close(void *arg)
351     {
352     file_handle *fh = (file_handle *)arg;
353     if (!fh)
354     return;
355    
356     close(fh->fd);
357     if (fh->name)
358     free(fh->name);
359     delete fh;
360     }
361    
362    
363     /*
364     * Read "length" bytes from file/device, starting at "offset", to "buffer",
365     * returns number of bytes read (or 0)
366     */
367    
368     size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
369     {
370     file_handle *fh = (file_handle *)arg;
371     if (!fh)
372     return 0;
373    
374     // Seek to position
375 cebix 1.3 #if defined(__linux__)
376 cebix 1.1 loff_t pos = offset + fh->start_byte, res;
377     if (_llseek(fh->fd, pos >> 32, pos, &res, SEEK_SET) < 0)
378     return 0;
379     #else
380     if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
381     return 0;
382     #endif
383    
384     // Read data
385     return read(fh->fd, buffer, length);
386     }
387    
388    
389     /*
390     * Write "length" bytes from "buffer" to file/device, starting at "offset",
391     * returns number of bytes written (or 0)
392     */
393    
394     size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
395     {
396     file_handle *fh = (file_handle *)arg;
397     if (!fh)
398     return 0;
399    
400     // Seek to position
401 cebix 1.3 #if defined(__linux__)
402 cebix 1.1 loff_t pos = offset + fh->start_byte, res;
403     if (_llseek(fh->fd, pos >> 32, pos, &res, SEEK_SET) < 0)
404     return 0;
405     #else
406     if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
407     return 0;
408     #endif
409    
410     // Write data
411     return write(fh->fd, buffer, length);
412     }
413    
414    
415     /*
416     * Return size of file/device (minus header)
417     */
418    
419     loff_t SysGetFileSize(void *arg)
420     {
421     file_handle *fh = (file_handle *)arg;
422     if (!fh)
423     return true;
424    
425     if (fh->is_file)
426     return fh->file_size;
427     else {
428 cebix 1.3 #if defined(__linux__)
429 cebix 1.1 loff_t pos = 0;
430     _llseek(fh->fd, 0, 0, &pos, SEEK_END);
431     return pos - fh->start_byte;
432     #else
433     return lseek(fh->fd, 0, SEEK_END) - fh->start_byte;
434     #endif
435     }
436     }
437    
438    
439     /*
440     * Eject volume (if applicable)
441     */
442    
443     void SysEject(void *arg)
444     {
445     file_handle *fh = (file_handle *)arg;
446     if (!fh)
447     return;
448    
449     #if defined(__linux__)
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, CDROMEJECT);
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 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
460 cebix 1.1 if (fh->is_floppy) {
461     fsync(fh->fd);
462     //ioctl(fh->fd, FDFLUSH);
463     //ioctl(fh->fd, FDEJECT);
464     } else if (fh->is_cdrom) {
465     ioctl(fh->fd, CDIOCEJECT);
466     close(fh->fd); // Close and reopen so the driver will see the media change
467     fh->fd = open(fh->name, O_RDONLY | O_NONBLOCK);
468     }
469     #endif
470     }
471    
472    
473     /*
474     * Format volume (if applicable)
475     */
476    
477     bool SysFormat(void *arg)
478     {
479     file_handle *fh = (file_handle *)arg;
480     if (!fh)
481     return false;
482    
483     //!!
484     return true;
485     }
486    
487    
488     /*
489     * Check if file/device is read-only (this includes the read-only flag on Sys_open())
490     */
491    
492     bool SysIsReadOnly(void *arg)
493     {
494     file_handle *fh = (file_handle *)arg;
495     if (!fh)
496     return true;
497    
498 cebix 1.3 #if defined(__linux__)
499 cebix 1.1 if (fh->is_floppy) {
500     struct floppy_drive_struct stat;
501     ioctl(fh->fd, FDGETDRVSTAT, &stat);
502     return !(stat.flags & FD_DISK_WRITABLE);
503     } else
504     #endif
505     return fh->read_only;
506     }
507    
508    
509     /*
510     * Check if the given file handle refers to a fixed or a removable disk
511     */
512    
513     bool SysIsFixedDisk(void *arg)
514     {
515     file_handle *fh = (file_handle *)arg;
516     if (!fh)
517     return true;
518    
519     if (fh->is_file)
520     return true;
521     else if (fh->is_floppy || fh->is_cdrom)
522     return false;
523     else
524     return true;
525     }
526    
527    
528     /*
529     * Check if a disk is inserted in the drive (always true for files)
530     */
531    
532     bool SysIsDiskInserted(void *arg)
533     {
534     file_handle *fh = (file_handle *)arg;
535     if (!fh)
536     return false;
537    
538     if (fh->is_file) {
539     return true;
540    
541     #if defined(__linux__)
542     } else if (fh->is_floppy) {
543     char block[512];
544     lseek(fh->fd, 0, SEEK_SET);
545     return read(fh->fd, block, 512) == 512;
546     } else if (fh->is_cdrom) {
547     #ifdef CDROM_DRIVE_STATUS
548     if (fh->cdrom_cap & CDC_DRIVE_STATUS) {
549     return ioctl(fh->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) == CDS_DISC_OK;
550     }
551     #endif
552     cdrom_tochdr header;
553     return ioctl(fh->fd, CDROMREADTOCHDR, &header) == 0;
554 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
555 cebix 1.1 } else if (fh->is_floppy) {
556     return false; //!!
557     } else if (fh->is_cdrom) {
558     struct ioc_toc_header header;
559     return ioctl(fh->fd, CDIOREADTOCHEADER, &header) == 0;
560     #endif
561    
562     } else
563     return true;
564     }
565    
566    
567     /*
568     * Prevent medium removal (if applicable)
569     */
570    
571     void SysPreventRemoval(void *arg)
572     {
573     file_handle *fh = (file_handle *)arg;
574     if (!fh)
575     return;
576    
577     #if defined(__linux__) && defined(CDROM_LOCKDOOR)
578     if (fh->is_cdrom)
579     ioctl(fh->fd, CDROM_LOCKDOOR, 1);
580     #endif
581     }
582    
583    
584     /*
585     * Allow medium removal (if applicable)
586     */
587    
588     void SysAllowRemoval(void *arg)
589     {
590     file_handle *fh = (file_handle *)arg;
591     if (!fh)
592     return;
593    
594 cebix 1.2 #if defined(__linux__) && defined(CDROM_LOCKDOOR)
595 cebix 1.1 if (fh->is_cdrom)
596     ioctl(fh->fd, CDROM_LOCKDOOR, 0);
597     #endif
598     }
599    
600    
601     /*
602     * Read CD-ROM TOC (binary MSF format, 804 bytes max.)
603     */
604    
605     bool SysCDReadTOC(void *arg, uint8 *toc)
606     {
607     file_handle *fh = (file_handle *)arg;
608     if (!fh)
609     return false;
610    
611     if (fh->is_cdrom) {
612     #if defined(__linux__)
613     uint8 *p = toc + 2;
614    
615     // Header
616     cdrom_tochdr header;
617     if (ioctl(fh->fd, CDROMREADTOCHDR, &header) < 0)
618     return false;
619     *p++ = header.cdth_trk0;
620     *p++ = header.cdth_trk1;
621    
622     // Tracks
623     cdrom_tocentry entry;
624     for (int i=header.cdth_trk0; i<=header.cdth_trk1; i++) {
625     entry.cdte_track = i;
626     entry.cdte_format = CDROM_MSF;
627     if (ioctl(fh->fd, CDROMREADTOCENTRY, &entry) < 0)
628     return false;
629     *p++ = 0;
630     *p++ = (entry.cdte_adr << 4) | entry.cdte_ctrl;
631     *p++ = entry.cdte_track;
632     *p++ = 0;
633     *p++ = 0;
634     *p++ = entry.cdte_addr.msf.minute;
635     *p++ = entry.cdte_addr.msf.second;
636     *p++ = entry.cdte_addr.msf.frame;
637     }
638    
639     // Leadout track
640     entry.cdte_track = CDROM_LEADOUT;
641     entry.cdte_format = CDROM_MSF;
642     if (ioctl(fh->fd, CDROMREADTOCENTRY, &entry) < 0)
643     return false;
644     *p++ = 0;
645     *p++ = (entry.cdte_adr << 4) | entry.cdte_ctrl;
646     *p++ = entry.cdte_track;
647     *p++ = 0;
648     *p++ = 0;
649     *p++ = entry.cdte_addr.msf.minute;
650     *p++ = entry.cdte_addr.msf.second;
651     *p++ = entry.cdte_addr.msf.frame;
652    
653     // TOC size
654     int toc_size = p - toc;
655     *toc++ = toc_size >> 8;
656     *toc++ = toc_size & 0xff;
657     return true;
658 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
659 cebix 1.1 uint8 *p = toc + 2;
660    
661     // Header
662     struct ioc_toc_header header;
663     if (ioctl(fh->fd, CDIOREADTOCHEADER, &header) < 0)
664     return false;
665     *p++ = header.starting_track;
666     *p++ = header.ending_track;
667    
668     // Tracks
669     struct ioc_read_toc_single_entry entry;
670     for (int i=header.starting_track; i<=header.ending_track; i++) {
671     entry.track = i;
672     entry.address_format = CD_MSF_FORMAT;
673     if (ioctl(fh->fd, CDIOREADTOCENTRY, &entry) < 0)
674     return false;
675     *p++ = 0;
676     *p++ = (entry.entry.addr_type << 4) | entry.entry.control;
677     *p++ = entry.entry.track;
678     *p++ = 0;
679     *p++ = 0;
680     *p++ = entry.entry.addr.msf.minute;
681     *p++ = entry.entry.addr.msf.second;
682     *p++ = entry.entry.addr.msf.frame;
683     }
684    
685     // Leadout track
686     entry.track = CD_TRACK_INFO;
687     entry.address_format = CD_MSF_FORMAT;
688     if (ioctl(fh->fd, CDIOREADTOCENTRY, &entry) < 0)
689     return false;
690     *p++ = 0;
691     *p++ = (entry.entry.addr_type << 4) | entry.entry.control;
692     *p++ = entry.entry.track;
693     *p++ = 0;
694     *p++ = 0;
695     *p++ = entry.entry.addr.msf.minute;
696     *p++ = entry.entry.addr.msf.second;
697     *p++ = entry.entry.addr.msf.frame;
698    
699     // TOC size
700     int toc_size = p - toc;
701     *toc++ = toc_size >> 8;
702     *toc++ = toc_size & 0xff;
703     return true;
704     #endif
705     } else
706     return false;
707     }
708    
709    
710     /*
711     * Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
712     */
713    
714     bool SysCDGetPosition(void *arg, uint8 *pos)
715     {
716     file_handle *fh = (file_handle *)arg;
717     if (!fh)
718     return false;
719    
720     if (fh->is_cdrom) {
721     #if defined(__linux__)
722     cdrom_subchnl chan;
723     chan.cdsc_format = CDROM_MSF;
724     if (ioctl(fh->fd, CDROMSUBCHNL, &chan) < 0)
725     return false;
726     *pos++ = 0;
727     *pos++ = chan.cdsc_audiostatus;
728     *pos++ = 0;
729     *pos++ = 12; // Sub-Q data length
730     *pos++ = 0;
731     *pos++ = (chan.cdsc_adr << 4) | chan.cdsc_ctrl;
732     *pos++ = chan.cdsc_trk;
733     *pos++ = chan.cdsc_ind;
734     *pos++ = 0;
735     *pos++ = chan.cdsc_absaddr.msf.minute;
736     *pos++ = chan.cdsc_absaddr.msf.second;
737     *pos++ = chan.cdsc_absaddr.msf.frame;
738     *pos++ = 0;
739     *pos++ = chan.cdsc_reladdr.msf.minute;
740     *pos++ = chan.cdsc_reladdr.msf.second;
741     *pos++ = chan.cdsc_reladdr.msf.frame;
742     return true;
743 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
744 cebix 1.1 struct ioc_read_subchannel chan;
745     chan.data_format = CD_MSF_FORMAT;
746     chan.address_format = CD_MSF_FORMAT;
747     chan.track = CD_CURRENT_POSITION;
748     if (ioctl(fh->fd, CDIOCREADSUBCHANNEL, &chan) < 0)
749     return false;
750     *pos++ = 0;
751     *pos++ = chan.data->header.audio_status;
752     *pos++ = 0;
753     *pos++ = 12; // Sub-Q data length
754     *pos++ = 0;
755     *pos++ = (chan.data->what.position.addr_type << 4) | chan.data->what.position.control;
756     *pos++ = chan.data->what.position.track_number;
757     *pos++ = chan.data->what.position.index_number;
758     *pos++ = 0;
759     *pos++ = chan.data->what.position.absaddr.msf.minute;
760     *pos++ = chan.data->what.position.absaddr.msf.second;
761     *pos++ = chan.data->what.position.absaddr.msf.frame;
762     *pos++ = 0;
763     *pos++ = chan.data->what.position.reladdr.msf.minute;
764     *pos++ = chan.data->what.position.reladdr.msf.second;
765     *pos++ = chan.data->what.position.reladdr.msf.frame;
766     return true;
767     #endif
768     } else
769     return false;
770     }
771    
772    
773     /*
774     * Play CD audio
775     */
776    
777     bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
778     {
779     file_handle *fh = (file_handle *)arg;
780     if (!fh)
781     return false;
782    
783     if (fh->is_cdrom) {
784     #if defined(__linux__)
785     cdrom_msf play;
786     play.cdmsf_min0 = start_m;
787     play.cdmsf_sec0 = start_s;
788     play.cdmsf_frame0 = start_f;
789     play.cdmsf_min1 = end_m;
790     play.cdmsf_sec1 = end_s;
791     play.cdmsf_frame1 = end_f;
792     return ioctl(fh->fd, CDROMPLAYMSF, &play) == 0;
793 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
794 cebix 1.1 struct ioc_play_msf play;
795     play.start_m = start_m;
796     play.start_s = start_s;
797     play.start_f = start_f;
798     play.end_m = end_m;
799     play.end_s = end_s;
800     play.end_f = end_f;
801     return ioctl(fh->fd, CDIOCPLAYMSF, &play) == 0;
802     #endif
803     } else
804     return false;
805     }
806    
807    
808     /*
809     * Pause CD audio
810     */
811    
812     bool SysCDPause(void *arg)
813     {
814     file_handle *fh = (file_handle *)arg;
815     if (!fh)
816     return false;
817    
818     if (fh->is_cdrom) {
819     #if defined(__linux__)
820     return ioctl(fh->fd, CDROMPAUSE) == 0;
821 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
822 cebix 1.1 return ioctl(fh->fd, CDIOCPAUSE) == 0;
823     #endif
824     } else
825     return false;
826     }
827    
828    
829     /*
830     * Resume paused CD audio
831     */
832    
833     bool SysCDResume(void *arg)
834     {
835     file_handle *fh = (file_handle *)arg;
836     if (!fh)
837     return false;
838    
839     if (fh->is_cdrom) {
840     #if defined(__linux__)
841     return ioctl(fh->fd, CDROMRESUME) == 0;
842 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
843 cebix 1.1 return ioctl(fh->fd, CDIOCRESUME) == 0;
844     #endif
845     } else
846     return false;
847     }
848    
849    
850     /*
851     * Stop CD audio
852     */
853    
854     bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
855     {
856     file_handle *fh = (file_handle *)arg;
857     if (!fh)
858     return false;
859    
860     if (fh->is_cdrom) {
861     #if defined(__linux__)
862     return ioctl(fh->fd, CDROMSTOP) == 0;
863 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
864 cebix 1.1 return ioctl(fh->fd, CDIOCSTOP) == 0;
865     #endif
866     } else
867     return false;
868     }
869    
870    
871     /*
872     * Perform CD audio fast-forward/fast-reverse operation starting from specified address
873     */
874    
875     bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
876     {
877     file_handle *fh = (file_handle *)arg;
878     if (!fh)
879     return false;
880    
881     // Not supported under Linux
882     return false;
883     }
884    
885    
886     /*
887     * Set CD audio volume (0..255 each channel)
888     */
889    
890     void SysCDSetVolume(void *arg, uint8 left, uint8 right)
891     {
892     file_handle *fh = (file_handle *)arg;
893     if (!fh)
894     return;
895    
896     if (fh->is_cdrom) {
897     #if defined(__linux__)
898     cdrom_volctrl vol;
899     vol.channel0 = vol.channel2 = left;
900     vol.channel1 = vol.channel3 = right;
901     ioctl(fh->fd, CDROMVOLCTRL, &vol);
902 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
903 cebix 1.1 struct ioc_vol vol;
904     vol.vol[0] = vol.vol[2] = left;
905     vol.vol[1] = vol.vol[3] = right;
906     ioctl(fh->fd, CDIOCSETVOL, &vol);
907     #endif
908     }
909     }
910    
911    
912     /*
913     * Get CD audio volume (0..255 each channel)
914     */
915    
916     void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
917     {
918     file_handle *fh = (file_handle *)arg;
919     if (!fh)
920     return;
921    
922     left = right = 0;
923     if (fh->is_cdrom) {
924     #if defined(__linux__)
925     cdrom_volctrl vol;
926     ioctl(fh->fd, CDROMVOLREAD, &vol);
927     left = vol.channel0;
928     right = vol.channel1;
929 cebix 1.3 #elif defined(__FreeBSD__) || defined(__NetBSD__)
930 cebix 1.1 struct ioc_vol vol;
931     ioctl(fh->fd, CDIOCGETVOL, &vol);
932     left = vol.vol[0];
933     right = vol.vol[1];
934     #endif
935     }
936     }