ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.18
Committed: 2002-04-28T14:06:17Z (22 years, 7 months ago) by cebix
Branch: MAIN
Changes since 1.17: +2 -0 lines
Log Message:
default CD-ROM drive is /dev/cd0c on NetBSD

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