ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/disk.cpp
Revision: 1.6
Committed: 2000-07-14T21:29:08Z (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

# Content
1 /*
2 * disk.cpp - Generic disk driver
3 *
4 * Basilisk II (C) 1997-2000 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 // Flag: Control(accRun) has been called, interrupt routine is now active
94 static bool acc_run_called = false;
95
96
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 * 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 * 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 acc_run_called = false;
233
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 D(bug(" %d blocks\n", info->num_blocks));
269 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 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 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 case 'vers': // Version
431 WriteMacInt32(pb + csParam + 4, 0x01008000);
432 break;
433 case 'devt': // Device type
434 if (info != NULL) {
435 if (ReadMacInt8(info->status + dsDiskInPlace) == 8)
436 WriteMacInt32(pb + csParam + 4, 'disk');
437 else
438 WriteMacInt32(pb + csParam + 4, 'rdsk');
439 } else
440 WriteMacInt32(pb + csParam + 4, 'disk');
441 break;
442 case 'intf': // Interface type
443 WriteMacInt32(pb + csParam + 4, 'basi');
444 break;
445 case 'sync': // Only synchronous operation?
446 WriteMacInt32(pb + csParam + 4, 0x01000000);
447 break;
448 case 'boot': // Boot ID
449 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 case 'wide': // 64-bit access supported?
456 WriteMacInt16(pb + csParam + 4, 0x0100);
457 break;
458 case 'purg': // Purge flags
459 WriteMacInt32(pb + csParam + 4, 0);
460 break;
461 case 'ejec': // Eject flags
462 WriteMacInt32(pb + csParam + 4, 0x00030003); // Don't eject on shutdown/restart
463 break;
464 case 'flus': // Flush flags
465 WriteMacInt16(pb + csParam + 4, 0);
466 break;
467 case 'vmop': // Virtual memory attributes
468 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 Mac2Mac_memcpy(pb + csParam, info->status, 22);
485 return noErr;
486
487 default:
488 printf("WARNING: Unknown DiskStatus(%d)\n", code);
489 return statusErr;
490 }
491 }
492
493
494 /*
495 * Driver interrupt routine (1Hz) - check for volumes to be mounted
496 */
497
498 void DiskInterrupt(void)
499 {
500 if (!acc_run_called)
501 return;
502
503 mount_mountable_volumes();
504 }