ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.7
Committed: 2000-07-22T16:07:15Z (23 years, 9 months ago) by cebix
Branch: MAIN
Changes since 1.6: +16 -16 lines
Log Message:
- new FOURCC() macro in macos_util.h

File Contents

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