ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/disk.cpp
Revision: 1.7
Committed: 2000-07-22T16:07:15Z (24 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.6: +14 -14 lines
Log Message:
- new FOURCC() macro in macos_util.h

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * disk.cpp - Generic disk 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 23: "Driver Education"
26     * Technote FL 24: "Don't Look at ioPosOffset for Devices"
27     */
28    
29     #include <string.h>
30    
31     #include "sysdeps.h"
32     #include "cpu_emulation.h"
33     #include "main.h"
34     #include "macos_util.h"
35     #include "sys.h"
36     #include "prefs.h"
37     #include "disk.h"
38    
39     #define DEBUG 0
40     #include "debug.h"
41    
42    
43     // .Disk Disk/drive icon
44     const uint8 DiskIcon[258] = {
45     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
46     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
47     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
48     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe,
50     0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01,
51     0x80, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01,
52     0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53    
54     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
55     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
56     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
57     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
58     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe,
59     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
60     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
61     0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
62    
63     0, 0
64     };
65    
66    
67     // Struct for each drive
68     struct DriveInfo {
69     DriveInfo()
70     {
71     next = NULL;
72     num = 0;
73     fh = NULL;
74     read_only = false;
75     status = 0;
76     }
77    
78     DriveInfo *next; // Pointer to next DriveInfo (must be first in struct!)
79     int num; // Drive number
80     void *fh; // File handle
81     uint32 num_blocks; // Size in 512-byte blocks
82     bool to_be_mounted; // Flag: drive must be mounted in accRun
83     bool read_only; // Flag: force write protection
84     uint32 status; // Mac address of drive status record
85     };
86    
87     // Linked list of DriveInfos
88     static DriveInfo *first_drive_info;
89    
90     // Icon address (Mac address space, set by PatchROM())
91     uint32 DiskIconAddr;
92    
93 cebix 1.2 // Flag: Control(accRun) has been called, interrupt routine is now active
94     static bool acc_run_called = false;
95    
96 cebix 1.1
97     /*
98     * Get pointer to drive info, NULL = invalid drive number
99     */
100    
101     static DriveInfo *get_drive_info(int num)
102     {
103     DriveInfo *info = first_drive_info;
104     while (info != NULL) {
105     if (info->num == num)
106     return info;
107     info = info->next;
108     }
109     return NULL;
110     }
111    
112    
113     /*
114     * Initialization
115     */
116    
117     void DiskInit(void)
118     {
119     first_drive_info = NULL;
120    
121     // No drives specified in prefs? Then add defaults
122     if (PrefsFindString("disk", 0) == NULL)
123     SysAddDiskPrefs();
124    
125     // Add drives specified in preferences
126     int32 index = 0;
127     const char *str;
128     while ((str = PrefsFindString("disk", index++)) != NULL) {
129     bool read_only = false;
130     if (str[0] == '*') {
131     read_only = true;
132     str++;
133     }
134     void *fh = Sys_open(str, read_only);
135     if (fh) {
136     D(bug(" adding drive '%s'\n", str));
137     DriveInfo *info = new DriveInfo;
138     info->fh = fh;
139     info->read_only = SysIsReadOnly(fh);
140     DriveInfo *p = (DriveInfo *)&first_drive_info;
141     while (p->next != NULL)
142     p = p->next;
143     p->next = info;
144     }
145     }
146     }
147    
148    
149     /*
150     * Deinitialization
151     */
152    
153     void DiskExit(void)
154     {
155     DriveInfo *info = first_drive_info, *next;
156     while (info != NULL) {
157     Sys_close(info->fh);
158     next = info->next;
159     delete info;
160     info = next;
161     }
162     }
163    
164    
165     /*
166     * Disk was inserted, flag for mounting
167     */
168    
169     bool DiskMountVolume(void *fh)
170     {
171     DriveInfo *info;
172     for (info = first_drive_info; info != NULL && info->fh != fh; info = info->next) ;
173     if (info) {
174     if (SysIsDiskInserted(info->fh)) {
175     info->read_only = SysIsReadOnly(info->fh);
176     WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk
177     WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0xff : 0);
178     info->num_blocks = SysGetFileSize(info->fh) / 512;
179     WriteMacInt16(info->status + dsDriveSize, info->num_blocks & 0xffff);
180     WriteMacInt16(info->status + dsDriveS1, info->num_blocks >> 16);
181     info->to_be_mounted = true;
182     }
183     return true;
184     } else
185     return false;
186     }
187    
188    
189     /*
190 cebix 1.2 * Mount volumes for which the to_be_mounted flag is set
191     * (called during interrupt time)
192     */
193    
194     static void mount_mountable_volumes(void)
195     {
196     DriveInfo *info = first_drive_info;
197     while (info != NULL) {
198    
199     // Disk in drive?
200     if (!ReadMacInt8(info->status + dsDiskInPlace)) {
201    
202     // No, check if disk was inserted
203     if (SysIsDiskInserted(info->fh))
204     DiskMountVolume(info->fh);
205     }
206    
207     // Mount disk if flagged
208     if (info->to_be_mounted) {
209     D(bug(" mounting drive %d\n", info->num));
210     M68kRegisters r;
211     r.d[0] = info->num;
212     r.a[0] = 7; // diskEvent
213     Execute68kTrap(0xa02f, &r); // PostEvent()
214     info->to_be_mounted = false;
215     }
216    
217     info = info->next;
218     }
219     }
220    
221    
222     /*
223 cebix 1.1 * Driver Open() routine
224     */
225    
226     int16 DiskOpen(uint32 pb, uint32 dce)
227     {
228     D(bug("DiskOpen\n"));
229    
230     // Set up DCE
231     WriteMacInt32(dce + dCtlPosition, 0);
232 cebix 1.2 acc_run_called = false;
233 cebix 1.1
234     // Install drives
235     for (DriveInfo *info = first_drive_info; info; info = info->next) {
236    
237     info->num = FindFreeDriveNumber(1);
238     info->to_be_mounted = false;
239    
240     if (info->fh) {
241    
242     // Allocate drive status record
243     M68kRegisters r;
244     r.d[0] = SIZEOF_DrvSts;
245     Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
246     if (r.a[0] == 0)
247     continue;
248     info->status = r.a[0];
249     D(bug(" DrvSts at %08lx\n", info->status));
250    
251     // Set up drive status
252     WriteMacInt16(info->status + dsQType, hard20);
253     WriteMacInt8(info->status + dsInstalled, 1);
254     bool disk_in_place = false;
255     if (SysIsFixedDisk(info->fh)) {
256     WriteMacInt8(info->status + dsDiskInPlace, 8); // Fixed disk
257     disk_in_place = true;
258     } else if (SysIsDiskInserted(info->fh)) {
259     WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk
260     disk_in_place = true;
261     }
262     if (disk_in_place) {
263     D(bug(" disk inserted\n"));
264     WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0x80 : 0);
265     info->num_blocks = SysGetFileSize(info->fh) / 512;
266     info->to_be_mounted = true;
267     }
268 cebix 1.3 D(bug(" %d blocks\n", info->num_blocks));
269 cebix 1.1 WriteMacInt16(info->status + dsDriveSize, info->num_blocks & 0xffff);
270     WriteMacInt16(info->status + dsDriveS1, info->num_blocks >> 16);
271    
272     // Add drive to drive queue
273     D(bug(" adding drive %d\n", info->num));
274     r.d[0] = (info->num << 16) | (DiskRefNum & 0xffff);
275     r.a[0] = info->status + dsQLink;
276     Execute68kTrap(0xa04e, &r); // AddDrive()
277     }
278     }
279     return noErr;
280     }
281    
282    
283     /*
284     * Driver Prime() routine
285     */
286    
287     int16 DiskPrime(uint32 pb, uint32 dce)
288     {
289     WriteMacInt32(pb + ioActCount, 0);
290    
291     // Drive valid and disk inserted?
292     DriveInfo *info;
293     if ((info = get_drive_info(ReadMacInt16(pb + ioVRefNum))) == NULL)
294     return nsDrvErr;
295     if (!ReadMacInt8(info->status + dsDiskInPlace))
296     return offLinErr;
297    
298     // Get parameters
299     void *buffer = Mac2HostAddr(ReadMacInt32(pb + ioBuffer));
300     size_t length = ReadMacInt32(pb + ioReqCount);
301     loff_t position = ReadMacInt32(dce + dCtlPosition);
302     if (ReadMacInt16(pb + ioPosMode) & 0x100) // 64 bit positioning
303     position = ((loff_t)ReadMacInt32(pb + ioWPosOffset) << 32) || ReadMacInt32(pb + ioWPosOffset + 4);
304     if ((length & 0x1ff) || (position & 0x1ff))
305     return paramErr;
306    
307     size_t actual = 0;
308     if ((ReadMacInt16(pb + ioTrap) & 0xff) == aRdCmd) {
309    
310     // Read
311     actual = Sys_read(info->fh, buffer, position, length);
312     if (actual != length)
313     return readErr;
314    
315     } else {
316    
317     // Write
318     if (info->read_only)
319     return wPrErr;
320     actual = Sys_write(info->fh, buffer, position, length);
321     if (actual != length)
322     return writErr;
323     }
324    
325     // Update ParamBlock and DCE
326     WriteMacInt32(pb + ioActCount, actual);
327     WriteMacInt32(dce + dCtlPosition, ReadMacInt32(dce + dCtlPosition) + actual);
328     return noErr;
329     }
330    
331    
332     /*
333     * Driver Control() routine
334     */
335    
336     int16 DiskControl(uint32 pb, uint32 dce)
337     {
338     uint16 code = ReadMacInt16(pb + csCode);
339     D(bug("DiskControl %d\n", code));
340    
341     // General codes
342     switch (code) {
343     case 1: // KillIO
344     return noErr;
345    
346 cebix 1.2 case 65: { // Periodic action (accRun, "insert" disks on startup)
347     mount_mountable_volumes();
348     WriteMacInt16(dce + dCtlFlags, ReadMacInt16(dce + dCtlFlags) & ~0x2000); // Disable periodic action
349     acc_run_called = true;
350 cebix 1.1 return noErr;
351     }
352     }
353    
354     // Drive valid?
355     DriveInfo *info;
356     if ((info = get_drive_info(ReadMacInt16(pb + ioVRefNum))) == NULL)
357     return nsDrvErr;
358    
359     // Drive-specific codes
360     switch (code) {
361     case 5: // Verify disk
362     if (ReadMacInt8(info->status + dsDiskInPlace) > 0)
363     return noErr;
364     else
365     return offLinErr;
366    
367     case 6: // Format disk
368     if (info->read_only)
369     return wPrErr;
370     else if (ReadMacInt8(info->status + dsDiskInPlace) > 0)
371     return noErr;
372     else
373     return offLinErr;
374    
375     case 7: // Eject disk
376     if (ReadMacInt8(info->status + dsDiskInPlace) == 8) {
377     // Fixed disk, re-insert
378     M68kRegisters r;
379     r.d[0] = info->num;
380     r.a[0] = 7; // diskEvent
381     Execute68kTrap(0xa02f, &r); // PostEvent()
382     } else if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
383     SysEject(info->fh);
384     WriteMacInt8(info->status + dsDiskInPlace, 0);
385     }
386     return noErr;
387    
388     case 21: // Get drive icon
389     case 22: // Get disk icon
390     WriteMacInt32(pb + csParam, DiskIconAddr);
391     return noErr;
392    
393     case 23: // Get drive info
394     if (ReadMacInt8(info->status + dsDiskInPlace) == 8)
395     WriteMacInt32(pb + csParam, 0x0601); // Unspecified fixed SCSI disk
396     else
397     WriteMacInt32(pb + csParam, 0x0201); // Unspecified SCSI disk
398     return noErr;
399    
400     case 24: // Get partition size
401     if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
402     WriteMacInt32(pb + csParam, info->num_blocks);
403     return noErr;
404     } else
405     return offLinErr;
406    
407     default:
408     printf("WARNING: Unknown DiskControl(%d)\n", code);
409     return controlErr;
410     }
411     }
412    
413    
414     /*
415     * Driver Status() routine
416     */
417    
418     int16 DiskStatus(uint32 pb, uint32 dce)
419     {
420     DriveInfo *info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
421     uint16 code = ReadMacInt16(pb + csCode);
422     D(bug("DiskStatus %d\n", code));
423    
424     // General codes
425     switch (code) {
426     case 43: { // Driver gestalt
427     uint32 sel = ReadMacInt32(pb + csParam);
428     D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16, sel >> 8, sel));
429     switch (sel) {
430 cebix 1.7 case FOURCC('v','e','r','s'): // Version
431 cebix 1.1 WriteMacInt32(pb + csParam + 4, 0x01008000);
432     break;
433 cebix 1.7 case FOURCC('d','e','v','t'): // Device type
434 cebix 1.1 if (info != NULL) {
435     if (ReadMacInt8(info->status + dsDiskInPlace) == 8)
436 cebix 1.7 WriteMacInt32(pb + csParam + 4, FOURCC('d','i','s','k'));
437 cebix 1.1 else
438 cebix 1.7 WriteMacInt32(pb + csParam + 4, FOURCC('r','d','s','k'));
439 cebix 1.1 } else
440 cebix 1.7 WriteMacInt32(pb + csParam + 4, FOURCC('d','i','s','k'));
441 cebix 1.1 break;
442 cebix 1.7 case FOURCC('i','n','t','f'): // Interface type
443     WriteMacInt32(pb + csParam + 4, FOURCC('b','a','s','i'));
444 cebix 1.1 break;
445 cebix 1.7 case FOURCC('s','y','n','c'): // Only synchronous operation?
446 cebix 1.1 WriteMacInt32(pb + csParam + 4, 0x01000000);
447     break;
448 cebix 1.7 case FOURCC('b','o','o','t'): // Boot ID
449 cebix 1.1 if (info != NULL)
450     WriteMacInt16(pb + csParam + 4, info->num);
451     else
452     WriteMacInt16(pb + csParam + 4, 0);
453     WriteMacInt16(pb + csParam + 6, (uint16)DiskRefNum);
454     break;
455 cebix 1.7 case FOURCC('w','i','d','e'): // 64-bit access supported?
456 cebix 1.1 WriteMacInt16(pb + csParam + 4, 0x0100);
457     break;
458 cebix 1.7 case FOURCC('p','u','r','g'): // Purge flags
459 cebix 1.1 WriteMacInt32(pb + csParam + 4, 0);
460     break;
461 cebix 1.7 case FOURCC('e','j','e','c'): // Eject flags
462 cebix 1.1 WriteMacInt32(pb + csParam + 4, 0x00030003); // Don't eject on shutdown/restart
463     break;
464 cebix 1.7 case FOURCC('f','l','u','s'): // Flush flags
465 cebix 1.1 WriteMacInt16(pb + csParam + 4, 0);
466     break;
467 cebix 1.7 case FOURCC('v','m','o','p'): // Virtual memory attributes
468 cebix 1.1 WriteMacInt32(pb + csParam + 4, 0); // Drive not available for VM
469     break;
470     default:
471     return statusErr;
472     }
473     return noErr;
474     }
475     }
476    
477     // Drive valid?
478     if (info == NULL)
479     return nsDrvErr;
480    
481     // Drive-specific codes
482     switch (code) {
483     case 8: // Get drive status
484 cebix 1.4 Mac2Mac_memcpy(pb + csParam, info->status, 22);
485 cebix 1.1 return noErr;
486    
487     default:
488     printf("WARNING: Unknown DiskStatus(%d)\n", code);
489     return statusErr;
490 cebix 1.2 }
491     }
492    
493    
494     /*
495 cebix 1.6 * Driver interrupt routine (1Hz) - check for volumes to be mounted
496 cebix 1.2 */
497    
498     void DiskInterrupt(void)
499     {
500     if (!acc_run_called)
501     return;
502    
503 cebix 1.6 mount_mountable_volumes();
504 cebix 1.1 }