home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 6 / AACD06.ISO / AACD / Emulation / BasiliskII / src / cdrom.cpp < prev    next >
C/C++ Source or Header  |  1999-11-03  |  29KB  |  982 lines

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