ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.1.1.1 (vendor branch)
Committed: 1999-10-03T14:16:25Z (24 years, 7 months ago) by cebix
Branch: cebix
CVS Tags: release-0_7-2, start
Changes since 1.1: +0 -0 lines
Log Message:
Imported sources

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