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 (22 years, 10 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

# 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), 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 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 // List of drives handled by this driver
88 typedef vector<disk_drive_info> drive_vec;
89 static drive_vec drives;
90
91 // Icon address (Mac address space, set by PatchROM())
92 uint32 DiskIconAddr;
93
94 // Flag: Control(accRun) has been called, interrupt routine is now active
95 static bool acc_run_called = false;
96
97
98 /*
99 * Get pointer to drive info or drives.end() if not found
100 */
101
102 static drive_vec::iterator get_drive_info(int num)
103 {
104 drive_vec::iterator info, end = drives.end();
105 for (info = drives.begin(); info != end; ++info) {
106 if (info->num == num)
107 return info;
108 }
109 return info;
110 }
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 int index = 0;
125 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 if (fh)
134 drives.push_back(disk_drive_info(fh, SysIsReadOnly(fh)));
135 }
136 }
137
138
139 /*
140 * Deinitialization
141 */
142
143 void DiskExit(void)
144 {
145 drive_vec::iterator info, end = drives.end();
146 for (info = drives.begin(); info != end; ++info)
147 info->close_fh();
148 drives.clear();
149 }
150
151
152 /*
153 * Disk was inserted, flag for mounting
154 */
155
156 bool DiskMountVolume(void *fh)
157 {
158 drive_vec::iterator info = drives.begin(), end = drives.end();
159 while (info != end && info->fh != fh)
160 ++info;
161 if (info != end) {
162 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 * 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 drive_vec::iterator info, end = drives.end();
185 for (info = drives.begin(); info != end; ++info) {
186
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 * 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 acc_run_called = false;
219
220 // Install drives
221 drive_vec::iterator info, end = drives.end();
222 for (info = drives.begin(); info != end; ++info) {
223
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 D(bug(" %d blocks\n", info->num_blocks));
256 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 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
280 if (info == drives.end())
281 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 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 return noErr;
338 }
339 }
340
341 // Drive valid?
342 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
343 if (info == drives.end())
344 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 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
408 uint16 code = ReadMacInt16(pb + csCode);
409 D(bug("DiskStatus %d\n", code));
410
411 // General codes (we can get these even if the drive was invalid)
412 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 case FOURCC('v','e','r','s'): // Version
418 WriteMacInt32(pb + csParam + 4, 0x01008000);
419 break;
420 case FOURCC('d','e','v','t'): // Device type
421 if (info != drives.end()) {
422 if (ReadMacInt8(info->status + dsDiskInPlace) == 8)
423 WriteMacInt32(pb + csParam + 4, FOURCC('d','i','s','k'));
424 else
425 WriteMacInt32(pb + csParam + 4, FOURCC('r','d','s','k'));
426 } else
427 WriteMacInt32(pb + csParam + 4, FOURCC('d','i','s','k'));
428 break;
429 case FOURCC('i','n','t','f'): // Interface type
430 WriteMacInt32(pb + csParam + 4, EMULATOR_ID_4);
431 break;
432 case FOURCC('s','y','n','c'): // Only synchronous operation?
433 WriteMacInt32(pb + csParam + 4, 0x01000000);
434 break;
435 case FOURCC('b','o','o','t'): // Boot ID
436 if (info != drives.end())
437 WriteMacInt16(pb + csParam + 4, info->num);
438 else
439 WriteMacInt16(pb + csParam + 4, 0);
440 WriteMacInt16(pb + csParam + 6, (uint16)DiskRefNum);
441 break;
442 case FOURCC('w','i','d','e'): // 64-bit access supported?
443 WriteMacInt16(pb + csParam + 4, 0x0100);
444 break;
445 case FOURCC('p','u','r','g'): // Purge flags
446 WriteMacInt32(pb + csParam + 4, 0);
447 break;
448 case FOURCC('e','j','e','c'): // Eject flags
449 WriteMacInt32(pb + csParam + 4, 0x00030003); // Don't eject on shutdown/restart
450 break;
451 case FOURCC('f','l','u','s'): // Flush flags
452 WriteMacInt16(pb + csParam + 4, 0);
453 break;
454 case FOURCC('v','m','o','p'): // Virtual memory attributes
455 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 if (info == drives.end())
466 return nsDrvErr;
467
468 // Drive-specific codes
469 switch (code) {
470 case 8: // Get drive status
471 Mac2Mac_memcpy(pb + csParam, info->status, 22);
472 return noErr;
473
474 default:
475 printf("WARNING: Unknown DiskStatus(%d)\n", code);
476 return statusErr;
477 }
478 }
479
480
481 /*
482 * Driver interrupt routine (1Hz) - check for volumes to be mounted
483 */
484
485 void DiskInterrupt(void)
486 {
487 if (!acc_run_called)
488 return;
489
490 mount_mountable_volumes();
491 }