ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.2
Committed: 1999-10-12T20:00:42Z (24 years, 7 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-21101999
Changes since 1.1: +62 -24 lines
Log Message:
- disk insertions are now checked for by the 60Hz interrupt routine
- localizable strings are split into a common and a platform-specific set
- fixed bug in CR->LF translation in AmigaOS/clip_amiga.cpp

File Contents

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