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 (24 years, 8 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-21101999
Changes since 1.3: +28 -2 lines
Log Message:
- some fixes 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__)
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 #elif defined(__NetBSD__)
333 fh->is_floppy = ((st.st_rdev >> 16) == 2);
334 #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 #if defined(__linux__)
378 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 #if defined(__linux__)
404 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 #if defined(__linux__)
431 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
462 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 #if defined(__linux__)
501 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
557 } 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 #if defined(__linux__) && defined(CDROM_LOCKDOOR)
597 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 #elif defined(__FreeBSD__)
661 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
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
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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
770 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
820 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
848 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
869 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
890 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
929 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 #elif defined(__FreeBSD__) || defined(__NetBSD__)
956 struct ioc_vol vol;
957 ioctl(fh->fd, CDIOCGETVOL, &vol);
958 left = vol.vol[0];
959 right = vol.vol[1];
960 #endif
961 }
962 }