ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.2
Committed: 1999-10-12T20:00:42Z (24 years, 7 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-21101999
Changes since 1.1: +62 -24 lines
Log Message:
- disk insertions are now checked for by the 60Hz interrupt routine
- localizable strings are split into a common and a platform-specific set
- fixed bug in CR->LF translation in AmigaOS/clip_amiga.cpp

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