ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.5
Committed: 2000-04-10T18:52:19Z (24 years, 7 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-13072000
Changes since 1.4: +1 -1 lines
Log Message:
- updated copyright info: 1999->2000

File Contents

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