home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / cdrom.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-02  |  28.2 KB  |  980 lines

  1. /*
  2.  *  cdrom.cpp - CD-ROM driver
  3.  *
  4.  *  Basilisk II (C) 1997-2001 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. /*
  22.  *  SEE ALSO
  23.  *    Inside Macintosh: Devices, chapter 1 "Device Manager"
  24.  *    Technote DV 05: "Drive Queue Elements"
  25.  *    Technote DV 22: "CD-ROM Driver Calls"
  26.  *    Technote DV 23: "Driver Education"
  27.  *    Technote FL 24: "Don't Look at ioPosOffset for Devices"
  28.  *    Technote FL 36: "Apple Extensions to ISO 9660"
  29.  */
  30.  
  31. #include <string.h>
  32.  
  33. #include "sysdeps.h"
  34. #include "cpu_emulation.h"
  35. #include "main.h"
  36. #include "macos_util.h"
  37. #include "sys.h"
  38. #include "prefs.h"
  39. #include "cdrom.h"
  40.  
  41. #define DEBUG 0
  42. #include "debug.h"
  43.  
  44.  
  45. // CDROM disk/drive icon
  46. const uint8 CDROMIcon[258] = {
  47.     0x3f, 0xff, 0xff, 0xf0, 0x40, 0x00, 0x00, 0x08, 0x80, 0x1f, 0xc0, 0x04, 0x80, 0x75, 0x70, 0x04,
  48.     0x81, 0xaa, 0xac, 0x04, 0x83, 0x55, 0x56, 0x04, 0x86, 0xaa, 0xab, 0x04, 0x8d, 0x55, 0x55, 0x84,
  49.     0x8a, 0xaa, 0xaa, 0xc4, 0x95, 0x5f, 0xd5, 0x44, 0x9a, 0xb0, 0x6a, 0xe4, 0xb5, 0x67, 0x35, 0x64,
  50.     0xaa, 0xcf, 0x9a, 0xb4, 0xb5, 0x5c, 0x55, 0x74, 0xaa, 0xd8, 0x5a, 0xb4, 0xb5, 0x58, 0x55, 0x74,
  51.     0xaa, 0xc8, 0x9a, 0xb4, 0xb5, 0x67, 0x35, 0x74, 0x9a, 0xb0, 0x6a, 0xf4, 0x95, 0x5f, 0xd5, 0x64,
  52.     0x8a, 0xaa, 0xaa, 0xe4, 0x8d, 0x55, 0x55, 0xc4, 0x86, 0xaa, 0xab, 0xc4, 0x83, 0x55, 0x57, 0x84,
  53.     0x81, 0xaa, 0xaf, 0x04, 0x80, 0xf5, 0x7e, 0x04, 0x80, 0x3f, 0xf8, 0x04, 0x80, 0x0f, 0xe0, 0x04,
  54.     0xff, 0xff, 0xff, 0xfc, 0x80, 0x00, 0x00, 0x04, 0x80, 0x1f, 0xf0, 0x04, 0x7f, 0xff, 0xff, 0xf8,
  55.  
  56.     0x3f, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc,
  57.     0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc,
  58.     0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc,
  59.     0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc,
  60.     0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc,
  61.     0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc,
  62.     0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc,
  63.     0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xf8,
  64.  
  65.     0, 0
  66. };
  67.  
  68.  
  69. // Tables for converting bin<->BCD
  70. static const uint8 bin2bcd[256] = {
  71.     0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
  72.     0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
  73.     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
  74.     0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
  75.     0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
  76.     0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
  77.     0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
  78.     0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
  79.     0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
  80.     0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
  81.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  82.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  83.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  84.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  85.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  86.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  87.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  88.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  89.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  90.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  91.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  92.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  93.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  94.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  95.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  96.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  97. };
  98.  
  99. static const uint8 bcd2bin[256] = {
  100.     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  101.     10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  102.     20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  103.     30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  104.     40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  105.     50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  106.     60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  107.     70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  108.     80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  109.     90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  110.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  111.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  112.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  113.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  114.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  115.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
  116. };
  117.  
  118.  
  119. // Struct for each drive
  120. struct DriveInfo {
  121.     DriveInfo()
  122.     {
  123.         next = NULL;
  124.         num = 0;
  125.         fh = NULL;
  126.         start_byte = 0;
  127.         status = 0;
  128.     }
  129.  
  130.     DriveInfo *next;    // Pointer to next DriveInfo (must be first in struct!)
  131.     int num;            // Drive number
  132.     void *fh;            // File handle
  133.     int block_size;        // CD-ROM block size
  134.     int twok_offset;    // Offset of beginning of 2K block to last Prime position
  135.     uint32 start_byte;    // Start of HFS partition on disk
  136.     bool to_be_mounted;    // Flag: drive must be mounted in accRun
  137.     bool mount_non_hfs;    // Flag: Issue disk-inserted events for non-HFS disks
  138.  
  139.     uint8 toc[804];        // TOC of currently inserted disk
  140.     uint8 lead_out[3];    // MSF address of lead-out track
  141.     uint8 stop_at[3];    // MSF address of audio play stopping point
  142.  
  143.     uint8 play_mode;    // Audio play mode
  144.     uint8 power_mode;    // Power mode
  145.     uint32 status;        // Mac address of drive status record
  146. };
  147.  
  148. // Linked list of DriveInfos
  149. static DriveInfo *first_drive_info;
  150.  
  151. // Icon address (Mac address space, set by PatchROM())
  152. uint32 CDROMIconAddr;
  153.  
  154. // Flag: Control(accRun) has been called, interrupt routine is now active
  155. static bool acc_run_called = false;
  156.  
  157.  
  158. /*
  159.  *  Get pointer to drive info, NULL = invalid drive number
  160.  */
  161.  
  162. static DriveInfo *get_drive_info(int num)
  163. {
  164.     DriveInfo *info = first_drive_info;
  165.     while (info != NULL) {
  166.         if (info->num == num)
  167.             return info;
  168.         info = info->next;
  169.     }
  170.     return NULL;
  171. }
  172.  
  173.  
  174. /*
  175.  *  Find HFS partition, set info->start_byte (0 = no HFS partition)
  176.  */
  177.  
  178. static void find_hfs_partition(DriveInfo *info)
  179. {
  180.     info->start_byte = 0;
  181.     uint8 *map = new uint8[512];
  182.  
  183.     // Search first 64 blocks for HFS partition
  184.     for (int i=0; i<64; i++) {
  185.         if (Sys_read(info->fh, map, i * 512, 512) != 512)
  186.             break;
  187.  
  188.         // Not a partition map block? Then look at next block
  189.         uint16 sig = (map[0] << 8) | map[1];
  190.         if (sig != 0x504d)
  191.             continue;
  192.  
  193.         // Partition map block found, Apple HFS partition?
  194.         if (strcmp((char *)(map + 48), "Apple_HFS") == 0) {
  195.             info->start_byte = ntohl(((uint32 *)map)[2]) << 9;
  196.             D(bug(" HFS partition found at %d, %d blocks\n", info->start_byte, ntohl(((uint32 *)map)[3])));
  197.             break;
  198.         }
  199.     }
  200.     delete[] map;
  201. }
  202.  
  203.  
  204. /*
  205.  *  Read TOC of disk and set lead_out
  206.  */
  207.  
  208. static void read_toc(DriveInfo *info)
  209. {
  210.     // Read TOC
  211.     memset(&info->toc, 0, sizeof(info->toc));
  212.     SysCDReadTOC(info->fh, info->toc);
  213.     D(bug(" TOC: %08lx %08lx\n", ntohl(((uint32 *)info->toc)[0]), ntohl(((uint32 *)info->toc)[1])));
  214.  
  215.     // Find lead-out track
  216.     info->lead_out[0] = 0;
  217.     info->lead_out[1] = 0;
  218.     info->lead_out[2] = 0;
  219.     for (int i=4; i<804; i+=8) {
  220.         if (info->toc[i+2] == 0xaa) {
  221.             info->stop_at[0] = info->lead_out[0] = info->toc[i+5];
  222.             info->stop_at[1] = info->lead_out[1] = info->toc[i+6];
  223.             info->stop_at[2] = info->lead_out[2] = info->toc[i+7];
  224.             break;
  225.         }
  226.     }
  227.     D(bug(" Lead-Out M %d S %d F %d\n", info->lead_out[0], info->lead_out[1], info->lead_out[2]));
  228. }
  229.  
  230.  
  231. /*
  232.  *  Convert audio positioning type/position to MSF address
  233.  *  Return: false = error
  234.  */
  235.  
  236. static bool position2msf(DriveInfo *info, uint16 postype, uint32 pos, bool stopping, uint8 &m, uint8 &s, uint8 &f)
  237. {
  238.     switch (postype) {
  239.         case 0:
  240.             m = pos / (60 * 75);
  241.             s = (pos / 75) % 60;
  242.             f = pos % 75;
  243.             return true;
  244.         case 1:
  245.             m = bcd2bin[(pos >> 16) & 0xff];
  246.             s = bcd2bin[(pos >> 8) & 0xff];
  247.             f = bcd2bin[pos & 0xff];
  248.             return true;
  249.         case 2: {
  250.             uint8 track = bcd2bin[pos & 0xff];
  251.             if (stopping)
  252.                 track++;
  253.             for (int i=4; i<804; i+=8) {
  254.                 if (info->toc[i+2] == track || info->toc[i+2] == 0xaa) {
  255.                     m = info->toc[i+5];
  256.                     s = info->toc[i+6];
  257.                     f = info->toc[i+7];
  258.                     return true;
  259.                 }
  260.             }
  261.             return false;
  262.         }
  263.         default:
  264.             return false;
  265.     }
  266. }
  267.  
  268.  
  269. /*
  270.  *  Initialization
  271.  */
  272.  
  273. void CDROMInit(void)
  274. {
  275.     first_drive_info = NULL;
  276.  
  277.     // No drives specified in prefs? Then add defaults
  278.     if (PrefsFindString("cdrom", 0) == NULL)
  279.         SysAddCDROMPrefs();
  280.  
  281.     // Add drives specified in preferences
  282.     int32 index = 0;
  283.     const char *str;
  284.     while ((str = PrefsFindString("cdrom", index++)) != NULL) {
  285.         void *fh = Sys_open(str, true);
  286.         if (fh) {
  287.             DriveInfo *info = new DriveInfo;
  288.             info->fh = fh;
  289.             DriveInfo *p = (DriveInfo *)&first_drive_info;
  290.             while (p->next != NULL)
  291.                 p = p->next;
  292.             p->next = info;
  293.         }
  294.     }
  295. }
  296.  
  297.  
  298. /*
  299.  *  Deinitialization
  300.  */
  301.  
  302. void CDROMExit(void)
  303. {
  304.     DriveInfo *info = first_drive_info, *next;
  305.     while (info != NULL) {
  306.         SysAllowRemoval(info->fh);
  307.         Sys_close(info->fh);
  308.         next = info->next;
  309.         delete info;
  310.         info = next;
  311.     }
  312. }
  313.  
  314.  
  315. /*
  316.  *  Disk was inserted, flag for mounting
  317.  */
  318.  
  319. bool CDROMMountVolume(void *fh)
  320. {
  321.     DriveInfo *info;
  322.     for (info = first_drive_info; info != NULL && info->fh != fh; info = info->next) ;
  323.     if (info) {
  324.         if (SysIsDiskInserted(info->fh)) {
  325.             SysPreventRemoval(info->fh);
  326.             WriteMacInt8(info->status + dsDiskInPlace, 1);
  327.             read_toc(info);
  328.             find_hfs_partition(info);
  329.             if (info->start_byte != 0 || info->mount_non_hfs)
  330.                 info->to_be_mounted = true;
  331.         }
  332.         return true;
  333.     } else
  334.         return false;
  335. }
  336.  
  337.  
  338. /*
  339.  *  Mount volumes for which the to_be_mounted flag is set
  340.  *  (called during interrupt time)
  341.  */
  342.  
  343. static void mount_mountable_volumes(void)
  344. {
  345.     DriveInfo *info = first_drive_info;
  346.     while (info != NULL) {
  347.  
  348.         // Disk in drive?
  349.         if (ReadMacInt8(info->status + dsDiskInPlace) == 0) {
  350.  
  351.             // No, check if disk was inserted
  352.             if (SysIsDiskInserted(info->fh))
  353.                 CDROMMountVolume(info->fh);
  354.         }
  355.  
  356.         // Mount disk if flagged
  357.         if (info->to_be_mounted) {
  358.             D(bug(" mounting drive %d\n", info->num));
  359.             M68kRegisters r;
  360.             r.d[0] = info->num;
  361.             r.a[0] = 7;    // diskEvent
  362.             Execute68kTrap(0xa02f, &r);        // PostEvent()
  363.             info->to_be_mounted = false;
  364.         }
  365.  
  366.         info = info->next;
  367.     }
  368. }
  369.  
  370.  
  371. /*
  372.  *  Driver Open() routine
  373.  */
  374.  
  375. int16 CDROMOpen(uint32 pb, uint32 dce)
  376. {
  377.     D(bug("CDROMOpen\n"));
  378.  
  379.     // Set up DCE
  380.     WriteMacInt32(dce + dCtlPosition, 0);
  381.     acc_run_called = false;
  382.  
  383.     // Install drives
  384.     for (DriveInfo *info = first_drive_info; info; info = info->next) {
  385.  
  386.         info->num = FindFreeDriveNumber(1);
  387.         info->to_be_mounted = false;
  388.  
  389.         if (info->fh) {
  390.             info->mount_non_hfs = true;
  391.             info->block_size = 512;
  392.             info->twok_offset = -1;
  393.             info->play_mode = 0x09;
  394.             info->power_mode = 0;
  395.  
  396.             // Allocate drive status record
  397.             M68kRegisters r;
  398.             r.d[0] = SIZEOF_DrvSts;
  399.             Execute68kTrap(0xa71e, &r);        // NewPtrSysClear()
  400.             if (r.a[0] == 0)
  401.                 continue;
  402.             info->status = r.a[0];
  403.             D(bug(" DrvSts at %08lx\n", info->status));
  404.  
  405.             // Set up drive status
  406.             WriteMacInt8(info->status + dsWriteProt, 0x80);
  407.             WriteMacInt8(info->status + dsInstalled, 1);
  408.             WriteMacInt8(info->status + dsSides, 1);
  409.  
  410.             // Disk in drive?
  411.             if (SysIsDiskInserted(info->fh)) {
  412.                 SysPreventRemoval(info->fh);
  413.                 WriteMacInt8(info->status + dsDiskInPlace, 1);
  414.                 read_toc(info);
  415.                 find_hfs_partition(info);
  416.                 info->to_be_mounted = true;
  417.             }
  418.  
  419.             // Add drive to drive queue
  420.             D(bug(" adding drive %d\n", info->num));
  421.             r.d[0] = (info->num << 16) | (CDROMRefNum & 0xffff);
  422.             r.a[0] = info->status + dsQLink;
  423.             Execute68kTrap(0xa04e, &r);        // AddDrive()
  424.         }
  425.     }
  426.     return noErr;
  427. }
  428.  
  429.  
  430. /*
  431.  *  Driver Prime() routine
  432.  */
  433.  
  434. int16 CDROMPrime(uint32 pb, uint32 dce)
  435. {
  436.     WriteMacInt32(pb + ioActCount, 0);
  437.  
  438.     // Drive valid and disk inserted?
  439.     DriveInfo *info;
  440.     if ((info = get_drive_info(ReadMacInt16(pb + ioVRefNum))) == NULL)
  441.         return nsDrvErr;
  442.     if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
  443.         return offLinErr;
  444.  
  445.     // Get parameters
  446.     void *buffer = Mac2HostAddr(ReadMacInt32(pb + ioBuffer));
  447.     size_t length = ReadMacInt32(pb + ioReqCount);
  448.     loff_t position = ReadMacInt32(dce + dCtlPosition);
  449.     if ((length & (info->block_size - 1)) || (position & (info->block_size - 1)))
  450.         return paramErr;
  451.     info->twok_offset = (position + info->start_byte) & 0x7ff;
  452.  
  453.     size_t actual = 0;
  454.     if ((ReadMacInt16(pb + ioTrap) & 0xff) == aRdCmd) {
  455.  
  456.         // Read
  457.         actual = Sys_read(info->fh, buffer, position + info->start_byte, length);
  458.         if (actual != length) {
  459.  
  460.             // Read error, tried to read HFS root block?
  461.             if (length == 0x200 && position == 0x400) {
  462.  
  463.                 // Yes, fake (otherwise audio CDs won't get mounted)
  464.                 memset(buffer, 0, 0x200);
  465.                 actual = 0x200;
  466.             } else
  467.                 return readErr;
  468.         }
  469.     } else
  470.         return wPrErr;
  471.  
  472.     // Update ParamBlock and DCE
  473.     WriteMacInt32(pb + ioActCount, actual);
  474.     WriteMacInt32(dce + dCtlPosition, ReadMacInt32(dce + dCtlPosition) + actual);
  475.     return noErr;
  476. }
  477.  
  478.  
  479. /*
  480.  *  Driver Control() routine
  481.  */
  482.  
  483. int16 CDROMControl(uint32 pb, uint32 dce)
  484. {
  485.     uint16 code = ReadMacInt16(pb + csCode);
  486.     D(bug("CDROMControl %d\n", code));
  487.  
  488.     // General codes
  489.     switch (code) {
  490.         case 1:        // KillIO
  491.             return noErr;
  492.  
  493.         case 65: {    // Periodic action (accRun, "insert" disks on startup)
  494.             mount_mountable_volumes();
  495.             WriteMacInt16(dce + dCtlFlags, ReadMacInt16(dce + dCtlFlags) & ~0x2000);    // Disable periodic action
  496.             acc_run_called = true;
  497.             return noErr;
  498.         }
  499.  
  500.         case 81:        // Set poll freq
  501.             WriteMacInt16(dce + dCtlDelay, ReadMacInt16(pb + csParam));
  502.             return noErr;
  503.     }
  504.  
  505.     // Drive valid?
  506.     DriveInfo *info;
  507.     if ((info = get_drive_info(ReadMacInt16(pb + ioVRefNum))) == NULL)
  508.         if (first_drive_info == NULL)
  509.             return nsDrvErr;
  510.         else
  511.             info = first_drive_info;    // This is needed for Apple's Audio CD program
  512.  
  513.     // Drive-specific codes
  514.     switch (code) {
  515.         case 5:            // VerifyTheDisc
  516.             if (ReadMacInt8(info->status + dsDiskInPlace) > 0)
  517.                 return noErr;
  518.             else
  519.                 return offLinErr;
  520.  
  521.         case 6:            // FormatTheDisc
  522.             return writErr;
  523.  
  524.         case 7:            // EjectTheDisc
  525.             if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
  526.                 SysAllowRemoval(info->fh);
  527.                 SysEject(info->fh);
  528.                 WriteMacInt8(info->status + dsDiskInPlace, 0);
  529.                 info->twok_offset = -1;
  530.             }
  531.             return noErr;
  532.  
  533.         case 21:        // GetDriveIcon
  534.         case 22:        // GetMediaIcon
  535.             WriteMacInt32(pb + csParam, CDROMIconAddr);
  536.             return noErr;
  537.  
  538.         case 23:        // DriveInfo
  539.             WriteMacInt32(pb + csParam, 0x00000b01);    // Unspecified external removable SCSI disk
  540.             return noErr;
  541.  
  542.         case 70: {        // SetPowerMode
  543.             uint8 mode = ReadMacInt8(pb + csParam);
  544.             if (mode > 3)
  545.                 return paramErr;
  546.             else {
  547.                 info->power_mode = mode;
  548.                 return noErr;
  549.             }
  550.         }
  551.  
  552.         case 76:        // ModifyPostEvent
  553.             info->mount_non_hfs = ReadMacInt16(pb + csParam);
  554.             return noErr;
  555.  
  556.         case 79: {        // Change block size
  557.             uint16 size = ReadMacInt16(pb + csParam);
  558.             D(bug(" change block size to %d bytes\n", size));
  559.             if (size != 512 && size != 2048)
  560.                 return paramErr;
  561.             else {
  562.                 info->block_size = size;
  563.                 return noErr;
  564.             }
  565.         }
  566.  
  567.         case 80:        // SetUserEject
  568.             if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
  569.                 if (ReadMacInt16(pb + csParam) == 1)
  570.                     SysAllowRemoval(info->fh);
  571.                 else
  572.                     SysPreventRemoval(info->fh);
  573.                 return noErr;
  574.             } else
  575.                 return offLinErr;
  576.  
  577.         case 100: {        // ReadTOC
  578.             if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
  579.                 return offLinErr;
  580.  
  581.             int action = ReadMacInt16(pb + csParam);
  582.             D(bug(" read TOC %d\n", action));
  583.             switch (action) {
  584.                 case 1:        // Get first/last track number
  585.                     WriteMacInt8(pb + csParam, bin2bcd[info->toc[2]]);
  586.                     WriteMacInt8(pb + csParam + 1, bin2bcd[info->toc[3]]);
  587.                     WriteMacInt16(pb + csParam + 2, 0);
  588.                     break;
  589.  
  590.                 case 2:        // Get lead out MSF starting address
  591.                     WriteMacInt8(pb + csParam, bin2bcd[info->lead_out[0]]);
  592.                     WriteMacInt8(pb + csParam + 1, bin2bcd[info->lead_out[1]]);
  593.                     WriteMacInt8(pb + csParam + 2, bin2bcd[info->lead_out[2]]);
  594.                     WriteMacInt8(pb + csParam + 3, 0);
  595.                     break;
  596.  
  597.                 case 3: {        // Get track starting address
  598.                     uint32 buf = ReadMacInt32(pb + csParam + 2);
  599.                     uint16 buf_size = ReadMacInt16(pb + csParam + 6);
  600.                     int track = bcd2bin[ReadMacInt8(pb + csParam + 8)];
  601.  
  602.                     // Search start track in TOC
  603.                     int i;
  604.                     for (i=4; i<804; i+=8) {
  605.                         if (info->toc[i+2] == track)
  606.                             break;
  607.                     }
  608.  
  609.                     // Fill buffer
  610.                     if (i != 804)
  611.                         while (buf_size > 0) {
  612.                             WriteMacInt8(buf, info->toc[i+1] & 0x0f); buf++;    // Control
  613.                             WriteMacInt8(buf, bin2bcd[info->toc[i+5]]); buf++;    // M
  614.                             WriteMacInt8(buf, bin2bcd[info->toc[i+6]]); buf++;    // S
  615.                             WriteMacInt8(buf, bin2bcd[info->toc[i+7]]); buf++;    // F
  616.  
  617.                             // Lead-Out? Then stop
  618.                             if (info->toc[i+2] == 0xaa)
  619.                                 break;
  620.  
  621.                             buf_size -= 4;
  622.                             i += 8;
  623.                         }
  624.                     break;
  625.                 }
  626.  
  627.                 case 5:        // Get session information
  628.                     WriteMacInt16(pb + csParam, 1);                            // First session number
  629.                     WriteMacInt16(pb + csParam + 2, 1);                        // Last session number
  630.                     WriteMacInt16(pb + csParam + 4, bin2bcd[info->toc[2]]);    // First track number of last session
  631.                     WriteMacInt8(pb + csParam + 6, info->toc[5] & 0x0f);    // Control
  632.                     WriteMacInt8(pb + csParam + 7, bin2bcd[info->toc[9]]);    // M
  633.                     WriteMacInt8(pb + csParam + 8, bin2bcd[info->toc[10]]);    // S
  634.                     WriteMacInt8(pb + csParam + 9, bin2bcd[info->toc[11]]);    // F
  635.                     break;
  636.  
  637.                 default:
  638.                     printf("FATAL: .AppleCD/Control(100): unimplemented TOC type\n");
  639.                     return paramErr;
  640.             }
  641.             return noErr;
  642.         }
  643.  
  644.         case 101: {        // ReadTheQSubcode
  645.             if (ReadMacInt8(info->status + dsDiskInPlace) == 0) {
  646.                 Mac_memset(pb + csParam, 0, 10);
  647.                 return offLinErr;
  648.             }
  649.  
  650.             uint8 pos[16];
  651.             if (SysCDGetPosition(info->fh, pos)) {
  652.                 uint32 p = pb + csParam;
  653.                 WriteMacInt8(p, pos[5] & 0x0f); p++;    // Control
  654.                 WriteMacInt8(p, bin2bcd[pos[6]]); p++;    // Track number
  655.                 WriteMacInt8(p, bin2bcd[pos[7]]); p++;    // Index number
  656.                 WriteMacInt8(p, bin2bcd[pos[13]]); p++;    // M (rel)
  657.                 WriteMacInt8(p, bin2bcd[pos[14]]); p++;    // S (rel)
  658.                 WriteMacInt8(p, bin2bcd[pos[15]]); p++;    // F (rel)
  659.                 WriteMacInt8(p, bin2bcd[pos[9]]); p++;    // M (abs)
  660.                 WriteMacInt8(p, bin2bcd[pos[10]]); p++;    // S (abs)
  661.                 WriteMacInt8(p, bin2bcd[pos[11]]); p++;    // F (abs)
  662.                 WriteMacInt8(p, 0);
  663.                 return noErr;
  664.             } else
  665.                 return ioErr;
  666.         }
  667.  
  668.         case 102:        // ReadHeader
  669.             printf("FATAL: .AppleCD/Control(102): unimplemented call\n");
  670.             return controlErr;
  671.  
  672.         case 103: {        // AudioTrackSearch
  673.             D(bug(" AudioTrackSearch postype %d, pos %08x, hold %d\n", ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), ReadMacInt16(pb + csParam + 6)));
  674.             if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
  675.                 return offLinErr;
  676.  
  677.             uint8 start_m, start_s, start_f;
  678.             if (!position2msf(info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), false, start_m, start_s, start_f))
  679.                 return paramErr;
  680.             info->play_mode = ReadMacInt8(pb + csParam + 9) & 0x0f;
  681.             if (!SysCDPlay(info->fh, start_m, start_s, start_f, info->stop_at[0], info->stop_at[1], info->stop_at[2]))
  682.                 return paramErr;
  683.             if (ReadMacInt16(pb + csParam + 6) == 0)    // Hold
  684.                 SysCDPause(info->fh);
  685.             return noErr;
  686.         }
  687.  
  688.         case 104:        // AudioPlay
  689.             D(bug(" AudioPlay postype %d, pos %08lx, hold %d\n", ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), ReadMacInt16(pb + csParam + 6)));
  690.             if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
  691.                 return offLinErr;
  692.  
  693.             if (ReadMacInt16(pb + csParam + 6)) {
  694.                 // Given stopping address
  695.                 if (!position2msf(info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), true, info->stop_at[0], info->stop_at[1], info->stop_at[2]))
  696.                     return paramErr;
  697.             } else {
  698.                 // Given starting address
  699.                 uint8 start_m, start_s, start_f;
  700.                 if (!position2msf(info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), false, start_m, start_s, start_f))
  701.                     return paramErr;
  702.                 info->play_mode = ReadMacInt8(pb + csParam + 9) & 0x0f;
  703.                 if (!SysCDPlay(info->fh, start_m, start_s, start_f, info->stop_at[0], info->stop_at[1], info->stop_at[2]))
  704.                     return paramErr;
  705.             }
  706.             return noErr;
  707.  
  708.         case 105:        // AudioPause
  709.             if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
  710.                 return offLinErr;
  711.  
  712.             switch (ReadMacInt32(pb + csParam)) {
  713.                 case 0:
  714.                     if (!SysCDResume(info->fh))
  715.                         return paramErr;
  716.                     break;
  717.                 case 1:
  718.                     if (!SysCDPause(info->fh))
  719.                         return paramErr;
  720.                     break;
  721.                 default:
  722.                     return paramErr;
  723.             }
  724.             return noErr;
  725.  
  726.         case 106:        // AudioStop
  727.             D(bug(" AudioStop postype %d, pos %08lx\n", ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2)));
  728.             if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
  729.                 return offLinErr;
  730.  
  731.             if (ReadMacInt16(pb + csParam) == 0 && ReadMacInt32(pb + csParam + 2) == 0) {
  732.                 // Stop immediately
  733.                 if (!SysCDStop(info->fh, info->lead_out[0], info->lead_out[1], info->lead_out[2]))
  734.                     return paramErr;
  735.             } else {
  736.                 // Given stopping address
  737.                 if (!position2msf(info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), true, info->stop_at[0], info->stop_at[1], info->stop_at[2]))
  738.                     return paramErr;
  739.             }
  740.             return noErr;
  741.  
  742.         case 107: {        // AudioStatus
  743.             if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
  744.                 return offLinErr;
  745.  
  746.             uint8 pos[16];
  747.             if (!SysCDGetPosition(info->fh, pos))
  748.                 return paramErr;
  749.  
  750.             uint32 p = pb + csParam;
  751.             switch (pos[1]) {
  752.                 case 0x11:
  753.                     WriteMacInt8(p, 0);    // Audio play in progress
  754.                     break;
  755.                 case 0x12:
  756.                     WriteMacInt8(p, 1);    // Audio play paused
  757.                     break;
  758.                 case 0x13:
  759.                     WriteMacInt8(p, 3);    // Audio play completed
  760.                     break;
  761.                 case 0x14:
  762.                     WriteMacInt8(p, 4);    // Error occurred
  763.                     break;
  764.                 default:
  765.                     WriteMacInt8(p, 5);    // No audio play operation requested
  766.                     break;
  767.             }
  768.             p++;
  769.             WriteMacInt8(p, info->play_mode); p++;
  770.             WriteMacInt8(p, pos[5] & 0x0f); p++;    // Control
  771.             WriteMacInt8(p, bin2bcd[pos[9]]); p++;    // M (abs)
  772.             WriteMacInt8(p, bin2bcd[pos[10]]); p++;    // S (abs)
  773.             WriteMacInt8(p, bin2bcd[pos[11]]); p++;    // F (abs)
  774.             return noErr;
  775.         }
  776.  
  777.         case 108: {        // AudioScan
  778.             if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
  779.                 return offLinErr;
  780.  
  781.             uint8 start_m, start_s, start_f;
  782.             if (!position2msf(info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), false, start_m, start_s, start_f))
  783.                 return paramErr;
  784.  
  785.             if (!SysCDScan(info->fh, start_m, start_s, start_f, ReadMacInt16(pb + csParam + 6)))
  786.                 return paramErr;
  787.             else
  788.                 return noErr;
  789.         }
  790.  
  791.         case 109:        // AudioControl
  792.             SysCDSetVolume(info->fh, ReadMacInt8(pb + csParam), ReadMacInt8(pb + csParam + 1));
  793.             return noErr;
  794.  
  795.         case 110:        // ReadMCN
  796.             printf("FATAL: .AppleCD/Control(110): unimplemented call\n");
  797.             return controlErr;
  798.  
  799.         case 111:        // ReadISRC
  800.             printf("FATAL: .AppleCD/Control(111): unimplemented call\n");
  801.             return controlErr;
  802.  
  803.         case 112: {        // ReadAudioVolume
  804.             uint8 left, right;
  805.             SysCDGetVolume(info->fh, left, right);
  806.             WriteMacInt8(pb + csParam, left);
  807.             WriteMacInt8(pb + csParam + 1, right);
  808.             return noErr;
  809.         }
  810.  
  811.         case 113:        // GetSpindleSpeed
  812.             WriteMacInt16(pb + csParam, 0xff);
  813.             return noErr;
  814.  
  815.         case 114:        // SetSpindleSpeed
  816.             return noErr;
  817.  
  818.         case 115:        // ReadAudio
  819.             printf("FATAL: .AppleCD/Control(115): unimplemented call\n");
  820.             return controlErr;
  821.  
  822.         case 116:        // ReadAllSubcodes
  823.             printf("FATAL: .AppleCD/Control(116): unimplemented call\n");
  824.             return controlErr;
  825.  
  826.         case 122:        // SetTrackList
  827.             printf("FATAL: .AppleCD/Control(122): unimplemented call\n");
  828.             return controlErr;
  829.  
  830.         case 123:        // GetTrackList
  831.             printf("FATAL: .AppleCD/Control(123): unimplemented call\n");
  832.             return controlErr;
  833.  
  834.         case 124:        // GetTrackIndex
  835.             printf("FATAL: .AppleCD/Control(124): unimplemented call\n");
  836.             return controlErr;
  837.  
  838.         case 125:        // SetPlayMode
  839.             D(bug(" SetPlayMode %04x\n", ReadMacInt16(pb + csParam)));
  840.             printf("FATAL: .AppleCD/Control(125): unimplemented call\n");
  841.             return controlErr;
  842.  
  843.         case 126:        // GetPlayMode (Apple's Audio CD program needs this)
  844.             WriteMacInt16(pb + csParam, 0);
  845.             return noErr;
  846.  
  847.         default:
  848.             printf("WARNING: Unknown CDROMControl(%d)\n", code);
  849.             return controlErr;
  850.     }
  851. }
  852.  
  853.  
  854. /*
  855.  *  Driver Status() routine
  856.  */
  857.  
  858. int16 CDROMStatus(uint32 pb, uint32 dce)
  859. {
  860.     DriveInfo *info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
  861.     uint16 code = ReadMacInt16(pb + csCode);
  862.     D(bug("CDROMStatus %d\n", code));
  863.  
  864.     // General codes
  865.     switch (code) {
  866.         case 43: {    // DriverGestalt
  867.             uint32 sel = ReadMacInt32(pb + csParam);
  868.             D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16,  sel >> 8, sel));
  869.             switch (sel) {
  870.                 case FOURCC('v','e','r','s'):    // Version
  871.                     WriteMacInt32(pb + csParam + 4, 0x05208000);
  872.                     break;
  873.                 case FOURCC('d','e','v','t'):    // Device type
  874.                     WriteMacInt32(pb + csParam + 4, FOURCC('c','d','r','m'));
  875.                     break;
  876.                 case FOURCC('i','n','t','f'):    // Interface type
  877.                     WriteMacInt32(pb + csParam + 4, EMULATOR_ID_4);
  878.                     break;
  879.                 case FOURCC('s','y','n','c'):    // Only synchronous operation?
  880.                     WriteMacInt32(pb + csParam + 4, 0x01000000);
  881.                     break;
  882.                 case FOURCC('b','o','o','t'):    // Boot ID
  883.                     if (info != NULL)
  884.                         WriteMacInt16(pb + csParam + 4, info->num);
  885.                     else
  886.                         WriteMacInt16(pb + csParam + 4, 0);
  887.                     WriteMacInt16(pb + csParam + 6, (uint16)CDROMRefNum);
  888.                     break;
  889.                 case FOURCC('w','i','d','e'):    // 64-bit access supported?
  890.                     WriteMacInt16(pb + csParam + 4, 0);
  891.                     break;
  892.                 case FOURCC('p','u','r','g'):    // Purge flags
  893.                     WriteMacInt32(pb + csParam + 4, 0);
  894.                     break;
  895.                 case FOURCC('e','j','e','c'):    // Eject flags
  896.                     WriteMacInt32(pb + csParam + 4, 0x00030003);    // Don't eject on shutdown/restart
  897.                     break;
  898.                 case FOURCC('f','l','u','s'):    // Flush flags
  899.                     WriteMacInt16(pb + csParam + 4, 0);
  900.                     break;
  901.                 case FOURCC('v','m','o','p'):    // Virtual memory attributes
  902.                     WriteMacInt32(pb + csParam + 4, 0);    // Drive not available for VM
  903.                     break;
  904.                 default:
  905.                     return statusErr;
  906.             }
  907.             return noErr;
  908.         }
  909.     }
  910.  
  911.     // Drive valid?
  912.     if (info == NULL)
  913.         if (first_drive_info == NULL)
  914.             return nsDrvErr;
  915.         else
  916.             info = first_drive_info;    // This is needed for Apple's Audio CD program
  917.  
  918.     // Drive-specific codes
  919.     switch (code) {
  920.         case 6:            // Return format list
  921.             if (ReadMacInt16(pb + csParam) > 0) {
  922.                 uint32 adr = ReadMacInt32(pb + csParam + 2);
  923.                 WriteMacInt16(pb + csParam, 1);                        // 1 format
  924.                 WriteMacInt32(adr, SysGetFileSize(info->fh) / 512);    // Number of blocks
  925.                 WriteMacInt32(adr + 4, 0);                            // heads/track/sectors
  926.                 return noErr;
  927.             } else
  928.                 return paramErr;
  929.  
  930.         case 8:            // DriveStatus
  931.             Mac2Mac_memcpy(pb + csParam, info->status, 22);
  932.             return noErr;
  933.  
  934.         case 70:        // GetPowerMode
  935.             WriteMacInt16(pb + csParam, info->power_mode << 8);
  936.             return noErr;
  937.  
  938.         case 95:        // Get2KOffset
  939.             if (info->twok_offset > 0) {
  940.                 WriteMacInt16(pb + csParam, info->twok_offset);
  941.                 return noErr;
  942.             } else
  943.                 return statusErr;
  944.  
  945.         case 96:        // Get drive type
  946.             WriteMacInt16(pb + csParam, 3);            // Apple CD 300 or newer
  947.             return noErr;
  948.  
  949.         case 98:        // Get block size
  950.             WriteMacInt16(pb + csParam, info->block_size);
  951.             return noErr;
  952.  
  953.         case 120:        // Return device ident
  954.             WriteMacInt32(pb + csParam, 0);
  955.             return noErr;
  956.  
  957.         case 121:        // Get CD features
  958.             WriteMacInt16(pb + csParam, 0x0200);    // 300 KB/s
  959.             WriteMacInt16(pb + csParam, 0x0300);    // SCSI-2, stereo
  960.             return noErr;
  961.  
  962.         default:
  963.             printf("WARNING: Unknown CDROMStatus(%d)\n", code);
  964.             return statusErr;
  965.     }
  966. }
  967.  
  968.  
  969. /*
  970.  *  Driver interrupt routine (1Hz) - check for volumes to be mounted
  971.  */
  972.  
  973. void CDROMInterrupt(void)
  974. {
  975.     if (!acc_run_called)
  976.         return;
  977.  
  978.     mount_mountable_volumes();
  979. }
  980.