ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/disk.cpp
Revision: 1.2
Committed: 1999-10-12T20:00:43Z (25 years, 1 month ago) by cebix
Branch: MAIN
CVS Tags: snapshot-21101999
Changes since 1.1: +62 -24 lines
Log Message:
- disk insertions are now checked for by the 60Hz interrupt routine
- localizable strings are split into a common and a platform-specific set
- fixed bug in CR->LF translation in AmigaOS/clip_amiga.cpp

File Contents

# User Rev Content
1 cebix 1.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 cebix 1.2 // 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 cebix 1.1
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 cebix 1.2 * 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 cebix 1.1 * 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 cebix 1.2 acc_run_called = false;
236 cebix 1.1
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(" %ld 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 cebix 1.2 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 cebix 1.1 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 cebix 1.2 }
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 cebix 1.1 }
512     }