|
|
1.1 ! root 1: #include <u.h> ! 2: ! 3: #include "lib.h" ! 4: #include "mem.h" ! 5: #include "dat.h" ! 6: #include "fns.h" ! 7: #include "io.h" ! 8: #include "ureg.h" ! 9: ! 10: #define DPRINT if(0)print ! 11: ! 12: typedef struct Drive Drive; ! 13: typedef struct Floppy Floppy; ! 14: typedef struct Type Type; ! 15: ! 16: enum ! 17: { ! 18: Pdor= 0x3f2, /* motor port */ ! 19: Fintena= 0x8, /* enable floppy interrupt */ ! 20: Fena= 0x4, /* 0 == reset controller */ ! 21: ! 22: Pmsr= 0x3f4, /* controller main status port */ ! 23: Fready= 0x80, /* ready to be touched */ ! 24: Ffrom= 0x40, /* data from controller */ ! 25: Fbusy= 0x10, /* operation not over */ ! 26: ! 27: Pdata= 0x3f5, /* controller data port */ ! 28: Frecal= 0x7, /* recalibrate cmd */ ! 29: Fseek= 0xf, /* seek cmd */ ! 30: Fsense= 0x8, /* sense cmd */ ! 31: Fread= 0x66, /* read cmd */ ! 32: Fwrite= 0x45, /* write cmd */ ! 33: Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */ ! 34: ! 35: /* digital input register */ ! 36: Pdir= 0x3F7, /* disk changed port (read only) */ ! 37: Pdsr= 0x3F7, /* data rate select port (write only) */ ! 38: Fchange= 0x80, /* disk has changed */ ! 39: ! 40: DMAmode0= 0xb, ! 41: DMAmode1= 0xc, ! 42: DMAaddr= 0x4, ! 43: DMAtop= 0x81, ! 44: DMAinit= 0xa, ! 45: DMAcount= 0x5, ! 46: ! 47: Maxfloppy= 4, /* floppies/controller */ ! 48: ! 49: /* sector size encodings */ ! 50: S128= 0, ! 51: S256= 1, ! 52: S512= 2, ! 53: S1024= 3, ! 54: ! 55: /* status 0 byte */ ! 56: Drivemask= 3<<0, ! 57: Seekend= 1<<5, ! 58: Codemask= (3<<6)|(3<<3), ! 59: }; ! 60: ! 61: #define MOTORBIT(i) (1<<((i)+4)) ! 62: ! 63: /* ! 64: * types of drive (from PC equipment byte) ! 65: */ ! 66: enum ! 67: { ! 68: Tnone= 0, ! 69: T360kb= 1, ! 70: T1200kb= 2, ! 71: T720kb= 3, ! 72: T1440kb= 4, ! 73: }; ! 74: ! 75: /* ! 76: * floppy types (all MFM encoding) ! 77: */ ! 78: struct Type ! 79: { ! 80: char *name; ! 81: int dt; /* compatible drive type */ ! 82: int bytes; /* bytes/sector */ ! 83: int sectors; /* sectors/track */ ! 84: int heads; /* number of heads */ ! 85: int steps; /* steps per cylinder */ ! 86: int tracks; /* tracks/disk */ ! 87: int gpl; /* intersector gap length for read/write */ ! 88: int fgpl; /* intersector gap length for format */ ! 89: int rate; /* rate code */ ! 90: ! 91: /* ! 92: * these depend on previous entries and are set filled in ! 93: * by floppyinit ! 94: */ ! 95: int bcode; /* coded version of bytes for the controller */ ! 96: long cap; /* drive capacity in bytes */ ! 97: long tsize; /* track size in bytes */ ! 98: }; ! 99: Type floppytype[] = ! 100: { ! 101: { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, }, ! 102: { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, }, ! 103: { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, }, ! 104: { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, }, ! 105: { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, }, ! 106: { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, }, ! 107: }; ! 108: #define NTYPES (sizeof(floppytype)/sizeof(Type)) ! 109: ! 110: /* ! 111: * bytes per sector encoding for the controller. ! 112: * - index for b2c is is (bytes per sector/128). ! 113: * - index for c2b is code from b2c ! 114: */ ! 115: static int b2c[] = ! 116: { ! 117: [1] 0, ! 118: [2] 1, ! 119: [4] 2, ! 120: [8] 3, ! 121: }; ! 122: static int c2b[] = ! 123: { ! 124: 128, ! 125: 256, ! 126: 512, ! 127: 1024, ! 128: }; ! 129: ! 130: /* ! 131: * a floppy drive ! 132: */ ! 133: struct Drive ! 134: { ! 135: Type *t; ! 136: int dt; ! 137: int dev; ! 138: ! 139: ulong lasttouched; /* time last touched */ ! 140: int cyl; /* current cylinder */ ! 141: int confused; /* needs to be recalibrated (or worse) */ ! 142: long offset; /* current offset */ ! 143: ! 144: int tcyl; /* target cylinder */ ! 145: int thead; /* target head */ ! 146: int tsec; /* target sector */ ! 147: long len; ! 148: int maxtries; ! 149: }; ! 150: ! 151: /* ! 152: * NEC PD765A controller for 4 floppys ! 153: */ ! 154: struct Floppy ! 155: { ! 156: Drive d[Maxfloppy]; /* the floppy drives */ ! 157: int rw; /* true if a read or write in progress */ ! 158: int seek; /* one bit for each seek in progress */ ! 159: uchar stat[8]; /* status of an operation */ ! 160: int intr; ! 161: int confused; ! 162: int motor; ! 163: Drive *selected; ! 164: int rate; ! 165: ! 166: int cdev; ! 167: uchar *ccache; /* cylinder cache */ ! 168: int ccyl; ! 169: int chead; ! 170: }; ! 171: ! 172: Floppy fl; ! 173: ! 174: static void floppyalarm(Alarm*); ! 175: static int floppysend(int); ! 176: static int floppyrcv(void); ! 177: static int floppyrdstat(int); ! 178: static void floppypos(Drive*, long); ! 179: static void floppywait(char*); ! 180: static int floppysense(Drive*); ! 181: static int floppyrecal(Drive*); ! 182: static void floppyon(Drive*); ! 183: static long floppyxfer(Drive*, int, void*, long); ! 184: static void floppyrevive(void); ! 185: static void floppystop(Drive*); ! 186: ! 187: static void ! 188: timedsleep(int ms) ! 189: { ! 190: ulong end; ! 191: ! 192: end = m->ticks + 1 + MS2TK(ms); ! 193: while(m->ticks < end) ! 194: ; ! 195: } ! 196: ! 197: /* ! 198: * set floppy drive to its default type ! 199: */ ! 200: static void ! 201: setdef(Drive *dp) ! 202: { ! 203: Type *t; ! 204: ! 205: for(t = floppytype; t < &floppytype[NTYPES]; t++) ! 206: if(dp->dt == t->dt){ ! 207: dp->t = t; ! 208: break; ! 209: } ! 210: } ! 211: ! 212: static void ! 213: floppyintr(Ureg*, void*) ! 214: { ! 215: fl.intr = 1; ! 216: } ! 217: ! 218: int ! 219: floppyinit(void) ! 220: { ! 221: Drive *dp; ! 222: uchar equip; ! 223: int mask; ! 224: Type *t; ! 225: char debstr[256]; ! 226: ! 227: setvec(Floppyvec, floppyintr, 0); ! 228: ! 229: /* reset the interface chip */ ! 230: sprint(debstr, "resetting floppy interface\n"); ! 231: delay(50); ! 232: outb(Pdor, 0); ! 233: delay(50); ! 234: outb(Pdor, Fintena | Fena); ! 235: delay(50); ! 236: sprint(debstr, "floppy interface reset\n"); ! 237: ! 238: /* ! 239: * init dependent parameters ! 240: */ ! 241: for(t = floppytype; t < &floppytype[NTYPES]; t++){ ! 242: t->cap = t->bytes * t->heads * t->sectors * t->tracks; ! 243: t->bcode = b2c[t->bytes/128]; ! 244: t->tsize = t->bytes * t->sectors; ! 245: } ! 246: ! 247: /* ! 248: * init drive parameters ! 249: */ ! 250: for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){ ! 251: dp->cyl = -1; ! 252: dp->dev = dp - fl.d; ! 253: dp->maxtries = 1; ! 254: } ! 255: ! 256: /* ! 257: * read nvram for types of floppies 0 & 1 ! 258: */ ! 259: mask = 0; ! 260: equip = nvramread(0x10); ! 261: if(Maxfloppy > 0 && (fl.d[0].dt = ((equip>>4) & 0xF))){ ! 262: setdef(&fl.d[0]); ! 263: mask |= 0x01; ! 264: } ! 265: if(Maxfloppy > 1 && (fl.d[1].dt = (equip & 0xF))){ ! 266: setdef(&fl.d[1]); ! 267: mask |= 0x02; ! 268: } ! 269: ! 270: fl.rate = -1; ! 271: fl.motor = 0; ! 272: fl.confused = 1; ! 273: fl.ccyl = -1; ! 274: fl.chead = -1; ! 275: fl.cdev = -1; ! 276: fl.ccache = (uchar*)ialloc(18*2*512, 1); ! 277: ! 278: /* to turn the motor off when inactive */ ! 279: alarm(5*1000, floppyalarm, (void *)0); ! 280: ! 281: return mask; ! 282: } ! 283: ! 284: static void ! 285: floppyon(Drive *dp) ! 286: { ! 287: int alreadyon; ! 288: int tries; ! 289: ! 290: if(fl.confused) ! 291: floppyrevive(); ! 292: ! 293: alreadyon = fl.motor & MOTORBIT(dp->dev); ! 294: fl.motor |= MOTORBIT(dp->dev); ! 295: outb(Pdor, fl.motor | Fintena | Fena | dp->dev); ! 296: ! 297: /* get motor going */ ! 298: if(!alreadyon) ! 299: timedsleep(750); ! 300: ! 301: /* set transfer rate */ ! 302: if(fl.rate != dp->t->rate){ ! 303: fl.rate = dp->t->rate; ! 304: outb(Pdsr, fl.rate); ! 305: } ! 306: ! 307: /* get drive to a known cylinder */ ! 308: if(dp->confused) ! 309: for(tries = 0; tries < 4; tries++) ! 310: if(floppyrecal(dp) >= 0) ! 311: break; ! 312: ! 313: dp->lasttouched = m->ticks; ! 314: fl.selected = dp; ! 315: } ! 316: ! 317: static void ! 318: floppyrevive(void) ! 319: { ! 320: Drive *dp; ! 321: ! 322: /* ! 323: * reset the controller if it's confused ! 324: */ ! 325: if(fl.confused){ ! 326: /* reset controller and turn all motors off */ ! 327: fl.intr = 0; ! 328: splhi(); ! 329: outb(Pdor, 0); ! 330: delay(1); ! 331: outb(Pdor, Fintena|Fena); ! 332: spllo(); ! 333: for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++) ! 334: dp->confused = 1; ! 335: fl.motor = 0; ! 336: floppywait("revive"); ! 337: fl.confused = 0; ! 338: outb(Pdsr, 0); ! 339: } ! 340: } ! 341: ! 342: static void ! 343: floppystop(Drive *dp) ! 344: { ! 345: fl.motor &= ~MOTORBIT(dp->dev); ! 346: outb(Pdor, fl.motor | Fintena | Fena | dp->dev); ! 347: fl.selected = dp; ! 348: } ! 349: ! 350: static void ! 351: floppyalarm(Alarm* a) ! 352: { ! 353: Drive *dp; ! 354: ! 355: for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){ ! 356: if((fl.motor&MOTORBIT(dp->dev)) && TK2SEC(m->ticks - dp->lasttouched) > 5) ! 357: floppystop(dp); ! 358: } ! 359: ! 360: alarm(5*1000, floppyalarm, 0); ! 361: cancel(a); ! 362: } ! 363: ! 364: static int ! 365: floppysend(int data) ! 366: { ! 367: int tries; ! 368: uchar c; ! 369: ! 370: for(tries = 0; tries < 100; tries++){ ! 371: /* ! 372: * see if its ready for data ! 373: */ ! 374: c = inb(Pmsr); ! 375: if((c&(Ffrom|Fready)) != Fready) ! 376: continue; ! 377: ! 378: /* ! 379: * send the data ! 380: */ ! 381: outb(Pdata, data); ! 382: return 0; ! 383: } ! 384: return -1; ! 385: } ! 386: ! 387: static int ! 388: floppyrcv(void) ! 389: { ! 390: int tries; ! 391: uchar c; ! 392: ! 393: for(tries = 0; tries < 100; tries++){ ! 394: /* ! 395: * see if its ready for data ! 396: */ ! 397: c = inb(Pmsr); ! 398: if((c&(Ffrom|Fready)) != (Ffrom|Fready)) ! 399: continue; ! 400: ! 401: /* ! 402: * get data ! 403: */ ! 404: return inb(Pdata)&0xff; ! 405: } ! 406: DPRINT("floppyrcv returns -1 status = %lux\n", c); ! 407: return -1; ! 408: } ! 409: ! 410: static int ! 411: floppyrdstat(int n) ! 412: { ! 413: int i; ! 414: int c; ! 415: ! 416: for(i = 0; i < n; i++){ ! 417: c = floppyrcv(); ! 418: if(c < 0) ! 419: return -1; ! 420: fl.stat[i] = c; ! 421: } ! 422: return 0; ! 423: } ! 424: ! 425: static void ! 426: floppypos(Drive *dp, long off) ! 427: { ! 428: int lsec; ! 429: int cyl; ! 430: ! 431: lsec = off/dp->t->bytes; ! 432: dp->tcyl = lsec/(dp->t->sectors*dp->t->heads); ! 433: dp->tsec = (lsec % dp->t->sectors) + 1; ! 434: dp->thead = (lsec/dp->t->sectors) % dp->t->heads; ! 435: ! 436: /* ! 437: * can't read across cylinder boundaries. ! 438: * if so, decrement the bytes to be read. ! 439: */ ! 440: lsec = (off+dp->len)/dp->t->bytes; ! 441: cyl = lsec/(dp->t->sectors*dp->t->heads); ! 442: if(cyl != dp->tcyl){ ! 443: dp->len -= (lsec % dp->t->sectors)*dp->t->bytes; ! 444: dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*dp->t->bytes ! 445: *dp->t->sectors; ! 446: } ! 447: ! 448: dp->lasttouched = m->ticks; ! 449: fl.intr = 0; ! 450: } ! 451: ! 452: static void ! 453: floppywait(char *cmd) ! 454: { ! 455: ulong start; ! 456: ! 457: for(start = m->ticks; TK2SEC(m->ticks - start) < 1 && fl.intr == 0;) ! 458: ; ! 459: if(TK2SEC(m->ticks - start) >= 1) ! 460: DPRINT("floppy timed out, cmd=%s\n", cmd); ! 461: fl.intr = 0; ! 462: } ! 463: ! 464: static int ! 465: floppysense(Drive *dp) ! 466: { ! 467: /* ! 468: * ask for floppy status ! 469: */ ! 470: if(floppysend(Fsense) < 0){ ! 471: fl.confused = 1; ! 472: return -1; ! 473: } ! 474: if(floppyrdstat(2) < 0){ ! 475: fl.confused = 1; ! 476: dp->confused = 1; ! 477: return -1; ! 478: } ! 479: ! 480: /* ! 481: * make sure it's the right drive ! 482: */ ! 483: if((fl.stat[0] & Drivemask) != dp->dev){ ! 484: DPRINT("sense failed, %lux %lux\n", fl.stat[0], fl.stat[1]); ! 485: dp->confused = 1; ! 486: return -1; ! 487: } ! 488: return 0; ! 489: } ! 490: ! 491: static int ! 492: floppyrecal(Drive *dp) ! 493: { ! 494: fl.intr = 0; ! 495: if(floppysend(Frecal) < 0 ! 496: || floppysend(dp - fl.d) < 0){ ! 497: DPRINT("recalibrate rejected\n"); ! 498: fl.confused = 0; ! 499: return -1; ! 500: } ! 501: floppywait("recal"); ! 502: ! 503: /* ! 504: * get return values ! 505: */ ! 506: if(floppysense(dp) < 0) ! 507: return -1; ! 508: ! 509: /* ! 510: * see what cylinder we got to ! 511: */ ! 512: dp->tcyl = 0; ! 513: dp->cyl = fl.stat[1]/dp->t->steps; ! 514: if(dp->cyl != dp->tcyl){ ! 515: DPRINT("recalibrate went to wrong cylinder %d\n", dp->cyl); ! 516: dp->confused = 1; ! 517: return -1; ! 518: } ! 519: ! 520: dp->confused = 0; ! 521: return 0; ! 522: } ! 523: ! 524: long ! 525: floppyseek(int dev, long off) ! 526: { ! 527: Drive *dp; ! 528: ! 529: dp = &fl.d[dev]; ! 530: floppyon(dp); ! 531: floppypos(dp, off); ! 532: if(dp->cyl == dp->tcyl){ ! 533: dp->offset = off; ! 534: return off; ! 535: } ! 536: ! 537: /* ! 538: * tell floppy to seek ! 539: */ ! 540: if(floppysend(Fseek) < 0 ! 541: || floppysend((dp->thead<<2) | dp->dev) < 0 ! 542: || floppysend(dp->tcyl * dp->t->steps) < 0){ ! 543: DPRINT("seek cmd failed\n"); ! 544: fl.confused = 1; ! 545: return -1; ! 546: } ! 547: ! 548: /* ! 549: * wait for interrupt ! 550: */ ! 551: floppywait("seek"); ! 552: ! 553: /* ! 554: * get floppy status ! 555: */ ! 556: if(floppysense(dp) < 0) ! 557: return -1; ! 558: ! 559: /* ! 560: * see if it worked ! 561: */ ! 562: if((fl.stat[0] & (Codemask|Seekend)) != Seekend){ ! 563: DPRINT("seek failed\n"); ! 564: dp->confused = 1; ! 565: return -1; ! 566: } ! 567: ! 568: /* ! 569: * see what cylinder we got to ! 570: */ ! 571: dp->cyl = fl.stat[1]/dp->t->steps; ! 572: if(dp->cyl != dp->tcyl){ ! 573: DPRINT("seek went to wrong cylinder %d instead of %d\n", ! 574: dp->cyl, dp->tcyl); ! 575: dp->confused = 1; ! 576: return -1; ! 577: } ! 578: ! 579: dp->offset = off; ! 580: DPRINT("seek to %d succeeded\n", dp->offset); ! 581: return dp->offset; ! 582: } ! 583: ! 584: static long ! 585: floppyxfer(Drive *dp, int cmd, void *a, long n) ! 586: { ! 587: ulong addr; ! 588: long offset; ! 589: ! 590: addr = (ulong)a; ! 591: ! 592: /* ! 593: * dma can't cross 64 k boundaries ! 594: */ ! 595: if((addr & 0xffff0000) != ((addr+n) & 0xffff0000)) ! 596: n -= (addr+n)&0xffff; ! 597: ! 598: dp->len = n; ! 599: if(floppyseek(dp->dev, dp->offset) < 0){ ! 600: DPRINT("xfer seek failed\n"); ! 601: return -1; ! 602: } ! 603: ! 604: DPRINT("floppy %d tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", ! 605: dp->dev, dp->tcyl, dp->thead, dp->tsec, addr, n);/**/ ! 606: ! 607: /* ! 608: * set up the dma ! 609: */ ! 610: outb(DMAmode1, cmd==Fread ? 0x46 : 0x4a); ! 611: outb(DMAmode0, cmd==Fread ? 0x46 : 0x4a); ! 612: outb(DMAaddr, addr); ! 613: outb(DMAaddr, addr>>8); ! 614: outb(DMAtop, addr>>16); ! 615: outb(DMAcount, n-1); ! 616: outb(DMAcount, (n-1)>>8); ! 617: outb(DMAinit, 2); ! 618: ! 619: /* ! 620: * tell floppy to go ! 621: */ ! 622: cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0); ! 623: if(floppysend(cmd) < 0 ! 624: || floppysend((dp->thead<<2) | dp->dev) < 0 ! 625: || floppysend(dp->tcyl * dp->t->steps) < 0 ! 626: || floppysend(dp->thead) < 0 ! 627: || floppysend(dp->tsec) < 0 ! 628: || floppysend(dp->t->bcode) < 0 ! 629: || floppysend(dp->t->sectors) < 0 ! 630: || floppysend(dp->t->gpl) < 0 ! 631: || floppysend(0xFF) < 0){ ! 632: DPRINT("xfer cmd failed\n"); ! 633: fl.confused = 1; ! 634: return -1; ! 635: } ! 636: ! 637: floppywait("xfer"); ! 638: ! 639: /* ! 640: * get status ! 641: */ ! 642: if(floppyrdstat(7) < 0){ ! 643: DPRINT("xfer status failed\n"); ! 644: fl.confused = 1; ! 645: return -1; ! 646: } ! 647: ! 648: if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){ ! 649: DPRINT("xfer failed %lux %lux %lux\n", fl.stat[0], ! 650: fl.stat[1], fl.stat[2]); ! 651: dp->confused = 1; ! 652: return -1; ! 653: } ! 654: ! 655: offset = (fl.stat[3]/dp->t->steps) * dp->t->heads + fl.stat[4]; ! 656: offset = offset*dp->t->sectors + fl.stat[5] - 1; ! 657: offset = offset * c2b[fl.stat[6]]; ! 658: if(offset != dp->offset+n){ ! 659: DPRINT("new offset %d instead of %d\n", offset, dp->offset+dp->len); ! 660: dp->confused = 1; ! 661: return -1;/**/ ! 662: } ! 663: dp->offset += dp->len; ! 664: return dp->len; ! 665: } ! 666: ! 667: long ! 668: floppyread(int dev, void *a, long n) ! 669: { ! 670: Drive *dp; ! 671: long rv, i, nn, offset, sec; ! 672: uchar *aa; ! 673: int tries; ! 674: ! 675: dp = &fl.d[dev]; ! 676: ! 677: dp->len = n; ! 678: floppypos(dp, dp->offset); ! 679: offset = dp->offset; ! 680: sec = dp->tsec + dp->t->sectors*dp->thead; ! 681: n = dp->len; ! 682: if(fl.ccyl==dp->tcyl && fl.cdev==dev) ! 683: goto out; ! 684: ! 685: fl.ccyl = -1; ! 686: fl.cdev = dev; ! 687: aa = fl.ccache; ! 688: nn = dp->t->bytes*dp->t->sectors*dp->t->heads; ! 689: dp->offset = dp->tcyl*nn; ! 690: for(rv = 0; rv < nn; rv += i){ ! 691: i = 0; ! 692: for(tries = 0; tries < dp->maxtries; tries++){ ! 693: i = floppyxfer(dp, Fread, aa+rv, nn-rv); ! 694: if(i > 0) ! 695: break; ! 696: } ! 697: if(tries == dp->maxtries) ! 698: break; ! 699: } ! 700: if(rv != nn){ ! 701: dp->confused = 1; ! 702: return -1; ! 703: } ! 704: fl.ccyl = dp->tcyl; ! 705: out: ! 706: memmove(a, fl.ccache + dp->t->bytes*(sec-1), n); ! 707: dp->offset = offset + n; ! 708: dp->maxtries = 3; ! 709: return n; ! 710: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.