ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.10
Committed: 2000-10-11T17:40:07Z (24 years ago) by cebix
Branch: MAIN
Changes since 1.9: +10 -0 lines
Log Message:
cdrom.cpp: implemented Status(6)

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