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

File Contents

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