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

File Contents

# 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 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     uint8 *buf = Mac2HostAddr(ReadMacInt32(pb + csParam + 2));
606     uint16 buf_size = ReadMacInt16(pb + csParam + 6);
607     int track = bcd2bin[ReadMacInt8(pb + csParam + 8)];
608    
609     // Search start track in TOC
610     int i;
611     for (i=4; i<804; i+=8) {
612     if (info->toc[i+2] == track)
613     break;
614     }
615    
616     // Fill buffer
617     if (i != 804)
618     while (buf_size > 0) {
619     *buf++ = info->toc[i+1] & 0x0f; // Control
620     *buf++ = bin2bcd[info->toc[i+5]]; // M
621     *buf++ = bin2bcd[info->toc[i+6]]; // S
622     *buf++ = bin2bcd[info->toc[i+7]]; // F
623    
624     // Lead-Out? Then stop
625     if (info->toc[i+2] == 0xaa)
626     break;
627    
628     buf_size -= 4;
629     i += 8;
630     }
631     break;
632     }
633    
634     case 5: // Get session information
635     WriteMacInt16(pb + csParam, 1); // First session number
636     WriteMacInt16(pb + csParam + 2, 1); // Last session number
637     WriteMacInt16(pb + csParam + 4, bin2bcd[info->toc[2]]); // First track number of last session
638     WriteMacInt8(pb + csParam + 6, info->toc[5] & 0x0f); // Control
639     WriteMacInt8(pb + csParam + 7, bin2bcd[info->toc[9]]); // M
640     WriteMacInt8(pb + csParam + 8, bin2bcd[info->toc[10]]); // S
641     WriteMacInt8(pb + csParam + 9, bin2bcd[info->toc[11]]); // F
642     break;
643    
644     default:
645     printf("FATAL: .AppleCD/Control(100): unimplemented TOC type\n");
646     return paramErr;
647     }
648     return noErr;
649     }
650    
651     case 101: { // ReadTheQSubcode
652     if (ReadMacInt8(info->status + dsDiskInPlace) == 0) {
653     memset(Mac2HostAddr(pb + csParam), 0, 10);
654     return offLinErr;
655     }
656    
657     uint8 pos[16];
658     if (SysCDGetPosition(info->fh, pos)) {
659     uint8 *p = Mac2HostAddr(pb + csParam);
660     *p++ = pos[5] & 0x0f; // Control
661     *p++ = bin2bcd[pos[6]]; // Track number
662     *p++ = bin2bcd[pos[7]]; // Index number
663     *p++ = bin2bcd[pos[13]]; // M (rel)
664     *p++ = bin2bcd[pos[14]]; // S (rel)
665     *p++ = bin2bcd[pos[15]]; // F (rel)
666     *p++ = bin2bcd[pos[9]]; // M (abs)
667     *p++ = bin2bcd[pos[10]]; // S (abs)
668     *p++ = bin2bcd[pos[11]]; // F (abs)
669     *p++ = 0;
670     return noErr;
671     } else
672     return ioErr;
673     }
674    
675     case 102: // ReadHeader
676     printf("FATAL: .AppleCD/Control(102): unimplemented call\n");
677     return controlErr;
678    
679     case 103: { // AudioTrackSearch
680     D(bug(" AudioTrackSearch postype %d, pos %08lx, hold %d\n", ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), ReadMacInt16(pb + csParam + 6)));
681     if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
682     return offLinErr;
683    
684     uint8 start_m, start_s, start_f;
685     if (!position2msf(info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), false, start_m, start_s, start_f))
686     return paramErr;
687     info->play_mode = ReadMacInt8(pb + csParam + 9) & 0x0f;
688     if (!SysCDPlay(info->fh, start_m, start_s, start_f, info->stop_at[0], info->stop_at[1], info->stop_at[2]))
689     return paramErr;
690     if (ReadMacInt16(pb + csParam + 6) == 0) // Hold
691     SysCDPause(info->fh);
692     return noErr;
693     }
694    
695     case 104: // AudioPlay
696     D(bug(" AudioPlay postype %d, pos %08lx, hold %d\n", ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), ReadMacInt16(pb + csParam + 6)));
697     if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
698     return offLinErr;
699    
700     if (ReadMacInt16(pb + csParam + 6)) {
701     // Given stopping address
702     if (!position2msf(info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), true, info->stop_at[0], info->stop_at[1], info->stop_at[2]))
703     return paramErr;
704     } else {
705     // Given starting address
706     uint8 start_m, start_s, start_f;
707     if (!position2msf(info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), false, start_m, start_s, start_f))
708     return paramErr;
709     info->play_mode = ReadMacInt8(pb + csParam + 9) & 0x0f;
710     if (!SysCDPlay(info->fh, start_m, start_s, start_f, info->stop_at[0], info->stop_at[1], info->stop_at[2]))
711     return paramErr;
712     }
713     return noErr;
714    
715     case 105: // AudioPause
716     if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
717     return offLinErr;
718    
719     switch (ReadMacInt32(pb + csParam)) {
720     case 0:
721     if (!SysCDResume(info->fh))
722     return paramErr;
723     break;
724     case 1:
725     if (!SysCDPause(info->fh))
726     return paramErr;
727     break;
728     default:
729     return paramErr;
730     }
731     return noErr;
732    
733     case 106: // AudioStop
734     D(bug(" AudioStop postype %d, pos %08lx\n", ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2)));
735     if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
736     return offLinErr;
737    
738     if (ReadMacInt16(pb + csParam) == 0 && ReadMacInt32(pb + csParam + 2) == 0) {
739     // Stop immediately
740     if (!SysCDStop(info->fh, info->lead_out[0], info->lead_out[1], info->lead_out[2]))
741     return paramErr;
742     } else {
743     // Given stopping address
744     if (!position2msf(info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), true, info->stop_at[0], info->stop_at[1], info->stop_at[2]))
745     return paramErr;
746     }
747     return noErr;
748    
749     case 107: { // AudioStatus
750     if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
751     return offLinErr;
752    
753     uint8 pos[16];
754     if (!SysCDGetPosition(info->fh, pos))
755     return paramErr;
756    
757     uint8 *p = Mac2HostAddr(pb + csParam);
758     switch (pos[1]) {
759     case 0x11:
760     *p++ = 0; // Audio play in progress
761     break;
762     case 0x12:
763     *p++ = 1; // Audio play paused
764     break;
765     case 0x13:
766     *p++ = 3; // Audio play completed
767     break;
768     case 0x14:
769     *p++ = 4; // Error occurred
770     break;
771     default:
772     *p++ = 5; // No audio play operation requested
773     break;
774     }
775     *p++ = info->play_mode;
776     *p++ = pos[5] & 0x0f; // Control
777     *p++ = bin2bcd[pos[9]]; // M (abs)
778     *p++ = bin2bcd[pos[10]]; // S (abs)
779     *p++ = bin2bcd[pos[11]]; // F (abs)
780     return noErr;
781     }
782    
783     case 108: { // AudioScan
784     if (ReadMacInt8(info->status + dsDiskInPlace) == 0)
785     return offLinErr;
786    
787     uint8 start_m, start_s, start_f;
788     if (!position2msf(info, ReadMacInt16(pb + csParam), ReadMacInt32(pb + csParam + 2), false, start_m, start_s, start_f))
789     return paramErr;
790    
791     if (!SysCDScan(info->fh, start_m, start_s, start_f, ReadMacInt16(pb + csParam + 6)))
792     return paramErr;
793     else
794     return noErr;
795     }
796    
797     case 109: // AudioControl
798     SysCDSetVolume(info->fh, ReadMacInt8(pb + csParam), ReadMacInt8(pb + csParam + 1));
799     return noErr;
800    
801     case 110: // ReadMCN
802     printf("FATAL: .AppleCD/Control(110): unimplemented call\n");
803     return controlErr;
804    
805     case 111: // ReadISRC
806     printf("FATAL: .AppleCD/Control(111): unimplemented call\n");
807     return controlErr;
808    
809     case 112: { // ReadAudioVolume
810     uint8 left, right;
811     SysCDGetVolume(info->fh, left, right);
812     WriteMacInt8(pb + csParam, left);
813     WriteMacInt8(pb + csParam + 1, right);
814     return noErr;
815     }
816    
817     case 113: // GetSpindleSpeed
818     WriteMacInt16(pb + csParam, 0xff);
819     return noErr;
820    
821     case 114: // SetSpindleSpeed
822     return noErr;
823    
824     case 115: // ReadAudio
825     printf("FATAL: .AppleCD/Control(115): unimplemented call\n");
826     return controlErr;
827    
828     case 116: // ReadAllSubcodes
829     printf("FATAL: .AppleCD/Control(116): unimplemented call\n");
830     return controlErr;
831    
832     case 122: // SetTrackList
833     printf("FATAL: .AppleCD/Control(122): unimplemented call\n");
834     return controlErr;
835    
836     case 123: // GetTrackList
837     printf("FATAL: .AppleCD/Control(123): unimplemented call\n");
838     return controlErr;
839    
840     case 124: // GetTrackIndex
841     printf("FATAL: .AppleCD/Control(124): unimplemented call\n");
842     return controlErr;
843    
844     case 125: // SetPlayMode
845     D(bug(" SetPlayMode %04x\n", ReadMacInt16(pb + csParam)));
846     printf("FATAL: .AppleCD/Control(125): unimplemented call\n");
847     return controlErr;
848    
849     case 126: // GetPlayMode (Apple's Audio CD program needs this)
850     WriteMacInt16(pb + csParam, 0);
851     return noErr;
852    
853     default:
854     printf("WARNING: Unknown CDROMControl(%d)\n", code);
855     return controlErr;
856     }
857     }
858    
859    
860     /*
861     * Driver Status() routine
862     */
863    
864     int16 CDROMStatus(uint32 pb, uint32 dce)
865     {
866     DriveInfo *info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
867     uint16 code = ReadMacInt16(pb + csCode);
868     D(bug("CDROMStatus %d\n", code));
869    
870     // General codes
871     switch (code) {
872     case 43: { // DriverGestalt
873     uint32 sel = ReadMacInt32(pb + csParam);
874     D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16, sel >> 8, sel));
875     switch (sel) {
876     case 'vers': // Version
877     WriteMacInt32(pb + csParam + 4, 0x05208000);
878     break;
879     case 'devt': // Device type
880     WriteMacInt32(pb + csParam + 4, 'cdrm');
881     break;
882     case 'intf': // Interface type
883     WriteMacInt32(pb + csParam + 4, 'basi');
884     break;
885     case 'sync': // Only synchronous operation?
886     WriteMacInt32(pb + csParam + 4, 0x01000000);
887     break;
888     case 'boot': // Boot ID
889     if (info != NULL)
890     WriteMacInt16(pb + csParam + 4, info->num);
891     else
892     WriteMacInt16(pb + csParam + 4, 0);
893     WriteMacInt16(pb + csParam + 6, (uint16)CDROMRefNum);
894     break;
895     case 'wide': // 64-bit access supported?
896     WriteMacInt16(pb + csParam + 4, 0);
897     break;
898     case 'purg': // Purge flags
899     WriteMacInt32(pb + csParam + 4, 0);
900     break;
901     case 'ejec': // Eject flags
902     WriteMacInt32(pb + csParam + 4, 0x00030003); // Don't eject on shutdown/restart
903     break;
904     case 'flus': // Flush flags
905     WriteMacInt16(pb + csParam + 4, 0);
906     break;
907     case 'vmop': // Virtual memory attributes
908     WriteMacInt32(pb + csParam + 4, 0); // Drive not available for VM
909     break;
910     default:
911     return statusErr;
912     }
913     return noErr;
914     }
915     }
916    
917     // Drive valid?
918     if (info == NULL)
919     if (first_drive_info == NULL)
920     return nsDrvErr;
921     else
922     info = first_drive_info; // This is needed for Apple's Audio CD program
923    
924     // Drive-specific codes
925     switch (code) {
926     case 8: // DriveStatus
927     memcpy(Mac2HostAddr(pb + csParam), Mac2HostAddr(info->status), 22);
928     return noErr;
929    
930     case 70: // GetPowerMode
931     WriteMacInt16(pb + csParam, info->power_mode << 8);
932     return noErr;
933    
934     case 95: // Get2KOffset
935     if (info->twok_offset > 0) {
936     WriteMacInt16(pb + csParam, info->twok_offset);
937     return noErr;
938     } else
939     return statusErr;
940    
941     case 96: // Get drive type
942     WriteMacInt16(pb + csParam, 3); // Apple CD 300 or newer
943     return noErr;
944    
945     case 98: // Get block size
946     WriteMacInt16(pb + csParam, info->block_size);
947     return noErr;
948    
949     case 120: // Return device ident
950     WriteMacInt32(pb + csParam, 0);
951     return noErr;
952    
953     case 121: // Get CD features
954     WriteMacInt16(pb + csParam, 0x0200); // 300 KB/s
955     WriteMacInt16(pb + csParam, 0x0300); // SCSI-2, stereo
956     return noErr;
957    
958     default:
959     printf("WARNING: Unknown CDROMStatus(%d)\n", code);
960     return statusErr;
961 cebix 1.2 }
962     }
963    
964    
965     /*
966     * Driver interrupt routine - check for volumes to be mounted
967     */
968    
969     void CDROMInterrupt(void)
970     {
971     static int tick_count = 0;
972     if (!acc_run_called)
973     return;
974    
975     tick_count++;
976     if (tick_count > driver_delay) {
977     tick_count = 0;
978     mount_mountable_volumes();
979 cebix 1.1 }
980     }