1 /* $NetBSD: fd.c,v 1.77 2007/10/17 19:53:15 garbled Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Christian E. Hopps 5 * Copyright (c) 1996 Ezra Story 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Christian E. Hopps. 19 * This product includes software developed by Ezra Story. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.77 2007/10/17 19:53:15 garbled Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/callout.h> 41 #include <sys/kernel.h> 42 #include <sys/malloc.h> 43 #include <sys/buf.h> 44 #include <sys/bufq.h> 45 #include <sys/device.h> 46 #include <sys/ioctl.h> 47 #include <sys/fcntl.h> 48 #include <sys/disklabel.h> 49 #include <sys/disk.h> 50 #include <sys/dkbad.h> 51 #include <sys/proc.h> 52 #include <sys/conf.h> 53 54 #include <uvm/uvm_extern.h> 55 56 #include <machine/cpu.h> 57 #include <amiga/amiga/device.h> 58 #include <amiga/amiga/custom.h> 59 #include <amiga/amiga/cia.h> 60 #include <amiga/amiga/cc.h> 61 62 #include "locators.h" 63 64 enum fdc_bits { FDB_CHANGED = 2, FDB_PROTECT, FDB_CYLZERO, FDB_READY }; 65 /* 66 * partitions in fd represent different format floppies 67 * partition a is 0 etc.. 68 */ 69 enum fd_parttypes { 70 FDAMIGAPART = 0, 71 FDMSDOSPART, 72 FDMAXPARTS 73 }; 74 75 #define FDBBSIZE (8192) 76 #define FDSBSIZE (8192) 77 78 #define FDUNIT(dev) DISKUNIT(dev) 79 #define FDPART(dev) DISKPART(dev) 80 #define FDMAKEDEV(m, u, p) MAKEDISKDEV((m), (u), (p)) 81 82 /* that's nice, but we don't want to always use this as an amiga drive 83 bunghole :-) */ 84 #define FDNHEADS (2) /* amiga drives always have 2 heads */ 85 #define FDSECSIZE (512) /* amiga drives always have 512 byte sectors */ 86 #define FDSECLWORDS (128) 87 88 #define FDSETTLEDELAY (18000) /* usec delay after seeking after switch dir */ 89 #define FDSTEPDELAY (3500) /* usec delay after steping */ 90 #define FDPRESIDEDELAY (1000) /* usec delay before writing can occur */ 91 #define FDWRITEDELAY (1300) /* usec delay after write */ 92 93 #define FDSTEPOUT (1) /* decrease track step */ 94 #define FDSTEPIN (0) /* increase track step */ 95 96 #define FDCUNITMASK (0x78) /* mask for all units (bits 6-3) */ 97 98 #define FDRETRIES (2) /* default number of retries */ 99 #define FDMAXUNITS (4) /* maximum number of supported units */ 100 101 #define DISKLEN_READ (0) /* fake mask for reading */ 102 #define DISKLEN_WRITE (1 << 14) /* bit for writing */ 103 #define DISKLEN_DMAEN (1 << 15) /* DMA go */ 104 #define DMABUFSZ ((DISKLEN_WRITE - 1) * 2) /* largest DMA possible */ 105 106 #define FDMFMSYNC (0x4489) 107 #define FDMFMID (0x5554) 108 #define FDMFMDATA (0x5545) 109 #define FDMFMGAP1 (0x9254) 110 #define FDMFMGAP2 (0xAAAA) 111 #define FDMFMGAP3 (0x9254) 112 #define CRC16POLY (0x1021) /* (x^16) + x^12 + x^5 + x^0 */ 113 114 /* 115 * Msdos-type MFM encode/decode 116 */ 117 static u_char msdecode[128]; 118 static u_char msencode[16] = 119 { 120 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, 121 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55 122 }; 123 static u_short mscrctab[256]; 124 125 /* 126 5554 aaaa aaaa aaa5 2aa4 4452 aa51 127 00 00 03 02 ac 0d 128 */ 129 130 /* 131 * floppy device type 132 */ 133 struct fdtype { 134 u_int driveid; /* drive identification (from drive) */ 135 u_int ncylinders; /* number of cylinders on drive */ 136 u_int amiga_nsectors; /* number of sectors per amiga track */ 137 u_int msdos_nsectors; /* number of sectors per msdos track */ 138 u_int nreadw; /* number of words (short) read per track */ 139 u_int nwritew; /* number of words (short) written per track */ 140 u_int gap; /* track gap size in long words */ 141 const u_int precomp[2]; /* 1st and 2nd precomp values */ 142 const char *desc; /* description of drive type (useq) */ 143 }; 144 145 /* 146 * floppy disk device data 147 */ 148 struct fd_softc { 149 struct device sc_dv; /* generic device info; must come first */ 150 struct disk dkdev; /* generic disk info */ 151 struct bufq_state *bufq;/* queue pending I/O operations */ 152 struct buf curbuf; /* state of current I/O operation */ 153 struct callout calibrate_ch; 154 struct callout motor_ch; 155 struct fdtype *type; 156 void *cachep; /* cached track data (write through) */ 157 int cachetrk; /* cahced track -1 for none */ 158 int hwunit; /* unit for amiga controlling hw */ 159 int unitmask; /* mask for cia select deslect */ 160 int pstepdir; /* previous step direction */ 161 int curcyl; /* current curcyl head positioned on */ 162 int flags; /* misc flags */ 163 int wlabel; 164 int stepdelay; /* useq to delay after seek user setable */ 165 int nsectors; /* number of sectors per track */ 166 int openpart; /* which partition [ab] == [12] is open */ 167 short retries; /* number of times to retry failed io */ 168 short retried; /* number of times current io retried */ 169 int bytespersec; /* number of bytes per sector */ 170 }; 171 172 /* fd_softc->flags */ 173 #define FDF_MOTORON (0x01) /* motor is running */ 174 #define FDF_MOTOROFF (0x02) /* motor is waiting to be turned off */ 175 #define FDF_WMOTOROFF (0x04) /* unit wants a wakeup after off */ 176 #define FDF_DIRTY (0x08) /* track cache needs write */ 177 #define FDF_WRITEWAIT (0x10) /* need to head select delay on next setpos */ 178 #define FDF_HAVELABEL (0x20) /* label is valid */ 179 #define FDF_JUSTFLUSH (0x40) /* don't bother caching track. */ 180 #define FDF_NOTRACK0 (0x80) /* was not able to recalibrate drive */ 181 182 int fdc_wantwakeup; 183 int fdc_side; 184 void *fdc_dmap; 185 struct fd_softc *fdc_indma; 186 int fdc_dmalen; 187 int fdc_dmawrite; 188 189 struct fdcargs { 190 struct fdtype *type; 191 int unit; 192 }; 193 194 int fdcmatch(struct device *, struct cfdata *, void *); 195 void fdcattach(struct device *, struct device *, void *); 196 int fdcprint(void *, const char *); 197 int fdmatch(struct device *, struct cfdata *, void *); 198 void fdattach(struct device *, struct device *, void *); 199 200 void fdintr(int); 201 void fdidxintr(void); 202 int fdloaddisk(struct fd_softc *); 203 void fdgetdefaultlabel(struct fd_softc *, struct disklabel *, int); 204 int fdgetdisklabel(struct fd_softc *, dev_t); 205 int fdsetdisklabel(struct fd_softc *, struct disklabel *); 206 int fdputdisklabel(struct fd_softc *, dev_t); 207 struct fdtype * fdcgetfdtype(int); 208 void fdmotoroff(void *); 209 void fdsetpos(struct fd_softc *, int, int); 210 void fdselunit(struct fd_softc *); 211 void fdstart(struct fd_softc *); 212 void fdcont(struct fd_softc *); 213 void fddmastart(struct fd_softc *, int); 214 void fdcalibrate(void *); 215 void fddmadone(struct fd_softc *, int); 216 void fddone(struct fd_softc *); 217 void fdfindwork(int); 218 void fdminphys(struct buf *); 219 void fdcachetoraw(struct fd_softc *); 220 void amcachetoraw(struct fd_softc *); 221 int amrawtocache(struct fd_softc *); 222 u_long *fdfindsync(u_long *, u_long *); 223 int fdrawtocache(struct fd_softc *); 224 void mscachetoraw(struct fd_softc *); 225 int msrawtocache(struct fd_softc *); 226 u_long *mfmblkencode(u_long *, u_long *, u_long *, int); 227 u_long *mfmblkdecode(u_long *, u_long *, u_long *, int); 228 u_short *msblkdecode(u_short *, u_char *, int); 229 u_short *msblkencode(u_short *, u_char *, int, u_short *); 230 231 /* 232 * read size is (nsectors + 1) * mfm secsize + gap bytes + 2 shorts 233 * write size is nsectors * mfm secsize + gap bytes + 3 shorts 234 * the extra shorts are to deal with a DMA hw bug in the controller 235 * they are probably too much (I belive the bug is 1 short on write and 236 * 3 bits on read) but there is no need to be cheap here. 237 */ 238 #define MAXTRKSZ (22 * FDSECSIZE) 239 struct fdtype fdtype[] = { 240 { 0x00000000, 80, 11, 9, 7358, 6815, 414, { 80, 161 }, "3.5dd" }, 241 { 0x55555555, 40, 11, 9, 7358, 6815, 414, { 80, 161 }, "5.25dd" }, 242 { 0xAAAAAAAA, 80, 22, 18, 14716, 13630, 828, { 80, 161 }, "3.5hd" } 243 }; 244 int nfdtype = sizeof(fdtype) / sizeof(*fdtype); 245 246 CFATTACH_DECL(fd, sizeof(struct fd_softc), 247 fdmatch, fdattach, NULL, NULL); 248 249 extern struct cfdriver fd_cd; 250 251 dev_type_open(fdopen); 252 dev_type_close(fdclose); 253 dev_type_read(fdread); 254 dev_type_write(fdwrite); 255 dev_type_ioctl(fdioctl); 256 dev_type_strategy(fdstrategy); 257 258 const struct bdevsw fd_bdevsw = { 259 fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK 260 }; 261 262 const struct cdevsw fd_cdevsw = { 263 fdopen, fdclose, fdread, fdwrite, fdioctl, 264 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 265 }; 266 267 struct dkdriver fddkdriver = { fdstrategy }; 268 269 CFATTACH_DECL(fdc, sizeof(struct device), 270 fdcmatch, fdcattach, NULL, NULL); 271 272 /* 273 * all hw access through macros, this helps to hide the active low 274 * properties 275 */ 276 277 #define FDUNITMASK(unit) (1 << (3 + (unit))) 278 279 /* 280 * select units using mask 281 */ 282 #define FDSELECT(um) do { ciab.prb &= ~(um); } while (0) 283 284 /* 285 * deselect units using mask 286 */ 287 #define FDDESELECT(um) do { ciab.prb |= (um); delay(1); } while (0) 288 289 /* 290 * test hw condition bits 291 */ 292 #define FDTESTC(bit) ((ciaa.pra & (1 << (bit))) == 0) 293 294 /* 295 * set motor for select units, true motor on else off 296 */ 297 #define FDSETMOTOR(on) do { \ 298 if (on) ciab.prb &= ~CIAB_PRB_MTR; else ciab.prb |= CIAB_PRB_MTR; \ 299 } while (0) 300 301 /* 302 * set head for select units 303 */ 304 #define FDSETHEAD(head) do { \ 305 if (head) ciab.prb &= ~CIAB_PRB_SIDE; else ciab.prb |= CIAB_PRB_SIDE; \ 306 delay(1); } while (0) 307 308 /* 309 * select direction, true towards spindle else outwards 310 */ 311 #define FDSETDIR(in) do { \ 312 if (in) ciab.prb &= ~CIAB_PRB_DIR; else ciab.prb |= CIAB_PRB_DIR; \ 313 delay(1); } while (0) 314 315 /* 316 * step the selected units 317 */ 318 #define FDSTEP do { \ 319 ciab.prb &= ~CIAB_PRB_STEP; ciab.prb |= CIAB_PRB_STEP; \ 320 } while (0) 321 322 #define FDDMASTART(len, towrite) do { \ 323 int dmasz = (len) | ((towrite) ? DISKLEN_WRITE : 0) | DISKLEN_DMAEN; \ 324 custom.dsklen = dmasz; custom.dsklen = dmasz; } while (0) 325 326 #define FDDMASTOP do { custom.dsklen = 0; } while (0) 327 328 329 int 330 fdcmatch(struct device *pdp, struct cfdata *cfp, void *auxp) 331 { 332 static int fdc_matched = 0; 333 334 /* Allow only once instance. */ 335 if (matchname("fdc", auxp) == 0 || fdc_matched) 336 return(0); 337 if ((fdc_dmap = alloc_chipmem(DMABUFSZ)) == NULL) { 338 printf("fdc: unable to allocate DMA buffer\n"); 339 return(0); 340 } 341 342 fdc_matched = 1; 343 return(1); 344 } 345 346 void 347 fdcattach(struct device *pdp, struct device *dp, void *auxp) 348 { 349 struct fdcargs args; 350 351 printf(": dmabuf pa 0x%x", (unsigned)kvtop(fdc_dmap)); 352 printf(": dmabuf ka %p\n", fdc_dmap); 353 args.unit = 0; 354 args.type = fdcgetfdtype(args.unit); 355 356 fdc_side = -1; 357 config_found(dp, &args, fdcprint); 358 for (args.unit++; args.unit < FDMAXUNITS; args.unit++) { 359 if ((args.type = fdcgetfdtype(args.unit)) == NULL) 360 continue; 361 config_found(dp, &args, fdcprint); 362 } 363 } 364 365 int 366 fdcprint(void *auxp, const char *pnp) 367 { 368 struct fdcargs *fcp; 369 370 fcp = auxp; 371 if (pnp) 372 aprint_normal("fd%d at %s unit %d:", fcp->unit, pnp, 373 fcp->type->driveid); 374 return(UNCONF); 375 } 376 377 /*ARGSUSED*/ 378 int 379 fdmatch(struct device *pdp, struct cfdata *cfp, void *auxp) 380 { 381 struct fdcargs *fdap; 382 383 fdap = auxp; 384 if (cfp->cf_loc[FDCCF_UNIT] == fdap->unit || 385 cfp->cf_loc[FDCCF_UNIT] == FDCCF_UNIT_DEFAULT) 386 return(1); 387 388 return(0); 389 } 390 391 void 392 fdattach(struct device *pdp, struct device *dp, void *auxp) 393 { 394 struct fdcargs *ap; 395 struct fd_softc *sc; 396 int i; 397 398 ap = auxp; 399 sc = (struct fd_softc *)dp; 400 401 bufq_alloc(&sc->bufq, "disksort", BUFQ_SORT_CYLINDER); 402 callout_init(&sc->calibrate_ch, 0); 403 callout_init(&sc->motor_ch, 0); 404 405 sc->curcyl = sc->cachetrk = -1; 406 sc->openpart = -1; 407 sc->type = ap->type; 408 sc->hwunit = ap->unit; 409 sc->unitmask = 1 << (3 + ap->unit); 410 sc->retries = FDRETRIES; 411 sc->stepdelay = FDSTEPDELAY; 412 sc->bytespersec = 512; 413 printf(" unit %d: %s %d cyl, %d head, %d sec [%d sec], 512 bytes/sec\n", 414 sc->hwunit, sc->type->desc, sc->type->ncylinders, FDNHEADS, 415 sc->type->amiga_nsectors, sc->type->msdos_nsectors); 416 417 /* 418 * Initialize and attach the disk structure. 419 */ 420 disk_init(&sc->dkdev, sc->sc_dv.dv_xname, &fddkdriver); 421 disk_attach(&sc->dkdev); 422 423 /* 424 * calibrate the drive 425 */ 426 fdsetpos(sc, 0, 0); 427 fdsetpos(sc, sc->type->ncylinders, 0); 428 fdsetpos(sc, 0, 0); 429 fdmotoroff(sc); 430 431 /* 432 * precalc msdos MFM and CRC 433 */ 434 for (i = 0; i < 128; i++) 435 msdecode[i] = 0xff; 436 for (i = 0; i < 16; i++) 437 msdecode[msencode[i]] = i; 438 for (i = 0; i < 256; i++) { 439 mscrctab[i] = (0x1021 * (i & 0xf0)) ^ (0x1021 * (i & 0x0f)) ^ 440 (0x1021 * (i >> 4)); 441 } 442 443 /* 444 * enable disk related interrupts 445 */ 446 custom.dmacon = DMAF_SETCLR | DMAF_MASTER | DMAF_DISK; 447 custom.intena = INTF_SETCLR | INTF_DSKBLK; 448 ciab.icr = CIA_ICR_FLG; 449 } 450 451 /*ARGSUSED*/ 452 int 453 fdopen(dev_t dev, int flags, int devtype, struct lwp *l) 454 { 455 struct fd_softc *sc; 456 int wasopen, fwork, error, s; 457 458 error = 0; 459 460 if (FDPART(dev) >= FDMAXPARTS) 461 return(ENXIO); 462 463 if ((sc = getsoftc(fd_cd, FDUNIT(dev))) == NULL) 464 return(ENXIO); 465 if (sc->flags & FDF_NOTRACK0) 466 return(ENXIO); 467 if (sc->cachep == NULL) 468 sc->cachep = malloc(MAXTRKSZ, M_DEVBUF, M_WAITOK); 469 470 s = splbio(); 471 /* 472 * if we are sleeping in fdclose(); waiting for a chance to 473 * shut the motor off, do a sleep here also. 474 */ 475 while (sc->flags & FDF_WMOTOROFF) 476 tsleep(fdmotoroff, PRIBIO, "fdopen", 0); 477 478 fwork = 0; 479 /* 480 * if not open let user open request type, otherwise 481 * ensure they are trying to open same type. 482 */ 483 if (sc->openpart == FDPART(dev)) 484 wasopen = 1; 485 else if (sc->openpart == -1) { 486 sc->openpart = FDPART(dev); 487 wasopen = 0; 488 } else { 489 wasopen = 1; 490 error = EPERM; 491 goto done; 492 } 493 494 /* 495 * wait for current io to complete if any 496 */ 497 if (fdc_indma) { 498 fwork = 1; 499 fdc_wantwakeup++; 500 tsleep(fdopen, PRIBIO, "fdopen", 0); 501 } 502 if ((error = fdloaddisk(sc)) != 0) 503 goto done; 504 if ((error = fdgetdisklabel(sc, dev)) != 0) 505 goto done; 506 #ifdef FDDEBUG 507 printf(" open successful\n"); 508 #endif 509 done: 510 /* 511 * if we requested that fddone()->fdfindwork() wake us, allow it to 512 * complete its job now 513 */ 514 if (fwork) 515 fdfindwork(FDUNIT(dev)); 516 splx(s); 517 518 /* 519 * if we were not open and we marked us so reverse that. 520 */ 521 if (error && wasopen == 0) 522 sc->openpart = -1; 523 return(error); 524 } 525 526 /*ARGSUSED*/ 527 int 528 fdclose(dev_t dev, int flags, int devtype, struct lwp *l) 529 { 530 struct fd_softc *sc; 531 int s; 532 533 #ifdef FDDEBUG 534 printf("fdclose()\n"); 535 #endif 536 sc = getsoftc(fd_cd, FDUNIT(dev)); 537 s = splbio(); 538 if (sc->flags & FDF_MOTORON) { 539 sc->flags |= FDF_WMOTOROFF; 540 tsleep(fdmotoroff, PRIBIO, "fdclose", 0); 541 sc->flags &= ~FDF_WMOTOROFF; 542 wakeup(fdmotoroff); 543 } 544 sc->openpart = -1; 545 splx(s); 546 return(0); 547 } 548 549 int 550 fdioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l) 551 { 552 struct fd_softc *sc; 553 int error, wlab; 554 555 sc = getsoftc(fd_cd, FDUNIT(dev)); 556 557 if ((sc->flags & FDF_HAVELABEL) == 0) 558 return(EBADF); 559 560 switch (cmd) { 561 case DIOCSBAD: 562 return(EINVAL); 563 case DIOCSRETRIES: 564 if (*(int *)addr < 0) 565 return(EINVAL); 566 sc->retries = *(int *)addr; 567 return(0); 568 case DIOCSSTEP: 569 if (*(int *)addr < FDSTEPDELAY) 570 return(EINVAL); 571 sc->dkdev.dk_label->d_trkseek = sc->stepdelay = *(int *)addr; 572 return(0); 573 case DIOCGDINFO: 574 *(struct disklabel *)addr = *(sc->dkdev.dk_label); 575 return(0); 576 case DIOCGPART: 577 ((struct partinfo *)addr)->disklab = sc->dkdev.dk_label; 578 ((struct partinfo *)addr)->part = 579 &sc->dkdev.dk_label->d_partitions[FDPART(dev)]; 580 return(0); 581 case DIOCSDINFO: 582 if ((flag & FWRITE) == 0) 583 return(EBADF); 584 return(fdsetdisklabel(sc, (struct disklabel *)addr)); 585 case DIOCWDINFO: 586 if ((flag & FWRITE) == 0) 587 return(EBADF); 588 if ((error = fdsetdisklabel(sc, (struct disklabel *)addr)) != 0) 589 return(error); 590 wlab = sc->wlabel; 591 sc->wlabel = 1; 592 error = fdputdisklabel(sc, dev); 593 sc->wlabel = wlab; 594 return(error); 595 case DIOCWLABEL: 596 if ((flag & FWRITE) == 0) 597 return(EBADF); 598 sc->wlabel = *(int *)addr; 599 return(0); 600 case DIOCGDEFLABEL: 601 fdgetdefaultlabel(sc, (struct disklabel *)addr, FDPART(dev)); 602 return(0); 603 default: 604 return(ENOTTY); 605 } 606 } 607 608 int 609 fdread(dev_t dev, struct uio *uio, int flags) 610 { 611 return (physio(fdstrategy, NULL, dev, B_READ, fdminphys, uio)); 612 } 613 614 int 615 fdwrite(dev_t dev, struct uio *uio, int flags) 616 { 617 return (physio(fdstrategy, NULL, dev, B_WRITE, fdminphys, uio)); 618 } 619 620 621 void 622 fdintr(int flag) 623 { 624 int s; 625 626 s = splbio(); 627 if (fdc_indma) 628 fddmadone(fdc_indma, 0); 629 splx(s); 630 } 631 632 void 633 fdidxintr(void) 634 { 635 if (fdc_indma && fdc_dmalen) { 636 /* 637 * turn off intr and start actual dma 638 */ 639 ciab.icr = CIA_ICR_FLG; 640 FDDMASTART(fdc_dmalen, fdc_dmawrite); 641 fdc_dmalen = 0; 642 } 643 } 644 645 void 646 fdstrategy(struct buf *bp) 647 { 648 struct disklabel *lp; 649 struct fd_softc *sc; 650 int unit, part, s; 651 652 unit = FDUNIT(bp->b_dev); 653 part = FDPART(bp->b_dev); 654 sc = getsoftc(fd_cd, unit); 655 656 #ifdef FDDEBUG 657 printf("fdstrategy: %p\n", bp); 658 #endif 659 /* 660 * check for valid partition and bounds 661 */ 662 lp = sc->dkdev.dk_label; 663 if ((sc->flags & FDF_HAVELABEL) == 0) { 664 bp->b_error = EIO; 665 goto done; 666 } 667 if (bounds_check_with_label(&sc->dkdev, bp, sc->wlabel) <= 0) 668 goto done; 669 670 /* 671 * trans count of zero or bounds check indicates io is done 672 * we are done. 673 */ 674 if (bp->b_bcount == 0) 675 goto done; 676 677 bp->b_rawblkno = bp->b_blkno; 678 679 /* 680 * queue the buf and kick the low level code 681 */ 682 s = splbio(); 683 BUFQ_PUT(sc->bufq, bp); 684 fdstart(sc); 685 splx(s); 686 return; 687 done: 688 bp->b_resid = bp->b_bcount; 689 biodone(bp); 690 } 691 692 /* 693 * make sure disk is loaded and label is up-to-date. 694 */ 695 int 696 fdloaddisk(struct fd_softc *sc) 697 { 698 /* 699 * if diskchange is low step drive to 0 then up one then to zero. 700 */ 701 fdselunit(sc); /* make sure the unit is selected */ 702 if (FDTESTC(FDB_CHANGED)) { 703 fdsetpos(sc, 0, 0); 704 sc->cachetrk = -1; /* invalidate the cache */ 705 sc->flags &= ~FDF_HAVELABEL; 706 fdsetpos(sc, FDNHEADS, 0); 707 fdsetpos(sc, 0, 0); 708 if (FDTESTC(FDB_CHANGED)) { 709 fdmotoroff(sc); 710 FDDESELECT(sc->unitmask); 711 return(ENXIO); 712 } 713 } 714 FDDESELECT(sc->unitmask); 715 fdmotoroff(sc); 716 sc->type = fdcgetfdtype(sc->hwunit); 717 if (sc->type == NULL) 718 return(ENXIO); 719 if (sc->openpart == FDMSDOSPART) 720 sc->nsectors = sc->type->msdos_nsectors; 721 else 722 sc->nsectors = sc->type->amiga_nsectors; 723 return(0); 724 } 725 726 void 727 fdgetdefaultlabel(struct fd_softc *sc, struct disklabel *lp, int part) 728 /* (variable part) XXX ick */ 729 { 730 731 bzero(lp, sizeof(struct disklabel)); 732 lp->d_secsize = FDSECSIZE; 733 lp->d_ntracks = FDNHEADS; 734 lp->d_ncylinders = sc->type->ncylinders; 735 lp->d_nsectors = sc->nsectors; 736 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 737 lp->d_type = DTYPE_FLOPPY; 738 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 739 lp->d_rpm = 300; /* good guess I suppose. */ 740 lp->d_interleave = 1; /* should change when adding msdos */ 741 sc->stepdelay = lp->d_trkseek = FDSTEPDELAY; 742 lp->d_bbsize = 0; 743 lp->d_sbsize = 0; 744 lp->d_partitions[part].p_size = lp->d_secperunit; 745 lp->d_partitions[part].p_fstype = FS_UNUSED; 746 lp->d_partitions[part].p_fsize = 1024; 747 lp->d_partitions[part].p_frag = 8; 748 lp->d_partitions[part].p_cpg = 2; /* adosfs: reserved blocks */ 749 lp->d_npartitions = part + 1; 750 lp->d_magic = lp->d_magic2 = DISKMAGIC; 751 lp->d_checksum = dkcksum(lp); 752 } 753 754 /* 755 * read disk label, if present otherwise create one 756 * return a new label if raw part and none found, otherwise err. 757 */ 758 int 759 fdgetdisklabel(struct fd_softc *sc, dev_t dev) 760 { 761 struct disklabel *lp, *dlp; 762 struct cpu_disklabel *clp; 763 struct buf *bp; 764 int error, part; 765 766 if (sc->flags & FDF_HAVELABEL && 767 sc->dkdev.dk_label->d_npartitions == (FDPART(dev) + 1)) 768 return(0); 769 #ifdef FDDEBUG 770 printf("fdgetdisklabel()\n"); 771 #endif 772 part = FDPART(dev); 773 lp = sc->dkdev.dk_label; 774 clp = sc->dkdev.dk_cpulabel; 775 bzero(lp, sizeof(struct disklabel)); 776 bzero(clp, sizeof(struct cpu_disklabel)); 777 778 lp->d_secsize = FDSECSIZE; 779 lp->d_ntracks = FDNHEADS; 780 lp->d_ncylinders = sc->type->ncylinders; 781 lp->d_nsectors = sc->nsectors; 782 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 783 lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 784 lp->d_npartitions = part + 1; 785 lp->d_partitions[part].p_size = lp->d_secperunit; 786 lp->d_partitions[part].p_fstype = FS_UNUSED; 787 lp->d_partitions[part].p_fsize = 1024; 788 lp->d_partitions[part].p_frag = 8; 789 lp->d_partitions[part].p_cpg = 2; /* for adosfs: reserved blks */ 790 791 sc->flags |= FDF_HAVELABEL; 792 793 bp = (void *)geteblk((int)lp->d_secsize); 794 bp->b_dev = dev; 795 bp->b_blkno = 0; 796 bp->b_cylinder = 0; 797 bp->b_bcount = FDSECSIZE; 798 bp->b_flags |= B_READ; 799 fdstrategy(bp); 800 if ((error = biowait(bp)) != 0) 801 goto nolabel; 802 dlp = (struct disklabel *)((char*)bp->b_data + LABELOFFSET); 803 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC || 804 dkcksum(dlp)) { 805 error = EINVAL; 806 goto nolabel; 807 } 808 bcopy(dlp, lp, sizeof(struct disklabel)); 809 if (lp->d_trkseek > FDSTEPDELAY) 810 sc->stepdelay = lp->d_trkseek; 811 brelse(bp, 0); 812 return(0); 813 nolabel: 814 fdgetdefaultlabel(sc, lp, part); 815 brelse(bp, 0); 816 return(0); 817 } 818 819 /* 820 * set the incore copy of this units disklabel 821 */ 822 int 823 fdsetdisklabel(struct fd_softc *sc, struct disklabel *lp) 824 { 825 struct disklabel *clp; 826 struct partition *pp; 827 828 /* 829 * must have at least opened raw unit to fetch the 830 * raw_part stuff. 831 */ 832 if ((sc->flags & FDF_HAVELABEL) == 0) 833 return(EINVAL); 834 clp = sc->dkdev.dk_label; 835 /* 836 * make sure things check out and we only have one valid 837 * partition 838 */ 839 #ifdef FDDEBUG 840 printf("fdsetdisklabel\n"); 841 #endif 842 if (lp->d_secsize != FDSECSIZE || 843 lp->d_nsectors != clp->d_nsectors || 844 lp->d_ntracks != FDNHEADS || 845 lp->d_ncylinders != clp->d_ncylinders || 846 lp->d_secpercyl != clp->d_secpercyl || 847 lp->d_secperunit != clp->d_secperunit || 848 lp->d_magic != DISKMAGIC || 849 lp->d_magic2 != DISKMAGIC || 850 lp->d_npartitions == 0 || 851 lp->d_npartitions > FDMAXPARTS || 852 (lp->d_partitions[0].p_offset && lp->d_partitions[1].p_offset) || 853 dkcksum(lp)) 854 return(EINVAL); 855 /* 856 * if any partitions are present make sure they 857 * represent the currently open type 858 */ 859 if ((pp = &lp->d_partitions[0])->p_size) { 860 if ((pp = &lp->d_partitions[1])->p_size == 0) 861 goto done; 862 else if (sc->openpart != 1) 863 return(EINVAL); 864 } else if (sc->openpart != 0) 865 return(EINVAL); 866 /* 867 * make sure selected partition is within bounds 868 * XXX on the second check, its to handle a bug in 869 * XXX the cluster routines as they require mutliples 870 * XXX of PAGE_SIZE currently 871 */ 872 if ((pp->p_offset + pp->p_size >= lp->d_secperunit) || 873 (pp->p_frag * pp->p_fsize % PAGE_SIZE)) 874 return(EINVAL); 875 done: 876 bcopy(lp, clp, sizeof(struct disklabel)); 877 return(0); 878 } 879 880 /* 881 * write out the incore copy of this units disklabel 882 */ 883 int 884 fdputdisklabel(struct fd_softc *sc, dev_t dev) 885 { 886 struct disklabel *lp, *dlp; 887 struct buf *bp; 888 int error; 889 890 if ((sc->flags & FDF_HAVELABEL) == 0) 891 return(EBADF); 892 #ifdef FDDEBUG 893 printf("fdputdisklabel\n"); 894 #endif 895 /* 896 * get buf and read in sector 0 897 */ 898 lp = sc->dkdev.dk_label; 899 bp = geteblk((int)lp->d_secsize); 900 bp->b_dev = FDMAKEDEV(major(dev), FDUNIT(dev), RAW_PART); 901 bp->b_blkno = 0; 902 bp->b_cylinder = 0; 903 bp->b_bcount = FDSECSIZE; 904 bp->b_flags |= B_READ; 905 fdstrategy(bp); 906 if ((error = biowait(bp)) != 0) 907 goto done; 908 /* 909 * copy disklabel to buf and write it out synchronous 910 */ 911 dlp = (struct disklabel *)((char*)bp->b_data + LABELOFFSET); 912 bcopy(lp, dlp, sizeof(struct disklabel)); 913 bp->b_blkno = 0; 914 bp->b_cylinder = 0; 915 bp->b_flags &= ~(B_READ|B_DONE); 916 bp->b_flags |= B_WRITE; 917 fdstrategy(bp); 918 error = biowait(bp); 919 done: 920 brelse(bp, 0); 921 return(error); 922 } 923 924 /* 925 * figure out drive type or NULL if none. 926 */ 927 struct fdtype * 928 fdcgetfdtype(int unit) 929 { 930 struct fdtype *ftp; 931 u_long id, idb; 932 int cnt, umask; 933 934 id = 0; 935 umask = 1 << (3 + unit); 936 937 FDDESELECT(FDCUNITMASK); 938 939 FDSETMOTOR(1); 940 delay(1); 941 FDSELECT(umask); 942 delay(1); 943 FDDESELECT(umask); 944 945 FDSETMOTOR(0); 946 delay(1); 947 FDSELECT(umask); 948 delay(1); 949 FDDESELECT(umask); 950 951 for (idb = 0x80000000; idb; idb >>= 1) { 952 FDSELECT(umask); 953 delay(1); 954 if (FDTESTC(FDB_READY) == 0) 955 id |= idb; 956 FDDESELECT(umask); 957 delay(1); 958 } 959 #ifdef FDDEBUG 960 printf("fdcgettype unit %d id 0x%lx\n", unit, id); 961 #endif 962 963 for (cnt = 0, ftp = fdtype; cnt < nfdtype; ftp++, cnt++) 964 if (ftp->driveid == id) 965 return(ftp); 966 /* 967 * 3.5dd's at unit 0 do not always return id. 968 */ 969 if (unit == 0) 970 return(fdtype); 971 return(NULL); 972 } 973 974 /* 975 * turn motor off if possible otherwise mark as needed and will be done 976 * later. 977 */ 978 void 979 fdmotoroff(void *arg) 980 { 981 struct fd_softc *sc; 982 int s; 983 984 sc = arg; 985 s = splbio(); 986 987 #ifdef FDDEBUG 988 printf("fdmotoroff: unit %d\n", sc->hwunit); 989 #endif 990 if ((sc->flags & FDF_MOTORON) == 0) 991 goto done; 992 /* 993 * if we have a timeout on a DMA operation let fddmadone() 994 * deal with it. 995 */ 996 if (fdc_indma == sc) { 997 fddmadone(sc, 1); 998 goto done; 999 } 1000 #ifdef FDDEBUG 1001 printf(" motor was on, turning off\n"); 1002 #endif 1003 1004 /* 1005 * flush cache if needed 1006 */ 1007 if (sc->flags & FDF_DIRTY) { 1008 sc->flags |= FDF_JUSTFLUSH | FDF_MOTOROFF; 1009 #ifdef FDDEBUG 1010 printf(" flushing dirty buffer first\n"); 1011 #endif 1012 /* 1013 * if DMA'ing done for now, fddone() will call us again 1014 */ 1015 if (fdc_indma) 1016 goto done; 1017 fddmastart(sc, sc->cachetrk); 1018 goto done; 1019 } 1020 1021 /* 1022 * if controller is busy just schedule us to be called back 1023 */ 1024 if (fdc_indma) { 1025 /* 1026 * someone else has the controller now 1027 * just set flag and let fddone() call us again. 1028 */ 1029 sc->flags |= FDF_MOTOROFF; 1030 goto done; 1031 } 1032 1033 #ifdef FDDEBUG 1034 printf(" hw turning unit off\n"); 1035 #endif 1036 1037 sc->flags &= ~(FDF_MOTORON | FDF_MOTOROFF); 1038 FDDESELECT(FDCUNITMASK); 1039 FDSETMOTOR(0); 1040 delay(1); 1041 FDSELECT(sc->unitmask); 1042 delay(4); 1043 FDDESELECT(sc->unitmask); 1044 delay(1); 1045 if (sc->flags & FDF_WMOTOROFF) 1046 wakeup(fdmotoroff); 1047 done: 1048 splx(s); 1049 } 1050 1051 /* 1052 * select drive seek to track exit with motor on. 1053 * fdsetpos(x, 0, 0) does calibrates the drive. 1054 */ 1055 void 1056 fdsetpos(struct fd_softc *sc, int trk, int towrite) 1057 { 1058 int nstep, sdir, ondly, ncyl, nside; 1059 1060 FDDESELECT(FDCUNITMASK); 1061 FDSETMOTOR(1); 1062 delay(1); 1063 FDSELECT(sc->unitmask); 1064 delay(1); 1065 if ((sc->flags & FDF_MOTORON) == 0) { 1066 ondly = 0; 1067 while (FDTESTC(FDB_READY) == 0) { 1068 delay(1000); 1069 if (++ondly >= 1000) 1070 break; 1071 } 1072 } 1073 sc->flags |= FDF_MOTORON; 1074 1075 ncyl = trk / FDNHEADS; 1076 nside = trk % FDNHEADS; 1077 1078 if (sc->curcyl == ncyl && fdc_side == nside) 1079 return; 1080 1081 if (towrite) 1082 sc->flags |= FDF_WRITEWAIT; 1083 1084 #ifdef FDDEBUG 1085 printf("fdsetpos: cyl %d head %d towrite %d\n", trk / FDNHEADS, 1086 trk % FDNHEADS, towrite); 1087 #endif 1088 nstep = ncyl - sc->curcyl; 1089 if (nstep) { 1090 /* 1091 * figure direction 1092 */ 1093 if (nstep > 0 && ncyl != 0) { 1094 sdir = FDSTEPIN; 1095 FDSETDIR(1); 1096 } else { 1097 nstep = -nstep; 1098 sdir = FDSTEPOUT; 1099 FDSETDIR(0); 1100 } 1101 if (ncyl == 0) { 1102 /* 1103 * either just want cylinder 0 or doing 1104 * a calibrate. 1105 */ 1106 nstep = 256; 1107 while (FDTESTC(FDB_CYLZERO) == 0 && nstep--) { 1108 FDSTEP; 1109 delay(sc->stepdelay); 1110 } 1111 if (nstep < 0) 1112 sc->flags |= FDF_NOTRACK0; 1113 } else { 1114 /* 1115 * step the needed amount amount. 1116 */ 1117 while (nstep--) { 1118 FDSTEP; 1119 delay(sc->stepdelay); 1120 } 1121 } 1122 /* 1123 * if switched directions 1124 * allow drive to settle. 1125 */ 1126 if (sc->pstepdir != sdir) 1127 delay(FDSETTLEDELAY); 1128 sc->pstepdir = sdir; 1129 sc->curcyl = ncyl; 1130 } 1131 if (nside == fdc_side) 1132 return; 1133 /* 1134 * select side 1135 */ 1136 fdc_side = nside; 1137 FDSETHEAD(nside); 1138 delay(FDPRESIDEDELAY); 1139 } 1140 1141 void 1142 fdselunit(struct fd_softc *sc) 1143 { 1144 FDDESELECT(FDCUNITMASK); /* deselect all */ 1145 FDSETMOTOR(sc->flags & FDF_MOTORON); /* set motor to unit's state */ 1146 delay(1); 1147 FDSELECT(sc->unitmask); /* select unit */ 1148 delay(1); 1149 } 1150 1151 /* 1152 * process next buf on device queue. 1153 * normall sequence of events: 1154 * fdstart() -> fddmastart(); 1155 * fdidxintr(); 1156 * fdintr() -> fddmadone() -> fddone(); 1157 * if the track is in the cache then fdstart() will short-circuit 1158 * to fddone() else if the track cache is dirty it will flush. If 1159 * the buf is not an entire track it will cache the requested track. 1160 */ 1161 void 1162 fdstart(struct fd_softc *sc) 1163 { 1164 int trk, error, write; 1165 struct buf *bp, *dp; 1166 int changed; 1167 1168 #ifdef FDDEBUG 1169 printf("fdstart: unit %d\n", sc->hwunit); 1170 #endif 1171 1172 /* 1173 * if DMA'ing just return. we must have been called from fdstartegy. 1174 */ 1175 if (fdc_indma) 1176 return; 1177 1178 /* 1179 * get next buf if there. 1180 */ 1181 dp = &sc->curbuf; 1182 if ((bp = BUFQ_PEEK(sc->bufq)) == NULL) { 1183 #ifdef FDDEBUG 1184 printf(" nothing to do\n"); 1185 #endif 1186 return; 1187 } 1188 1189 /* 1190 * Mark us as busy now, in case fddone() gets called in one 1191 * of the cases below. 1192 */ 1193 disk_busy(&sc->dkdev); 1194 1195 /* 1196 * make sure same disk is loaded 1197 */ 1198 fdselunit(sc); 1199 changed = FDTESTC(FDB_CHANGED); 1200 FDDESELECT(sc->unitmask); 1201 if (changed) { 1202 /* 1203 * disk missing, invalidate all future io on 1204 * this unit until re-open()'ed also invalidate 1205 * all current io 1206 */ 1207 printf("fdstart: disk changed\n"); 1208 #ifdef FDDEBUG 1209 printf(" disk was removed invalidating all io\n"); 1210 #endif 1211 sc->flags &= ~FDF_HAVELABEL; 1212 for (;;) { 1213 bp = BUFQ_GET(sc->bufq); 1214 bp->b_error = EIO; 1215 if (BUFQ_PEEK(sc->bufq) == NULL) 1216 break; 1217 biodone(bp); 1218 } 1219 /* 1220 * do fddone() on last buf to allow other units to start. 1221 */ 1222 BUFQ_PUT(sc->bufq, bp); 1223 fddone(sc); 1224 return; 1225 } 1226 1227 /* 1228 * we have a valid buf, setup our local version 1229 * we use this count to allow reading over multiple tracks. 1230 * into a single buffer 1231 */ 1232 dp->b_bcount = bp->b_bcount; 1233 dp->b_blkno = bp->b_blkno; 1234 dp->b_data = bp->b_data; 1235 dp->b_flags = bp->b_flags; 1236 dp->b_resid = 0; 1237 1238 if (bp->b_flags & B_READ) 1239 write = 0; 1240 else if (FDTESTC(FDB_PROTECT) == 0) 1241 write = 1; 1242 else { 1243 error = EPERM; 1244 goto done; 1245 } 1246 1247 /* 1248 * figure trk given blkno 1249 */ 1250 trk = bp->b_blkno / sc->nsectors; 1251 1252 /* 1253 * check to see if same as currently cached track 1254 * if so we need to do no DMA read. 1255 */ 1256 if (trk == sc->cachetrk) { 1257 fddone(sc); 1258 return; 1259 } 1260 1261 /* 1262 * if we will be overwriting the entire cache, don't bother to 1263 * fetch it. 1264 */ 1265 if (bp->b_bcount == (sc->nsectors * FDSECSIZE) && write && 1266 bp->b_blkno % sc->nsectors == 0) { 1267 if (sc->flags & FDF_DIRTY) 1268 sc->flags |= FDF_JUSTFLUSH; 1269 else { 1270 sc->cachetrk = trk; 1271 fddone(sc); 1272 return; 1273 } 1274 } 1275 1276 /* 1277 * start DMA read of `trk' 1278 */ 1279 fddmastart(sc, trk); 1280 return; 1281 done: 1282 bp->b_error = error; 1283 fddone(sc); 1284 } 1285 1286 /* 1287 * continue a started operation on next track. always begin at 1288 * sector 0 on the next track. 1289 */ 1290 void 1291 fdcont(struct fd_softc *sc) 1292 { 1293 struct buf *dp, *bp; 1294 int trk, write; 1295 1296 dp = &sc->curbuf; 1297 bp = BUFQ_PEEK(sc->bufq); 1298 dp->b_data = (char*)dp->b_data + (dp->b_bcount - bp->b_resid); 1299 dp->b_blkno += (dp->b_bcount - bp->b_resid) / FDSECSIZE; 1300 dp->b_bcount = bp->b_resid; 1301 1302 /* 1303 * figure trk given blkno 1304 */ 1305 trk = dp->b_blkno / sc->nsectors; 1306 #ifdef DEBUG 1307 if (trk != sc->cachetrk + 1 || dp->b_blkno % sc->nsectors != 0) 1308 panic("fdcont: confused"); 1309 #endif 1310 if (dp->b_flags & B_READ) 1311 write = 0; 1312 else 1313 write = 1; 1314 /* 1315 * if we will be overwriting the entire cache, don't bother to 1316 * fetch it. 1317 */ 1318 if (dp->b_bcount == (sc->nsectors * FDSECSIZE) && write) { 1319 if (sc->flags & FDF_DIRTY) 1320 sc->flags |= FDF_JUSTFLUSH; 1321 else { 1322 sc->cachetrk = trk; 1323 fddone(sc); 1324 return; 1325 } 1326 } 1327 /* 1328 * start DMA read of `trk' 1329 */ 1330 fddmastart(sc, trk); 1331 return; 1332 } 1333 1334 void 1335 fddmastart(struct fd_softc *sc, int trk) 1336 { 1337 int adkmask, ndmaw, write, dmatrk; 1338 1339 #ifdef FDDEBUG 1340 printf("fddmastart: unit %d cyl %d head %d", sc->hwunit, 1341 trk / FDNHEADS, trk % FDNHEADS); 1342 #endif 1343 /* 1344 * flush the cached track if dirty else read requested track. 1345 */ 1346 if (sc->flags & FDF_DIRTY) { 1347 fdcachetoraw(sc); 1348 ndmaw = sc->type->nwritew; 1349 dmatrk = sc->cachetrk; 1350 write = 1; 1351 } else { 1352 ndmaw = sc->type->nreadw; 1353 dmatrk = trk; 1354 write = 0; 1355 } 1356 1357 #ifdef FDDEBUG 1358 printf(" %s", write ? " flushing cache\n" : " loading cache\n"); 1359 #endif 1360 sc->cachetrk = trk; 1361 fdc_indma = sc; 1362 fdsetpos(sc, dmatrk, write); 1363 1364 /* 1365 * setup dma stuff 1366 */ 1367 if (write == 0) { 1368 custom.adkcon = ADKF_MSBSYNC; 1369 custom.adkcon = ADKF_SETCLR | ADKF_WORDSYNC | ADKF_FAST; 1370 custom.dsksync = FDMFMSYNC; 1371 } else { 1372 custom.adkcon = ADKF_PRECOMP1 | ADKF_PRECOMP0 | ADKF_WORDSYNC | 1373 ADKF_MSBSYNC; 1374 adkmask = ADKF_SETCLR | ADKF_FAST | ADKF_MFMPREC; 1375 if (dmatrk >= sc->type->precomp[0]) 1376 adkmask |= ADKF_PRECOMP0; 1377 if (dmatrk >= sc->type->precomp[1]) 1378 adkmask |= ADKF_PRECOMP1; 1379 custom.adkcon = adkmask; 1380 } 1381 custom.dskpt = (u_char *)kvtop(fdc_dmap); 1382 1383 /* 1384 * If writing an MSDOS track, activate disk index pulse 1385 * interrupt, DMA will be started in the intr routine fdidxintr() 1386 * Otherwise, start the DMA here. 1387 */ 1388 if (write && sc->openpart == FDMSDOSPART) { 1389 fdc_dmalen = ndmaw; 1390 fdc_dmawrite = write; 1391 ciab.icr = CIA_ICR_IR_SC | CIA_ICR_FLG; 1392 } else { 1393 FDDMASTART(ndmaw, write); 1394 fdc_dmalen = 0; 1395 } 1396 1397 #ifdef FDDEBUG 1398 printf(" DMA started\n"); 1399 #endif 1400 } 1401 1402 /* 1403 * recalibrate the drive 1404 */ 1405 void 1406 fdcalibrate(void *arg) 1407 { 1408 struct fd_softc *sc; 1409 static int loopcnt; 1410 1411 sc = arg; 1412 1413 if (loopcnt == 0) { 1414 /* 1415 * seek cyl 0 1416 */ 1417 fdc_indma = sc; 1418 sc->stepdelay += 900; 1419 if (sc->cachetrk > 1) 1420 fdsetpos(sc, sc->cachetrk % FDNHEADS, 0); 1421 sc->stepdelay -= 900; 1422 } 1423 if (loopcnt++ & 1) 1424 fdsetpos(sc, sc->cachetrk, 0); 1425 else 1426 fdsetpos(sc, sc->cachetrk + FDNHEADS, 0); 1427 /* 1428 * trk++, trk, trk++, trk, trk++, trk, trk++, trk and DMA 1429 */ 1430 if (loopcnt < 8) 1431 callout_reset(&sc->calibrate_ch, hz / 8, fdcalibrate, sc); 1432 else { 1433 loopcnt = 0; 1434 fdc_indma = NULL; 1435 callout_reset(&sc->motor_ch, 3 * hz / 2, fdmotoroff, sc); 1436 fddmastart(sc, sc->cachetrk); 1437 } 1438 } 1439 1440 void 1441 fddmadone(struct fd_softc *sc, int timeo) 1442 { 1443 #ifdef FDDEBUG 1444 printf("fddmadone: unit %d, timeo %d\n", sc->hwunit, timeo); 1445 #endif 1446 fdc_indma = NULL; 1447 callout_stop(&sc->motor_ch); 1448 FDDMASTOP; 1449 1450 /* 1451 * guarantee the drive has been at current head and cyl 1452 * for at least FDWRITEDELAY after a write. 1453 */ 1454 if (sc->flags & FDF_WRITEWAIT) { 1455 delay(FDWRITEDELAY); 1456 sc->flags &= ~FDF_WRITEWAIT; 1457 } 1458 1459 if ((sc->flags & FDF_MOTOROFF) == 0) { 1460 /* 1461 * motor runs for 1.5 seconds after last DMA 1462 */ 1463 callout_reset(&sc->motor_ch, 3 * hz / 2, fdmotoroff, sc); 1464 } 1465 if (sc->flags & FDF_DIRTY) { 1466 /* 1467 * if buffer dirty, the last DMA cleaned it 1468 */ 1469 sc->flags &= ~FDF_DIRTY; 1470 if (timeo) 1471 printf("%s: write of track cache timed out.\n", 1472 sc->sc_dv.dv_xname); 1473 if (sc->flags & FDF_JUSTFLUSH) { 1474 sc->flags &= ~FDF_JUSTFLUSH; 1475 /* 1476 * we are done DMA'ing 1477 */ 1478 fddone(sc); 1479 return; 1480 } 1481 /* 1482 * load the cache 1483 */ 1484 fddmastart(sc, sc->cachetrk); 1485 return; 1486 } 1487 #ifdef FDDEBUG 1488 else if (sc->flags & FDF_MOTOROFF) 1489 panic("fddmadone: FDF_MOTOROFF with no FDF_DIRTY"); 1490 #endif 1491 1492 /* 1493 * cache loaded decode it into cache buffer 1494 */ 1495 if (timeo == 0 && fdrawtocache(sc) == 0) 1496 sc->retried = 0; 1497 else { 1498 #ifdef FDDEBUG 1499 if (timeo) 1500 printf("%s: fddmadone: cache load timed out.\n", 1501 sc->sc_dv.dv_xname); 1502 #endif 1503 if (sc->retried >= sc->retries) { 1504 sc->retried = 0; 1505 sc->cachetrk = -1; 1506 } else { 1507 sc->retried++; 1508 /* 1509 * this will be restarted at end of calibrate loop. 1510 */ 1511 callout_stop(&sc->motor_ch); 1512 fdcalibrate(sc); 1513 return; 1514 } 1515 } 1516 fddone(sc); 1517 } 1518 1519 void 1520 fddone(struct fd_softc *sc) 1521 { 1522 struct buf *dp, *bp; 1523 char *data; 1524 int sz; 1525 1526 #ifdef FDDEBUG 1527 printf("fddone: unit %d\n", sc->hwunit); 1528 #endif 1529 /* 1530 * check to see if unit is just flushing the cache, 1531 * that is we have no io queued. 1532 */ 1533 if (sc->flags & FDF_MOTOROFF) 1534 goto nobuf; 1535 1536 dp = &sc->curbuf; 1537 if ((bp = BUFQ_PEEK(sc->bufq)) == NULL) 1538 panic ("fddone"); 1539 /* 1540 * check for an error that may have occurred 1541 * while getting the track. 1542 */ 1543 if (sc->cachetrk == -1) { 1544 sc->retried = 0; 1545 bp->b_error = EIO; 1546 } else if (bp->b_error == 0) { 1547 data = sc->cachep; 1548 /* 1549 * get offset of data in track cache and limit 1550 * the copy size to not exceed the cache's end. 1551 */ 1552 data += (dp->b_blkno % sc->nsectors) * FDSECSIZE; 1553 sz = sc->nsectors - dp->b_blkno % sc->nsectors; 1554 sz *= FDSECSIZE; 1555 sz = min(dp->b_bcount, sz); 1556 if (bp->b_flags & B_READ) 1557 bcopy(data, dp->b_data, sz); 1558 else { 1559 bcopy(dp->b_data, data, sz); 1560 sc->flags |= FDF_DIRTY; 1561 } 1562 bp->b_resid = dp->b_bcount - sz; 1563 if (bp->b_resid == 0) { 1564 bp->b_error = 0; 1565 } else { 1566 /* 1567 * not done yet need to read next track 1568 */ 1569 fdcont(sc); 1570 return; 1571 } 1572 } 1573 /* 1574 * remove from queue. 1575 */ 1576 (void)BUFQ_GET(sc->bufq); 1577 1578 disk_unbusy(&sc->dkdev, (bp->b_bcount - bp->b_resid), 1579 (bp->b_flags & B_READ)); 1580 1581 biodone(bp); 1582 nobuf: 1583 fdfindwork(device_unit(&sc->sc_dv)); 1584 } 1585 1586 void 1587 fdfindwork(int unit) 1588 { 1589 struct fd_softc *ssc, *sc; 1590 int i, last; 1591 1592 /* 1593 * first see if we have any fdopen()'s waiting 1594 */ 1595 if (fdc_wantwakeup) { 1596 wakeup(fdopen); 1597 fdc_wantwakeup--; 1598 return; 1599 } 1600 1601 /* 1602 * start next available unit, linear search from the next unit 1603 * wrapping and finally this unit. 1604 */ 1605 last = 0; 1606 ssc = NULL; 1607 for (i = unit + 1; last == 0; i++) { 1608 if (i == unit) 1609 last = 1; 1610 if (i >= fd_cd.cd_ndevs) { 1611 i = -1; 1612 continue; 1613 } 1614 if ((sc = fd_cd.cd_devs[i]) == NULL) 1615 continue; 1616 1617 /* 1618 * if unit has requested to be turned off 1619 * and it has no buf's queued do it now 1620 */ 1621 if (sc->flags & FDF_MOTOROFF) { 1622 if (BUFQ_PEEK(sc->bufq) == NULL) 1623 fdmotoroff(sc); 1624 else { 1625 /* 1626 * we gained a buf request while 1627 * we waited, forget the motoroff 1628 */ 1629 sc->flags &= ~FDF_MOTOROFF; 1630 } 1631 /* 1632 * if we now have DMA unit must have needed 1633 * flushing, quit 1634 */ 1635 if (fdc_indma) 1636 return; 1637 } 1638 /* 1639 * if we have no start unit and the current unit has 1640 * io waiting choose this unit to start. 1641 */ 1642 if (ssc == NULL && BUFQ_PEEK(sc->bufq) != NULL) 1643 ssc = sc; 1644 } 1645 if (ssc) 1646 fdstart(ssc); 1647 } 1648 1649 /* 1650 * min byte count to whats left of the track in question 1651 */ 1652 void 1653 fdminphys(struct buf *bp) 1654 { 1655 struct fd_softc *sc; 1656 int trk, sec, toff, tsz; 1657 1658 if ((sc = getsoftc(fd_cd, FDUNIT(bp->b_dev))) == NULL) 1659 panic("fdminphys: couldn't get softc"); 1660 1661 trk = bp->b_blkno / sc->nsectors; 1662 sec = bp->b_blkno % sc->nsectors; 1663 1664 toff = sec * FDSECSIZE; 1665 tsz = sc->nsectors * FDSECSIZE; 1666 #ifdef FDDEBUG 1667 printf("fdminphys: before %ld", bp->b_bcount); 1668 #endif 1669 bp->b_bcount = min(bp->b_bcount, tsz - toff); 1670 #ifdef FDDEBUG 1671 printf(" after %ld\n", bp->b_bcount); 1672 #endif 1673 minphys(bp); 1674 } 1675 1676 /* 1677 * encode the track cache into raw MFM ready for DMA 1678 * when we go to multiple disk formats, this will call type dependent 1679 * functions 1680 */ 1681 void fdcachetoraw(struct fd_softc *sc) 1682 { 1683 if (sc->openpart == FDMSDOSPART) 1684 mscachetoraw(sc); 1685 else 1686 amcachetoraw(sc); 1687 } 1688 1689 /* 1690 * decode raw MFM from DMA into units track cache. 1691 * when we go to multiple disk formats, this will call type dependent 1692 * functions 1693 */ 1694 int 1695 fdrawtocache(struct fd_softc *sc) 1696 { 1697 1698 if (sc->openpart == FDMSDOSPART) 1699 return(msrawtocache(sc)); 1700 else 1701 return(amrawtocache(sc)); 1702 } 1703 1704 void 1705 amcachetoraw(struct fd_softc *sc) 1706 { 1707 static u_long mfmnull[4]; 1708 u_long *rp, *crp, *dp, hcksum, dcksum, info, zero; 1709 int sec, i; 1710 1711 rp = fdc_dmap; 1712 1713 /* 1714 * not yet one sector (- 1 long) gap. 1715 * for now use previous drivers values 1716 */ 1717 for (i = 0; i < sc->type->gap; i++) 1718 *rp++ = 0xaaaaaaaa; 1719 /* 1720 * process sectors 1721 */ 1722 dp = sc->cachep; 1723 zero = 0; 1724 info = 0xff000000 | (sc->cachetrk << 16) | sc->nsectors; 1725 for (sec = 0; sec < sc->nsectors; sec++, info += (1 << 8) - 1) { 1726 hcksum = dcksum = 0; 1727 /* 1728 * sector format 1729 * offset description 1730 *----------------------------------- 1731 * 0 null 1732 * 1 sync 1733 * oddbits evenbits 1734 *---------------------- 1735 * 2 3 [0xff]b [trk]b [sec]b [togap]b 1736 * 4-7 8-11 null 1737 * 12 13 header cksum [2-11] 1738 * 14 15 data cksum [16-271] 1739 * 16-143 144-271 data 1740 */ 1741 *rp = 0xaaaaaaaa; 1742 if (*(rp - 1) & 0x1) 1743 *rp &= 0x7fffffff; /* clock bit correction */ 1744 rp++; 1745 *rp++ = (FDMFMSYNC << 16) | FDMFMSYNC; 1746 rp = mfmblkencode(&info, rp, &hcksum, 1); 1747 rp = mfmblkencode(mfmnull, rp, &hcksum, 4); 1748 rp = mfmblkencode(&hcksum, rp, NULL, 1); 1749 1750 crp = rp; 1751 rp = mfmblkencode(dp, rp + 2, &dcksum, FDSECLWORDS); 1752 dp += FDSECLWORDS; 1753 crp = mfmblkencode(&dcksum, crp, NULL, 1); 1754 if (*(crp - 1) & 0x1) 1755 *crp &= 0x7fffffff; /* clock bit correction */ 1756 else if ((*crp & 0x40000000) == 0) 1757 *crp |= 0x80000000; 1758 } 1759 *rp = 0xaaa80000; 1760 if (*(rp - 1) & 0x1) 1761 *rp &= 0x7fffffff; 1762 } 1763 1764 u_long * 1765 fdfindsync(u_long *rp, u_long *ep) 1766 { 1767 u_short *sp; 1768 1769 sp = (u_short *)rp; 1770 while ((u_long *)sp < ep && *sp != FDMFMSYNC) 1771 sp++; 1772 while ((u_long *)sp < ep && *sp == FDMFMSYNC) 1773 sp++; 1774 if ((u_long *)sp < ep) 1775 return((u_long *)sp); 1776 return(NULL); 1777 } 1778 1779 int 1780 amrawtocache(struct fd_softc *sc) 1781 { 1782 u_long mfmnull[4]; 1783 u_long *dp, *rp, *erp, *crp, *srp, hcksum, dcksum, info, cktmp; 1784 int cnt, doagain; 1785 1786 doagain = 1; 1787 srp = rp = fdc_dmap; 1788 erp = (u_long *)((u_short *)rp + sc->type->nreadw); 1789 cnt = 0; 1790 again: 1791 if (doagain == 0 || (rp = srp = fdfindsync(srp, erp)) == NULL) { 1792 #ifdef DIAGNOSTIC 1793 printf("%s: corrupted track (%d) data.\n", 1794 sc->sc_dv.dv_xname, sc->cachetrk); 1795 #endif 1796 return(-1); 1797 } 1798 1799 /* 1800 * process sectors 1801 */ 1802 for (; cnt < sc->nsectors; cnt++) { 1803 hcksum = dcksum = 0; 1804 rp = mfmblkdecode(rp, &info, &hcksum, 1); 1805 rp = mfmblkdecode(rp, mfmnull, &hcksum, 4); 1806 rp = mfmblkdecode(rp, &cktmp, NULL, 1); 1807 if (cktmp != hcksum) { 1808 #ifdef FDDEBUG 1809 printf(" info 0x%lx hchksum 0x%lx trkhcksum 0x%lx\n", 1810 info, hcksum, cktmp); 1811 #endif 1812 goto again; 1813 } 1814 if (((info >> 16) & 0xff) != sc->cachetrk) { 1815 #ifdef DEBUG 1816 printf("%s: incorrect track found: 0x%lx %d\n", 1817 sc->sc_dv.dv_xname, info, sc->cachetrk); 1818 #endif 1819 goto again; 1820 } 1821 #ifdef FDDEBUG 1822 printf(" info 0x%lx\n", info); 1823 #endif 1824 1825 rp = mfmblkdecode(rp, &cktmp, NULL, 1); 1826 dp = sc->cachep; 1827 dp += FDSECLWORDS * ((info >> 8) & 0xff); 1828 crp = mfmblkdecode(rp, dp, &dcksum, FDSECLWORDS); 1829 if (cktmp != dcksum) { 1830 #ifdef FDDEBUG 1831 printf(" info 0x%lx dchksum 0x%lx trkdcksum 0x%lx\n", 1832 info, dcksum, cktmp); 1833 #endif 1834 goto again; 1835 } 1836 1837 /* 1838 * if we are at gap then we can no longer be sure 1839 * of correct sync marks 1840 */ 1841 if ((info && 0xff) == 1) 1842 doagain = 1; 1843 else 1844 doagain = 0; 1845 srp = rp = fdfindsync(crp, erp); 1846 } 1847 return(0); 1848 } 1849 1850 void 1851 mscachetoraw(struct fd_softc *sc) 1852 { 1853 u_short *rp, *erp, crc; 1854 u_char *cp, tb[5]; 1855 int sec, i; 1856 1857 rp = (u_short *)fdc_dmap; 1858 erp = rp + sc->type->nwritew; 1859 cp = sc->cachep; 1860 1861 /* 1862 * initial track filler (828 * GAP1) 1863 */ 1864 for (i = 0; i < sc->type->gap; i++) { 1865 *rp++ = FDMFMGAP1; 1866 *rp++ = FDMFMGAP1; 1867 } 1868 1869 for (sec = 0; sec < sc->nsectors; sec++) { 1870 1871 /* 1872 * leading sector gap 1873 * (12 * GAP2) + (3 * SYNC) 1874 */ 1875 for (i = 0; i < 12; i++) 1876 *rp++ = FDMFMGAP2; 1877 *rp++ = FDMFMSYNC; 1878 *rp++ = FDMFMSYNC; 1879 *rp++ = FDMFMSYNC; 1880 1881 /* 1882 * sector information 1883 * (ID) + track + side + sector + sector size + CRC16 1884 */ 1885 *rp++ = FDMFMID; 1886 tb[0] = sc->cachetrk / FDNHEADS; 1887 tb[1] = sc->cachetrk % FDNHEADS; 1888 tb[2] = sec + 1; 1889 i = sc->bytespersec; 1890 tb[3] = i < 256 ? 0 : (i < 512 ? 1 : (i < 1024 ? 2 : 3)); 1891 rp = msblkencode(rp, tb, 4, &crc); 1892 tb[0] = crc >> 8; 1893 tb[1] = crc & 0xff; 1894 tb[2] = 0x4e; /* GAP1 decoded */ 1895 rp = msblkencode(rp, tb, 3, 0); 1896 1897 /* 1898 * sector info/data gap 1899 * (22 * GAP1) + (12 * GAP2) + (3 * SYNC) 1900 */ 1901 for (i = 0; i < 21; i++) 1902 *rp++ = FDMFMGAP1; 1903 for (i = 0; i < 12; i++) 1904 *rp++ = FDMFMGAP2; 1905 *rp++ = FDMFMSYNC; 1906 *rp++ = FDMFMSYNC; 1907 *rp++ = FDMFMSYNC; 1908 1909 /* 1910 * sector data 1911 * (DATA) + ...data... + CRC16 1912 */ 1913 *rp++ = FDMFMDATA; 1914 rp = msblkencode(rp, cp, sc->bytespersec, &crc); 1915 cp += sc->bytespersec; 1916 tb[0] = crc >> 8; 1917 tb[1] = crc & 0xff; 1918 tb[2] = 0x4e; /* GAP3 decoded */ 1919 rp = msblkencode(rp, tb, 3, 0); 1920 1921 /* 1922 * trailing sector gap 1923 * (80 * GAP3) 1924 */ 1925 for (i = 0; i < 79; i++) 1926 *rp++ = FDMFMGAP3; 1927 } 1928 1929 /* 1930 * fill rest of track with GAP3 1931 */ 1932 while (rp != erp) 1933 *rp++ = FDMFMGAP3; 1934 1935 } 1936 1937 int 1938 msrawtocache(struct fd_softc *sc) 1939 { 1940 u_short *rp, *srp, *erp; 1941 u_char tb[5], *cp; 1942 int ct, sec, retry; 1943 1944 srp = rp = (u_short *)fdc_dmap; 1945 erp = rp + sc->type->nreadw; 1946 cp = sc->cachep; 1947 1948 for (ct = 0; ct < sc->nsectors; ct++) { 1949 retry = 1; 1950 do { 1951 /* 1952 * skip leading gap to sync 1953 */ 1954 if ((rp = (u_short *)fdfindsync((u_long *)rp, (u_long *)erp)) == NULL) { 1955 #ifdef DIAGNOSTIC 1956 printf("%s: corrupted track (%d) data.\n", 1957 sc->sc_dv.dv_xname, sc->cachetrk); 1958 #endif 1959 return(-1); 1960 } 1961 1962 /* 1963 * Grab sector info 1964 */ 1965 if (*rp++ != FDMFMID) 1966 continue; 1967 rp = msblkdecode(rp, tb, 4); 1968 #ifdef FDDEBUG 1969 printf("sector id: sector %d, track %d, side %d," 1970 "bps %d\n", tb[2], tb[0], tb[1], 128 << tb[3]); 1971 #endif 1972 if ((tb[0] * FDNHEADS + tb[1]) != sc->cachetrk || 1973 tb[2] > sc->nsectors) 1974 continue; 1975 1976 sec = tb[2]; 1977 sc->bytespersec = 128 << tb[3]; 1978 rp += 2; /* skip CRC-16 */ 1979 1980 /* 1981 * skip gap and read in data 1982 */ 1983 if ((rp = (u_short *)fdfindsync((u_long *)rp, (u_long *)erp)) == NULL) 1984 return(-1); 1985 if (*rp++ != FDMFMDATA) 1986 continue; 1987 rp = msblkdecode(rp, cp + ((sec-1) * sc->bytespersec), 1988 sc->bytespersec); 1989 rp += 2; /* skip CRC-16 */ 1990 1991 retry = 0; 1992 } while (retry); 1993 } 1994 return(0); 1995 } 1996 1997 /* 1998 * encode len longwords of `dp' data in amiga mfm block format (`rp') 1999 * this format specified that the odd bits are at current pos and even 2000 * bits at len + current pos 2001 */ 2002 u_long * 2003 mfmblkencode(u_long *dp, u_long *rp, u_long *cp, int len) 2004 { 2005 u_long *sdp, *edp, d, dtmp, correct; 2006 2007 sdp = dp; 2008 edp = dp + len; 2009 2010 if (*(rp - 1) & 0x1) 2011 correct = 1; 2012 else 2013 correct = 0; 2014 /* 2015 * do odd bits 2016 */ 2017 while (dp < edp) { 2018 d = (*dp >> 1) & 0x55555555; /* remove clock bits */ 2019 dtmp = d ^ 0x55555555; 2020 d |= ((dtmp >> 1) | 0x80000000) & (dtmp << 1); 2021 /* 2022 * correct upper clock bit if needed 2023 */ 2024 if (correct) 2025 d &= 0x7fffffff; 2026 if (d & 0x1) 2027 correct = 1; 2028 else 2029 correct = 0; 2030 /* 2031 * do checksums and store in raw buffer 2032 */ 2033 if (cp) 2034 *cp ^= d; 2035 *rp++ = d; 2036 dp++; 2037 } 2038 /* 2039 * do even bits 2040 */ 2041 dp = sdp; 2042 while (dp < edp) { 2043 d = *dp & 0x55555555; /* remove clock bits */ 2044 dtmp = d ^ 0x55555555; 2045 d |= ((dtmp >> 1) | 0x80000000) & (dtmp << 1); 2046 /* 2047 * correct upper clock bit if needed 2048 */ 2049 if (correct) 2050 d &= 0x7fffffff; 2051 if (d & 0x1) 2052 correct = 1; 2053 else 2054 correct = 0; 2055 /* 2056 * do checksums and store in raw buffer 2057 */ 2058 if (cp) 2059 *cp ^= d; 2060 *rp++ = d; 2061 dp++; 2062 } 2063 if (cp) 2064 *cp &= 0x55555555; 2065 return(rp); 2066 } 2067 2068 /* 2069 * decode len longwords of `dp' data in amiga mfm block format (`rp') 2070 * this format specified that the odd bits are at current pos and even 2071 * bits at len + current pos 2072 */ 2073 u_long * 2074 mfmblkdecode(u_long *rp, u_long *dp, u_long *cp, int len) 2075 { 2076 u_long o, e; 2077 int cnt; 2078 2079 cnt = len; 2080 while (cnt--) { 2081 o = *rp; 2082 e = *(rp + len); 2083 if (cp) { 2084 *cp ^= o; 2085 *cp ^= e; 2086 } 2087 o &= 0x55555555; 2088 e &= 0x55555555; 2089 *dp++ = (o << 1) | e; 2090 rp++; 2091 } 2092 if (cp) 2093 *cp &= 0x55555555; 2094 return(rp + len); 2095 } 2096 2097 /* 2098 * decode len words in standard MFM format to len bytes 2099 * of data. 2100 */ 2101 u_short * 2102 msblkdecode(u_short *rp, u_char *cp, int len) 2103 { 2104 while (len--) { 2105 *cp++ = msdecode[*rp & 0x7f] | 2106 (msdecode[(*rp >> 8) & 0x7f] << 4); 2107 rp++; 2108 } 2109 2110 return(rp); 2111 } 2112 2113 /* 2114 * encode len bytes of data into len words in standard MFM format. 2115 * If a pointer is supplied for crc, calculate the CRC-16 of the data 2116 * as well. 2117 */ 2118 u_short * 2119 msblkencode(u_short *rp, u_char *cp, int len, u_short *crc) 2120 { 2121 u_short td; 2122 u_short mycrc; 2123 2124 /* preload crc for header (4 bytes) 2125 * or data (anything else) 2126 */ 2127 mycrc = (len == 4) ? 0xb230 : 0xe295; 2128 2129 while (len--) { 2130 td = (msencode[*cp >> 4] << 8) | msencode[*cp & 0x0f]; 2131 2132 /* Check for zeros in top bit of encode and bottom 2133 * bit of previous encode. if so, slap a one in betweem 2134 * them. 2135 */ 2136 if ((td & 0x140) == 0) 2137 td |= 0x80; 2138 if ((td & 0x4000) == 0 && (rp[-1] & 1) == 0) 2139 td |= 0x8000; 2140 2141 *rp++ = td; 2142 2143 /* 2144 * calc crc if requested 2145 */ 2146 if (crc) 2147 mycrc = (mycrc << 8) ^ mscrctab[*cp ^ (mycrc >> 8)]; 2148 2149 cp++; 2150 } 2151 2152 if (crc) 2153 *crc = mycrc; 2154 2155 return(rp); 2156 } 2157