ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.23
Committed: 2008-06-28T18:36:18Z (16 years, 5 months ago) by asvitkine
Branch: MAIN
CVS Tags: HEAD
Changes since 1.22: +12 -1 lines
Log Message:
[patch from Kelvin Delbarre]
The CDROM status call "WhoIsThere" (csCode 97) is now implemented. Apart from
eliminating "WARNING: Unknown CDROMStatus(97)" complaints from the console log,
this does not appear to have had any effects whatsoever.

A typo in the implementation of the CDROM status call "GetCDFeatures" has been
corrected per Technical Note DV22:
	http://developer.apple.com/technotes/dv/dv_22.html

File Contents

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