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

File Contents

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