ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/sony.cpp
Revision: 1.13
Committed: 2002-01-15T14:58:32Z (22 years, 10 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-15012002
Changes since 1.12: +1 -1 lines
Log Message:
- documentation updates
- 2001 -> 2002
- version 0.9 -> 1.0

File Contents

# Content
1 /*
2 * sony.cpp - Replacement .Sony driver (floppy drives)
3 *
4 * Basilisk II (C) 1997-2002 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 07: "Forcing Floppy Disk Size to be Either 400K or 800K"
26 * Technote DV 17: "Sony Driver: What Your Sony Drives For You"
27 * Technote DV 23: "Driver Education"
28 * Technote FL 24: "Don't Look at ioPosOffset for Devices"
29 */
30
31 #include "sysdeps.h"
32
33 #include <string.h>
34 #include <vector>
35
36 #ifndef NO_STD_NAMESPACE
37 using std::vector;
38 #endif
39
40 #include "cpu_emulation.h"
41 #include "main.h"
42 #include "macos_util.h"
43 #include "rom_patches.h"
44 #include "sys.h"
45 #include "prefs.h"
46 #include "sony.h"
47
48 #define DEBUG 0
49 #include "debug.h"
50
51
52 // Check for inserted disks by polling?
53 #ifdef AMIGA
54 #define DISK_INSERT_CHECK 1
55 #else
56 #define DISK_INSERT_CHECK 0
57 #endif
58
59
60 // Floppy disk icon
61 const uint8 SonyDiskIcon[258] = {
62 0x7f, 0xff, 0xff, 0xf8, 0x81, 0x00, 0x01, 0x04, 0x81, 0x00, 0x71, 0x02, 0x81, 0x00, 0x89, 0x01,
63 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01,
64 0x81, 0x00, 0x71, 0x01, 0x81, 0x00, 0x01, 0x01, 0x80, 0xff, 0xfe, 0x01, 0x80, 0x00, 0x00, 0x01,
65 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01,
66 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x87, 0xff, 0xff, 0xe1, 0x88, 0x00, 0x00, 0x11,
67 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11,
68 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11,
69 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x7f, 0xff, 0xff, 0xfe,
70
71 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
72 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
73 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
74 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
75 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
76 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
77 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
78 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfe,
79
80 0, 0
81 };
82
83 // Floppy drive icon
84 const uint8 SonyDriveIcon[258] = {
85 0x7f, 0xff, 0xff, 0xf8, 0x81, 0x00, 0x01, 0x04, 0x81, 0x00, 0x71, 0x02, 0x81, 0x00, 0x89, 0x01,
86 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01, 0x81, 0x00, 0x89, 0x01,
87 0x81, 0x00, 0x71, 0x01, 0x81, 0x00, 0x01, 0x01, 0x80, 0xff, 0xfe, 0x01, 0x80, 0x00, 0x00, 0x01,
88 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01,
89 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x87, 0xff, 0xff, 0xe1, 0x88, 0x00, 0x00, 0x11,
90 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11,
91 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11,
92 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x88, 0x00, 0x00, 0x11, 0x7f, 0xff, 0xff, 0xfe,
93
94 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
95 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
96 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
97 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
98 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
99 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
100 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
101 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xfe,
102
103 0, 0
104 };
105
106
107 // Struct for each drive
108 struct sony_drive_info {
109 sony_drive_info() : num(0), fh(NULL), read_only(false), status(0) {}
110 sony_drive_info(void *fh_, bool ro) : num(0), fh(fh_), read_only(ro), status(0) {}
111
112 void close_fh(void) { Sys_close(fh); }
113
114 int num; // Drive number
115 void *fh; // Floppy driver file handle
116 bool to_be_mounted; // Flag: drive must be mounted in accRun
117 bool read_only; // Flag: force write protection
118 uint32 tag_buffer; // Mac address of tag buffer
119 uint32 status; // Mac address of drive status record
120 };
121
122 // List of drives handled by this driver
123 typedef vector<sony_drive_info> drive_vec;
124 static drive_vec drives;
125
126 // Icon addresses (Mac address space, set by PatchROM())
127 uint32 SonyDiskIconAddr;
128 uint32 SonyDriveIconAddr;
129
130 // Flag: Control(accRun) has been called, interrupt routine is now active
131 static bool acc_run_called = false;
132
133
134 /*
135 * Get reference to drive info or drives.end() if not found
136 */
137
138 static drive_vec::iterator get_drive_info(int num)
139 {
140 drive_vec::iterator info, end = drives.end();
141 for (info = drives.begin(); info != end; ++info) {
142 if (info->num == num)
143 return info;
144 }
145 return info;
146 }
147
148
149 /*
150 * Initialization
151 */
152
153 void SonyInit(void)
154 {
155 // No drives specified in prefs? Then add defaults
156 if (PrefsFindString("floppy", 0) == NULL)
157 SysAddFloppyPrefs();
158
159 // Add drives specified in preferences
160 int index = 0;
161 const char *str;
162 while ((str = PrefsFindString("floppy", index++)) != NULL) {
163 bool read_only = false;
164 if (str[0] == '*') {
165 read_only = true;
166 str++;
167 }
168 void *fh = Sys_open(str, read_only);
169 if (fh)
170 drives.push_back(sony_drive_info(fh, SysIsReadOnly(fh)));
171 }
172 }
173
174
175 /*
176 * Deinitialization
177 */
178
179 void SonyExit(void)
180 {
181 drive_vec::iterator info, end = drives.end();
182 for (info = drives.begin(); info != end; ++info)
183 info->close_fh();
184 drives.clear();
185 }
186
187
188 /*
189 * Disk was inserted, flag for mounting
190 */
191
192 bool SonyMountVolume(void *fh)
193 {
194 drive_vec::iterator info = drives.begin(), end = drives.end();
195 while (info != end && info->fh != fh)
196 ++info;
197 if (info != end) {
198 if (SysIsDiskInserted(info->fh)) {
199 info->read_only = SysIsReadOnly(info->fh);
200 WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk
201 WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0xff : 0);
202 info->to_be_mounted = true;
203 }
204 return true;
205 } else
206 return false;
207 }
208
209
210 /*
211 * Mount volumes for which the to_be_mounted flag is set
212 * (called during interrupt time)
213 */
214
215 static void mount_mountable_volumes(void)
216 {
217 drive_vec::iterator info, end = drives.end();
218 for (info = drives.begin(); info != end; ++info) {
219
220 #if DISK_INSERT_CHECK
221 // Disk in drive?
222 if (!ReadMacInt8(info->status + dsDiskInPlace)) {
223
224 // No, check if disk was inserted
225 if (SysIsDiskInserted(info->fh))
226 SonyMountVolume(info->fh);
227 }
228 #endif
229
230 // Mount disk if flagged
231 if (info->to_be_mounted) {
232 D(bug(" mounting drive %d\n", info->num));
233 M68kRegisters r;
234 r.d[0] = info->num;
235 r.a[0] = 7; // diskEvent
236 Execute68kTrap(0xa02f, &r); // PostEvent()
237 info->to_be_mounted = false;
238 }
239 }
240 }
241
242
243 /*
244 * Set error code in DskErr
245 */
246
247 static int16 set_dsk_err(int16 err)
248 {
249 WriteMacInt16(0x142, err);
250 return err;
251 }
252
253
254 /*
255 * Driver Open() routine
256 */
257
258 int16 SonyOpen(uint32 pb, uint32 dce)
259 {
260 D(bug("SonyOpen\n"));
261
262 // Set up DCE
263 WriteMacInt32(dce + dCtlPosition, 0);
264 WriteMacInt16(dce + dCtlQHdr + qFlags, ReadMacInt16(dce + dCtlQHdr + qFlags) & 0xff00 | 3); // Version number, must be >=3 or System 8 will replace us
265 acc_run_called = false;
266
267 // Install driver again with refnum -2 (HD20)
268 uint32 utab = ReadMacInt32(0x11c);
269 WriteMacInt32(utab + 4, ReadMacInt32(utab + 16));
270
271 // Set up fake SonyVars
272 WriteMacInt32(0x134, 0xdeadbeef);
273
274 // Clear DskErr
275 set_dsk_err(0);
276
277 // Install drives
278 drive_vec::iterator info, end = drives.end();
279 for (info = drives.begin(); info != end; ++info) {
280
281 info->num = FindFreeDriveNumber(1);
282 info->to_be_mounted = false;
283 info->tag_buffer = 0;
284
285 if (info->fh) {
286
287 // Allocate drive status record
288 M68kRegisters r;
289 r.d[0] = SIZEOF_DrvSts;
290 Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
291 if (r.a[0] == 0)
292 continue;
293 info->status = r.a[0];
294 D(bug(" DrvSts at %08lx\n", info->status));
295
296 // Set up drive status
297 WriteMacInt16(info->status + dsQType, sony);
298 WriteMacInt8(info->status + dsInstalled, 1);
299 WriteMacInt8(info->status + dsSides, 0xff);
300 WriteMacInt8(info->status + dsTwoSideFmt, 0xff);
301 WriteMacInt8(info->status + dsNewIntf, 0xff);
302 WriteMacInt8(info->status + dsMFMDrive, 0xff);
303 WriteMacInt8(info->status + dsMFMDisk, 0xff);
304 WriteMacInt8(info->status + dsTwoMegFmt, 0xff);
305
306 // Disk in drive?
307 if (SysIsDiskInserted(info->fh)) {
308 WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk
309 WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0xff : 0);
310 info->to_be_mounted = true;
311 }
312
313 // Add drive to drive queue
314 D(bug(" adding drive %d\n", info->num));
315 r.d[0] = (info->num << 16) | (SonyRefNum & 0xffff);
316 r.a[0] = info->status + dsQLink;
317 Execute68kTrap(0xa04e, &r); // AddDrive()
318 }
319 }
320 return noErr;
321 }
322
323
324 /*
325 * Driver Prime() routine
326 */
327
328 int16 SonyPrime(uint32 pb, uint32 dce)
329 {
330 WriteMacInt32(pb + ioActCount, 0);
331
332 // Drive valid and disk inserted?
333 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
334 if (info == drives.end())
335 return set_dsk_err(nsDrvErr);
336 if (!ReadMacInt8(info->status + dsDiskInPlace))
337 return set_dsk_err(offLinErr);
338 WriteMacInt8(info->status + dsDiskInPlace, 2); // Disk accessed
339
340 // Get parameters
341 void *buffer = Mac2HostAddr(ReadMacInt32(pb + ioBuffer));
342 size_t length = ReadMacInt32(pb + ioReqCount);
343 loff_t position = ReadMacInt32(dce + dCtlPosition);
344 if ((length & 0x1ff) || (position & 0x1ff))
345 return set_dsk_err(paramErr);
346
347 size_t actual = 0;
348 if ((ReadMacInt16(pb + ioTrap) & 0xff) == aRdCmd) {
349
350 // Read
351 actual = Sys_read(info->fh, buffer, position, length);
352 if (actual != length)
353 return set_dsk_err(readErr);
354
355 // Clear TagBuf
356 WriteMacInt32(0x2fc, 0);
357 WriteMacInt32(0x300, 0);
358 WriteMacInt32(0x304, 0);
359
360 } else {
361
362 // Write
363 if (info->read_only)
364 return set_dsk_err(wPrErr);
365 actual = Sys_write(info->fh, buffer, position, length);
366 if (actual != length)
367 return set_dsk_err(writErr);
368 }
369
370 // Update ParamBlock and DCE
371 WriteMacInt32(pb + ioActCount, actual);
372 WriteMacInt32(dce + dCtlPosition, ReadMacInt32(dce + dCtlPosition) + actual);
373 return set_dsk_err(noErr);
374 }
375
376
377 /*
378 * Driver Control() routine
379 */
380
381 int16 SonyControl(uint32 pb, uint32 dce)
382 {
383 uint16 code = ReadMacInt16(pb + csCode);
384 D(bug("SonyControl %d\n", code));
385
386 // General codes
387 switch (code) {
388 case 1: // KillIO
389 return set_dsk_err(-1);
390
391 case 9: // Track cache
392 return set_dsk_err(noErr);
393
394 case 65: // Periodic action (accRun, "insert" disks on startup)
395 mount_mountable_volumes();
396 PatchAfterStartup(); // Install patches after system startup
397 WriteMacInt16(dce + dCtlFlags, ReadMacInt16(dce + dCtlFlags) & ~0x2000); // Disable periodic action
398 acc_run_called = true;
399 return noErr;
400 }
401
402 // Drive valid?
403 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
404 if (info == drives.end())
405 return set_dsk_err(nsDrvErr);
406
407 // Drive-specific codes
408 int16 err = noErr;
409 switch (code) {
410 case 5: // Verify disk
411 if (ReadMacInt8(info->status + dsDiskInPlace) <= 0)
412 err = verErr;
413 break;
414
415 case 6: // Format disk
416 if (info->read_only)
417 err = wPrErr;
418 else if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
419 if (!SysFormat(info->fh))
420 err = writErr;
421 } else
422 err = offLinErr;
423 break;
424
425 case 7: // Eject
426 if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
427 SysEject(info->fh);
428 WriteMacInt8(info->status + dsDiskInPlace, 0);
429 }
430 break;
431
432 case 8: // Set tag buffer
433 info->tag_buffer = ReadMacInt32(pb + csParam);
434 break;
435
436 case 21: // Get drive icon
437 WriteMacInt32(pb + csParam, SonyDriveIconAddr);
438 break;
439
440 case 22: // Get disk icon
441 WriteMacInt32(pb + csParam, SonyDiskIconAddr);
442 break;
443
444 case 23: // Get drive info
445 if (info->num == 1)
446 WriteMacInt32(pb + csParam, 0x0004); // Internal drive
447 else
448 WriteMacInt32(pb + csParam, 0x0104); // External drive
449 break;
450
451 case 0x5343: // Format and write to disk ('SC'), used by DiskCopy
452 if (!ReadMacInt8(info->status + dsDiskInPlace))
453 err = offLinErr;
454 else if (info->read_only)
455 err = wPrErr;
456 else {
457 void *data = Mac2HostAddr(ReadMacInt32(pb + csParam + 2));
458 size_t actual = Sys_write(info->fh, data, 0, 2880*512);
459 if (actual != 2880*512)
460 err = writErr;
461 }
462 break;
463
464 default:
465 printf("WARNING: Unknown SonyControl(%d)\n", code);
466 err = controlErr;
467 break;
468 }
469
470 return set_dsk_err(err);
471 }
472
473
474 /*
475 * Driver Status() routine
476 */
477
478 int16 SonyStatus(uint32 pb, uint32 dce)
479 {
480 uint16 code = ReadMacInt16(pb + csCode);
481 D(bug("SonyStatus %d\n", code));
482
483 // Drive valid?
484 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
485 if (info == drives.end())
486 return set_dsk_err(nsDrvErr);
487
488 int16 err = noErr;
489 switch (code) {
490 case 6: // Return format list
491 if (ReadMacInt16(pb + csParam) > 0) {
492 uint32 adr = ReadMacInt32(pb + csParam + 2);
493 WriteMacInt16(pb + csParam, 1); // 1 format
494 WriteMacInt32(adr, 2880); // 2880 sectors
495 WriteMacInt32(adr + 4, 0xd2120050); // 2 heads, 18 secs/track, 80 tracks
496 } else
497 err = paramErr;
498 break;
499
500 case 8: // Get drive status
501 Mac2Mac_memcpy(pb + csParam, info->status, 22);
502 break;
503
504 case 10: // Get disk type
505 WriteMacInt32(pb + csParam, ReadMacInt32(info->status + dsMFMDrive) & 0xffffff00 | 0xfe);
506 break;
507
508 case 0x4456: // Duplicator version supported ('DV')
509 WriteMacInt16(pb + csParam, 0x0410);
510 break;
511
512 case 0x5343: // Get address header format byte ('SC')
513 WriteMacInt8(pb + csParam, 0x22); // 512 bytes/sector
514 break;
515
516 default:
517 printf("WARNING: Unknown SonyStatus(%d)\n", code);
518 err = statusErr;
519 break;
520 }
521
522 return set_dsk_err(err);
523 }
524
525
526 /*
527 * Driver interrupt routine (1Hz) - check for volumes to be mounted
528 */
529
530 void SonyInterrupt(void)
531 {
532 if (!acc_run_called)
533 return;
534
535 mount_mountable_volumes();
536 }