ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/disk.cpp
Revision: 1.11
Committed: 2001-07-14T20:01:18Z (22 years, 10 months ago) by cebix
Branch: MAIN
Changes since 1.10: +43 -5 lines
Log Message:
- disk.cpp looks for HFS partition info in the disk image; this makes it
  possible to, for example, use MacOS-partitioned hard disks and removable
  media under B2/Unix even if the OS doesn't understand Mac partition maps
  by specifying the appropriate block device name as a Mac volume
- fixed typo in audio_dummy.cpp
- added minimally required UDP tunneling code to ether_dummy.cpp
- main_unix.cpp: if pthreads are not supported, we trigger the Ethernet
  interrupt in the 60Hz ticker; this makes UDP tunneling work under
  NetBSD/m68k (as the only form of networking)

File Contents

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