ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.20
Committed: 2004-01-12T15:29:21Z (20 years, 10 months ago) by cebix
Branch: MAIN
CVS Tags: nigel-build-16, nigel-build-15
Changes since 1.19: +1 -1 lines
Log Message:
Happy New Year! :)

File Contents

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