ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.13
Committed: 2001-07-02T11:59:31Z (22 years, 10 months ago) by gbeauche
Branch: MAIN
Changes since 1.12: +5 -5 lines
Log Message:
- there is no implicit conversion from vector<T>::iterator to T&

File Contents

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