ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.17
Committed: 2002-02-07T16:10:54Z (22 years, 3 months ago) by cebix
Branch: MAIN
Changes since 1.16: +3 -2 lines
Log Message:
cleaned up pthread attributes [Brian Johnson]

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