home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / BeOS / sys_beos.cpp < prev    next >
C/C++ Source or Header  |  1999-10-03  |  17KB  |  832 lines

  1. /*
  2.  *  sys_beos.cpp - System dependent routines, BeOS 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 <StorageKit.h>
  22. #include <InterfaceKit.h>
  23. #include <kernel/fs_info.h>
  24. #include <drivers/Drivers.h>
  25. #include <device/scsi.h>
  26.  
  27. #include <unistd.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <fcntl.h>
  32.  
  33. #include "sysdeps.h"
  34. #include "main.h"
  35. #include "macos_util.h"
  36. #include "prefs.h"
  37. #include "user_strings.h"
  38. #include "sys.h"
  39.  
  40. #define DEBUG 0
  41. #include "debug.h"
  42.  
  43.  
  44. // File handles are pointers to these structures
  45. struct file_handle {
  46.     file_handle *next;    // Pointer to next file handle (must be first in struct!)
  47.     const char *name;    // File/device name (copied, for mount menu)
  48.     int fd;                // fd of file/device
  49.     bool is_file;        // Flag: plain file or /dev/something?
  50.     bool read_only;        // Copy of Sys_open() flag
  51.     loff_t start_byte;    // Size of file header (if any)
  52.     loff_t file_size;    // Size of file data (only valid if is_file is true)
  53. };
  54.  
  55. // Linked list of file handles
  56. static file_handle *first_file_handle;
  57.  
  58. // Temporary buffer for transfers from/to kernel space
  59. const int TMP_BUF_SIZE = 0x10000;
  60. static uint8 *tmp_buf;
  61.  
  62. // For B_SCSI_PREVENT_ALLOW
  63. static const int32 PREVENT = 1;
  64. static const int32 ALLOW = 0;
  65.  
  66.  
  67. /*
  68.  *  Check if device is a mounted HFS volume, get mount name
  69.  */
  70.  
  71. static bool is_drive_mounted(const char *dev_name, char *mount_name)
  72. {
  73.     int32 i = 0;
  74.     dev_t d;
  75.     fs_info info;
  76.     while ((d = next_dev(&i)) >= 0) {
  77.         fs_stat_dev(d, &info);
  78.         if (strcmp(dev_name, info.device_name) == 0) {
  79.             status_t err = -1;
  80.             BPath mount;
  81.             BDirectory dir;
  82.             BEntry entry;
  83.             node_ref node;
  84.             node.device = info.dev;
  85.             node.node = info.root;
  86.             err = dir.SetTo(&node);
  87.             if (!err)
  88.                 err = dir.GetEntry(&entry);
  89.             if (!err)
  90.                 err = entry.GetPath(&mount);
  91.             if (!err) {
  92.                 strcpy(mount_name, mount.Path());
  93.                 return true;
  94.             }
  95.         }
  96.     }
  97.     return false;
  98. }
  99.  
  100.  
  101. /*
  102.  *  Initialization
  103.  */
  104.  
  105. void SysInit(void)
  106. {
  107.     first_file_handle = NULL;
  108.  
  109.     // Allocate temporary buffer
  110.     tmp_buf = new uint8[TMP_BUF_SIZE];
  111. }
  112.  
  113.  
  114. /*
  115.  *  Deinitialization
  116.  */
  117.  
  118. void SysExit(void)
  119. {
  120.     delete[] tmp_buf;
  121. }
  122.  
  123.  
  124. /*
  125.  *  Create menu of used volumes (for "mount" menu)
  126.  */
  127.  
  128. void SysCreateVolumeMenu(BMenu *menu, uint32 msg)
  129. {
  130.     for (file_handle *fh=first_file_handle; fh; fh=fh->next)
  131.         if (!SysIsFixedDisk(fh))
  132.             menu->AddItem(new BMenuItem(fh->name, new BMessage(msg)));
  133. }
  134.  
  135.  
  136. /*
  137.  *  Mount volume given name from mount menu
  138.  */
  139.  
  140. void SysMountVolume(const char *name)
  141. {
  142.     file_handle *fh;
  143.     for (fh=first_file_handle; fh && strcmp(fh->name, name); fh=fh->next) ;
  144.     if (fh)
  145.         MountVolume(fh);
  146. }
  147.  
  148.  
  149. /*
  150.  *  This gets called when no "floppy" prefs items are found
  151.  *  It scans for available floppy drives and adds appropriate prefs items
  152.  */
  153.  
  154. void SysAddFloppyPrefs(void)
  155. {
  156.     // Only one floppy drive under BeOS
  157.     PrefsAddString("floppy", "/dev/disk/floppy/raw");
  158. }
  159.  
  160.  
  161. /*
  162.  *  This gets called when no "disk" prefs items are found
  163.  *  It scans for available HFS volumes and adds appropriate prefs items
  164.  */
  165.  
  166. void SysAddDiskPrefs(void)
  167. {
  168.     // Let BeOS scan for HFS drives
  169.     D(bug("Looking for Mac volumes...\n"));
  170.     system("mountvolume -allhfs");
  171.  
  172.     // Add all HFS volumes
  173.     int32 i = 0;
  174.     dev_t d;
  175.     fs_info info;
  176.     while ((d = next_dev(&i)) >= 0) {
  177.         fs_stat_dev(d, &info);
  178.         status_t err = -1;
  179.         BPath mount;
  180.         if (!strcmp(info.fsh_name, "hfs")) {
  181.             BDirectory dir;
  182.             BEntry entry;
  183.             node_ref node;
  184.             node.device = info.dev;
  185.             node.node = info.root;
  186.             err = dir.SetTo(&node);
  187.             if (!err)
  188.                 err = dir.GetEntry(&entry);
  189.             if (!err)
  190.                 err = entry.GetPath(&mount);
  191.         }
  192.         if (!err)
  193.             err = unmount(mount.Path());
  194.         if (!err) {
  195.             char dev_name[B_FILE_NAME_LENGTH];
  196.             if (info.flags & B_FS_IS_READONLY) {
  197.                 dev_name[0] = '*';
  198.                 dev_name[1] = 0;
  199.             } else
  200.                 dev_name[0] = 0;
  201.             strcat(dev_name, info.device_name);
  202.             PrefsAddString("disk", dev_name);
  203.         }
  204.     }
  205. }
  206.  
  207.  
  208. /*
  209.  *  This gets called when no "cdrom" prefs items are found
  210.  *  It scans for available CD-ROM drives and adds appropriate prefs items
  211.  */
  212.  
  213. // Scan directory for CD-ROM drives, add them to prefs
  214. static void scan_for_cdrom_drives(const char *directory)
  215. {
  216.     // Set directory
  217.     BDirectory dir;
  218.     dir.SetTo(directory);
  219.     if (dir.InitCheck() != B_NO_ERROR)
  220.         return;
  221.     dir.Rewind();
  222.  
  223.     // Scan each entry
  224.     BEntry entry;
  225.     while (dir.GetNextEntry(&entry) >= 0) {
  226.  
  227.         // Get path and ref for entry
  228.         BPath path;
  229.         if (entry.GetPath(&path) != B_NO_ERROR)
  230.             continue;
  231.         const char *name = path.Path();
  232.         entry_ref e;
  233.         if (entry.GetRef(&e) != B_NO_ERROR)
  234.             continue;
  235.  
  236.         // Recursively enter subdirectories (except for floppy)
  237.         if (entry.IsDirectory()) {
  238.             if (!strcmp(e.name, "floppy"))
  239.                 continue;
  240.             scan_for_cdrom_drives(name);
  241.         } else {
  242.  
  243.             D(bug(" checking '%s'\n", name));
  244.  
  245.             // Ignore partitions
  246.             if (strcmp(e.name, "raw"))
  247.                 continue;
  248.  
  249.             // Open device
  250.             int fd = open(name, O_RDONLY);
  251.             if (fd < 0)
  252.                 continue;
  253.  
  254.             // Get geometry and device type
  255.             device_geometry g;
  256.             if (ioctl(fd, B_GET_GEOMETRY, &g, sizeof(g)) < 0) {
  257.                 close(fd);
  258.                 continue;
  259.             }
  260.  
  261.             // Insert to list if it is a CD drive
  262.             if (g.device_type == B_CD)
  263.                 PrefsAddString("cdrom", name);
  264.             close(fd);
  265.         }
  266.     }
  267. }
  268.  
  269. void SysAddCDROMPrefs(void)
  270. {
  271.     // Don't scan for drives if nocdrom option given
  272.     if (PrefsFindBool("nocdrom"))
  273.         return;
  274.  
  275.     // Look for CD-ROM drives and add prefs items
  276.     D(bug("Looking for CD-ROM drives...\n"));
  277.     scan_for_cdrom_drives("/dev/disk");
  278. }
  279.  
  280.  
  281. /*
  282.  *  Add default serial prefs (must be added, even if no ports present)
  283.  */
  284.  
  285. void SysAddSerialPrefs(void)
  286. {
  287.     system_info info;
  288.     get_system_info(&info);
  289.     switch (info.platform_type) {
  290.         case B_BEBOX_PLATFORM:
  291.         case B_AT_CLONE_PLATFORM:
  292.             PrefsAddString("seriala", "serial1");
  293.             PrefsAddString("serialb", "serial2");
  294.             break;
  295.         case B_MAC_PLATFORM:
  296.             PrefsAddString("seriala", "modem");
  297.             PrefsAddString("serialb", "printer");
  298.             break;
  299.         default:
  300.             PrefsAddString("seriala", "none");
  301.             PrefsAddString("serialb", "none");
  302.             break;
  303.     }
  304. }
  305.  
  306.  
  307. /*
  308.  *  Open file/device, create new file handle (returns NULL on error)
  309.  */
  310.  
  311. void *Sys_open(const char *name, bool read_only)
  312. {
  313.     static bool published_all = false;
  314.     bool is_file = (strstr(name, "/dev/") != name);
  315.  
  316.     D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write"));
  317.  
  318.     // Print warning message and eventually unmount drive when this is an HFS volume mounted under BeOS (double mounting will corrupt the volume)
  319.     char mount_name[B_FILE_NAME_LENGTH];
  320.     if (!is_file && !read_only && is_drive_mounted(name, mount_name)) {
  321.         char str[256 + B_FILE_NAME_LENGTH];
  322.         sprintf(str, GetString(STR_VOLUME_IS_MOUNTED_WARN), mount_name);
  323.         WarningAlert(str);
  324.         if (unmount(mount_name) != 0) {
  325.             sprintf(str, GetString(STR_CANNOT_UNMOUNT_WARN), mount_name);
  326.             WarningAlert(str);
  327.             return NULL;
  328.         }
  329.     }
  330.  
  331.     int fd = open(name, read_only ? O_RDONLY : O_RDWR);
  332.     if (fd < 0 && !published_all) {
  333.         // Open failed, create all device nodes and try again, but only the first time
  334.         system("mountvolume -publishall");
  335.         published_all = true;
  336.         fd = open(name, read_only ? O_RDONLY : O_RDWR);
  337.     }
  338.     if (fd >= 0) {
  339.         file_handle *fh = new file_handle;
  340.         fh->name = strdup(name);
  341.         fh->fd = fd;
  342.         fh->is_file = is_file;
  343.         fh->read_only = read_only;
  344.         fh->start_byte = 0;
  345.         if (fh->is_file) {
  346.             // Detect disk image file layout
  347.             loff_t size = lseek(fd, 0, SEEK_END);
  348.             uint8 data[256];
  349.             lseek(fd, 0, SEEK_SET);
  350.             read(fd, data, 256);
  351.             FileDiskLayout(size, data, fh->start_byte, fh->file_size);
  352.         }
  353.  
  354.         // Enqueue file handle
  355.         fh->next = NULL;
  356.         file_handle *q = first_file_handle;
  357.         if (q) {
  358.             while (q->next)
  359.                 q = q->next;
  360.             q->next = fh;
  361.         } else
  362.             first_file_handle = fh;
  363.         return fh;
  364.     } else
  365.         return NULL;
  366. }
  367.  
  368.  
  369. /*
  370.  *  Close file/device, delete file handle
  371.  */
  372.  
  373. void Sys_close(void *arg)
  374. {
  375.     file_handle *fh = (file_handle *)arg;
  376.     if (!fh)
  377.         return;
  378.  
  379.     // Free device name and close file/device
  380.     free((void *)fh->name);
  381.     close(fh->fd);
  382.  
  383.     // Dequeue file handle
  384.     file_handle *q = first_file_handle;
  385.     if (q == fh) {
  386.         first_file_handle = NULL;
  387.         delete fh;
  388.         return;
  389.     }
  390.     while (q) {
  391.         if (q->next == fh) {
  392.             q->next = fh->next;
  393.             delete fh;
  394.             return;
  395.         }
  396.         q = q->next;
  397.     }
  398. }
  399.  
  400.  
  401. /*
  402.  *  Read "length" bytes from file/device, starting at "offset", to "buffer",
  403.  *  returns number of bytes read (or 0)
  404.  */
  405.  
  406. static inline ssize_t sread(int fd, void *buf, size_t count)
  407. {
  408.     ssize_t res;
  409.     while ((res = read(fd, buf, count)) == B_INTERRUPTED) ;
  410.     return res;
  411. }
  412.  
  413. size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
  414. {
  415.     file_handle *fh = (file_handle *)arg;
  416.     if (!fh)
  417.         return 0;
  418.  
  419. //    D(bug("Sys_read(%08lx, %08lx, %Ld, %d)\n", fh, buffer, offset, length));
  420.  
  421.     // Seek to position
  422.     if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
  423.         return 0;
  424.  
  425.     // Buffer in kernel space?
  426.     size_t actual = 0;
  427.     if ((uint32)buffer < 0x80000000) {
  428.  
  429.         // Yes, transfer via buffer
  430.         while (length) {
  431.             size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length;
  432.             if (sread(fh->fd, tmp_buf, transfer_size) != transfer_size)
  433.                 return actual;
  434.             memcpy(buffer, tmp_buf, transfer_size);
  435.             buffer = (void *)((uint8 *)buffer + transfer_size);
  436.             length -= transfer_size;
  437.             actual += transfer_size;
  438.         }
  439.  
  440.     } else {
  441.  
  442.         // No, transfer directly
  443.         actual = sread(fh->fd, buffer, length);
  444.         if (actual < 0)
  445.             actual = 0;
  446.     }
  447.     return actual;
  448. }
  449.  
  450.  
  451. /*
  452.  *  Write "length" bytes from "buffer" to file/device, starting at "offset",
  453.  *  returns number of bytes written (or 0)
  454.  */
  455.  
  456. static inline ssize_t swrite(int fd, void *buf, size_t count)
  457. {
  458.     ssize_t res;
  459.     while ((res = write(fd, buf, count)) == B_INTERRUPTED) ;
  460.     return res;
  461. }
  462.  
  463. size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
  464. {
  465.     file_handle *fh = (file_handle *)arg;
  466.     if (!fh)
  467.         return 0;
  468.  
  469. //    D(bug("Sys_write(%08lx, %08lx, %Ld, %d)\n", fh, buffer, offset, length));
  470.  
  471.     // Seek to position
  472.     if (lseek(fh->fd, offset + fh->start_byte, SEEK_SET) < 0)
  473.         return 0;
  474.  
  475.     // Buffer in kernel space?
  476.     size_t actual = 0;
  477.     if ((uint32)buffer < 0x80000000) {
  478.  
  479.         // Yes, transfer via buffer
  480.         while (length) {
  481.             size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length;
  482.             memcpy(tmp_buf, buffer, transfer_size);
  483.             if (swrite(fh->fd, tmp_buf, transfer_size) != transfer_size)
  484.                 return actual;
  485.             buffer = (void *)((uint8 *)buffer + transfer_size);
  486.             length -= transfer_size;
  487.             actual += transfer_size;
  488.         }
  489.  
  490.     } else {
  491.  
  492.         // No, transfer directly
  493.         actual = swrite(fh->fd, buffer, length);
  494.         if (actual < 0)
  495.             actual = 0;
  496.     }
  497.     return actual;
  498. }
  499.  
  500.  
  501. /*
  502.  *  Return size of file/device (minus header)
  503.  */
  504.  
  505. loff_t SysGetFileSize(void *arg)
  506. {
  507.     file_handle *fh = (file_handle *)arg;
  508.     if (!fh)
  509.         return true;
  510.  
  511.     if (fh->is_file)
  512.         return fh->file_size;
  513.     else {
  514.         device_geometry g;
  515.         if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0)
  516.             return (loff_t)g.bytes_per_sector * g.sectors_per_track * g.cylinder_count * g.head_count;
  517.         else
  518.             return 0;
  519.     }
  520. }
  521.  
  522.  
  523. /*
  524.  *  Eject volume (if applicable)
  525.  */
  526.  
  527. void SysEject(void *arg)
  528. {
  529.     file_handle *fh = (file_handle *)arg;
  530.     if (!fh)
  531.         return;
  532.  
  533.     if (!fh->is_file)
  534.         ioctl(fh->fd, B_EJECT_DEVICE);
  535. }
  536.  
  537.  
  538. /*
  539.  *  Format volume (if applicable)
  540.  */
  541.  
  542. bool SysFormat(void *arg)
  543. {
  544.     file_handle *fh = (file_handle *)arg;
  545.     if (!fh)
  546.         return false;
  547.  
  548.     if (!fh->is_file)
  549.         return ioctl(fh->fd, B_FORMAT_DEVICE) >= 0;
  550.     else
  551.         return false;
  552. }
  553.  
  554.  
  555. /*
  556.  *  Check if file/device is read-only (this includes the read-only flag on Sys_open())
  557.  */
  558.  
  559. bool SysIsReadOnly(void *arg)
  560. {
  561.     file_handle *fh = (file_handle *)arg;
  562.     if (!fh)
  563.         return true;
  564.  
  565.     if (fh->is_file) {
  566.  
  567.         // File, return flag given to Sys_open
  568.         return fh->read_only;
  569.  
  570.     } else {
  571.  
  572.         // Device, check write protection
  573.         device_geometry g;
  574.         if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0)
  575.             return g.read_only | fh->read_only;
  576.         else
  577.             return fh->read_only;    // Removable but not inserted
  578.     }
  579. }
  580.  
  581.  
  582. /*
  583.  *  Check if the given file handle refers to a fixed or a removable disk
  584.  */
  585.  
  586. bool SysIsFixedDisk(void *arg)
  587. {
  588.     file_handle *fh = (file_handle *)arg;
  589.     if (!fh)
  590.         return true;
  591.  
  592.     if (fh->is_file)
  593.         return true;
  594.     else {
  595.         device_geometry g;
  596.         if (ioctl(fh->fd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0)
  597.             return !g.removable;
  598.         else
  599.             return false;    // Removable but not inserted
  600.     }
  601. }
  602.  
  603.  
  604. /*
  605.  *  Check if a disk is inserted in the drive (always true for files)
  606.  */
  607.  
  608. bool SysIsDiskInserted(void *arg)
  609. {
  610.     file_handle *fh = (file_handle *)arg;
  611.     if (!fh)
  612.         return false;
  613.  
  614.     if (fh->is_file)
  615.         return true;
  616.     else {
  617.         status_t l;
  618.         if (ioctl(fh->fd, B_GET_MEDIA_STATUS, &l, sizeof(l)) >= 0 && l == B_NO_ERROR)
  619.             return true;
  620.         else
  621.             return false;
  622.     }
  623. }
  624.  
  625.  
  626. /*
  627.  *  Prevent medium removal (if applicable)
  628.  */
  629.  
  630. void SysPreventRemoval(void *arg)
  631. {
  632.     file_handle *fh = (file_handle *)arg;
  633.     if (!fh)
  634.         return;
  635.  
  636.     if (!fh->is_file)
  637.         ioctl(fh->fd, B_SCSI_PREVENT_ALLOW, &PREVENT, sizeof(PREVENT));
  638. }
  639.  
  640.  
  641. /*
  642.  *  Allow medium removal (if applicable)
  643.  */
  644.  
  645. void SysAllowRemoval(void *arg)
  646. {
  647.     file_handle *fh = (file_handle *)arg;
  648.     if (!fh)
  649.         return;
  650.  
  651.     if (!fh->is_file)
  652.         ioctl(fh->fd, B_SCSI_PREVENT_ALLOW, &ALLOW, sizeof(ALLOW));
  653. }
  654.  
  655.  
  656. /*
  657.  *  Read CD-ROM TOC (binary MSF format, 804 bytes max.)
  658.  */
  659.  
  660. bool SysCDReadTOC(void *arg, uint8 *toc)
  661. {
  662.     file_handle *fh = (file_handle *)arg;
  663.     if (!fh)
  664.         return false;
  665.  
  666.     if (!fh->is_file) {
  667.         memset(tmp_buf, 0, 804);
  668.         if (ioctl(fh->fd, B_SCSI_GET_TOC, tmp_buf, 804) < 0)
  669.             return false;
  670.         memcpy(toc, tmp_buf, 804);
  671.         return true;
  672.     } else
  673.         return false;
  674. }
  675.  
  676.  
  677. /*
  678.  *  Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
  679.  */
  680.  
  681. bool SysCDGetPosition(void *arg, uint8 *pos)
  682. {
  683.     file_handle *fh = (file_handle *)arg;
  684.     if (!fh)
  685.         return false;
  686.  
  687.     if (!fh->is_file) {
  688.         if (ioctl(fh->fd, B_SCSI_GET_POSITION, tmp_buf, 16) < 0)
  689.             return false;
  690.         memcpy(pos, tmp_buf, 16);
  691.         return true;
  692.     } else
  693.         return false;
  694. }
  695.  
  696.  
  697. /*
  698.  *  Play CD audio
  699.  */
  700.  
  701. bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
  702. {
  703.     file_handle *fh = (file_handle *)arg;
  704.     if (!fh)
  705.         return false;
  706.  
  707.     if (!fh->is_file) {
  708.         scsi_play_position *p = (scsi_play_position *)tmp_buf;
  709.         p->start_m = start_m;
  710.         p->start_s = start_s;
  711.         p->start_f = start_f;
  712.         p->end_m = end_m;
  713.         p->end_s = end_s;
  714.         p->end_f = end_f;
  715.         return ioctl(fh->fd, B_SCSI_PLAY_POSITION, p, sizeof(scsi_play_position)) == 0;
  716.     } else
  717.         return false;
  718. }
  719.  
  720.  
  721. /*
  722.  *  Pause CD audio
  723.  */
  724.  
  725. bool SysCDPause(void *arg)
  726. {
  727.     file_handle *fh = (file_handle *)arg;
  728.     if (!fh)
  729.         return true;
  730.  
  731.     if (!fh->is_file)
  732.         return ioctl(fh->fd, B_SCSI_PAUSE_AUDIO) == 0;
  733.     else
  734.         return false;
  735. }
  736.  
  737.  
  738. /*
  739.  *  Resume paused CD audio
  740.  */
  741.  
  742. bool SysCDResume(void *arg)
  743. {
  744.     file_handle *fh = (file_handle *)arg;
  745.     if (!fh)
  746.         return false;
  747.  
  748.     if (!fh->is_file)
  749.         return ioctl(fh->fd, B_SCSI_RESUME_AUDIO) == 0;
  750.     else
  751.         return false;
  752. }
  753.  
  754.  
  755. /*
  756.  *  Stop CD audio
  757.  */
  758.  
  759. bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
  760. {
  761.     file_handle *fh = (file_handle *)arg;
  762.     if (!fh)
  763.         return false;
  764.  
  765.     if (!fh->is_file)
  766.         return ioctl(fh->fd, B_SCSI_STOP_AUDIO) == 0;
  767.     else
  768.         return false;
  769. }
  770.  
  771.  
  772. /*
  773.  *  Perform CD audio fast-forward/fast-reverse operation starting from specified address
  774.  */
  775.  
  776. bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
  777. {
  778.     file_handle *fh = (file_handle *)arg;
  779.     if (!fh)
  780.         return false;
  781.  
  782.     if (!fh->is_file) {
  783.         scsi_scan *p = (scsi_scan *)tmp_buf;
  784.         p->speed = 0;
  785.         p->direction = reverse ? -1 : 1;
  786.         return ioctl(fh->fd, B_SCSI_SCAN, p, sizeof(scsi_scan)) == 0;
  787.     } else
  788.         return false;
  789. }
  790.  
  791.  
  792. /*
  793.  *  Set CD audio volume (0..255 each channel)
  794.  */
  795.  
  796. void SysCDSetVolume(void *arg, uint8 left, uint8 right)
  797. {
  798.     file_handle *fh = (file_handle *)arg;
  799.     if (!fh)
  800.         return;
  801.  
  802.     if (!fh->is_file) {
  803.         scsi_volume *p = (scsi_volume *)tmp_buf;
  804.         p->flags = B_SCSI_PORT0_VOLUME | B_SCSI_PORT1_VOLUME;
  805.         p->port0_volume = left;
  806.         p->port1_volume = right;
  807.         ioctl(fh->fd, B_SCSI_SET_VOLUME, p, sizeof(scsi_volume));
  808.     }
  809. }
  810.  
  811.  
  812. /*
  813.  *  Get CD audio volume (0..255 each channel)
  814.  */
  815.  
  816. void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
  817. {
  818.     file_handle *fh = (file_handle *)arg;
  819.     if (!fh)
  820.         return;
  821.  
  822.     left = right = 0;
  823.     if (!fh->is_file) {
  824.         scsi_volume *p = (scsi_volume *)tmp_buf;
  825.         p->flags = B_SCSI_PORT0_VOLUME | B_SCSI_PORT1_VOLUME;
  826.         if (ioctl(fh->fd, B_SCSI_GET_VOLUME, p, sizeof(scsi_volume)) == 0) {
  827.             left = p->port0_volume;
  828.             right = p->port1_volume;
  829.         }
  830.     }
  831. }
  832.