ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/disk.cpp
Revision: 1.3
Committed: 1999-10-31T23:18:32Z (25 years ago) by cebix
Branch: MAIN
CVS Tags: snapshot-02111999
Changes since 1.2: +1 -1 lines
Log Message:
- removed MemoryDispatch() replacement; routine from ROM is now used if
  possible
- rom_patches.cpp: check for double PACK 4 resources; if only one is found,
  assume that the ROM requires an FPU and issue a warning if FPU emulation
  is turned off
- UAE CPU opcode routines no longer return the cycle count
- main_unix.cpp: pressing Ctrl-C dumps the UAE CPU state before entering mon
- sys_unix.cpp: under Linux, partition sizes are read with BLKGETSIZE instead
  of llseek()

File Contents

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