ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/cdrom.cpp
Revision: 1.6
Committed: 2000-07-14T21:29:07Z (23 years, 10 months ago) by cebix
Branch: MAIN
Changes since 1.5: +2 -10 lines
Log Message:
- AmigaOS bug fixes by J.Lachmann (floppy, 2060scsi.device, "Add Volume" in
  prefs editor)
- imported some changes from the Windows source (1Hz interrupt, FPU fixes)

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