ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.9
Committed: 2000-07-25T15:19:39Z (23 years, 9 months ago) by cebix
Branch: MAIN
Changes since 1.8: +1 -1 lines
Log Message:
- more cleanups
- splitted prefs.cpp into prefs.cpp and prefs_items.cpp to make prefs.cpp
  reusable for other projects

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