ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/disk.cpp
Revision: 1.10
Committed: 2001-07-01T14:38:02Z (23 years, 4 months ago) by cebix
Branch: MAIN
Changes since 1.9: +42 -55 lines
Log Message:
- sony.cpp/disk.cpp/cdrom.cpp use vector<> of drive_info objects instead of
  linked list
- color depth switching updates slot ROM
- video_x.cpp always supports 1-bit window modes
- timer_create()/clock_gettime() are pulled from librt if present

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