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

File Contents

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