home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / AmigaOS / sys_amiga.cpp < prev    next >
C/C++ Source or Header  |  1999-11-01  |  22KB  |  980 lines

  1. /*
  2.  *  sys_amiga.cpp - System dependent routines, Amiga 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 <exec/types.h>
  22. #include <exec/memory.h>
  23. #include <devices/newstyle.h>
  24. #include <devices/trackdisk.h>
  25. #include <devices/scsidisk.h>
  26. #include <resources/disk.h>
  27. #include <proto/dos.h>
  28. #include <proto/exec.h>
  29. #include <proto/disk.h>
  30.  
  31. #include "sysdeps.h"
  32. #include "main.h"
  33. #include "macos_util.h"
  34. #include "prefs.h"
  35. #include "user_strings.h"
  36. #include "sys.h"
  37.  
  38. #define DEBUG 0
  39. #include "debug.h"
  40.  
  41.  
  42. // File handles are pointers to these structures
  43. struct file_handle {
  44.     bool is_file;            // Flag: plain file or /dev/something?
  45.     bool read_only;            // Copy of Sys_open() flag
  46.     loff_t start_byte;        // Size of file header (if any)
  47.     loff_t size;            // Size of file/device (minus header)
  48.  
  49.     BPTR f;                    // AmigaDOS file handle (if is_file == true)
  50.  
  51.     struct IOStdReq *io;    // Pointer to IORequest (if is_file == false)
  52.     ULONG block_size;        // Block size of device (must be a power of two)
  53.     bool is_nsd;            // New style device?
  54.     bool does_64bit;        // Supports 64 bit trackdisk commands?
  55. };
  56.  
  57.  
  58. // FileInfoBlock (must be global because it has to be on a longword boundary)
  59. static struct FileInfoBlock FIB;
  60.  
  61. // Message port for device communication
  62. static struct MsgPort *the_port = NULL;
  63.  
  64. // Temporary buffer in chip memory
  65. const int TMP_BUF_SIZE = 0x10000;
  66. static UBYTE *tmp_buf = NULL;
  67.  
  68.  
  69. /*
  70.  *  Initialization
  71.  */
  72.  
  73. void SysInit(void)
  74. {
  75.     // Create port and temporary buffer
  76.     the_port = CreateMsgPort();
  77.     tmp_buf = (UBYTE *)AllocMem(TMP_BUF_SIZE, MEMF_CHIP | MEMF_PUBLIC);
  78.     if (the_port == NULL || tmp_buf == NULL) {
  79.         ErrorAlert(GetString(STR_NO_MEM_ERR));
  80.         QuitEmulator();
  81.     }
  82. }
  83.  
  84.  
  85. /*
  86.  *  Deinitialization
  87.  */
  88.  
  89. void SysExit(void)
  90. {
  91.     // Delete port and temporary buffer
  92.     if (the_port)
  93.         DeleteMsgPort(the_port);
  94.     if (tmp_buf)
  95.         FreeMem(tmp_buf, TMP_BUF_SIZE);
  96. }
  97.  
  98.  
  99. /*
  100.  *  This gets called when no "floppy" prefs items are found
  101.  *  It scans for available floppy drives and adds appropriate prefs items
  102.  */
  103.  
  104. void SysAddFloppyPrefs(void)
  105. {
  106. #if 0
  107.     for (int i=0; i<4; i++) {
  108.         ULONG id = GetUnitID(i);
  109.         if (id == DRT_150RPM) {    // We need an HD drive
  110.             char str[256];
  111.             sprintf(str, "/dev/mfm.device/%d/0/0/1474560/512", i);
  112.             PrefsAddString("floppy", str);
  113.         }
  114.     }
  115. #endif
  116. }
  117.  
  118.  
  119. /*
  120.  *  This gets called when no "disk" prefs items are found
  121.  *  It scans for available HFS volumes and adds appropriate prefs items
  122.  */
  123.  
  124. void SysAddDiskPrefs(void)
  125. {
  126.     // AmigaOS doesn't support MacOS partitioning, so this probably doesn't make much sense...
  127. }
  128.  
  129.  
  130. /*
  131.  *  This gets called when no "cdrom" prefs items are found
  132.  *  It scans for available CD-ROM drives and adds appropriate prefs items
  133.  */
  134.  
  135. void SysAddCDROMPrefs(void)
  136. {
  137.     // Don't scan for drives if nocdrom option given
  138.     if (PrefsFindBool("nocdrom"))
  139.         return;
  140.  
  141.     //!!
  142. }
  143.  
  144.  
  145. /*
  146.  *  Add default serial prefs (must be added, even if no ports present)
  147.  */
  148.  
  149. void SysAddSerialPrefs(void)
  150. {
  151.     PrefsAddString("seriala", "serial.device/0");
  152.     PrefsAddString("serialb", "*parallel.device/0");
  153. }
  154.  
  155.  
  156. /*
  157.  *  Open file/device, create new file handle (returns NULL on error)
  158.  *
  159.  *  Format for device names: /dev/<name>/<unit>/<open flags>/<start block>/<size (blocks)>/<block size>
  160.  */
  161.  
  162. void *Sys_open(const char *name, bool read_only)
  163. {
  164.     bool is_file = (strstr(name, "/dev/") != name);
  165.  
  166.     D(bug("Sys_open(%s, %s)\n", name, read_only ? "read-only" : "read/write"));
  167.  
  168.     // File or device?
  169.     if (is_file) {
  170.  
  171.         // File, open it and get stats
  172.         BPTR f = Open((char *)name, MODE_OLDFILE);
  173.         if (!f)
  174.             return NULL;
  175.         if (!ExamineFH(f, &FIB)) {
  176.             Close(f);
  177.             return NULL;
  178.         }
  179.  
  180.         // Check if file is write protected
  181.         if (FIB.fib_Protection & FIBF_WRITE)
  182.             read_only = true;
  183.  
  184.         // Create file_handle
  185.         file_handle *fh = new file_handle;
  186.         fh->f = f;
  187.         fh->is_file = true;
  188.         fh->read_only = read_only;
  189.  
  190.         // Detect disk image file layout
  191.         loff_t size = FIB.fib_Size;
  192.         Seek(fh->f, 0, OFFSET_BEGINNING);
  193.         Read(fh->f, tmp_buf, 256);
  194.         FileDiskLayout(size, tmp_buf, fh->start_byte, fh->size);
  195.         return fh;
  196.  
  197.     } else {
  198.  
  199.         // Device, parse string
  200.         char dev_name[256];
  201.         ULONG dev_unit = 0, dev_flags = 0, dev_start = 0, dev_size = 16, dev_bsize = 512;
  202.         if (sscanf(name, "/dev/%[^/]/%ld/%ld/%ld/%ld/%ld", dev_name, &dev_unit, &dev_flags, &dev_start, &dev_size, &dev_bsize) < 2)
  203.             return NULL;
  204.  
  205.         // Create IORequest
  206.         struct IOStdReq *io = (struct IOStdReq *)CreateIORequest(the_port, sizeof(struct IOExtTD));
  207.         if (io == NULL)
  208.             return NULL;
  209.  
  210.         // Open device
  211.         if (OpenDevice((UBYTE *)dev_name, dev_unit, (struct IORequest *)io, dev_flags)) {
  212.             D(bug(" couldn't open device\n"));
  213.             DeleteIORequest(io);
  214.             return NULL;
  215.         }
  216.  
  217.         // Check for new style device
  218.         bool is_nsd = false, does_64bit = false;
  219.         struct NSDeviceQueryResult nsdqr;
  220.         nsdqr.DevQueryFormat = 0;
  221.         nsdqr.SizeAvailable = 0;
  222.         io->io_Command = NSCMD_DEVICEQUERY;
  223.         io->io_Length = sizeof(nsdqr);
  224.         io->io_Data = (APTR)&nsdqr;
  225.         LONG error = DoIO((struct IORequest *)io);
  226.         D(bug("DEVICEQUERY returned %ld (length %ld, actual %ld)\n", error, io->io_Length, io->io_Actual));
  227.         if ((!error) && (io->io_Actual >= 16) && (io->io_Actual <= sizeof(nsdqr)) && (nsdqr.SizeAvailable == io->io_Actual)) {
  228.  
  229.             // Looks like an NSD
  230.             is_nsd = true;
  231.             D(bug(" new style device, type %ld\n", nsdqr.DeviceType));
  232.  
  233.             // We only work with trackdisk-like devices
  234.             if (nsdqr.DeviceType != NSDEVTYPE_TRACKDISK) {
  235.                 CloseDevice((struct IORequest *)io);
  236.                 DeleteIORequest(io);
  237.                 return NULL;
  238.             }
  239.  
  240.             // Check whether device is 64 bit capable
  241.             UWORD *cmdcheck;
  242.             for (cmdcheck = nsdqr.SupportedCommands; *cmdcheck; cmdcheck++) {
  243.                 if (*cmdcheck == NSCMD_TD_READ64) {
  244.                     D(bug(" supports 64 bit commands\n"));
  245.                     does_64bit = true;
  246.                 }
  247.             }
  248.         }
  249.  
  250.         // Create file_handle
  251.         file_handle *fh = new file_handle;
  252.         fh->io = io;
  253.         fh->is_file = false;
  254.         fh->read_only = read_only;
  255.         fh->start_byte = (loff_t)dev_start * dev_bsize;
  256.         fh->size = (loff_t)dev_size * dev_bsize;
  257.         fh->block_size = dev_bsize;
  258.         fh->is_nsd = is_nsd;
  259.         fh->does_64bit = does_64bit;
  260.         return fh;
  261.     }
  262. }
  263.  
  264.  
  265. /*
  266.  *  Close file/device, delete file handle
  267.  */
  268.  
  269. void Sys_close(void *arg)
  270. {
  271.     file_handle *fh = (file_handle *)arg;
  272.     if (!fh)
  273.         return;
  274.  
  275.     D(bug("Sys_close(%08lx)\n", arg));
  276.  
  277.     // File or device?
  278.     if (fh->is_file) {
  279.  
  280.         // File, simply close it
  281.         Close(fh->f);
  282.  
  283.     } else {
  284.  
  285.         // Device, close it and delete IORequest
  286.         fh->io->io_Command = CMD_UPDATE;
  287.         DoIO((struct IORequest *)fh->io);
  288.  
  289.         fh->io->io_Command = TD_MOTOR;
  290.         fh->io->io_Length = 0;
  291.         DoIO((struct IORequest *)fh->io);
  292.  
  293.         CloseDevice((struct IORequest *)fh->io);
  294.         DeleteIORequest(fh->io);
  295.     }
  296.     delete fh;
  297. }
  298.  
  299.  
  300. /*
  301.  *  Send one I/O request, using 64-bit addressing if the device supports it
  302.  */
  303.  
  304. static loff_t send_io_request(file_handle *fh, bool writing, ULONG length, loff_t offset, APTR data)
  305. {
  306.     if (fh->does_64bit) {
  307.         fh->io->io_Command = writing ? NSCMD_TD_WRITE64 : NSCMD_TD_READ64;
  308.         fh->io->io_Actual = offset >> 32;
  309.     } else {
  310.         fh->io->io_Command = writing ? CMD_WRITE : CMD_READ;
  311.         fh->io->io_Actual = 0;
  312.     }
  313.     fh->io->io_Length = length;
  314.     fh->io->io_Offset = offset;
  315.     fh->io->io_Data = data;
  316.     if (DoIO((struct IORequest *)fh->io) || fh->io->io_Actual != length)
  317.         return 0;
  318.     return fh->io->io_Actual;
  319. }
  320.  
  321.  
  322. /*
  323.  *  Read "length" bytes from file/device, starting at "offset", to "buffer",
  324.  *  returns number of bytes read (or 0)
  325.  */
  326.  
  327. size_t Sys_read(void *arg, void *buffer, loff_t offset, size_t length)
  328. {
  329.     file_handle *fh = (file_handle *)arg;
  330.     if (!fh)
  331.         return 0;
  332.  
  333.     // File or device?
  334.     if (fh->is_file) {
  335.  
  336.         // File, seek to position
  337.         if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1)
  338.             return 0;
  339.  
  340.         // Read data
  341.         LONG actual = Read(fh->f, buffer, length);
  342.         if (actual == -1)
  343.             return 0;
  344.         else
  345.             return actual;
  346.  
  347.     } else {
  348.  
  349.         // Device, pre-read (partial read of first block) necessary?
  350.         loff_t pos = offset + fh->start_byte;
  351.         size_t actual = 0;
  352.         uint32 pre_offset = pos % fh->block_size;
  353.         if (pre_offset) {
  354.  
  355.             // Yes, read one block
  356.             if (send_io_request(fh, false, fh->block_size, pos - pre_offset, tmp_buf) == 0)
  357.                 return 0;
  358.  
  359.             // Copy data to destination buffer
  360.             size_t pre_length = fh->block_size - pre_offset;
  361.             if (pre_length > length)
  362.                 pre_length = length;
  363.             memcpy(buffer, tmp_buf + pre_offset, pre_length);
  364.  
  365.             // Adjust data pointers
  366.             buffer = (uint8 *)buffer + pre_length;
  367.             pos += pre_length;
  368.             length -= pre_length;
  369.             actual += pre_length;
  370.         }
  371.  
  372.         // Main read (complete reads of middle blocks) possible?
  373.         if (length >= fh->block_size) {
  374.  
  375.             // Yes, read blocks
  376.             size_t main_length = length & ~(fh->block_size - 1);
  377.             if (send_io_request(fh, false, main_length, pos, buffer) == 0)
  378.                 return 0;
  379.  
  380.             // Adjust data pointers
  381.             buffer = (uint8 *)buffer + main_length;
  382.             pos += main_length;
  383.             length -= main_length;
  384.             actual += main_length;
  385.         }
  386.  
  387.         // Post-read (partial read of last block) necessary?
  388.         if (length) {
  389.  
  390.             // Yes, read one block
  391.             if (send_io_request(fh, false, fh->block_size, pos, tmp_buf) == 0)
  392.                 return 0;
  393.  
  394.             // Copy data to destination buffer
  395.             memcpy(buffer, tmp_buf, length);
  396.             actual += length;
  397.         }
  398.  
  399.         return actual;
  400.     }
  401. }
  402.  
  403.  
  404. /*
  405.  *  Write "length" bytes from "buffer" to file/device, starting at "offset",
  406.  *  returns number of bytes written (or 0)
  407.  */
  408.  
  409. size_t Sys_write(void *arg, void *buffer, loff_t offset, size_t length)
  410. {
  411.     file_handle *fh = (file_handle *)arg;
  412.     if (!fh)
  413.         return 0;
  414.  
  415.     // File or device?
  416.     if (fh->is_file) {
  417.  
  418.         // File, seek to position if necessary
  419.         if (Seek(fh->f, offset + fh->start_byte, OFFSET_BEGINNING) == -1)
  420.             return 0;
  421.  
  422.         // Write data
  423.         LONG actual = Write(fh->f, buffer, length);
  424.         if (actual == -1)
  425.             return 0;
  426.         else
  427.             return actual;
  428.  
  429.     } else {
  430.  
  431.         // Device, pre-write (partial write of first block) necessary
  432.         loff_t pos = offset + fh->start_byte;
  433.         size_t actual = 0;
  434.         uint32 pre_offset = pos % fh->block_size;
  435.         if (pre_offset) {
  436.  
  437.             // Yes, read one block
  438.             if (send_io_request(fh, false, fh->block_size, pos - pre_offset, tmp_buf) == 0)
  439.                 return 0;
  440.  
  441.             // Copy data from source buffer
  442.             size_t pre_length = fh->block_size - pre_offset;
  443.             if (pre_length > length)
  444.                 pre_length = length;
  445.             memcpy(tmp_buf + pre_offset, buffer, pre_length);
  446.  
  447.             // Write block back
  448.             if (send_io_request(fh, true, fh->block_size, pos - pre_offset, tmp_buf) == 0)
  449.                 return 0;
  450.  
  451.             // Adjust data pointers
  452.             buffer = (uint8 *)buffer + pre_length;
  453.             pos += pre_length;
  454.             length -= pre_length;
  455.             actual += pre_length;
  456.         }
  457.  
  458.         // Main write (complete writes of middle blocks) possible?
  459.         if (length >= fh->block_size) {
  460.  
  461.             // Yes, write blocks
  462.             size_t main_length = length & ~(fh->block_size - 1);
  463.             if (send_io_request(fh, true, main_length, pos, buffer) == 0)
  464.                 return 0;
  465.  
  466.             // Adjust data pointers
  467.             buffer = (uint8 *)buffer + main_length;
  468.             pos += main_length;
  469.             length -= main_length;
  470.             actual += main_length;
  471.         }
  472.  
  473.         // Post-write (partial write of last block) necessary?
  474.         if (length) {
  475.  
  476.             // Yes, read one block
  477.             if (send_io_request(fh, false, fh->block_size, pos, tmp_buf) == 0)
  478.                 return 0;
  479.  
  480.             // Copy data from source buffer
  481.             memcpy(buffer, tmp_buf, length);
  482.  
  483.             // Write block back
  484.             if (send_io_request(fh, true, fh->block_size, pos, tmp_buf) == 0)
  485.                 return 0;
  486.             actual += length;
  487.         }
  488.  
  489.         return actual;
  490.     }
  491. }
  492.  
  493.  
  494. /*
  495.  *  Return size of file/device (minus header)
  496.  */
  497.  
  498. loff_t SysGetFileSize(void *arg)
  499. {
  500.     file_handle *fh = (file_handle *)arg;
  501.     if (!fh)
  502.         return true;
  503.  
  504.     return fh->size;
  505. }
  506.  
  507.  
  508. /*
  509.  *  Eject volume (if applicable)
  510.  */
  511.  
  512. void SysEject(void *arg)
  513. {
  514.     file_handle *fh = (file_handle *)arg;
  515.     if (!fh)
  516.         return;
  517.  
  518.     if (!fh->is_file) {
  519.  
  520.         // Flush buffer, turn off the drive motor and eject volume
  521.         fh->io->io_Command = CMD_UPDATE;
  522.         DoIO((struct IORequest *)fh->io);
  523.  
  524.         fh->io->io_Command = TD_MOTOR;
  525.         fh->io->io_Length = 0;
  526.         DoIO((struct IORequest *)fh->io);
  527.  
  528.         fh->io->io_Command = TD_EJECT;
  529.         fh->io->io_Length = 1;
  530.         DoIO((struct IORequest *)fh->io);
  531.     }
  532. }
  533.  
  534.  
  535. /*
  536.  *  Format volume (if applicable)
  537.  */
  538.  
  539. bool SysFormat(void *arg)
  540. {
  541.     file_handle *fh = (file_handle *)arg;
  542.     if (!fh)
  543.         return false;
  544.  
  545.     //!!
  546.     return true;
  547. }
  548.  
  549.  
  550. /*
  551.  *  Check if file/device is read-only (this includes the read-only flag on Sys_open())
  552.  */
  553.  
  554. bool SysIsReadOnly(void *arg)
  555. {
  556.     file_handle *fh = (file_handle *)arg;
  557.     if (!fh)
  558.         return true;
  559.  
  560.     if (fh->is_file) {
  561.  
  562.         // File, return flag given to Sys_open
  563.         return fh->read_only;
  564.  
  565.     } else {
  566.  
  567.         // Device, check write protection
  568.         fh->io->io_Flags = IOF_QUICK;
  569.         fh->io->io_Command = TD_PROTSTATUS;
  570.         BeginIO((struct IORequest *)fh->io);
  571.         if (fh->io->io_Actual)
  572.             return true;
  573.         else
  574.             return fh->read_only;
  575.     }
  576. }
  577.  
  578.  
  579. /*
  580.  *  Check if the given file handle refers to a fixed or a removable disk
  581.  */
  582.  
  583. bool SysIsFixedDisk(void *arg)
  584. {
  585.     file_handle *fh = (file_handle *)arg;
  586.     if (!fh)
  587.         return true;
  588.  
  589.     return true;
  590. }
  591.  
  592.  
  593. /*
  594.  *  Check if a disk is inserted in the drive (always true for files)
  595.  */
  596.  
  597. bool SysIsDiskInserted(void *arg)
  598. {
  599.     file_handle *fh = (file_handle *)arg;
  600.     if (!fh)
  601.         return false;
  602.  
  603.     if (fh->is_file)
  604.         return true;
  605.     else {
  606.  
  607.         // Check medium status
  608.         fh->io->io_Flags = IOF_QUICK;
  609.         fh->io->io_Command = TD_CHANGESTATE;
  610.         fh->io->io_Actual = 0;
  611.         BeginIO((struct IORequest *)fh->io);
  612.         return fh->io->io_Actual == 0;
  613.     }
  614. }
  615.  
  616.  
  617. /*
  618.  *  Prevent medium removal (if applicable)
  619.  */
  620.  
  621. void SysPreventRemoval(void *arg)
  622. {
  623.     file_handle *fh = (file_handle *)arg;
  624.     if (!fh)
  625.         return;
  626.  
  627.     if (!fh->is_file) {
  628.  
  629.         // Send PREVENT ALLOW MEDIUM REMOVAL SCSI command
  630.         struct SCSICmd scsi;
  631.         static const UBYTE the_cmd[6] = {0x1e, 0, 0, 0, 1, 0};
  632.         scsi.scsi_Length = 0;
  633.         scsi.scsi_Command = (UBYTE *)the_cmd;
  634.         scsi.scsi_CmdLength = 6;
  635.         scsi.scsi_Flags = SCSIF_READ;
  636.         scsi.scsi_Status = 0;
  637.         fh->io->io_Data = &scsi;
  638.         fh->io->io_Length = sizeof(scsi);
  639.         fh->io->io_Command = HD_SCSICMD;
  640.         DoIO((struct IORequest *)fh->io);
  641.     }
  642. }
  643.  
  644.  
  645. /*
  646.  *  Allow medium removal (if applicable)
  647.  */
  648.  
  649. void SysAllowRemoval(void *arg)
  650. {
  651.     file_handle *fh = (file_handle *)arg;
  652.     if (!fh)
  653.         return;
  654.  
  655.     if (!fh->is_file) {
  656.  
  657.         // Send PREVENT ALLOW MEDIUM REMOVAL SCSI command
  658.         struct SCSICmd scsi;
  659.         static const UBYTE the_cmd[6] = {0x1e, 0, 0, 0, 0, 0};
  660.         scsi.scsi_Length = 0;
  661.         scsi.scsi_Command = (UBYTE *)the_cmd;
  662.         scsi.scsi_CmdLength = 6;
  663.         scsi.scsi_Flags = SCSIF_READ;
  664.         scsi.scsi_Status = 0;
  665.         fh->io->io_Data = &scsi;
  666.         fh->io->io_Length = sizeof(scsi);
  667.         fh->io->io_Command = HD_SCSICMD;
  668.         DoIO((struct IORequest *)fh->io);
  669.     }
  670. }
  671.  
  672.  
  673. /*
  674.  *  Read CD-ROM TOC (binary MSF format, 804 bytes max.)
  675.  */
  676.  
  677. bool SysCDReadTOC(void *arg, uint8 *toc)
  678. {
  679.     file_handle *fh = (file_handle *)arg;
  680.     if (!fh)
  681.         return false;
  682.  
  683.     if (fh->is_file)
  684.         return false;
  685.     else {
  686.  
  687.         // Send READ TOC MSF SCSI command
  688.         struct SCSICmd scsi;
  689.         static const UBYTE read_toc_cmd[10] = {0x43, 0x02, 0, 0, 0, 0, 0, 0x03, 0x24, 0};
  690.         scsi.scsi_Data = (UWORD *)tmp_buf;
  691.         scsi.scsi_Length = 804;
  692.         scsi.scsi_Command = (UBYTE *)read_toc_cmd;
  693.         scsi.scsi_CmdLength = 10;
  694.         scsi.scsi_Flags = SCSIF_READ;
  695.         scsi.scsi_Status = 0;
  696.         fh->io->io_Data = &scsi;
  697.         fh->io->io_Length = sizeof(scsi);
  698.         fh->io->io_Command = HD_SCSICMD;
  699.         if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
  700.             return false;
  701.         memcpy(toc, tmp_buf, 804);
  702.         return true;
  703.     }
  704. }
  705.  
  706.  
  707. /*
  708.  *  Read CD-ROM position data (Sub-Q Channel, 16 bytes, see SCSI standard)
  709.  */
  710.  
  711. bool SysCDGetPosition(void *arg, uint8 *pos)
  712. {
  713.     file_handle *fh = (file_handle *)arg;
  714.     if (!fh)
  715.         return false;
  716.  
  717.     if (fh->is_file)
  718.         return false;
  719.     else {
  720.  
  721.         // Send READ SUB-CHANNEL SCSI command
  722.         struct SCSICmd scsi;
  723.         static const UBYTE read_subq_cmd[10] = {0x42, 0x02, 0x40, 0x01, 0, 0, 0, 0, 0x10, 0};
  724.         scsi.scsi_Data = (UWORD *)tmp_buf;
  725.         scsi.scsi_Length = 16;
  726.         scsi.scsi_Command = (UBYTE *)read_subq_cmd;
  727.         scsi.scsi_CmdLength = 10;
  728.         scsi.scsi_Flags = SCSIF_READ;
  729.         scsi.scsi_Status = 0;
  730.         fh->io->io_Data = &scsi;
  731.         fh->io->io_Length = sizeof(scsi);
  732.         fh->io->io_Command = HD_SCSICMD;
  733.         if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
  734.             return false;
  735.         memcpy(pos, tmp_buf, 16);
  736.         return true;
  737.     }
  738. }
  739.  
  740.  
  741. /*
  742.  *  Play CD audio
  743.  */
  744.  
  745. bool SysCDPlay(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, uint8 end_m, uint8 end_s, uint8 end_f)
  746. {
  747.     file_handle *fh = (file_handle *)arg;
  748.     if (!fh)
  749.         return false;
  750.  
  751.     if (fh->is_file)
  752.         return false;
  753.     else {
  754.  
  755.         // Send PLAY AUDIO MSF SCSI command
  756.         struct SCSICmd scsi;
  757.         UBYTE play_cmd[10] = {0x47, 0, 0, start_m, start_s, start_f, end_m, end_s, end_f, 0};
  758.         scsi.scsi_Data = (UWORD *)tmp_buf;
  759.         scsi.scsi_Length = 0;
  760.         scsi.scsi_Command = play_cmd;
  761.         scsi.scsi_CmdLength = 10;
  762.         scsi.scsi_Flags = SCSIF_READ;
  763.         scsi.scsi_Status = 0;
  764.         fh->io->io_Data = &scsi;
  765.         fh->io->io_Length = sizeof(scsi);
  766.         fh->io->io_Command = HD_SCSICMD;
  767.         if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
  768.             return false;
  769.         return true;
  770.     }
  771. }
  772.  
  773.  
  774. /*
  775.  *  Pause CD audio
  776.  */
  777.  
  778. bool SysCDPause(void *arg)
  779. {
  780.     file_handle *fh = (file_handle *)arg;
  781.     if (!fh)
  782.         return false;
  783.  
  784.     if (fh->is_file)
  785.         return false;
  786.     else {
  787.  
  788.         // Send PAUSE RESUME SCSI command
  789.         struct SCSICmd scsi;
  790.         static const UBYTE pause_cmd[10] = {0x4b, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  791.         scsi.scsi_Data = (UWORD *)tmp_buf;
  792.         scsi.scsi_Length = 0;
  793.         scsi.scsi_Command = (UBYTE *)pause_cmd;
  794.         scsi.scsi_CmdLength = 10;
  795.         scsi.scsi_Flags = SCSIF_READ;
  796.         scsi.scsi_Status = 0;
  797.         fh->io->io_Data = &scsi;
  798.         fh->io->io_Length = sizeof(scsi);
  799.         fh->io->io_Command = HD_SCSICMD;
  800.         if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
  801.             return false;
  802.         return true;
  803.     }
  804. }
  805.  
  806.  
  807. /*
  808.  *  Resume paused CD audio
  809.  */
  810.  
  811. bool SysCDResume(void *arg)
  812. {
  813.     file_handle *fh = (file_handle *)arg;
  814.     if (!fh)
  815.         return false;
  816.  
  817.     if (fh->is_file)
  818.         return false;
  819.     else {
  820.  
  821.         // Send PAUSE RESUME SCSI command
  822.         struct SCSICmd scsi;
  823.         static const UBYTE resume_cmd[10] = {0x4b, 0, 0, 0, 0, 0, 0, 0, 1, 0};
  824.         scsi.scsi_Data = (UWORD *)tmp_buf;
  825.         scsi.scsi_Length = 0;
  826.         scsi.scsi_Command = (UBYTE *)resume_cmd;
  827.         scsi.scsi_CmdLength = 10;
  828.         scsi.scsi_Flags = SCSIF_READ;
  829.         scsi.scsi_Status = 0;
  830.         fh->io->io_Data = &scsi;
  831.         fh->io->io_Length = sizeof(scsi);
  832.         fh->io->io_Command = HD_SCSICMD;
  833.         if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
  834.             return false;
  835.         return true;
  836.     }
  837. }
  838.  
  839.  
  840. /*
  841.  *  Stop CD audio
  842.  */
  843.  
  844. bool SysCDStop(void *arg, uint8 lead_out_m, uint8 lead_out_s, uint8 lead_out_f)
  845. {
  846.     file_handle *fh = (file_handle *)arg;
  847.     if (!fh)
  848.         return false;
  849.  
  850.     if (fh->is_file)
  851.         return false;
  852.     else {
  853.  
  854.         uint8 end_m = lead_out_m;
  855.         uint8 end_s = lead_out_s;
  856.         uint8 end_f = lead_out_f + 1;
  857.         if (end_f >= 75) {
  858.             end_f = 0;
  859.             end_s++;
  860.             if (end_s >= 60) {
  861.                 end_s = 0;
  862.                 end_m++;
  863.             }
  864.         }
  865.  
  866.         // Send PLAY AUDIO MSF SCSI command (play first frame of lead-out area)
  867.         struct SCSICmd scsi;
  868.         UBYTE play_cmd[10] = {0x47, 0, 0, lead_out_m, lead_out_s, lead_out_f, end_m, end_s, end_f, 0};
  869.         scsi.scsi_Data = (UWORD *)tmp_buf;
  870.         scsi.scsi_Length = 0;
  871.         scsi.scsi_Command = play_cmd;
  872.         scsi.scsi_CmdLength = 10;
  873.         scsi.scsi_Flags = SCSIF_READ;
  874.         scsi.scsi_Status = 0;
  875.         fh->io->io_Data = &scsi;
  876.         fh->io->io_Length = sizeof(scsi);
  877.         fh->io->io_Command = HD_SCSICMD;
  878.         if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
  879.             return false;
  880.         return true;
  881.     }
  882. }
  883.  
  884.  
  885. /*
  886.  *  Perform CD audio fast-forward/fast-reverse operation starting from specified address
  887.  */
  888.  
  889. bool SysCDScan(void *arg, uint8 start_m, uint8 start_s, uint8 start_f, bool reverse)
  890. {
  891.     file_handle *fh = (file_handle *)arg;
  892.     if (!fh)
  893.         return false;
  894.  
  895.     //!!
  896.     return false;
  897. }
  898.  
  899.  
  900. /*
  901.  *  Set CD audio volume (0..255 each channel)
  902.  */
  903.  
  904. void SysCDSetVolume(void *arg, uint8 left, uint8 right)
  905. {
  906.     file_handle *fh = (file_handle *)arg;
  907.     if (!fh)
  908.         return;
  909.  
  910.     if (!fh->is_file) {
  911.  
  912.         // Send MODE SENSE (CD-ROM Audio Control Parameters Page) SCSI command
  913.         struct SCSICmd scsi;
  914.         static const UBYTE mode_sense_cmd[6] = {0x1a, 0x08, 0x0e, 0, 20, 0};
  915.         scsi.scsi_Data = (UWORD *)tmp_buf;
  916.         scsi.scsi_Length = 20;
  917.         scsi.scsi_Command = (UBYTE *)mode_sense_cmd;
  918.         scsi.scsi_CmdLength = 6;
  919.         scsi.scsi_Flags = SCSIF_READ;
  920.         scsi.scsi_Status = 0;
  921.         fh->io->io_Data = &scsi;
  922.         fh->io->io_Length = sizeof(scsi);
  923.         fh->io->io_Command = HD_SCSICMD;
  924.         if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
  925.             return;
  926.  
  927.         tmp_buf[6] = 0x04;        // Immed
  928.         tmp_buf[9] = 0;            // LBA/sec format
  929.         tmp_buf[10] = 0;        // LBA/sec
  930.         tmp_buf[11] = 0;
  931.         tmp_buf[13] = left;        // Port 0 volume
  932.         tmp_buf[15] = right;    // Port 1 volume
  933.  
  934.         // Send MODE SELECT (CD-ROM Audio Control Parameters Page) SCSI command
  935.         static const UBYTE mode_select_cmd[6] = {0x15, 0x10, 0, 0, 20, 0};
  936.         scsi.scsi_Data = (UWORD *)tmp_buf;
  937.         scsi.scsi_Length = 20;
  938.         scsi.scsi_Command = (UBYTE *)mode_select_cmd;
  939.         scsi.scsi_CmdLength = 6;
  940.         scsi.scsi_Flags = SCSIF_WRITE;
  941.         scsi.scsi_Status = 0;
  942.         fh->io->io_Data = &scsi;
  943.         fh->io->io_Length = sizeof(scsi);
  944.         fh->io->io_Command = HD_SCSICMD;
  945.         DoIO((struct IORequest *)fh->io);
  946.     }
  947. }
  948.  
  949.  
  950. /*
  951.  *  Get CD audio volume (0..255 each channel)
  952.  */
  953.  
  954. void SysCDGetVolume(void *arg, uint8 &left, uint8 &right)
  955. {
  956.     file_handle *fh = (file_handle *)arg;
  957.     if (!fh)
  958.         return;
  959.  
  960.     if (!fh->is_file) {
  961.  
  962.         // Send MODE SENSE (CD-ROM Audio Control Parameters Page) SCSI command
  963.         struct SCSICmd scsi;
  964.         static const UBYTE mode_sense_cmd[6] = {0x1a, 0x08, 0x0e, 0, 20, 0};
  965.         scsi.scsi_Data = (UWORD *)tmp_buf;
  966.         scsi.scsi_Length = 20;
  967.         scsi.scsi_Command = (UBYTE *)mode_sense_cmd;
  968.         scsi.scsi_CmdLength = 6;
  969.         scsi.scsi_Flags = SCSIF_READ;
  970.         scsi.scsi_Status = 0;
  971.         fh->io->io_Data = &scsi;
  972.         fh->io->io_Length = sizeof(scsi);
  973.         fh->io->io_Command = HD_SCSICMD;
  974.         if (DoIO((struct IORequest *)fh->io) || scsi.scsi_Status)
  975.             return;
  976.         left = tmp_buf[13];        // Port 0 volume
  977.         right = tmp_buf[15];    // Port 1 volume
  978.     }
  979. }
  980.