ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.1
Committed: 1999-10-03T14:16:25Z (24 years, 7 months ago) by cebix
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# User Rev Content
1 cebix 1.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     }