/* * Papa's got a brand new bag on the side. */#include "all.h"#include "io.h"#include "mem.h" #define dprint(...) if(0)print(__VA_ARGS__) typedef struct Floppy Floppy;typedef struct Ctlr Ctlr;typedef struct Type Type; enum{ Pdor= 0x3f2, /* motor port */ Fintena= 0x8, /* enable floppy interrupt */ Fena= 0x4, /* 0 == reset controller */ Pmsr= 0x3f4, /* controller main status port */ Fready= 0x80, /* ready to be touched */ Ffrom= 0x40, /* data from controller */ Fbusy= 0x10, /* operation not over */ Pdata= 0x3f5, /* controller data port */ Frecal= 0x7, /* recalibrate cmd */ Fseek= 0xf, /* seek cmd */ Fsense= 0x8, /* sense cmd */ Fread= 0x66, /* read cmd */ Fwrite= 0x45, /* write cmd */ Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */ /* digital input register */ Pdir= 0x3F7, /* disk changed port (read only) */ Pdsr= 0x3F7, /* data rate select port (write only) */ Fchange= 0x80, /* disk has changed */ DMAmode0= 0xb, DMAmode1= 0xc, DMAaddr= 0x4, DMAtop= 0x81, DMAinit= 0xa, DMAcount= 0x5, Maxfloppy= 4, /* floppies/controller */ /* sector size encodings */ S128= 0, S256= 1, S512= 2, S1024= 3, /* status 0 byte */ Floppymask= 3<<0, Seekend= 1<<5, Codemask= (3<<6)|(3<<3), Cmdexec= 1<<6, /* status 1 byte */ Overrun= 0x10,}; #define MOTORBIT(i) (1<<((i)+4)) /* * types of drive (from PC equipment byte) */enum{ T360kb= 1, T1200kb= 2, T720kb= 3, T1440kb= 4,}; /* * floppy types (all MFM encoding) */struct Type{ char *name; int dt; /* compatible drive type */ int bytes; /* bytes/sector */ int sectors; /* sectors/track */ int heads; /* number of heads */ int steps; /* steps per cylinder */ int tracks; /* tracks/disk */ int gpl; /* intersector gap length for read/write */ int fgpl; /* intersector gap length for format */ int rate; /* rate code */ /* * these depend on previous entries and are set filled in * by floppyinit */ int bcode; /* coded version of bytes for the controller */ long cap; /* drive capacity in bytes */ long tsize; /* track size in bytes */};Type floppytype[] ={ { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, }, { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, }, { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, }, { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, }, { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, }, { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },};#define NTYPES (nelem(floppytype)) /* * bytes per sector encoding for the controller. * - index for b2c is is (bytes per sector/128). * - index for c2b is code from b2c */static int b2c[] ={[1] 0,[2] 1,[4] 2,[8] 3,};static int c2b[] ={ 128, 256, 512, 1024,}; /* * a floppy drive */struct Floppy{ Type *t; int dt; int dev; Timet lasttouched; /* time last touched */ int cyl; /* current cylinder */ int confused; /* needs to be recalibrated (or worse) */ long offset; /* current offset */ int tcyl; /* target cylinder */ int thead; /* target head */ int tsec; /* target sector */ long len; int maxtries;}; /* * NEC PD765A controller for 4 floppys */struct Ctlr{ QLock; Rendez; Floppy d[Maxfloppy]; /* the floppy drives */ int rw; /* true if a read or write in progress */ int seek; /* one bit for each seek in progress */ uchar stat[8]; /* status of an operation */ int intr; Rendez r; int confused; int motor; Floppy *selected; int rate; int cdev; uchar *ccache; /* cyclinder cache */ int ccyl; int chead;}; Ctlr fl; static int floppysend(int);static int floppyrcv(void);static int floppyrdstat(int);static void floppypos(Floppy*, long);static void floppywait(char*);static int floppysense(Floppy*);static int floppyrecal(Floppy*);static void floppyon(Floppy*);static long floppyxfer(Floppy*, int, void*, long);static void floppyrevive(void); /* * set floppy drive to its default type */static voidsetdef(Floppy *dp){ Type *t; for(t = floppytype; t < &floppytype[NTYPES]; t++) if(dp->dt == t->dt){ dp->t = t; break; }} static voidfloppyintr(Ureg *, void*){ fl.intr = 1; wakeup(&fl.r);} static voidfloppystop(Floppy *dp){ fl.motor &= ~MOTORBIT(dp->dev); outb(Pdor, fl.motor | Fintena | Fena | dp->dev);} voidfloppyhalt(void*){ Floppy *dp; for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++) if((fl.motor&MOTORBIT(dp->dev)) && canqlock(&fl)){ floppystop(dp); qunlock(&fl); }} voidfloppyproc(void){ Floppy *dp; for(;;){ for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){ if((fl.motor&MOTORBIT(dp->dev)) && TK2SEC(Ticks - dp->lasttouched) > 5 && canqlock(&fl)){ floppystop(dp); qunlock(&fl); } } tsleep(&fl, no, 0, 5000); } } intfloppyinit(void){ Floppy *dp; uchar equip; int nfloppy = 0; Type *t; setvec(Floppyvec, floppyintr, &fl); delay(10); outb(Pdor, 0); delay(1); outb(Pdor, Fintena | Fena); delay(10); /* * init dependent parameters */ for(t = floppytype; t < &floppytype[NTYPES]; t++){ t->cap = t->bytes * t->heads * t->sectors * t->tracks; t->bcode = b2c[t->bytes/128]; t->tsize = t->bytes * t->sectors; } /* * init drive parameters */ for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){ dp->cyl = -1; dp->dev = dp - fl.d; dp->maxtries = 1; } /* * read nvram for types of floppies 0 & 1 */ equip = nvramread(0x10); if(Maxfloppy > 0){ fl.d[0].dt = (equip >> 4) & 0xf; setdef(&fl.d[0]); nfloppy++; } if(Maxfloppy > 1){ fl.d[1].dt = equip & 0xf; setdef(&fl.d[1]); nfloppy++; } fl.rate = -1; fl.motor = 0; fl.confused = 1; fl.ccyl = -1; fl.chead = -1; fl.cdev = -1; fl.ccache = (uchar*)ialloc(18*2*512, 64*1024); if(DMAOK(fl.ccache, 18*2*512) == 0) panic("floppy: no memory < 16Mb\n"); userinit(floppyproc, 0, "floppyproc"); atexit(floppyhalt, 0); return nfloppy;} static voidfloppyon(Floppy *dp){ int alreadyon; int tries; if(fl.confused) floppyrevive(); dp->lasttouched = Ticks; alreadyon = fl.motor & MOTORBIT(dp->dev); fl.motor |= MOTORBIT(dp->dev); outb(Pdor, fl.motor | Fintena | Fena | dp->dev); /* get motor going */ if(!alreadyon) tsleep(&u->tsleep, no, 0, 750); /* set transfer rate */ if(fl.rate != dp->t->rate){ fl.rate = dp->t->rate; outb(Pdsr, fl.rate); } /* get drive to a known cylinder */ if(dp->confused) for(tries = 0; tries < 4; tries++) if(floppyrecal(dp) >= 0) break; dp->lasttouched = Ticks; fl.selected = dp;} static voidfloppyrevive(void){ Floppy *dp; /* * reset the controller if it's confused */ if(fl.confused){ /* reset controller and turn all motors off */ fl.intr = 0; splhi(); outb(Pdor, 0); delay(1); outb(Pdor, Fintena|Fena); spllo(); for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++) dp->confused = 1; fl.motor = 0; floppywait("revive"); fl.confused = 0; outb(Pdsr, 0); }} static intfloppysend(int data){ int tries; for(tries = 0; tries < 1000; tries++){ if((inb(Pmsr)&(Ffrom|Fready)) == Fready){ outb(Pdata, data); return 0; } microdelay(8); } return -1;} static intfloppyrcv(void){ int tries; uchar c; for(tries = 0; tries < 1000; tries++){ if((inb(Pmsr)&(Ffrom|Fready)) == (Ffrom|Fready)) return inb(Pdata)&0xff; microdelay(8); } dprint("floppyrcv returns -1 status = %ux\n", c); return -1;} static intfloppyrdstat(int n){ int i; int c; for(i = 0; i < n; i++){ c = floppyrcv(); if(c < 0) return -1; fl.stat[i] = c; } return 0;} static voidfloppypos(Floppy *dp, long off){ int lsec; int cyl; lsec = off/dp->t->bytes; dp->tcyl = lsec/(dp->t->sectors*dp->t->heads); dp->tsec = (lsec % dp->t->sectors) + 1; dp->thead = (lsec/dp->t->sectors) % dp->t->heads; /* * can't read across cylinder boundaries. * if so, decrement the bytes to be read. */ lsec = (off+dp->len)/dp->t->bytes; cyl = lsec/(dp->t->sectors*dp->t->heads); if(cyl != dp->tcyl){ dp->len -= (lsec % dp->t->sectors)*dp->t->bytes; dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*dp->t->bytes *dp->t->sectors; } dp->lasttouched = Ticks; fl.intr = 0;} static intflintr(void*){ return fl.intr;} static voidfloppywait(char *cmd){ tsleep(&u->tsleep, no, flintr, Ticks + 1 + MS2TK(750)); if(fl.intr == 0) return; dprint("floppy timed out, cmd=%s\n", cmd); fl.intr = 0;} static intfloppysense(Floppy *dp){ /* * ask for floppy status */ if(floppysend(Fsense) < 0){ fl.confused = 1; return -1; } if(floppyrdstat(2) < 0){ fl.confused = 1; dp->confused = 1; return -1; } /* * make sure it's the right drive */ if((fl.stat[0] & Floppymask) != dp->dev){ dprint("sense failed, %ux %ux\n", fl.stat[0], fl.stat[1]); dp->confused = 1; return -1; } return 0;} static intfloppyrecal(Floppy *dp){ fl.intr = 0; if(floppysend(Frecal) < 0 || floppysend(dp - fl.d) < 0){ dprint("recalibrate rejected\n"); fl.confused = 0; return -1; } floppywait("recal"); Lines 1–500 of 765. Load more
/* * Papa's got a brand new bag on the side. */ #include "all.h" #include "io.h" #include "mem.h" #define dprint(...) if(0)print(__VA_ARGS__) typedef struct Floppy Floppy; typedef struct Ctlr Ctlr; typedef struct Type Type; enum { Pdor= 0x3f2, /* motor port */ Fintena= 0x8, /* enable floppy interrupt */ Fena= 0x4, /* 0 == reset controller */ Pmsr= 0x3f4, /* controller main status port */ Fready= 0x80, /* ready to be touched */ Ffrom= 0x40, /* data from controller */ Fbusy= 0x10, /* operation not over */ Pdata= 0x3f5, /* controller data port */ Frecal= 0x7, /* recalibrate cmd */ Fseek= 0xf, /* seek cmd */ Fsense= 0x8, /* sense cmd */ Fread= 0x66, /* read cmd */ Fwrite= 0x45, /* write cmd */ Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */ /* digital input register */ Pdir= 0x3F7, /* disk changed port (read only) */ Pdsr= 0x3F7, /* data rate select port (write only) */ Fchange= 0x80, /* disk has changed */ DMAmode0= 0xb, DMAmode1= 0xc, DMAaddr= 0x4, DMAtop= 0x81, DMAinit= 0xa, DMAcount= 0x5, Maxfloppy= 4, /* floppies/controller */ /* sector size encodings */ S128= 0, S256= 1, S512= 2, S1024= 3, /* status 0 byte */ Floppymask= 3<<0, Seekend= 1<<5, Codemask= (3<<6)|(3<<3), Cmdexec= 1<<6, /* status 1 byte */ Overrun= 0x10, }; #define MOTORBIT(i) (1<<((i)+4)) /* * types of drive (from PC equipment byte) */ enum { T360kb= 1, T1200kb= 2, T720kb= 3, T1440kb= 4, }; /* * floppy types (all MFM encoding) */ struct Type { char *name; int dt; /* compatible drive type */ int bytes; /* bytes/sector */ int sectors; /* sectors/track */ int heads; /* number of heads */ int steps; /* steps per cylinder */ int tracks; /* tracks/disk */ int gpl; /* intersector gap length for read/write */ int fgpl; /* intersector gap length for format */ int rate; /* rate code */ /* * these depend on previous entries and are set filled in * by floppyinit */ int bcode; /* coded version of bytes for the controller */ long cap; /* drive capacity in bytes */ long tsize; /* track size in bytes */ }; Type floppytype[] = { { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, }, { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, }, { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, }, { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, }, { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, }, { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, }, }; #define NTYPES (nelem(floppytype)) /* * bytes per sector encoding for the controller. * - index for b2c is is (bytes per sector/128). * - index for c2b is code from b2c */ static int b2c[] = { [1] 0, [2] 1, [4] 2, [8] 3, }; static int c2b[] = { 128, 256, 512, 1024, }; /* * a floppy drive */ struct Floppy { Type *t; int dt; int dev; Timet lasttouched; /* time last touched */ int cyl; /* current cylinder */ int confused; /* needs to be recalibrated (or worse) */ long offset; /* current offset */ int tcyl; /* target cylinder */ int thead; /* target head */ int tsec; /* target sector */ long len; int maxtries; }; /* * NEC PD765A controller for 4 floppys */ struct Ctlr { QLock; Rendez; Floppy d[Maxfloppy]; /* the floppy drives */ int rw; /* true if a read or write in progress */ int seek; /* one bit for each seek in progress */ uchar stat[8]; /* status of an operation */ int intr; Rendez r; int confused; int motor; Floppy *selected; int rate; int cdev; uchar *ccache; /* cyclinder cache */ int ccyl; int chead; }; Ctlr fl; static int floppysend(int); static int floppyrcv(void); static int floppyrdstat(int); static void floppypos(Floppy*, long); static void floppywait(char*); static int floppysense(Floppy*); static int floppyrecal(Floppy*); static void floppyon(Floppy*); static long floppyxfer(Floppy*, int, void*, long); static void floppyrevive(void); /* * set floppy drive to its default type */ static void setdef(Floppy *dp) { Type *t; for(t = floppytype; t < &floppytype[NTYPES]; t++) if(dp->dt == t->dt){ dp->t = t; break; } } static void floppyintr(Ureg *, void*) { fl.intr = 1; wakeup(&fl.r); } static void floppystop(Floppy *dp) { fl.motor &= ~MOTORBIT(dp->dev); outb(Pdor, fl.motor | Fintena | Fena | dp->dev); } void floppyhalt(void*) { Floppy *dp; for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++) if((fl.motor&MOTORBIT(dp->dev)) && canqlock(&fl)){ floppystop(dp); qunlock(&fl); } } void floppyproc(void) { Floppy *dp; for(;;){ for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){ if((fl.motor&MOTORBIT(dp->dev)) && TK2SEC(Ticks - dp->lasttouched) > 5 && canqlock(&fl)){ floppystop(dp); qunlock(&fl); } } tsleep(&fl, no, 0, 5000); } } int floppyinit(void) { Floppy *dp; uchar equip; int nfloppy = 0; Type *t; setvec(Floppyvec, floppyintr, &fl); delay(10); outb(Pdor, 0); delay(1); outb(Pdor, Fintena | Fena); delay(10); /* * init dependent parameters */ for(t = floppytype; t < &floppytype[NTYPES]; t++){ t->cap = t->bytes * t->heads * t->sectors * t->tracks; t->bcode = b2c[t->bytes/128]; t->tsize = t->bytes * t->sectors; } /* * init drive parameters */ for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){ dp->cyl = -1; dp->dev = dp - fl.d; dp->maxtries = 1; } /* * read nvram for types of floppies 0 & 1 */ equip = nvramread(0x10); if(Maxfloppy > 0){ fl.d[0].dt = (equip >> 4) & 0xf; setdef(&fl.d[0]); nfloppy++; } if(Maxfloppy > 1){ fl.d[1].dt = equip & 0xf; setdef(&fl.d[1]); nfloppy++; } fl.rate = -1; fl.motor = 0; fl.confused = 1; fl.ccyl = -1; fl.chead = -1; fl.cdev = -1; fl.ccache = (uchar*)ialloc(18*2*512, 64*1024); if(DMAOK(fl.ccache, 18*2*512) == 0) panic("floppy: no memory < 16Mb\n"); userinit(floppyproc, 0, "floppyproc"); atexit(floppyhalt, 0); return nfloppy; } static void floppyon(Floppy *dp) { int alreadyon; int tries; if(fl.confused) floppyrevive(); dp->lasttouched = Ticks; alreadyon = fl.motor & MOTORBIT(dp->dev); fl.motor |= MOTORBIT(dp->dev); outb(Pdor, fl.motor | Fintena | Fena | dp->dev); /* get motor going */ if(!alreadyon) tsleep(&u->tsleep, no, 0, 750); /* set transfer rate */ if(fl.rate != dp->t->rate){ fl.rate = dp->t->rate; outb(Pdsr, fl.rate); } /* get drive to a known cylinder */ if(dp->confused) for(tries = 0; tries < 4; tries++) if(floppyrecal(dp) >= 0) break; dp->lasttouched = Ticks; fl.selected = dp; } static void floppyrevive(void) { Floppy *dp; /* * reset the controller if it's confused */ if(fl.confused){ /* reset controller and turn all motors off */ fl.intr = 0; splhi(); outb(Pdor, 0); delay(1); outb(Pdor, Fintena|Fena); spllo(); for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++) dp->confused = 1; fl.motor = 0; floppywait("revive"); fl.confused = 0; outb(Pdsr, 0); } } static int floppysend(int data) { int tries; for(tries = 0; tries < 1000; tries++){ if((inb(Pmsr)&(Ffrom|Fready)) == Fready){ outb(Pdata, data); return 0; } microdelay(8); } return -1; } static int floppyrcv(void) { int tries; uchar c; for(tries = 0; tries < 1000; tries++){ if((inb(Pmsr)&(Ffrom|Fready)) == (Ffrom|Fready)) return inb(Pdata)&0xff; microdelay(8); } dprint("floppyrcv returns -1 status = %ux\n", c); return -1; } static int floppyrdstat(int n) { int i; int c; for(i = 0; i < n; i++){ c = floppyrcv(); if(c < 0) return -1; fl.stat[i] = c; } return 0; } static void floppypos(Floppy *dp, long off) { int lsec; int cyl; lsec = off/dp->t->bytes; dp->tcyl = lsec/(dp->t->sectors*dp->t->heads); dp->tsec = (lsec % dp->t->sectors) + 1; dp->thead = (lsec/dp->t->sectors) % dp->t->heads; /* * can't read across cylinder boundaries. * if so, decrement the bytes to be read. */ lsec = (off+dp->len)/dp->t->bytes; cyl = lsec/(dp->t->sectors*dp->t->heads); if(cyl != dp->tcyl){ dp->len -= (lsec % dp->t->sectors)*dp->t->bytes; dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*dp->t->bytes *dp->t->sectors; } dp->lasttouched = Ticks; fl.intr = 0; } static int flintr(void*) { return fl.intr; } static void floppywait(char *cmd) { tsleep(&u->tsleep, no, flintr, Ticks + 1 + MS2TK(750)); if(fl.intr == 0) return; dprint("floppy timed out, cmd=%s\n", cmd); fl.intr = 0; } static int floppysense(Floppy *dp) { /* * ask for floppy status */ if(floppysend(Fsense) < 0){ fl.confused = 1; return -1; } if(floppyrdstat(2) < 0){ fl.confused = 1; dp->confused = 1; return -1; } /* * make sure it's the right drive */ if((fl.stat[0] & Floppymask) != dp->dev){ dprint("sense failed, %ux %ux\n", fl.stat[0], fl.stat[1]); dp->confused = 1; return -1; } return 0; } static int floppyrecal(Floppy *dp) { fl.intr = 0; if(floppysend(Frecal) < 0 || floppysend(dp - fl.d) < 0){ dprint("recalibrate rejected\n"); fl.confused = 0; return -1; } floppywait("recal");