ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.3
Committed: 1999-10-23T17:57:42Z (25 years, 1 month ago) by cebix
Branch: MAIN
CVS Tags: snapshot-02111999
Changes since 1.2: +1 -0 lines
Log Message:
- audio_linux.cpp renamed to audio_oss_esd.cpp (now also used under FreeBSD)
  and added support for ESD
- medium removal is allowed for CD-ROM on exit
- added mkinstalldirs to "make install" target

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 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 uint8 *buf = Mac2HostAddr(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 *buf++ = info->toc[i+1] & 0x0f; // Control
620 *buf++ = bin2bcd[info->toc[i+5]]; // M
621 *buf++ = bin2bcd[info->toc[i+6]]; // S
622 *buf++ = bin2bcd[info->toc[i+7]]; // 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 memset(Mac2HostAddr(pb + csParam), 0, 10);
654 return offLinErr;
655 }
656
657 uint8 pos[16];
658 if (SysCDGetPosition(info->fh, pos)) {
659 uint8 *p = Mac2HostAddr(pb + csParam);
660 *p++ = pos[5] & 0x0f; // Control
661 *p++ = bin2bcd[pos[6]]; // Track number
662 *p++ = bin2bcd[pos[7]]; // Index number
663 *p++ = bin2bcd[pos[13]]; // M (rel)
664 *p++ = bin2bcd[pos[14]]; // S (rel)
665 *p++ = bin2bcd[pos[15]]; // F (rel)
666 *p++ = bin2bcd[pos[9]]; // M (abs)
667 *p++ = bin2bcd[pos[10]]; // S (abs)
668 *p++ = bin2bcd[pos[11]]; // F (abs)
669 *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 uint8 *p = Mac2HostAddr(pb + csParam);
758 switch (pos[1]) {
759 case 0x11:
760 *p++ = 0; // Audio play in progress
761 break;
762 case 0x12:
763 *p++ = 1; // Audio play paused
764 break;
765 case 0x13:
766 *p++ = 3; // Audio play completed
767 break;
768 case 0x14:
769 *p++ = 4; // Error occurred
770 break;
771 default:
772 *p++ = 5; // No audio play operation requested
773 break;
774 }
775 *p++ = info->play_mode;
776 *p++ = pos[5] & 0x0f; // Control
777 *p++ = bin2bcd[pos[9]]; // M (abs)
778 *p++ = bin2bcd[pos[10]]; // S (abs)
779 *p++ = bin2bcd[pos[11]]; // F (abs)
780 return noErr;
781 }
782
783 case 108: { // AudioScan
784 if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
785 return offLinErr;
786
787 uint8 start_m, start_s, start_f;
788 if (!position2msf(info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), false, start_m, start_s, start_f))
789 return paramErr;
790
791 if (!SysCDScan(info->fh, start_m, start_s, start_f, ReadMacInt16(pb + csParam + 6)))
792 return paramErr;
793 else
794 return noErr;
795 }
796
797 case 109: // AudioControl
798 SysCDSetVolume(info->fh, ReadMacInt8(pb + csParam), ReadMacInt8(pb + csParam + 1));
799 return noErr;
800
801 case 110: // ReadMCN
802 printf("FATAL: .AppleCD/Control(110): unimplemented call\n");
803 return controlErr;
804
805 case 111: // ReadISRC
806 printf("FATAL: .AppleCD/Control(111): unimplemented call\n");
807 return controlErr;
808
809 case 112: { // ReadAudioVolume
810 uint8 left, right;
811 SysCDGetVolume(info->fh, left, right);
812 WriteMacInt8(pb + csParam, left);
813 WriteMacInt8(pb + csParam + 1, right);
814 return noErr;
815 }
816
817 case 113: // GetSpindleSpeed
818 WriteMacInt16(pb + csParam, 0xff);
819 return noErr;
820
821 case 114: // SetSpindleSpeed
822 return noErr;
823
824 case 115: // ReadAudio
825 printf("FATAL: .AppleCD/Control(115): unimplemented call\n");
826 return controlErr;
827
828 case 116: // ReadAllSubcodes
829 printf("FATAL: .AppleCD/Control(116): unimplemented call\n");
830 return controlErr;
831
832 case 122: // SetTrackList
833 printf("FATAL: .AppleCD/Control(122): unimplemented call\n");
834 return controlErr;
835
836 case 123: // GetTrackList
837 printf("FATAL: .AppleCD/Control(123): unimplemented call\n");
838 return controlErr;
839
840 case 124: // GetTrackIndex
841 printf("FATAL: .AppleCD/Control(124): unimplemented call\n");
842 return controlErr;
843
844 case 125: // SetPlayMode
845 D(bug(" SetPlayMode %04x\n", ReadMacInt16(pb + csParam)));
846 printf("FATAL: .AppleCD/Control(125): unimplemented call\n");
847 return controlErr;
848
849 case 126: // GetPlayMode (Apple's Audio CD program needs this)
850 WriteMacInt16(pb + csParam, 0);
851 return noErr;
852
853 default:
854 printf("WARNING: Unknown CDROMControl(%d)\n", code);
855 return controlErr;
856 }
857 }
858
859
860 /*
861 * Driver Status() routine
862 */
863
864 int16 CDROMStatus(uint32 pb, uint32 dce)
865 {
866 DriveInfo *info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
867 uint16 code = ReadMacInt16(pb + csCode);
868 D(bug("CDROMStatus %d\n", code));
869
870 // General codes
871 switch (code) {
872 case 43: { // DriverGestalt
873 uint32 sel = ReadMacInt32(pb + csParam);
874 D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16, sel >> 8, sel));
875 switch (sel) {
876 case 'vers': // Version
877 WriteMacInt32(pb + csParam + 4, 0x05208000);
878 break;
879 case 'devt': // Device type
880 WriteMacInt32(pb + csParam + 4, 'cdrm');
881 break;
882 case 'intf': // Interface type
883 WriteMacInt32(pb + csParam + 4, 'basi');
884 break;
885 case 'sync': // Only synchronous operation?
886 WriteMacInt32(pb + csParam + 4, 0x01000000);
887 break;
888 case 'boot': // Boot ID
889 if (info != NULL)
890 WriteMacInt16(pb + csParam + 4, info->num);
891 else
892 WriteMacInt16(pb + csParam + 4, 0);
893 WriteMacInt16(pb + csParam + 6, (uint16)CDROMRefNum);
894 break;
895 case 'wide': // 64-bit access supported?
896 WriteMacInt16(pb + csParam + 4, 0);
897 break;
898 case 'purg': // Purge flags
899 WriteMacInt32(pb + csParam + 4, 0);
900 break;
901 case 'ejec': // Eject flags
902 WriteMacInt32(pb + csParam + 4, 0x00030003); // Don't eject on shutdown/restart
903 break;
904 case 'flus': // Flush flags
905 WriteMacInt16(pb + csParam + 4, 0);
906 break;
907 case 'vmop': // Virtual memory attributes
908 WriteMacInt32(pb + csParam + 4, 0); // Drive not available for VM
909 break;
910 default:
911 return statusErr;
912 }
913 return noErr;
914 }
915 }
916
917 // Drive valid?
918 if (info == NULL)
919 if (first_drive_info == NULL)
920 return nsDrvErr;
921 else
922 info = first_drive_info; // This is needed for Apple's Audio CD program
923
924 // Drive-specific codes
925 switch (code) {
926 case 8: // DriveStatus
927 memcpy(Mac2HostAddr(pb + csParam), Mac2HostAddr(info->status), 22);
928 return noErr;
929
930 case 70: // GetPowerMode
931 WriteMacInt16(pb + csParam, info->power_mode << 8);
932 return noErr;
933
934 case 95: // Get2KOffset
935 if (info->twok_offset > 0) {
936 WriteMacInt16(pb + csParam, info->twok_offset);
937 return noErr;
938 } else
939 return statusErr;
940
941 case 96: // Get drive type
942 WriteMacInt16(pb + csParam, 3); // Apple CD 300 or newer
943 return noErr;
944
945 case 98: // Get block size
946 WriteMacInt16(pb + csParam, info->block_size);
947 return noErr;
948
949 case 120: // Return device ident
950 WriteMacInt32(pb + csParam, 0);
951 return noErr;
952
953 case 121: // Get CD features
954 WriteMacInt16(pb + csParam, 0x0200); // 300 KB/s
955 WriteMacInt16(pb + csParam, 0x0300); // SCSI-2, stereo
956 return noErr;
957
958 default:
959 printf("WARNING: Unknown CDROMStatus(%d)\n", code);
960 return statusErr;
961 }
962 }
963
964
965 /*
966 * Driver interrupt routine - check for volumes to be mounted
967 */
968
969 void CDROMInterrupt(void)
970 {
971 static int tick_count = 0;
972 if (!acc_run_called)
973 return;
974
975 tick_count++;
976 if (tick_count > driver_delay) {
977 tick_count = 0;
978 mount_mountable_volumes();
979 }
980 }