ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.5
Committed: 2000-04-10T18:52:19Z (24 years, 7 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-13072000
Changes since 1.4: +1 -1 lines
Log Message:
- updated copyright info: 1999->2000

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