/***************************************************************************** * pce * *****************************************************************************/ /***************************************************************************** * File name: src/arch/macplus/sony.c * * Created: 2007-11-15 by Hampa Hug * * Copyright: (C) 2007-2023 Hampa Hug * *****************************************************************************/ /***************************************************************************** * This program is free software. You can redistribute it and / or modify it * * under the terms of the GNU General Public License version 2 as published * * by the Free Software Foundation. * * * * This program is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY, without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * * Public License for more details. * *****************************************************************************/ #include "main.h" #include "sony.h" #include #include #include #include #include #include #define MAC_HOOK_SONY 16 #define MAC_HOOK_SONY_OPEN (MAC_HOOK_SONY + 0) #define MAC_HOOK_SONY_PRIME (MAC_HOOK_SONY + 1) #define MAC_HOOK_SONY_CTRL (MAC_HOOK_SONY + 2) #define MAC_HOOK_SONY_STATUS (MAC_HOOK_SONY + 3) #define MAC_HOOK_SONY_CLOSE (MAC_HOOK_SONY + 4) /* sony variable offsets */ #define SONY_TRACK 0 /* current track */ #define SONY_WPROT 2 /* FF = write protected, 00 = writeable */ #define SONY_DISKINPLACE 3 /* 0 = no disk, 1 = inserted, 2 = accessed */ #define SONY_INSTALLED 4 /* 0 = unknown, 1 = installed, ff = not installed */ #define SONY_SIDES 5 /* 0 single sided, ff double sided */ #define SONY_QLINK 6 #define SONY_QTYPE 10 #define SONY_QDRIVENO 12 #define SONY_QREFNUM 14 /* driver reference number (0xfffb) */ #define SONY_QFSID 16 #define SONY_TWOSIDEFMT 18 /* ff double-sided, 0 single-sided */ #define SONY_NEWIF 19 /* ff new 800K interface, 0 old 400K interface */ #define SONY_DRIVEERRS 20 /* drive soft errors */ /* parameter block offsets */ #define qLink 0 #define qType 4 #define ioTrap 6 #define ioCmdAddr 8 #define ioCompletion 12 #define ioResult 16 #define ioNamePtr 18 #define ioVRefNum 22 #define ioRefNum 24 #define ioVersNum 26 #define ioPermssn 27 #define ioMisc 28 #define ioBuffer 32 #define ioReqCount 36 #define ioActCount 40 #define ioPosMode 44 #define ioPosOffset 46 #define csCode 26 #define csParam 28 /* device control entry offsets */ #define dCtlDriver 0 #define dCtlFlags 4 #define dCtlQHdr 6 #define dCtlPosition 16 #define dCtlStorage 20 #define dCtlRefNum 24 #define dCtlCurTicks 26 /* positioning modes */ #define fsAtMark 0 #define fsFromStart 1 #define fsFromMark 3 #define rdVerify 64 /* trap word flags */ #define asyncTrpBit 0x0100 #define noQueueBit 0x0200 /* result codes */ #define noErr 0 #define controlErr -17 #define statusErr -18 #define readErr -19 #define writeErr -20 #define abortErr -27 #define wPrErr -44 #define paramErr -50 #define nsDrvErr -56 #define noDriveErr -64 #define offLineErr -65 #define verErr -84 void mac_sony_init (mac_sony_t *sony, int enable) { unsigned i; sony->open = 0; sony->patched = 0; sony->enable = (enable != 0); sony->mem = NULL; sony->dsks = NULL; sony->check_addr = 0; sony->icon_addr[0] = 0; sony->icon_addr[1] = 0; sony->tag_buf = 0; sony->format_hd_as_dd = 0; sony->format_cnt = 0; for (i = 0; i < SONY_DRIVES; i++) { sony->delay_val[i] = 0; sony->delay_cnt[i] = 0; } } void mac_sony_free (mac_sony_t *sony) { } void mac_sony_set_mem (mac_sony_t *sony, memory_t *mem) { sony->mem = mem; } void mac_sony_set_disks (mac_sony_t *sony, disks_t *dsks) { sony->dsks = dsks; } static unsigned long mac_sony_get_vars (mac_sony_t *sony, unsigned drive) { unsigned long ret; ret = mem_get_uint32_be (sony->mem, 0x0134); if ((drive >= 1) && (drive <= SONY_DRIVES)) { ret += 8 + 66 * drive; } return (ret); } static unsigned long mac_sony_find_pcex (mac_sony_t *sony, unsigned long addr) { unsigned long cnt; if (mem_get_uint32_be (sony->mem, addr) != 0x50434558) { return (0); } cnt = mem_get_uint32_be (sony->mem, addr + 8); if (cnt < 4) { return (0); } sony->check_addr = addr + mem_get_uint32_be (sony->mem, addr + 16); sony->icon_addr[0] = addr + mem_get_uint32_be (sony->mem, addr + 20); sony->icon_addr[1] = addr + mem_get_uint32_be (sony->mem, addr + 24); addr += mem_get_uint32_be (sony->mem, addr + 12); return (addr); } static unsigned long mac_sony_find (mac_sony_t *sony, unsigned long addr, unsigned long size) { unsigned long sony_addr; while (size > 0) { addr += 1; size -= 1; if (mem_get_uint16_be (sony->mem, addr - 1) != 0x052e) { continue; } if (mem_get_uint32_be (sony->mem, addr + 1) != 0x536f6e79) { continue; } sony_addr = addr - 19; if (mem_get_uint16_be (sony->mem, sony_addr) != 0x4f00) { continue; } return (sony_addr); } return (0); } static void mac_sony_unpatch_rom (mac_sony_t *sony) { unsigned i, j; unsigned sofs; unsigned long sadr; unsigned char *buf; if (sony->patched == 0) { return; } if ((sony->sony_addr == 0) || (sony->pcex_addr == 0)) { return; } buf = sony->patch_buf; for (i = 0; i < 5; i++) { sofs = mem_get_uint16_be (sony->mem, sony->sony_addr + 8 + 2 * i); sadr = sony->sony_addr + sofs; for (j = 0; j < 6; j++) { mem_set_uint8_rw (sony->mem, sadr + j, *(buf++)); } } sony->patched = 0; } static void mac_sony_patch_rom (mac_sony_t *sony) { unsigned i, j; unsigned sofs, dofs; unsigned long sadr, dadr; unsigned char *buf; if ((sony->sony_addr == 0) || (sony->pcex_addr == 0)) { return; } buf = sony->patch_buf; for (i = 0; i < 5; i++) { sofs = mem_get_uint16_be (sony->mem, sony->sony_addr + 8 + 2 * i); sadr = sony->sony_addr + sofs; dofs = mem_get_uint16_be (sony->mem, sony->pcex_addr + 8 + 2 * i); dadr = sony->pcex_addr + dofs; for (j = 0; j < 6; j++) { *(buf++) = mem_get_uint8 (sony->mem, sadr + j); } mem_set_uint8_rw (sony->mem, sadr + 0, 0x4e); mem_set_uint8_rw (sony->mem, sadr + 1, 0xf9); mem_set_uint8_rw (sony->mem, sadr + 2, (dadr >> 24) & 0xff); mem_set_uint8_rw (sony->mem, sadr + 3, (dadr >> 16) & 0xff); mem_set_uint8_rw (sony->mem, sadr + 4, (dadr >> 8) & 0xff); mem_set_uint8_rw (sony->mem, sadr + 5, dadr & 0xff); #ifdef DEBUG_SONY mac_log_deb ("sony: patch %u: %06lx -> %06lx\n", i, sadr, dadr); #endif } } void mac_sony_patch (mac_sony_t *sony) { if (sony->enable == 0) { return; } if (sony->patched) { return; } sony->patched = 1; sony->pcex_addr = 0; sony->sony_addr = 0; sony->pcex_addr = mac_sony_find_pcex (sony, 0xf80000); if (sony->pcex_addr == 0) { pce_log_tag (MSG_ERR, "SONY:", "PCE ROM extension not found\n"); return; } pce_log_tag (MSG_INF, "SONY:", "PCE ROM extension at 0x%06lx\n", sony->pcex_addr); sony->sony_addr = mac_sony_find (sony, 0x400000, 1024UL * 1024UL); if (sony->sony_addr == 0) { pce_log_tag (MSG_ERR, "SONY:", "sony driver not found\n"); return; } pce_log_tag (MSG_INF, "SONY:", "sony driver at 0x%06lx\n", sony->sony_addr); mac_sony_patch_rom (sony); } void mac_sony_set_delay (mac_sony_t *sony, unsigned drive, unsigned delay) { if (drive < SONY_DRIVES) { sony->delay_val[drive] = delay; sony->delay_cnt[drive] = delay; } } void mac_sony_insert (mac_sony_t *sony, unsigned drive) { unsigned long vars; disk_t *dsk; if (sony->open == 0) { return; } if ((drive < 1) || (drive > SONY_DRIVES)) { return; } dsk = dsks_get_disk (sony->dsks, drive); if (dsk == NULL) { return; } vars = mac_sony_get_vars (sony, drive); if (mem_get_uint8 (sony->mem, vars + SONY_DISKINPLACE) == 0x00) { pce_log_tag (MSG_INF, "SONY:", "insert drive %u\n", drive); mem_set_uint8 (sony->mem, vars + SONY_DISKINPLACE, 0x01); if (dsk_get_block_cnt (dsk) < 1600) { mem_set_uint8 (sony->mem, vars + SONY_TWOSIDEFMT, 0x00); mem_set_uint8 (sony->mem, vars + SONY_SIDES, 0x00); mem_set_uint8 (sony->mem, vars + SONY_NEWIF, 0x00); } else { mem_set_uint8 (sony->mem, vars + SONY_TWOSIDEFMT, 0xff); mem_set_uint8 (sony->mem, vars + SONY_SIDES, 0xff); mem_set_uint8 (sony->mem, vars + SONY_NEWIF, 0xff); } if (dsk_get_readonly (dsk)) { mem_set_uint8 (sony->mem, vars + SONY_WPROT, 0xff); } else { mem_set_uint8 (sony->mem, vars + SONY_WPROT, 0x00); } } } /* * Check if disks need to be inserted. */ int mac_sony_check (mac_sony_t *sony) { int check; unsigned i; unsigned long vars; disk_t *dsk; if (sony->open == 0) { return (0); } check = 0; for (i = 0; i < SONY_DRIVES; i++) { if (sony->delay_cnt[i] > 0) { sony->delay_cnt[i] -= 1; if (sony->delay_cnt[i] == 0) { mac_sony_insert (sony, i + 1); } } dsk = dsks_get_disk (sony->dsks, i + 1); if (dsk != NULL) { vars = mac_sony_get_vars (sony, i + 1); if (mem_get_uint8 (sony->mem, vars + SONY_DISKINPLACE) == 0x01) { check = 1; } } } return (check); } static void mac_sony_open (mac_sony_t *sony) { #ifdef DEBUG_SONY mac_log_deb ("sony: open\n"); #endif sony->open = 1; if (mac_sony_check (sony)) { sony->pc = sony->check_addr; } } static unsigned long mac_sony_get_pblk (mac_sony_t *sony, unsigned ofs, unsigned size) { if (size == 1) { return (mem_get_uint8 (sony->mem, sony->a0 + ofs)); } else if (size == 2) { return (mem_get_uint16_be (sony->mem, sony->a0 + ofs)); } else if (size == 4) { return (mem_get_uint32_be (sony->mem, sony->a0 + ofs)); } return (0); } static void mac_sony_set_pblk (mac_sony_t *sony, unsigned ofs, unsigned size, unsigned long val) { if (size == 1) { mem_set_uint8 (sony->mem, sony->a0 + ofs, val); } else if (size == 2) { mem_set_uint16_be (sony->mem, sony->a0 + ofs, val); } else if (size == 4) { mem_set_uint32_be (sony->mem, sony->a0 + ofs, val); } } static unsigned long mac_sony_get_dctl (mac_sony_t *sony, unsigned ofs, unsigned size) { if (size == 1) { return (mem_get_uint8 (sony->mem, sony->a1 + ofs)); } else if (size == 2) { return (mem_get_uint16_be (sony->mem, sony->a1 + ofs)); } else if (size == 4) { return (mem_get_uint32_be (sony->mem, sony->a1 + ofs)); } return (0); } static void mac_sony_set_dctl (mac_sony_t *sony, unsigned ofs, unsigned size, unsigned long val) { if (size == 1) { mem_set_uint8 (sony->mem, sony->a1 + ofs, val); } else if (size == 2) { mem_set_uint16_be (sony->mem, sony->a1 + ofs, val); } else if (size == 4) { mem_set_uint32_be (sony->mem, sony->a1 + ofs, val); } } static void mac_sony_return (mac_sony_t *sony, unsigned res, int rts) { unsigned trap; unsigned long val; sony->d0 = (res & 0x8000) ? (0xffff0000 | res) : 0; trap = mac_sony_get_pblk (sony, ioTrap, 2); mac_sony_set_pblk (sony, ioResult, 2, res); if ((rts == 0) && ((trap & noQueueBit) == 0)) { val = mem_get_uint32_be (sony->mem, 0x0134); val = mem_get_uint32_be (sony->mem, val); sony->a1 = val; sony->pc = mem_get_uint32_be (sony->mem, 0x08fc); } } static unsigned long mac_sony_get_offset (mac_sony_t *sony) { unsigned posmode; unsigned long ofs; posmode = mac_sony_get_pblk (sony, ioPosMode, 2); switch (posmode & 0x0f) { case fsAtMark: ofs = mac_sony_get_dctl (sony, dCtlPosition, 4); break; case fsFromStart: ofs = mac_sony_get_pblk (sony, ioPosOffset, 4); break; case fsFromMark: ofs = mac_sony_get_pblk (sony, ioPosOffset, 4); ofs += mac_sony_get_dctl (sony, dCtlPosition, 4); break; default: return (0); } return (ofs); } /* * Get the disk type from a number of blocks */ static unsigned mac_sony_get_disk_type (unsigned long blk) { if (blk < ((800 + 1440) / 2)) { return (0); } else if (blk < ((1440 + 1600) / 2)) { return (2); } else if (blk < ((1600 + 2880) / 2)) { return (1); } else if (blk < (2 * 2880)) { return (3); } return (255); } static int mac_sony_get_chs (unsigned long blk, unsigned long lba, unsigned *c, unsigned *h, unsigned *s) { unsigned type; unsigned i, hn, sn; type = mac_sony_get_disk_type (blk); if ((type == 0) || (type == 1)) { hn = (type == 0) ? 1 : 2; sn = 12; *c = 0; for (i = 0; i < 5; i++) { if (lba < (16 * hn * sn)) { *s = (lba % sn); *h = (lba / sn) % hn; *c += lba / (sn * hn); return (0); } lba -= 16 * hn * sn; *c += 16; sn -= 1; } return (1); } else if (type == 2) { *s = (lba % 9) + 1; *h = (lba / 9) % 2; *c = lba / 18; } else if (type == 3) { *s = (lba % 18) + 1; *h = (lba / 18) % 2; *c = lba / 36; } else { mac_log_deb ("sony: chs error (blk=%lu, lba=%lu)\n", blk, lba); return (1); } return (0); } static int mac_sony_read_block (disk_t *dsk, void *buf, void *tag, unsigned long idx) { unsigned c, h, s; unsigned cnt; if (dsk_get_type (dsk) != PCE_DISK_PSI) { memset (tag, 0, 12); if (dsk_read_lba (dsk, buf, idx, 1)) { return (1); } return (0); } if (mac_sony_get_chs (dsk_get_block_cnt (dsk), idx, &c, &h, &s)) { return (1); } dsk_psi_read_tags (dsk->ext, tag, 12, c, h, s, 0); cnt = 512; if (dsk_psi_read_chs (dsk->ext, buf, &cnt, c, h, s, 0) != PCE_BLK_PSI_OK) { mac_log_deb ("sony: read error at %u/%u/%u\n", c, h, s); return (1); } return (0); } static int mac_sony_write_block (disk_t *dsk, const void *buf, const void *tag, unsigned long idx) { unsigned c, h, s; unsigned type; unsigned cnt; if (dsk_get_type (dsk) != PCE_DISK_PSI) { if (dsk_write_lba (dsk, buf, idx, 1)) { return (1); } return (0); } if (mac_sony_get_chs (dsk_get_block_cnt (dsk), idx, &c, &h, &s)) { return (1); } type = mac_sony_get_disk_type (dsk_get_block_cnt (dsk)); if ((type == 0) || (type == 1)) { dsk_psi_write_tags (dsk->ext, tag, 12, c, h, s, 0); } cnt = 512; if (dsk_psi_write_chs (dsk->ext, buf, &cnt, c, h, s, 0) != PCE_BLK_PSI_OK) { mac_log_deb ("sony: write error at %u/%u/%u\n", c, h, s); return (1); } return (0); } static void mac_sony_prime_read (mac_sony_t *sony, unsigned drive) { unsigned long addr, vars; unsigned long ofs, cnt; unsigned long i, n; unsigned j; disk_t *dsk; unsigned char buf[512]; unsigned char tag[12]; unsigned posmode; ofs = mac_sony_get_offset (sony); cnt = mac_sony_get_pblk (sony, ioReqCount, 4); addr = mac_sony_get_pblk (sony, ioBuffer, 4) & 0x00ffffff; posmode = mac_sony_get_pblk (sony, ioPosMode, 2); #ifdef DEBUG_SONY mac_log_deb ("sony: prime: read (drive=%u, ofs=0x%08lx, cnt=0x%04lx, addr=0x%08lx)\n", drive, ofs, cnt, addr ); #endif dsk = dsks_get_disk (sony->dsks, drive); if (dsk == NULL) { mac_sony_return (sony, offLineErr, 0); return; } if (posmode & 0x40) { /* verify */ mac_sony_return (sony, noErr, 0); return; } if ((ofs & 511) || (cnt & 511)) { mac_log_deb ("sony: non-aligned read\n"); mac_sony_return (sony, paramErr, 0); return; } n = cnt / 512; for (i = 0; i < n; i++) { if (mac_sony_read_block (dsk, buf, tag, (ofs / 512) + i)) { mac_log_deb ("sony: read error at block %lu\n", (ofs / 512) + i ); mac_sony_return (sony, 0xffff, 0); return; } for (j = 0; j < 512; j++) { mem_set_uint8 (sony->mem, addr + 512 * i + j, buf[j]); } for (j = 0; j < 12; j++) { mem_set_uint8 (sony->mem, 0x2fc + j, tag[j]); } if (sony->tag_buf != 0) { for (j = 0; j < 12; j++) { mem_set_uint8 (sony->mem, sony->tag_buf + 12 * i + j, tag[j]); } } } vars = mac_sony_get_vars (sony, drive); mem_set_uint8 (sony->mem, vars + SONY_DISKINPLACE, 0x02); mac_sony_set_pblk (sony, ioActCount, 4, cnt); ofs = mac_sony_get_dctl (sony, dCtlPosition, 4); mac_sony_set_dctl (sony, dCtlPosition, 4, ofs + cnt); mac_sony_return (sony, noErr, 0); } static void mac_sony_prime_write (mac_sony_t *sony, unsigned drive) { unsigned long addr; unsigned long ofs, cnt; unsigned relblk; unsigned long i, n; unsigned j; disk_t *dsk; unsigned char buf[512]; unsigned char tag[12]; ofs = mac_sony_get_offset (sony); cnt = mac_sony_get_pblk (sony, ioReqCount, 4); addr = mac_sony_get_pblk (sony, ioBuffer, 4) & 0x00ffffff; #ifdef DEBUG_SONY mac_log_deb ("sony: prime: write (drive=%u, ofs=0x%08lx, cnt=0x%04lx, addr=0x%08lx)\n", drive, ofs, cnt, addr ); #endif dsk = dsks_get_disk (sony->dsks, drive); if (dsk == NULL) { mac_sony_return (sony, offLineErr, 0); return; } if (dsk_get_readonly (dsk)) { mac_sony_return (sony, wPrErr, 0); return; } if ((cnt & 511) || (ofs & 511)) { mac_log_deb ("sony: non-aligned write\n"); mac_sony_return (sony, paramErr, 0); return; } memset (tag, 0, 12); relblk = mem_get_uint16_be (sony->mem, 0x302); n = cnt / 512; for (i = 0; i < n; i++) { for (j = 0; j < 512; j++) { buf[j] = mem_get_uint8 (sony->mem, addr + 512 * i + j); } if (sony->tag_buf != 0) { for (j = 0; j < 12; j++) { tag[j] = mem_get_uint8 (sony->mem, sony->tag_buf + 12 * i + j); mem_set_uint8 (sony->mem, 0x2fc + j, tag[j]); } } else { mem_set_uint16_be (sony->mem, 0x302, relblk + i); for (j = 0; j < 12; j++) { tag[j] = mem_get_uint8 (sony->mem, 0x2fc + j); } } if (mac_sony_write_block (dsk, buf, tag, (ofs / 512) + i)) { mac_log_deb ("sony: write error at block %lu\n", (ofs / 512) + i ); mac_sony_return (sony, 0xffff, 0); return; } } mac_sony_set_pblk (sony, ioActCount, 4, cnt); ofs = mac_sony_get_dctl (sony, dCtlPosition, 4); mac_sony_set_dctl (sony, dCtlPosition, 4, ofs + cnt); mac_sony_return (sony, noErr, 0); } static void mac_sony_prime (mac_sony_t *sony) { unsigned long vars; unsigned trap, vref; trap = mac_sony_get_pblk (sony, ioTrap, 2); vref = mac_sony_get_pblk (sony, ioVRefNum, 2); if ((vref < 1) || (vref > SONY_DRIVES)) { mac_sony_return (sony, nsDrvErr, 0); return; } vars = mac_sony_get_vars (sony, vref); if (mem_get_uint8 (sony->mem, vars + SONY_DISKINPLACE) == 0) { mac_sony_return (sony, offLineErr, 0); return; } mem_set_uint8 (sony->mem, vars + SONY_DISKINPLACE, 0x02); switch (trap & 0xff) { case 2: /* read */ mac_sony_prime_read (sony, vref); break; case 3: /* write */ mac_sony_prime_write (sony, vref); break; default: mac_log_deb ("sony: prime: unknown (trap=0x%04x)\n", trap); mac_sony_return (sony, 0xffef, 0); break; } } static int mac_sony_format (disk_t *dsk, unsigned long blk) { unsigned long i, n; unsigned c, h, s, hn, sn; unsigned type; unsigned char buf[512]; psi_sct_t *sct; disk_psi_t *psi; if (dsk_get_type (dsk) != PCE_DISK_PSI) { n = dsk_get_block_cnt (dsk); if (n != blk) { return (1); } memset (buf, 0x00, 512); for (i = 0; i < n; i++) { dsk_write_lba (dsk, buf, i, 1); } return (0); } psi = dsk->ext; memset (buf, 0, 12); type = mac_sony_get_disk_type (blk); dsk_psi_erase_disk (psi); if ((type == 0) || (type == 1)) { dsk_psi_set_encoding (psi, PSI_ENC_GCR); hn = (type == 0) ? 1 : 2; sn = 13; for (c = 0; c < 80; c++) { if ((c & 15) == 0) { sn -= 1; } for (h = 0; h < hn; h++) { for (s = 0; s < sn; s++) { dsk_psi_format_sector (psi, c, h, c, h, s, 512, 0); sct = psi_img_get_sector (psi->img, c, h, s, 1); if (sct != NULL) { psi_sct_set_tags (sct, buf, 12); } } } } } else if ((type == 2) || (type == 3)) { dsk_psi_set_encoding (psi, (type == 2) ? PSI_ENC_MFM_DD : PSI_ENC_MFM_HD); sn = (type == 2) ? 9 : 18; for (c = 0; c < 80; c++) { for (h = 0; h < 2; h++) { for (s = 0; s < sn; s++) { dsk_psi_format_sector (psi, c, h, c, h, s + 1, 512, 0); } } } } else { return (1); } mac_log_deb ("sony: formatted disk (%lu blocks)\n", dsk_get_block_cnt (dsk)); return (0); } static void mac_sony_ctl_verify (mac_sony_t *sony) { unsigned vref; disk_t *dsk; vref = mac_sony_get_pblk (sony, ioVRefNum, 2); #ifdef DEBUG_SONY mac_log_deb ("sony: control: verify (drive=%u)\n", vref); #endif if ((vref < 1) || (vref > SONY_DRIVES)) { mac_sony_return (sony, nsDrvErr, 0); return; } dsk = dsks_get_disk (sony->dsks, vref); if (dsk == NULL) { mac_sony_return (sony, noDriveErr, 0); return; } mac_sony_return (sony, noErr, 0); } static void mac_sony_ctl_eject (mac_sony_t *sony) { unsigned vref; unsigned long vars; vref = mac_sony_get_pblk (sony, ioVRefNum, 2); #ifdef DEBUG_SONY mac_log_deb ("sony: control eject (drive=%u)\n", vref); #endif if ((vref < 1) || (vref > SONY_DRIVES)) { mac_sony_return (sony, nsDrvErr, 0); return; } vars = mac_sony_get_vars (sony, vref); mem_set_uint8 (sony->mem, vars + SONY_DISKINPLACE, 0x00); mem_set_uint8 (sony->mem, vars + SONY_WPROT, 0x00); mem_set_uint8 (sony->mem, vars + SONY_TWOSIDEFMT, 0x00); mac_sony_return (sony, noErr, 0); } static void mac_sony_ctl_set_tag_buf (mac_sony_t *sony) { unsigned long tagbuf; tagbuf = mac_sony_get_pblk (sony, csParam, 4); #ifdef DEBUG_SONY mac_log_deb ("sony: control: set tag buffer (buf=0x%08lx)\n", tagbuf); #endif sony->tag_buf = tagbuf & 0x00ffffff; mac_sony_return (sony, noErr, 0); } static void mac_sony_ctl_format (mac_sony_t *sony) { unsigned vref, format; unsigned long blk; unsigned long vars; disk_t *dsk; vref = mac_sony_get_pblk (sony, ioVRefNum, 2); format = mac_sony_get_pblk (sony, csParam, 2); #ifdef DEBUG_SONY mac_log_deb ("sony: control format (drive=%u, format=%u)\n", vref, format); #endif if ((vref < 1) || (vref > SONY_DRIVES)) { mac_sony_return (sony, nsDrvErr, 0); return; } dsk = dsks_get_disk (sony->dsks, vref); if (dsk == NULL) { mac_sony_return (sony, noDriveErr, 0); return; } if (dsk->readonly) { mac_sony_return (sony, wPrErr, 0); return; } if ((format > 0) && (format <= sony->format_cnt)) { blk = sony->format_list[2 * (format - 1)]; } else { blk = dsk_get_block_cnt (dsk); if (dsk_get_type (dsk) == PCE_DISK_PSI) { if (format == 1) { blk = 800; } else if (format == 2) { blk = 1600; } if (blk == 0) { blk = 800; } } } if (mac_sony_format (dsk, blk)) { mac_sony_return (sony, paramErr, 0); return; } vars = mac_sony_get_vars (sony, vref); mem_set_uint16_be (sony->mem, vars + 18, blk); mem_set_uint16_be (sony->mem, vars + 20, blk >> 16); mac_sony_return (sony, noErr, 0); } static void mac_sony_ctl_get_icon (mac_sony_t *sony, int which) { unsigned vref; unsigned long addr, addr1, addr2; disk_t *dsk; vref = mac_sony_get_pblk (sony, ioVRefNum, 2); #ifdef DEBUG_SONY mac_log_deb ("sony: control: get %s icon (drive=%u)\n", which ? "media" : "drive", vref ); #endif if ((vref < 1) || (vref > SONY_DRIVES)) { mac_sony_return (sony, nsDrvErr, 0); return; } addr1 = sony->icon_addr[0]; addr2 = sony->icon_addr[1]; dsk = dsks_get_disk (sony->dsks, vref); if (dsk == NULL) { addr = addr1; } else { switch (dsk_get_block_cnt (dsk)) { case 800: case 1600: case 1440: case 2880: addr = addr1; break; default: addr = addr2; break; } } mac_sony_set_pblk (sony, csParam, 4, addr); mac_sony_return (sony, noErr, 0); } static void mac_sony_ctl_get_drive_info (mac_sony_t *sony) { unsigned vref, val; vref = mac_sony_get_pblk (sony, ioVRefNum, 2); #ifdef DEBUG_SONY mac_log_deb ("sony: control: get drive info (drive=%u)\n", vref); #endif if ((vref < 1) || (vref > SONY_DRIVES)) { mac_sony_return (sony, nsDrvErr, 0); return; } val = vref - 1; val = ((val << 3) & 8) | ((val >> 1) & 1); mac_sony_set_pblk (sony, csParam, 4, (val << 8) | 0x04); mac_sony_return (sony, noErr, 0); } static void mac_sony_ctl_format_copy (mac_sony_t *sony) { unsigned i; unsigned vref, format, type; unsigned long data, tags; unsigned long idx, blk; unsigned char buf[512]; unsigned char tag[12]; disk_t *dsk; vref = mac_sony_get_pblk (sony, ioVRefNum, 2); format = mac_sony_get_pblk (sony, csParam, 2); data = mac_sony_get_pblk (sony, csParam + 2, 4); tags = mac_sony_get_pblk (sony, csParam + 6, 4); #ifdef DEBUG_SONY mac_log_deb ("sony: control: format/copy (drive=%u, format=%u, data=0x%08lx, tags=0x%08lx)\n", vref, format, data, tags ); #endif if ((vref < 1) || (vref > SONY_DRIVES)) { mac_sony_return (sony, nsDrvErr, 0); return; } dsk = dsks_get_disk (sony->dsks, vref); if (dsk == NULL) { mac_sony_return (sony, noDriveErr, 0); return; } if (dsk->readonly) { mac_sony_return (sony, wPrErr, 0); return; } if ((format > 0) && (format <= sony->format_cnt)) { blk = sony->format_list[2 * (format - 1)]; } else { mac_sony_return (sony, paramErr, 0); return; } type = mac_sony_get_disk_type (blk); if (mac_sony_format (dsk, blk)) { mac_sony_return (sony, paramErr, 0); return; } data &= 0x00ffffff; tags &= 0x00ffffff; memset (tag, 0, 12); for (idx = 0; idx < blk; idx++) { for (i = 0; i < 512; i++) { buf[i] = mem_get_uint8 (sony->mem, data + i); } if ((type != 2) && (type != 3)) { for (i = 0; i < 12; i++) { tag[i] = mem_get_uint8 (sony->mem, tags + i); } } if (mac_sony_write_block (dsk, buf, tag, idx)) { mac_sony_return (sony, 0xffff, 0); return; } data += 512; tags += 12; } mac_sony_return (sony, noErr, 0); } static void mac_sony_control (mac_sony_t *sony) { unsigned cscode; cscode = mac_sony_get_pblk (sony, csCode, 2); switch (cscode) { case 1: /* kill io */ mac_sony_return (sony, abortErr, 1); break; case 5: /* verify disk */ mac_sony_ctl_verify (sony); break; case 7: /* eject disk */ mac_sony_ctl_eject (sony); return; case 8: /* set tag buffer */ mac_sony_ctl_set_tag_buf (sony); break; case 9: /* track cache control */ mac_sony_return (sony, 0xffc8, 0); break; case 6: /* format disk */ mac_sony_ctl_format (sony); return; case 21: /* get drive icon */ mac_sony_ctl_get_icon (sony, 0); return; case 22: /* get media icon */ mac_sony_ctl_get_icon (sony, 1); return; case 23: /* get drive info */ mac_sony_ctl_get_drive_info (sony); return; case 21315: /* FmtCopy */ mac_sony_ctl_format_copy (sony); return; default: mac_log_deb ("sony: control: unknown (opcode=0x%04x)\n", cscode); mac_sony_return (sony, controlErr, 0); return; } } static void mac_sony_status_format_list (mac_sony_t *sony) { unsigned i; unsigned long ptr; unsigned vref, cnt; unsigned long blk; unsigned long *list; disk_t *dsk; vref = mac_sony_get_pblk (sony, ioVRefNum, 2); cnt = mac_sony_get_pblk (sony, csParam, 2); ptr = mac_sony_get_pblk (sony, csParam + 2, 4); #ifdef DEBUG_SONY mac_log_deb ("sony: status: get format list (drive=%u, maxfmt=%u)\n", vref, cnt ); #endif if ((vref < 1) || (vref > SONY_DRIVES)) { mac_sony_return (sony, nsDrvErr, 0); return; } dsk = dsks_get_disk (sony->dsks, vref); if (dsk == NULL) { mac_sony_return (sony, noDriveErr, 0); return; } blk = dsk_get_block_cnt (dsk); list = sony->format_list; if (dsk_get_type (dsk) == PCE_DISK_PSI) { sony->format_cnt = 4; list[0] = 800; list[1] = 0x810a0050; list[2] = 1600; list[3] = 0x820a0050; list[4] = 1440; list[5] = 0x82090050; list[6] = 2880; list[7] = 0x92120050; switch (mac_sony_get_disk_type (blk)) { case 0: list[1] |= 0x40000000; break; case 1: list[3] |= 0x40000000; break; case 2: list[5] |= 0x40000000; break; case 3: default: if (sony->format_hd_as_dd) { list[7] |= 0x40000000; } else { sony->format_cnt = 1; list[0] = 2880; list[1] = 0xd2120050; } break; } } else { sony->format_cnt = 1; list[0] = blk; list[1] = 0; } if (cnt > sony->format_cnt) { cnt = sony->format_cnt; } for (i = 0; i < cnt; i++) { mem_set_uint32_be (sony->mem, ptr + 8 * i + 0, list[2 * i + 0]); mem_set_uint32_be (sony->mem, ptr + 8 * i + 4, list[2 * i + 1]); } mac_sony_set_pblk (sony, csParam, 2, cnt); mac_sony_return (sony, noErr, 0); } static void mac_sony_status_drive_status (mac_sony_t *sony) { unsigned i; unsigned vref, val; unsigned long src; disk_t *dsk; vref = mac_sony_get_pblk (sony, ioVRefNum, 2); #ifdef DEBUG_SONY mac_log_deb ("sony: status: get drive status (drive=%u)\n", vref); #endif if ((vref < 1) || (vref > SONY_DRIVES)) { mac_sony_return (sony, nsDrvErr, 0); return; } dsk = dsks_get_disk (sony->dsks, vref); if (dsk == NULL) { mac_sony_return (sony, noDriveErr, 0); return; } src = mac_sony_get_vars (sony, vref); for (i = 0; i < 11; i++) { val = mem_get_uint16_be (sony->mem, src + 2 * i); mac_sony_set_pblk (sony, csParam + 2 * i, 2, val); } mac_sony_return (sony, noErr, 0); } static void mac_sony_status (mac_sony_t *sony) { unsigned cscode; cscode = mac_sony_get_pblk (sony, csCode, 2); switch (cscode) { case 6: /* return format list */ mac_sony_status_format_list (sony); break; case 8: /* drive status */ mac_sony_status_drive_status (sony); break; default: mac_sony_return (sony, statusErr, 0); mac_log_deb ("sony: status: unknown (cs=0x%04x)\n", cscode); break; } } int mac_sony_hook (mac_sony_t *sony, unsigned val) { switch (val) { case MAC_HOOK_SONY_OPEN: mac_sony_open (sony); return (0); case MAC_HOOK_SONY_PRIME: mac_sony_prime (sony); return (0); case MAC_HOOK_SONY_CTRL: mac_sony_control (sony); return (0); case MAC_HOOK_SONY_STATUS: mac_sony_status (sony); return (0); case MAC_HOOK_SONY_CLOSE: return (0); } return (1); } void mac_sony_reset (mac_sony_t *sony) { unsigned i; mac_sony_unpatch_rom (sony); sony->open = 0; for (i = 0; i < SONY_DRIVES; i++) { sony->delay_cnt[i] = sony->delay_val[i]; } }