ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.17
Committed: 2002-02-07T16:10:54Z (22 years, 3 months ago) by cebix
Branch: MAIN
Changes since 1.16: +3 -2 lines
Log Message:
cleaned up pthread attributes [Brian Johnson]

File Contents

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