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, 8 months ago) by cebix
Branch: MAIN
Changes since 1.2: +32 -22 lines
Log Message:
- integrated patches for NetBSD

File Contents

# Content
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 #if defined(__FreeBSD__) || defined(__NetBSD__)
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 #elif defined(__NetBSD__)
125 PrefsAddString("floppy", "/dev/fd0a");
126 PrefsAddString("floppy", "/dev/fd1a");
127 #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 if (sscanf(line, "%as %as %as", &dev, &mnt_point, &fstype) == 3) {
155 if (strcmp(fstype, "hfs") == 0)
156 PrefsAddString("disk", dev);
157 }
158 free(dev); free(mnt_point); free(fstype);
159 }
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 #elif defined(__NetBSD__)
182 PrefsAddString("cdrom", "/dev/cd0d");
183 #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 #elif defined(__NetBSD__)
200 PrefsAddString("seriala", "/dev/tty00");
201 PrefsAddString("serialb", "/dev/tty01");
202 #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 char *dummy;
227 sscanf(line, "%as %s", &dummy, mount_name);
228 free(dummy);
229 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 #if defined(__FreeBSD__)
248 // 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 #if defined(__linux__)
276 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 #if defined(__linux__)
298 _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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
323 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 #if defined(__linux__)
376 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 #if defined(__linux__)
402 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 #if defined(__linux__)
429 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
460 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 #if defined(__linux__)
499 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
555 } 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 #if defined(__linux__) && defined(CDROM_LOCKDOOR)
595 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
659 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
744 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
794 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
822 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
843 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
864 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
903 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
930 struct ioc_vol vol;
931 ioctl(fh->fd, CDIOCGETVOL, &vol);
932 left = vol.vol[0];
933 right = vol.vol[1];
934 #endif
935 }
936 }