ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.16
Committed: 2002-01-15T14:58:32Z (22 years, 3 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-15012002
Changes since 1.15: +1 -1 lines
Log Message:
- documentation updates
- 2001 -> 2002
- version 0.9 -> 1.0

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