ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/sony.cpp
Revision: 1.17
Committed: 2008-01-01T09:40:31Z (16 years, 4 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.16: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * sony.cpp - Replacement .Sony driver (floppy drives)
3 *
4 * Basilisk II (C) 1997-2008 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 D(bug("Looking for disk in drive %d\n", info->num));
199 if (SysIsDiskInserted(info->fh)) {
200 info->read_only = SysIsReadOnly(info->fh);
201 WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk
202 WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0xff : 0);
203 D(bug(" disk inserted, mounting\n"));
204 info->to_be_mounted = true;
205 }
206 return true;
207 } else
208 return false;
209 }
210
211
212 /*
213 * Mount volumes for which the to_be_mounted flag is set
214 * (called during interrupt time)
215 */
216
217 static void mount_mountable_volumes(void)
218 {
219 drive_vec::iterator info, end = drives.end();
220 for (info = drives.begin(); info != end; ++info) {
221
222 #if DISK_INSERT_CHECK
223 // Disk in drive?
224 if (ReadMacInt8(info->status + dsDiskInPlace) == 0) {
225
226 // No, check if disk was inserted
227 if (SysIsDiskInserted(info->fh))
228 SonyMountVolume(info->fh);
229 }
230 #endif
231
232 // Mount disk if flagged
233 if (info->to_be_mounted) {
234 D(bug(" mounting drive %d\n", info->num));
235 M68kRegisters r;
236 r.d[0] = info->num;
237 r.a[0] = 7; // diskEvent
238 Execute68kTrap(0xa02f, &r); // PostEvent()
239 info->to_be_mounted = false;
240 }
241 }
242 }
243
244
245 /*
246 * Set error code in DskErr
247 */
248
249 static int16 set_dsk_err(int16 err)
250 {
251 D(bug("set_dsk_err(%d)\n", err));
252 WriteMacInt16(0x142, err);
253 return err;
254 }
255
256
257 /*
258 * Driver Open() routine
259 */
260
261 int16 SonyOpen(uint32 pb, uint32 dce)
262 {
263 D(bug("SonyOpen\n"));
264
265 // Set up DCE
266 WriteMacInt32(dce + dCtlPosition, 0);
267 WriteMacInt16(dce + dCtlQHdr + qFlags, ReadMacInt16(dce + dCtlQHdr + qFlags) & 0xff00 | 3); // Version number, must be >=3 or System 8 will replace us
268 acc_run_called = false;
269
270 // Install driver again with refnum -2 (HD20)
271 uint32 utab = ReadMacInt32(0x11c);
272 WriteMacInt32(utab + 4, ReadMacInt32(utab + 16));
273
274 // Set up fake SonyVars
275 WriteMacInt32(0x134, 0xdeadbeef);
276
277 // Clear DskErr
278 set_dsk_err(0);
279
280 // Install drives
281 drive_vec::iterator info, end = drives.end();
282 for (info = drives.begin(); info != end; ++info) {
283
284 info->num = FindFreeDriveNumber(1);
285 info->to_be_mounted = false;
286 info->tag_buffer = 0;
287
288 if (info->fh) {
289
290 // Allocate drive status record
291 M68kRegisters r;
292 r.d[0] = SIZEOF_DrvSts;
293 Execute68kTrap(0xa71e, &r); // NewPtrSysClear()
294 if (r.a[0] == 0)
295 continue;
296 info->status = r.a[0];
297 D(bug(" DrvSts at %08lx\n", info->status));
298
299 // Set up drive status
300 WriteMacInt16(info->status + dsQType, sony);
301 WriteMacInt8(info->status + dsInstalled, 1);
302 WriteMacInt8(info->status + dsSides, 0xff);
303 WriteMacInt8(info->status + dsTwoSideFmt, 0xff);
304 WriteMacInt8(info->status + dsNewIntf, 0xff);
305 WriteMacInt8(info->status + dsMFMDrive, 0xff);
306 WriteMacInt8(info->status + dsMFMDisk, 0xff);
307 WriteMacInt8(info->status + dsTwoMegFmt, 0xff);
308
309 // Disk in drive?
310 if (SysIsDiskInserted(info->fh)) {
311 WriteMacInt8(info->status + dsDiskInPlace, 1); // Inserted removable disk
312 WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0xff : 0);
313 D(bug(" disk inserted, flagging for mount\n"));
314 info->to_be_mounted = true;
315 }
316
317 // Add drive to drive queue
318 D(bug(" adding drive %d\n", info->num));
319 r.d[0] = (info->num << 16) | (SonyRefNum & 0xffff);
320 r.a[0] = info->status + dsQLink;
321 Execute68kTrap(0xa04e, &r); // AddDrive()
322 }
323 }
324 return noErr;
325 }
326
327
328 /*
329 * Driver Prime() routine
330 */
331
332 int16 SonyPrime(uint32 pb, uint32 dce)
333 {
334 WriteMacInt32(pb + ioActCount, 0);
335
336 // Drive valid and disk inserted?
337 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
338 if (info == drives.end())
339 return set_dsk_err(nsDrvErr);
340 if (!ReadMacInt8(info->status + dsDiskInPlace))
341 return set_dsk_err(offLinErr);
342 WriteMacInt8(info->status + dsDiskInPlace, 2); // Disk accessed
343
344 // Get parameters
345 void *buffer = Mac2HostAddr(ReadMacInt32(pb + ioBuffer));
346 size_t length = ReadMacInt32(pb + ioReqCount);
347 loff_t position = ReadMacInt32(dce + dCtlPosition);
348 if ((length & 0x1ff) || (position & 0x1ff))
349 return set_dsk_err(paramErr);
350
351 size_t actual = 0;
352 if ((ReadMacInt16(pb + ioTrap) & 0xff) == aRdCmd) {
353
354 // Read
355 actual = Sys_read(info->fh, buffer, position, length);
356 if (actual != length)
357 return set_dsk_err(readErr);
358
359 // Clear TagBuf
360 WriteMacInt32(0x2fc, 0);
361 WriteMacInt32(0x300, 0);
362 WriteMacInt32(0x304, 0);
363
364 } else {
365
366 // Write
367 if (info->read_only)
368 return set_dsk_err(wPrErr);
369 actual = Sys_write(info->fh, buffer, position, length);
370 if (actual != length)
371 return set_dsk_err(writErr);
372 }
373
374 // Update ParamBlock and DCE
375 WriteMacInt32(pb + ioActCount, actual);
376 WriteMacInt32(dce + dCtlPosition, ReadMacInt32(dce + dCtlPosition) + actual);
377 return set_dsk_err(noErr);
378 }
379
380
381 /*
382 * Driver Control() routine
383 */
384
385 int16 SonyControl(uint32 pb, uint32 dce)
386 {
387 uint16 code = ReadMacInt16(pb + csCode);
388 D(bug("SonyControl %d\n", code));
389
390 // General codes
391 switch (code) {
392 case 1: // KillIO
393 return set_dsk_err(-1);
394
395 case 9: // Track cache
396 return set_dsk_err(noErr);
397
398 case 65: // Periodic action (accRun, "insert" disks on startup)
399 mount_mountable_volumes();
400 PatchAfterStartup(); // Install patches after system startup
401 WriteMacInt16(dce + dCtlFlags, ReadMacInt16(dce + dCtlFlags) & ~0x2000); // Disable periodic action
402 acc_run_called = true;
403 return noErr;
404 }
405
406 // Drive valid?
407 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
408 if (info == drives.end())
409 return set_dsk_err(nsDrvErr);
410
411 // Drive-specific codes
412 int16 err = noErr;
413 switch (code) {
414 case 5: // Verify disk
415 if (ReadMacInt8(info->status + dsDiskInPlace) <= 0)
416 err = verErr;
417 break;
418
419 case 6: // Format disk
420 if (info->read_only)
421 err = wPrErr;
422 else if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
423 if (!SysFormat(info->fh))
424 err = writErr;
425 } else
426 err = offLinErr;
427 break;
428
429 case 7: // Eject
430 if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
431 SysEject(info->fh);
432 WriteMacInt8(info->status + dsDiskInPlace, 0);
433 }
434 break;
435
436 case 8: // Set tag buffer
437 info->tag_buffer = ReadMacInt32(pb + csParam);
438 break;
439
440 case 21: // Get drive icon
441 WriteMacInt32(pb + csParam, SonyDriveIconAddr);
442 break;
443
444 case 22: // Get disk icon
445 WriteMacInt32(pb + csParam, SonyDiskIconAddr);
446 break;
447
448 case 23: // Get drive info
449 if (info->num == 1)
450 WriteMacInt32(pb + csParam, 0x0004); // Internal drive
451 else
452 WriteMacInt32(pb + csParam, 0x0104); // External drive
453 break;
454
455 case 0x5343: // Format and write to disk ('SC'), used by DiskCopy
456 if (!ReadMacInt8(info->status + dsDiskInPlace))
457 err = offLinErr;
458 else if (info->read_only)
459 err = wPrErr;
460 else {
461 void *data = Mac2HostAddr(ReadMacInt32(pb + csParam + 2));
462 size_t actual = Sys_write(info->fh, data, 0, 2880*512);
463 if (actual != 2880*512)
464 err = writErr;
465 }
466 break;
467
468 default:
469 printf("WARNING: Unknown SonyControl(%d)\n", code);
470 err = controlErr;
471 break;
472 }
473
474 return set_dsk_err(err);
475 }
476
477
478 /*
479 * Driver Status() routine
480 */
481
482 int16 SonyStatus(uint32 pb, uint32 dce)
483 {
484 uint16 code = ReadMacInt16(pb + csCode);
485 D(bug("SonyStatus %d\n", code));
486
487 // Drive valid?
488 drive_vec::iterator info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
489 if (info == drives.end())
490 return set_dsk_err(nsDrvErr);
491
492 int16 err = noErr;
493 switch (code) {
494 case 6: // Return format list
495 if (ReadMacInt16(pb + csParam) > 0) {
496 uint32 adr = ReadMacInt32(pb + csParam + 2);
497 WriteMacInt16(pb + csParam, 1); // 1 format
498 WriteMacInt32(adr, 2880); // 2880 sectors
499 WriteMacInt32(adr + 4, 0xd2120050); // 2 heads, 18 secs/track, 80 tracks
500 } else
501 err = paramErr;
502 break;
503
504 case 8: // Get drive status
505 Mac2Mac_memcpy(pb + csParam, info->status, 22);
506 break;
507
508 case 10: // Get disk type
509 WriteMacInt32(pb + csParam, ReadMacInt32(info->status + dsMFMDrive) & 0xffffff00 | 0xfe);
510 break;
511
512 case 0x4456: // Duplicator version supported ('DV')
513 WriteMacInt16(pb + csParam, 0x0410);
514 break;
515
516 case 0x5343: // Get address header format byte ('SC')
517 WriteMacInt8(pb + csParam, 0x22); // 512 bytes/sector
518 break;
519
520 default:
521 printf("WARNING: Unknown SonyStatus(%d)\n", code);
522 err = statusErr;
523 break;
524 }
525
526 return set_dsk_err(err);
527 }
528
529
530 /*
531 * Driver interrupt routine (1Hz) - check for volumes to be mounted
532 */
533
534 void SonyInterrupt(void)
535 {
536 if (!acc_run_called)
537 return;
538
539 mount_mountable_volumes();
540 }