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

# Content
1 /*
2 * disk.cpp - Generic disk driver
3 *
4 * Basilisk II (C) 1997-2001 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 23: "Driver Education"
26 * Technote FL 24: "Don't Look at ioPosOffset for Devices"
27 */
28
29 #include <string.h>
30 #include <vector>
31
32 #ifndef NO_STD_NAMESPACE
33 using std::vector;
34 #endif
35
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 struct disk_drive_info {
74 disk_drive_info() : num(0), fh(NULL), start_byte(0), read_only(false), status(0) {}
75 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
79 int num; // Drive number
80 void *fh; // File handle
81 loff_t start_byte; // Start of HFS partition on disk
82 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 // List of drives handled by this driver
89 typedef vector<disk_drive_info> drive_vec;
90 static drive_vec drives;
91
92 // Icon address (Mac address space, set by PatchROM())
93 uint32 DiskIconAddr;
94
95 // Flag: Control(accRun) has been called, interrupt routine is now active
96 static bool acc_run_called = false;
97
98
99 /*
100 * Get pointer to drive info or drives.end() if not found
101 */
102
103 static drive_vec::iterator get_drive_info(int num)
104 {
105 drive_vec::iterator info, end = drives.end();
106 for (info = drives.begin(); info != end; ++info) {
107 if (info->num == num)
108 return info;
109 }
110 return info;
111 }
112
113
114 /*
115 * 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 * 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 int index = 0;
159 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 if (fh)
168 drives.push_back(disk_drive_info(fh, SysIsReadOnly(fh)));
169 }
170 }
171
172
173 /*
174 * Deinitialization
175 */
176
177 void DiskExit(void)
178 {
179 drive_vec::iterator info, end = drives.end();
180 for (info = drives.begin(); info != end; ++info)
181 info->close_fh();
182 drives.clear();
183 }
184
185
186 /*
187 * Disk was inserted, flag for mounting
188 */
189
190 bool DiskMountVolume(void *fh)
191 {
192 drive_vec::iterator info = drives.begin(), end = drives.end();
193 while (info != end && info->fh != fh)
194 ++info;
195 if (info != end) {
196 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 find_hfs_partition(*info);
201 if (info->start_byte == 0)
202 info->num_blocks = SysGetFileSize(info->fh) / 512;
203 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 * 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 drive_vec::iterator info, end = drives.end();
221 for (info = drives.begin(); info != end; ++info) {
222
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 * 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 acc_run_called = false;
255
256 // Install drives
257 drive_vec::iterator info, end = drives.end();
258 for (info = drives.begin(); info != end; ++info) {
259
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 find_hfs_partition(*info);
289 if (info->start_byte == 0)
290 info->num_blocks = SysGetFileSize(info->fh) / 512;
291 info->to_be_mounted = true;
292 }
293 D(bug(" %d blocks\n", info->num_blocks));
294 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 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
318 if (info == drives.end())
319 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 actual = Sys_read(info->fh, buffer, position + info->start_byte, length);
337 if (actual != length)
338 return readErr;
339
340 } else {
341
342 // Write
343 if (info->read_only)
344 return wPrErr;
345 actual = Sys_write(info->fh, buffer, position + info->start_byte, length);
346 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 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 return noErr;
376 }
377 }
378
379 // Drive valid?
380 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
381 if (info == drives.end())
382 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 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
446 uint16 code = ReadMacInt16(pb + csCode);
447 D(bug("DiskStatus %d\n", code));
448
449 // General codes (we can get these even if the drive was invalid)
450 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 case FOURCC('v','e','r','s'): // Version
456 WriteMacInt32(pb + csParam + 4, 0x01008000);
457 break;
458 case FOURCC('d','e','v','t'): // Device type
459 if (info != drives.end()) {
460 if (ReadMacInt8(info->status + dsDiskInPlace) == 8)
461 WriteMacInt32(pb + csParam + 4, FOURCC('d','i','s','k'));
462 else
463 WriteMacInt32(pb + csParam + 4, FOURCC('r','d','s','k'));
464 } else
465 WriteMacInt32(pb + csParam + 4, FOURCC('d','i','s','k'));
466 break;
467 case FOURCC('i','n','t','f'): // Interface type
468 WriteMacInt32(pb + csParam + 4, EMULATOR_ID_4);
469 break;
470 case FOURCC('s','y','n','c'): // Only synchronous operation?
471 WriteMacInt32(pb + csParam + 4, 0x01000000);
472 break;
473 case FOURCC('b','o','o','t'): // Boot ID
474 if (info != drives.end())
475 WriteMacInt16(pb + csParam + 4, info->num);
476 else
477 WriteMacInt16(pb + csParam + 4, 0);
478 WriteMacInt16(pb + csParam + 6, (uint16)DiskRefNum);
479 break;
480 case FOURCC('w','i','d','e'): // 64-bit access supported?
481 WriteMacInt16(pb + csParam + 4, 0x0100);
482 break;
483 case FOURCC('p','u','r','g'): // Purge flags
484 WriteMacInt32(pb + csParam + 4, 0);
485 break;
486 case FOURCC('e','j','e','c'): // Eject flags
487 WriteMacInt32(pb + csParam + 4, 0x00030003); // Don't eject on shutdown/restart
488 break;
489 case FOURCC('f','l','u','s'): // Flush flags
490 WriteMacInt16(pb + csParam + 4, 0);
491 break;
492 case FOURCC('v','m','o','p'): // Virtual memory attributes
493 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 if (info == drives.end())
504 return nsDrvErr;
505
506 // Drive-specific codes
507 switch (code) {
508 case 8: // Get drive status
509 Mac2Mac_memcpy(pb + csParam, info->status, 22);
510 return noErr;
511
512 default:
513 printf("WARNING: Unknown DiskStatus(%d)\n", code);
514 return statusErr;
515 }
516 }
517
518
519 /*
520 * Driver interrupt routine (1Hz) - check for volumes to be mounted
521 */
522
523 void DiskInterrupt(void)
524 {
525 if (!acc_run_called)
526 return;
527
528 mount_mountable_volumes();
529 }