fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 730 lines 12 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/drivers/block/blkfdc.c * 7 * Created: 2010-08-11 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2010-2025 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 <drivers/block/blkpsi.h> 24 25#include <stdlib.h> 26#include <stdint.h> 27#include <string.h> 28 29#include <drivers/psi/psi.h> 30#include <drivers/psi/psi-img.h> 31 32 33static 34int dsk_psi_apply_weak (unsigned char *dst, const unsigned char *msk, unsigned cnt) 35{ 36 int r; 37 unsigned i, v; 38 39 r = 0; 40 41 for (i = 0; i < cnt; i++) { 42 if (msk[i] != 0) { 43 v = (rand() >> 4) & msk[i]; 44 45 if (v) { 46 dst[i] ^= v; 47 r = 1; 48 } 49 } 50 } 51 52 return (r); 53} 54 55unsigned dsk_psi_read_chs (disk_psi_t *fdc, void *buf, unsigned *cnt, 56 unsigned c, unsigned h, unsigned s, int phy) 57{ 58 unsigned ret; 59 psi_sct_t *sct, *alt; 60 61 if (fdc->img == NULL) { 62 *cnt = 0; 63 return (PCE_BLK_PSI_NO_ID); 64 } 65 66 ret = 0; 67 68 sct = psi_img_get_sector (fdc->img, c, h, s, phy); 69 70 if (sct == NULL) { 71 *cnt = 0; 72 return (PCE_BLK_PSI_NO_ID); 73 } 74 75 alt = psi_sct_get_alternate (sct, sct->cur_alt); 76 77 if (alt == NULL) { 78 sct->cur_alt = 0; 79 alt = sct; 80 } 81 82 if (*cnt > alt->n) { 83 *cnt = alt->n; 84 ret |= PCE_BLK_PSI_DATALEN; 85 } 86 87 if (*cnt > 0) { 88 memcpy (buf, alt->data, *cnt); 89 90 if (alt->weak != NULL) { 91 if (dsk_psi_apply_weak (buf, alt->weak, *cnt)) { 92 ret |= PCE_BLK_PSI_CRC_DATA; 93 } 94 } 95 } 96 97 if (alt->flags & PSI_FLAG_NO_DAM) { 98 ret |= PCE_BLK_PSI_NO_DATA; 99 } 100 101 if (alt->flags & PSI_FLAG_CRC_ID) { 102 ret |= PCE_BLK_PSI_CRC_ID; 103 } 104 105 if (alt->flags & PSI_FLAG_CRC_DATA) { 106 ret |= PCE_BLK_PSI_CRC_DATA; 107 } 108 109 if (alt->flags & PSI_FLAG_DEL_DAM) { 110 ret |= PCE_BLK_PSI_DEL_DAM; 111 } 112 113 if (sct->next != NULL) { 114 sct->cur_alt += 1; 115 } 116 117 return (ret); 118} 119 120unsigned dsk_psi_read_tags (disk_psi_t *fdc, void *buf, unsigned cnt, 121 unsigned c, unsigned h, unsigned s, int phy) 122{ 123 psi_sct_t *sct, *alt; 124 125 memset (buf, 0, cnt); 126 127 if (fdc->img == NULL) { 128 return (0); 129 } 130 131 sct = psi_img_get_sector (fdc->img, c, h, s, phy); 132 133 if (sct == NULL) { 134 return (0); 135 } 136 137 alt = psi_sct_get_alternate (sct, sct->cur_alt); 138 139 if (alt == NULL) { 140 sct->cur_alt = 0; 141 alt = sct; 142 } 143 144 cnt = psi_sct_get_tags (alt, buf, cnt); 145 146 return (cnt); 147} 148 149unsigned dsk_psi_write_chs (disk_psi_t *fdc, const void *buf, unsigned *cnt, 150 unsigned c, unsigned h, unsigned s, int phy) 151{ 152 unsigned ret; 153 psi_sct_t *sct; 154 155 if (fdc->img == NULL) { 156 *cnt = 0; 157 return (PCE_BLK_PSI_NO_ID); 158 } 159 160 if (fdc->dsk.readonly) { 161 return (PCE_BLK_PSI_WPROT); 162 } 163 164 ret = 0; 165 166 sct = psi_img_get_sector (fdc->img, c, h, s, phy); 167 168 if (sct == NULL) { 169 *cnt = 0; 170 return (PCE_BLK_PSI_NO_ID); 171 } 172 173 if (sct->flags & PSI_FLAG_NO_DAM) { 174 sct->flags &= ~PSI_FLAG_NO_DAM; 175 } 176 177 fdc->dirty = 1; 178 179 if (*cnt > sct->n) { 180 *cnt = sct->n; 181 ret |= PCE_BLK_PSI_DATALEN; 182 } 183 184 if (*cnt > 0) { 185 memcpy (sct->data, buf, *cnt); 186 } 187 188 if (sct->weak == NULL) { 189 sct->flags &= ~PSI_FLAG_CRC_DATA; 190 } 191 192 if (sct->next != NULL) { 193 psi_sct_del (sct->next); 194 195 sct->next = NULL; 196 sct->cur_alt = 0; 197 } 198 199 return (ret); 200} 201 202unsigned dsk_psi_write_tags (disk_psi_t *fdc, const void *buf, unsigned cnt, 203 unsigned c, unsigned h, unsigned s, int phy) 204{ 205 psi_sct_t *sct; 206 207 if (fdc->img == NULL) { 208 return (0); 209 } 210 211 if (fdc->dsk.readonly) { 212 return (0); 213 } 214 215 sct = psi_img_get_sector (fdc->img, c, h, s, phy); 216 217 if (sct == NULL) { 218 return (0); 219 } 220 221 fdc->dirty = 1; 222 223 cnt = psi_sct_set_tags (sct, buf, cnt); 224 225 return (cnt); 226} 227 228int dsk_psi_erase_track (disk_psi_t *fdc, unsigned c, unsigned h) 229{ 230 psi_trk_t *trk; 231 232 if (fdc->img == NULL) { 233 return (1); 234 } 235 236 if (fdc->dsk.readonly) { 237 return (1); 238 } 239 240 trk = psi_img_get_track (fdc->img, c, h, 0); 241 242 if (trk == NULL) { 243 return (0); 244 } 245 246 fdc->dirty = 1; 247 248 fdc->dsk.blocks -= trk->sct_cnt; 249 250 psi_trk_free (trk); 251 252 return (0); 253} 254 255int dsk_psi_erase_disk (disk_psi_t *fdc) 256{ 257 if (fdc->img == NULL) { 258 return (1); 259 } 260 261 if (fdc->dsk.readonly) { 262 return (1); 263 } 264 265 psi_img_erase (fdc->img); 266 267 fdc->dsk.blocks = 0; 268 269 fdc->dirty = 1; 270 271 return (0); 272} 273 274void dsk_psi_set_encoding (disk_psi_t *fdc, unsigned enc) 275{ 276 fdc->encoding = enc; 277} 278 279int dsk_psi_format_sector (disk_psi_t *fdc, 280 unsigned pc, unsigned ph, unsigned c, unsigned h, unsigned s, 281 unsigned cnt, unsigned fill) 282{ 283 psi_trk_t *trk; 284 psi_sct_t *sct; 285 286 if (fdc->img == NULL) { 287 return (1); 288 } 289 290 if (fdc->dsk.readonly) { 291 return (1); 292 } 293 294 trk = psi_img_get_track (fdc->img, pc, ph, 1); 295 296 if (trk == NULL) { 297 return (1); 298 } 299 300 fdc->dirty = 1; 301 302 sct = psi_sct_new (c, h, s, cnt); 303 304 if (sct == NULL) { 305 return (1); 306 } 307 308 psi_sct_fill (sct, fill); 309 310 if (psi_trk_add_sector (trk, sct)) { 311 psi_sct_del (sct); 312 return (1); 313 } 314 315 psi_sct_set_encoding (sct, fdc->encoding); 316 317 fdc->dsk.blocks += 1; 318 319 return (0); 320} 321 322int dsk_psi_read_id (disk_psi_t *fdc, 323 unsigned pc, unsigned ph, unsigned ps, 324 unsigned *c, unsigned *h, unsigned *s, unsigned *cnt, unsigned *cnt_id, 325 unsigned long *pos) 326{ 327 unsigned mfm_size; 328 psi_sct_t *sct; 329 330 if (fdc->img == NULL) { 331 return (1); 332 } 333 334 sct = psi_img_get_sector (fdc->img, pc, ph, ps, 1); 335 336 if (sct == NULL) { 337 return (1); 338 } 339 340 *c = sct->c; 341 *h = sct->h; 342 *s = sct->s; 343 *cnt = sct->n; 344 *cnt_id = sct->n; 345 346 if (pos != NULL) { 347 if (sct->position == (unsigned long) -1) { 348 *pos = 0; 349 } 350 else { 351 *pos = sct->position; 352 } 353 } 354 355 if (sct->have_mfm_size) { 356 mfm_size = psi_sct_get_mfm_size (sct); 357 358 if (mfm_size <= 8) { 359 *cnt_id = 128U << mfm_size; 360 } 361 } 362 363 return (0); 364} 365 366 367static 368int dsk_psi_read (disk_t *dsk, void *buf, uint32_t i, uint32_t n) 369{ 370 disk_psi_t *fdc; 371 unsigned c, h, s; 372 unsigned cnt; 373 unsigned char *tmp; 374 375 fdc = dsk->ext; 376 377 tmp = buf; 378 379 while (n > 0) { 380 if (psi_img_map_sector (fdc->img, i, &c, &h, &s)) { 381 return (1); 382 } 383 384 cnt = 512; 385 386 if (dsk_psi_read_chs (fdc, tmp, &cnt, c, h, s, 1)) { 387 return (1); 388 } 389 390 if (cnt != 512) { 391 return (1); 392 } 393 394 tmp += 512; 395 396 i += 1; 397 n -= 1; 398 } 399 400 return (0); 401} 402 403static 404int dsk_psi_write (disk_t *dsk, const void *buf, uint32_t i, uint32_t n) 405{ 406 disk_psi_t *fdc; 407 unsigned c, h, s; 408 unsigned cnt; 409 const unsigned char *tmp; 410 411 if (dsk->readonly) { 412 return (1); 413 } 414 415 fdc = dsk->ext; 416 417 tmp = buf; 418 419 while (n > 0) { 420 if (psi_img_map_sector (fdc->img, i, &c, &h, &s)) { 421 return (1); 422 } 423 424 cnt = 512; 425 426 if (dsk_psi_write_chs (fdc, tmp, &cnt, c, h, s, 1)) { 427 return (1); 428 } 429 430 if (cnt != 512) { 431 return (1); 432 } 433 434 tmp += 512; 435 436 i += 1; 437 n -= 1; 438 } 439 440 return (0); 441} 442 443 444static 445int fdc_save (disk_psi_t *fdc) 446{ 447 if (fdc->dsk.fname == NULL) { 448 return (1); 449 } 450 451 if (fdc->img == NULL) { 452 return (1); 453 } 454 455 if (dsk_get_readonly (&fdc->dsk)) { 456 return (1); 457 } 458 459 if (psi_save (fdc->dsk.fname, fdc->img, fdc->type)) { 460 return (1); 461 } 462 463 return (0); 464} 465 466static 467int fdc_set_geometry (disk_psi_t *fdc) 468{ 469 unsigned c, h, s, t; 470 unsigned cyl_cnt, trk_cnt, sct_cnt; 471 psi_img_t *img; 472 psi_cyl_t *cyl; 473 psi_trk_t *trk; 474 475 img = fdc->img; 476 477 cyl_cnt = img->cyl_cnt; 478 trk_cnt = 0; 479 sct_cnt = 0; 480 481 for (c = 0; c < img->cyl_cnt; c++) { 482 cyl = img->cyl[c]; 483 484 trk_cnt += cyl->trk_cnt; 485 486 for (t = 0; t < cyl->trk_cnt; t++) { 487 trk = cyl->trk[t]; 488 489 sct_cnt += trk->sct_cnt; 490 } 491 } 492 493 if ((cyl_cnt == 0) || (trk_cnt == 0) || (sct_cnt == 0)) { 494 return (1); 495 } 496 497 c = cyl_cnt; 498 h = (trk_cnt + (trk_cnt / cyl_cnt / 2)) / cyl_cnt; 499 s = (sct_cnt + (sct_cnt / trk_cnt / 2)) / trk_cnt; 500 501 if (dsk_set_geometry (&fdc->dsk, sct_cnt, c, h, s)) { 502 return (1); 503 } 504 505 dsk_set_visible_chs (&fdc->dsk, c, h, s); 506 507 return (0); 508} 509 510static 511int dsk_psi_set_msg (disk_t *dsk, const char *msg, const char *val) 512{ 513 disk_psi_t *fdc; 514 515 fdc = dsk->ext; 516 517 if (strcmp (msg, "commit") == 0) { 518 if (fdc_save (fdc)) { 519 return (1); 520 } 521 522 fdc->dirty = 0; 523 524 return (0); 525 } 526 527 return (1); 528} 529 530static 531void dsk_psi_del (disk_t *dsk) 532{ 533 disk_psi_t *fdc; 534 535 fdc = dsk->ext; 536 537 if (fdc->dirty) { 538 fprintf (stderr, "disk %u: writing back psi image to %s\n", 539 fdc->dsk.drive, 540 (fdc->dsk.fname != NULL) ? fdc->dsk.fname : "<none>" 541 ); 542 543 if (fdc_save (fdc)) { 544 fprintf (stderr, "disk %u: writing back failed\n", 545 dsk->drive 546 ); 547 } 548 } 549 550 if (fdc->img != NULL) { 551 psi_img_del (fdc->img); 552 } 553 554 free (fdc); 555} 556 557disk_t *dsk_psi_open_fp (FILE *fp, unsigned type, int ro) 558{ 559 disk_psi_t *fdc; 560 561 fdc = malloc (sizeof (disk_psi_t)); 562 563 if (fdc == NULL) { 564 return (NULL); 565 } 566 567 dsk_init (&fdc->dsk, fdc, 0, 0, 0, 0); 568 dsk_set_type (&fdc->dsk, PCE_DISK_PSI); 569 dsk_set_readonly (&fdc->dsk, ro); 570 571 fdc->dsk.del = dsk_psi_del; 572 fdc->dsk.read = dsk_psi_read; 573 fdc->dsk.write = dsk_psi_write; 574 fdc->dsk.set_msg = dsk_psi_set_msg; 575 576 fdc->type = type; 577 fdc->encoding = PSI_ENC_MFM; 578 fdc->dirty = 0; 579 580 fdc->img = psi_load_fp (fp, type); 581 582 if (fdc->img == NULL) { 583 dsk_psi_del (&fdc->dsk); 584 return (NULL); 585 } 586 587 fdc_set_geometry (fdc); 588 589 return (&fdc->dsk); 590} 591 592disk_t *dsk_psi_open (const char *fname, unsigned type, int ro) 593{ 594 disk_t *dsk; 595 FILE *fp; 596 597 if (type == PSI_FORMAT_NONE) { 598 type = psi_probe (fname); 599 600 if (type == PSI_FORMAT_NONE) { 601 type = psi_guess_type (fname); 602 } 603 } 604 605 if (type == PSI_FORMAT_NONE) { 606 return (NULL); 607 } 608 609 if (ro) { 610 fp = fopen (fname, "rb"); 611 } 612 else { 613 fp = fopen (fname, "r+b"); 614 615 if (fp == NULL) { 616 ro = 1; 617 fp = fopen (fname, "rb"); 618 } 619 } 620 621 if (fp == NULL) { 622 return (NULL); 623 } 624 625 dsk = dsk_psi_open_fp (fp, type, ro); 626 627 fclose (fp); 628 629 if (dsk == NULL) { 630 return (NULL); 631 } 632 633 dsk_set_fname (dsk, fname); 634 635 return (dsk); 636} 637 638 639static 640int dsk_psi_init_psi (psi_img_t *img, unsigned long c, unsigned long h, unsigned long s) 641{ 642 unsigned ci, hi, si; 643 psi_trk_t *trk; 644 psi_sct_t *sct; 645 646 if ((c > 65535) || (h > 65535) || (s > 65535)) { 647 return (1); 648 } 649 650 for (ci = 0; ci < c; ci++) { 651 for (hi = 0; hi < h; hi++) { 652 trk = psi_img_get_track (img, ci, hi, 1); 653 654 if (trk == NULL) { 655 return (1); 656 } 657 658 for (si = 0; si < s; si++) { 659 sct = psi_sct_new (ci, hi, si + 1, 512); 660 661 if (sct == NULL) { 662 return (1); 663 } 664 665 psi_sct_fill (sct, 0); 666 psi_sct_set_encoding (sct, 0); 667 668 psi_trk_add_sector (trk, sct); 669 } 670 } 671 } 672 673 return (0); 674} 675 676int dsk_psi_create_fp (FILE *fp, unsigned type, uint32_t c, uint32_t h, uint32_t s) 677{ 678 int r; 679 psi_img_t *img; 680 681 img = psi_img_new(); 682 683 if (img == NULL) { 684 return (1); 685 } 686 687 if (dsk_psi_init_psi (img, c, h, s)) { 688 psi_img_del (img); 689 return (1); 690 } 691 692 r = psi_save_fp (fp, img, type); 693 694 psi_img_del (img); 695 696 return (r); 697} 698 699int dsk_psi_create (const char *name, unsigned type, uint32_t c, uint32_t h, uint32_t s) 700{ 701 int r; 702 FILE *fp; 703 704 if (type == PSI_FORMAT_NONE) { 705 type = psi_guess_type (name); 706 } 707 708 fp = fopen (name, "wb"); 709 710 if (fp == NULL) { 711 return (1); 712 } 713 714 r = dsk_psi_create_fp (fp, type, c, h, s); 715 716 fclose (fp); 717 718 return (r); 719} 720 721 722unsigned dsk_psi_probe_fp (FILE *fp) 723{ 724 return (psi_probe_fp (fp)); 725} 726 727unsigned dsk_psi_probe (const char *fname) 728{ 729 return (psi_probe (fname)); 730}