fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 349 lines 7.0 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/devices/fdc.c * 7 * Created: 2007-09-06 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2007-2023 Hampa Hug <hampa@hampa.ch> * 9 *****************************************************************************/ 10 11/***************************************************************************** 12 * This program is free software. You can redistribute it and / or modify it * 13 * under the terms of the GNU General Public License version 2 as published * 14 * by the Free Software Foundation. * 15 * * 16 * This program is distributed in the hope that it will be useful, but * 17 * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 * Public License for more details. * 20 *****************************************************************************/ 21 22 23#include <stdlib.h> 24#include <string.h> 25 26#include <devices/fdc.h> 27 28#include <drivers/block/blkpsi.h> 29 30 31/* 32 * This is the glue code between the 8272 FDC, block devices and 33 * the rest of the emulator. 34 */ 35 36 37static 38struct { 39 unsigned v1; 40 unsigned v2; 41} errmap[] = { 42 { PCE_BLK_PSI_NO_ID, E8272_ERR_NO_ID }, 43 { PCE_BLK_PSI_NO_DATA, E8272_ERR_NO_DATA }, 44 { PCE_BLK_PSI_CRC_ID, E8272_ERR_CRC_ID }, 45 { PCE_BLK_PSI_CRC_DATA, E8272_ERR_CRC_DATA }, 46 { PCE_BLK_PSI_DEL_DAM, E8272_ERR_DEL_DAM }, 47 { PCE_BLK_PSI_DATALEN, E8272_ERR_DATALEN }, 48 { PCE_BLK_PSI_WPROT, E8272_ERR_WPROT }, 49 { 0, 0 } 50}; 51 52 53static void dev_fdc_del_dev (device_t *dev); 54 55 56/* 57 * Map an error code from PCE_BLK_PSI_* to E8272_ERR_*. 58 */ 59static 60unsigned dev_fdc_map_error (unsigned err) 61{ 62 unsigned i; 63 unsigned ret; 64 65 ret = 0; 66 67 i = 0; 68 69 while (errmap[i].v1 != 0) { 70 if (err & errmap[i].v1) { 71 err &= ~errmap[i].v1; 72 ret |= errmap[i].v2; 73 } 74 75 i += 1; 76 } 77 78 if (err) { 79 ret |= E8272_ERR_OTHER; 80 } 81 82 return (ret); 83} 84 85static 86unsigned dev_fdc_diskop_read (dev_fdc_t *fdc, e8272_diskop_t *p) 87{ 88 unsigned ret, err; 89 disk_t *dsk; 90 91 dsk = dsks_get_disk (fdc->dsks, fdc->drive[p->pd & 3]); 92 93 if (dsk == NULL) { 94 p->cnt = 0; 95 return (E8272_ERR_NO_DATA); 96 } 97 98 if (dsk_get_type (dsk) != PCE_DISK_PSI) { 99 if (p->cnt < 512) { 100 p->cnt = 0; 101 return (E8272_ERR_OTHER); 102 } 103 104 if (dsk_read_chs (dsk, p->buf, p->pc, p->ph, p->ls, 1)) { 105 p->cnt = 0; 106 return (E8272_ERR_NO_DATA); 107 } 108 109 p->cnt = 512; 110 111 return (0); 112 } 113 114 err = dsk_psi_read_chs (dsk->ext, p->buf, &p->cnt, p->pc, p->ph, p->ps, 1); 115 116 ret = dev_fdc_map_error (err); 117 118 return (ret); 119} 120 121static 122unsigned dev_fdc_diskop_write (dev_fdc_t *fdc, e8272_diskop_t *p) 123{ 124 unsigned err, ret; 125 disk_t *dsk; 126 127 dsk = dsks_get_disk (fdc->dsks, fdc->drive[p->pd & 3]); 128 129 if (dsk == NULL) { 130 p->cnt = 0; 131 return (E8272_ERR_NO_DATA); 132 } 133 134 if (dsk_get_type (dsk) != PCE_DISK_PSI) { 135 if (p->cnt != 512) { 136 return (E8272_ERR_OTHER); 137 } 138 139 if (dsk_write_chs (dsk, p->buf, p->pc, p->ph, p->ls, 1)) { 140 p->cnt = 0; 141 return (E8272_ERR_OTHER); 142 } 143 144 return (0); 145 } 146 147 err = dsk_psi_write_chs (dsk->ext, p->buf, &p->cnt, p->pc, p->ph, p->ps, 1); 148 149 ret = dev_fdc_map_error (err); 150 151 return (ret); 152} 153 154static 155unsigned dev_fdc_diskop_format (dev_fdc_t *fdc, e8272_diskop_t *p) 156{ 157 unsigned cnt; 158 disk_t *dsk; 159 unsigned char buf[512]; 160 161 dsk = dsks_get_disk (fdc->dsks, fdc->drive[p->pd & 3]); 162 163 if (dsk == NULL) { 164 return (E8272_ERR_NO_DATA); 165 } 166 167 cnt = 128 << p->ln; 168 169 if (dsk_get_type (dsk) != PCE_DISK_PSI) { 170 if (cnt != 512) { 171 return (E8272_ERR_OTHER); 172 } 173 174 memset (buf, p->fill, 512); 175 176 if (dsk_write_chs (dsk, buf, p->pc, p->ph, p->ps + 1, 1)) { 177 return (E8272_ERR_OTHER); 178 } 179 180 return (0); 181 } 182 183 if (p->ps == 0) { 184 dsk_psi_erase_track (dsk->ext, p->pc, p->ph); 185 } 186 187 if (dsk_psi_format_sector (dsk->ext, p->pc, p->ph, p->lc, p->lh, p->ls, cnt, p->fill)) { 188 return (E8272_ERR_OTHER); 189 } 190 191 return (0); 192} 193 194static 195unsigned dev_fdc_diskop_readid (dev_fdc_t *fdc, e8272_diskop_t *p) 196{ 197 disk_t *dsk; 198 unsigned char buf[512]; 199 unsigned lc, lh, ls, cnt, cnt_id; 200 unsigned long pos; 201 202 dsk = dsks_get_disk (fdc->dsks, fdc->drive[p->pd & 3]); 203 204 if (dsk == NULL) { 205 return (E8272_ERR_NO_ID); 206 } 207 208 if (dsk_get_type (dsk) != PCE_DISK_PSI) { 209 if (dsk_read_chs (dsk, buf, p->pc, p->ph, p->ps + 1, 1)) { 210 return (E8272_ERR_NO_ID); 211 } 212 213 p->lc = p->pc; 214 p->lh = p->ph; 215 p->ls = p->ps + 1; 216 p->ln = 2; 217 218 return (0); 219 } 220 221 if (dsk_psi_read_id (dsk->ext, p->pc, p->ph, p->ps, &lc, &lh, &ls, &cnt, &cnt_id, &pos)) { 222 return (E8272_ERR_NO_ID); 223 } 224 225 p->lc = lc; 226 p->lh = lh; 227 p->ls = ls; 228 p->ln = 0; 229 p->pos = pos; 230 231 while (cnt_id > 128) { 232 cnt_id >>= 1; 233 p->ln += 1; 234 } 235 236 return (0); 237} 238static 239unsigned dev_fdc_diskop (dev_fdc_t *fdc, unsigned op, e8272_diskop_t *p) 240{ 241 switch (op) { 242 case E8272_DISKOP_READ: 243 return (dev_fdc_diskop_read (fdc, p)); 244 245 case E8272_DISKOP_WRITE: 246 return (dev_fdc_diskop_write (fdc, p)); 247 248 case E8272_DISKOP_FORMAT: 249 return (dev_fdc_diskop_format (fdc, p)); 250 251 case E8272_DISKOP_READID: 252 return (dev_fdc_diskop_readid (fdc, p)); 253 } 254 255 return (E8272_ERR_OTHER); 256} 257 258 259static 260void dev_fdc_clock (dev_fdc_t *fdc, unsigned n) 261{ 262 e8272_clock (&fdc->e8272, n); 263} 264 265dev_fdc_t *dev_fdc_new (unsigned long addr) 266{ 267 unsigned i; 268 dev_fdc_t *fdc; 269 270 fdc = malloc (sizeof (dev_fdc_t)); 271 272 if (fdc == NULL) { 273 return (NULL); 274 } 275 276 dev_init (&fdc->dev, fdc, "fdc"); 277 278 fdc->dev.del = dev_fdc_del_dev; 279 fdc->dev.clock = (void *) dev_fdc_clock; 280 281 e8272_init (&fdc->e8272); 282 e8272_set_diskop_fct (&fdc->e8272, fdc, dev_fdc_diskop); 283 284 mem_blk_init (&fdc->blk, addr, 8, 0); 285 286 mem_blk_set_fct (&fdc->blk, &fdc->e8272, 287 e8272_get_uint8, NULL, NULL, 288 e8272_set_uint8, NULL, NULL 289 ); 290 291 for (i = 0; i < 4; i++) { 292 fdc->drive[i] = 0xffff; 293 } 294 295 return (fdc); 296} 297 298void dev_fdc_del (dev_fdc_t *fdc) 299{ 300 if (fdc != NULL) { 301 mem_blk_free (&fdc->blk); 302 e8272_free (&fdc->e8272); 303 304 free (fdc); 305 } 306} 307 308static 309void dev_fdc_del_dev (device_t *dev) 310{ 311 dev_fdc_del (dev->ext); 312} 313 314void dev_fdc_mem_add_io (dev_fdc_t *fdc, memory_t *io) 315{ 316 mem_add_blk (io, &fdc->blk, 0); 317} 318 319void dev_fdc_mem_rmv_io (dev_fdc_t *fdc, memory_t *io) 320{ 321 mem_rmv_blk (io, &fdc->blk); 322} 323 324 325void dev_fdc_reset (dev_fdc_t *fdc) 326{ 327 e8272_reset (&fdc->e8272); 328} 329 330void dev_fdc_set_disks (dev_fdc_t *fdc, disks_t *dsks) 331{ 332 fdc->dsks = dsks; 333} 334 335void dev_fdc_set_drive (dev_fdc_t *fdc, unsigned fdcdrv, unsigned drive) 336{ 337 if (fdcdrv < 4) { 338 fdc->drive[fdcdrv] = drive; 339 } 340} 341 342unsigned dev_fdc_get_drive (dev_fdc_t *fdc, unsigned fdcdrv) 343{ 344 if (fdcdrv < 4) { 345 return (fdc->drive[fdcdrv]); 346 } 347 348 return (0xffff); 349}