| plan 9 kernel history: overview | file list | diff list |
1991/0731/pc/devfloppy.c (diff list | history)
| 1991/0730/sys/src/9/pc/devfloppy.c:29,35 – 1991/0731/sys/src/9/pc/devfloppy.c:29,35 (short | long | prev | next) | ||
| 1991/0727 | Fwrite= 0x47, /* write cmd */ Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */ | |
| 1991/0731 | Ndrive= 4, /* floppies/controller */ | |
| 1991/0727 | ||
| 1991/0728 | DMAchan= 2, /* floppy dma channel */ | |
| 1991/0730/sys/src/9/pc/devfloppy.c:46,53 – 1991/0731/sys/src/9/pc/devfloppy.c:46,53 | ||
| 1991/0728 | /* file types */ Qdir= 0, | |
| 1991/0731 | Qdata= 1, Qstruct= 2, | |
| 1991/0727 | }; /* | |
| 1991/0730/sys/src/9/pc/devfloppy.c:62,84 – 1991/0731/sys/src/9/pc/devfloppy.c:62,102 | ||
| 1991/0727 | int steps; /* steps per cylinder */ int tracks; /* tracks/disk */ int gpl; /* intersector gap length for read/write */ | |
| 1991/0731 | int fgpl; /* intersector gap length for format */ /* * these depend on previous entries and are set filled in * by floppyinit */ int bcode; /* coded version of bytes for the controller */ | |
| 1991/0727 | long cap; /* drive capacity in bytes */ }; Type floppytype[] = { | |
| 1991/0731 | { "MF2HD", 512, 18, 2, 1, 80, 0x1B, 0x54, }, { "MF2DD", 512, 9, 2, 1, 80, 0x1B, 0x54, }, { "F2HD", 512, 15, 2, 1, 80, 0x2A, 0x50, }, { "F2DD", 512, 8, 2, 2, 40, 0x2A, 0x50, }, { "F1DD", 512, 8, 1, 2, 40, 0x2A, 0x50, }, | |
| 1991/0727 | }; | |
| 1991/0731 | #define NTYPES (sizeof(floppytype)/sizeof(Type)) /* * bytes/sector encoding for the controller, index is (bytes per sector/128) */ static int b2c[] = | |
| 1991/0727 | { | |
| 1991/0731 | [1] 0, [2] 1, [4] 2, [8] 3, }; static int c2b[] = { | |
| 1991/0727 | 128, 256, 512, | |
| 1991/0731 | 1024, | |
| 1991/0727 | }; /* | |
| 1991/0730/sys/src/9/pc/devfloppy.c:86,92 – 1991/0731/sys/src/9/pc/devfloppy.c:104,111 | ||
| 1991/0727 | */ struct Drive { | |
| 1991/0731 | QLock; /* exclusive access to the drive */ | |
| 1991/0727 | Type *t; int dev; | |
| 1991/0730/sys/src/9/pc/devfloppy.c:99,108 – 1991/0731/sys/src/9/pc/devfloppy.c:118,127 | ||
| 1991/0727 | int tcyl; /* target cylinder */ int thead; /* target head */ int tsec; /* target sector */ | |
| 1991/0731 | long len; /* size of xfer */ | |
| 1991/0727 | int busy; /* true if drive is seeking */ | |
| 1991/0731 | Rendez r; /* waiting here for motor to spin up */ | |
| 1991/0727 | }; /* | |
| 1991/0730/sys/src/9/pc/devfloppy.c:110,139 – 1991/0731/sys/src/9/pc/devfloppy.c:129,261 | ||
| 1991/0727 | */ struct Controller { | |
| 1991/0731 | QLock; /* exclusive access to the contoller */ Drive d[Ndrive]; /* the floppy drives */ | |
| 1991/0727 | int busy; /* true if a read or write in progress */ uchar stat[8]; /* status of an operation */ int confused; | |
| 1991/0731 | int intr; /* true if interrupt occured */ Rendez r; /* wait here for command termination */ | |
| 1991/0727 | }; | |
| 1991/0728 | Controller floppy; | |
| 1991/0727 | /* | |
| 1991/0731 | * predeclared */ static void motoron(Drive*); static void motoroff(Drive*); static void floppykproc(void*); static int floppysend(int); static int floppyrcv(void); static int floppyresult(int); static void floppypos(Drive*); static int floppysense(Drive*); static int interrupted(void*); static int floppyrecal(Drive*); static void floppyrevive(void); static long floppyseek(Drive*); static long floppyxfer(Drive*, int, void*, long); static void floppyintr(Ureg*); static int floppygen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp) { long l; Drive *dp; if(s >= ntab) return -1; if(c->dev >= Ndrive) return -1; tab += s; dp = &floppy.d[c->dev]; if((tab->qid.path&~Mask) == Qdata) l = dp->t->cap; else l = 8; devdir(c, tab->qid, tab->name, l, tab->perm, dp); return 1; } void floppyreset(void) { Drive *dp; for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ dp->dev = dp - floppy.d; dp->t = &floppytype[0]; /* default type */ dp->motoron = 1; dp->cyl = -1; motoroff(dp); } setvec(Floppyvec, floppyintr); } void floppyinit(void) { Type *t; /* * init dependent parameters */ for(t = floppytype; t < &floppytype[NTYPES], t++){ t->cap = t->bytes * t->heads * t->sectors * t->tracks; t->bcode = bcode[t->bytes/128]; } /* * watchdog to turn off the motors */ kproc(floppykproc, 0); } long floppyread(Chan *c, void *a, long n) { Drive *dp; long rv, i; uchar *aa = a; dp = &floppy.d[c->dev]; for(rv = 0; rv < n; rv += i){ i = floppyxfer(dp, Fread, aa+rv, n-rv); if(i <= 0) break; } return rv; } long floppywrite(Chan *c, void *a, long n) { Drive *dp; long rv, i; uchar *aa = a; dp = &floppy.d[c->dev]; for(rv = 0; rv < n; rv += i){ i = floppyxfer(dp, Fwrite, aa+rv, n-rv); if(i <= 0) break; } return rv; } /* | |
| 1991/0727 | * start a floppy drive's motor. set an alarm for 1 second later to * mark it as started (we get no interrupt to tell us). * * assume the caller qlocked the drive. */ | |
| 1991/0731 | static void motoron(Drive *dp) | |
| 1991/0727 | { int cmd; | |
| 1991/0730/sys/src/9/pc/devfloppy.c:146,153 – 1991/0731/sys/src/9/pc/devfloppy.c:268,275 | ||
| 1991/0727 | /* * stop the floppy if it hasn't been used in 5 seconds */ | |
| 1991/0731 | static void motoroff(Drive *dp) | |
| 1991/0727 | { int cmd; | |
| 1991/0730/sys/src/9/pc/devfloppy.c:155,176 – 1991/0731/sys/src/9/pc/devfloppy.c:277,301 | ||
| 1991/0727 | outb(Fmotor, cmd); dp->motoron = 0; } | |
| 1991/0731 | static void floppykproc(void *a) | |
| 1991/0727 | { Drive *dp; | |
| 1991/0731 | for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ | |
| 1991/0728 | if(dp->motoron && TK2SEC(m->ticks - dp->lasttouched) > 5 && canqlock(dp)){ | |
| 1991/0729 | if(TK2SEC(m->ticks - dp->lasttouched) > 5) | |
| 1991/0731 | motoroff(dp); | |
| 1991/0728 | qunlock(dp); } | |
| 1991/0727 | } } | |
| 1991/0731 | /* * send a byte to the floppy */ static int | |
| 1991/0727 | floppysend(int data) { int tries; | |
| 1991/0730/sys/src/9/pc/devfloppy.c:193,199 – 1991/0731/sys/src/9/pc/devfloppy.c:318,327 | ||
| 1991/0727 | return -1; } | |
| 1991/0731 | /* * get a byte from the floppy */ static int | |
| 1991/0727 | floppyrcv(void) { int tries; | |
| 1991/0730/sys/src/9/pc/devfloppy.c:215,222 – 1991/0731/sys/src/9/pc/devfloppy.c:343,353 | ||
| 1991/0727 | return -1; } | |
| 1991/0731 | /* * read a command result message from the floppy */ static int floppyresult(int n) | |
| 1991/0727 | { int i; int c; | |
| 1991/0730/sys/src/9/pc/devfloppy.c:230,243 – 1991/0731/sys/src/9/pc/devfloppy.c:361,379 | ||
| 1991/0727 | return 0; } | |
| 1991/0731 | /* * calculate physical address of a logical byte offset into the disk * * truncate dp->length if it crosses a cylinder boundary */ static void floppypos(Drive *dp) | |
| 1991/0727 | { int lsec; int end; int cyl; | |
| 1991/0731 | lsec = dp->off/dp->t->bytes; | |
| 1991/0727 | 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; | |
| 1991/0730/sys/src/9/pc/devfloppy.c:246,261 – 1991/0731/sys/src/9/pc/devfloppy.c:382,401 | ||
| 1991/0727 | * can't read across cylinder boundaries. * if so, decrement the bytes to be read. */ | |
| 1991/0731 | lsec = (dp->off+dp->len)/dp->t->bytes; | |
| 1991/0727 | cyl = lsec/(dp->t->sectors*dp->t->heads); if(cyl != dp->tcyl){ | |
| 1991/0731 | dp->len -= (lsec % dp->t->sectors)*dp->t->bytes; dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*dp->t->bytes | |
| 1991/0727 | *dp->t->sectors; } } | |
| 1991/0731 | /* * get the interrupt cause from the floppy. we need to do this * after seeks and recalibrations since they don't return results. */ static int | |
| 1991/0727 | floppysense(Drive *dp) { /* | |
| 1991/0730/sys/src/9/pc/devfloppy.c:265,271 – 1991/0731/sys/src/9/pc/devfloppy.c:405,411 | ||
| 1991/0727 | floppy.confused = 1; return -1; } | |
| 1991/0731 | if(floppyresult(2) < 0){ | |
| 1991/0727 | floppy.confused = 1; dp->confused = 1; return -1; | |
| 1991/0730/sys/src/9/pc/devfloppy.c:282,288 – 1991/0731/sys/src/9/pc/devfloppy.c:422,440 | ||
| 1991/0727 | return 0; } | |
| 1991/0731 | /* * return true if interrupt occurred */ static int interrupted(void *a) { return floppy.intr; } /* * we've lost the floppy position, go to cylinder 0. */ static int | |
| 1991/0727 | floppyrecal(Drive *dp) { floppy.intr = 0; | |
| 1991/0730/sys/src/9/pc/devfloppy.c:291,297 – 1991/0731/sys/src/9/pc/devfloppy.c:443,449 | ||
| 1991/0727 | floppy.confused = 0; return -1; } | |
| 1991/0731 | sleep(&floppy.r, interrupted, 0); | |
| 1991/0727 | /* * get return values | |
| 1991/0730/sys/src/9/pc/devfloppy.c:323,355 – 1991/0731/sys/src/9/pc/devfloppy.c:475,491 | ||
| 1991/0727 | return 0; } | |
| 1991/0731 | /* * if the controller or a specific drive is in a confused state, * reset it and get back to a kown state */ | |
| 1991/0727 | void | |
| 1991/0728 |
| |
| 1991/0731 | floppyrevive(void) | |
| 1991/0727 | { Drive *dp; | |
| 1991/0728 |
| |
| 1991/0727 |
| |
| 1991/0728 |
| |
| 1991/0727 |
| |
| 1991/0728 |
| |
| 1991/0727 |
| |
| 1991/0731 | * reset the floppy if it's confused | |
| 1991/0727 | */ if(floppy.confused){ /* reset controller and turn all motors off */ | |
| 1991/0730/sys/src/9/pc/devfloppy.c:359,369 – 1991/0731/sys/src/9/pc/devfloppy.c:495,505 | ||
| 1991/0727 | delay(1); outb(Fmotor, Fintena|Fena); spllo(); | |
| 1991/0731 | for(dp = floppy.d; dp < &floppy.d[Ndrive]; dp++){ | |
| 1991/0727 | dp->motoron = 0; dp->confused = 1; } | |
| 1991/0731 | sleep(&floppy.r, interrupted, 0); | |
| 1991/0727 | floppy.confused = 0; } | |
| 1991/0730/sys/src/9/pc/devfloppy.c:370,376 – 1991/0731/sys/src/9/pc/devfloppy.c:506,512 | ||
| 1991/0727 | /* * recalibrate any confused drives */ | |
| 1991/0731 | for(dp = floppy.d; floppy.confused == 0 && dp < &floppy.d[Ndrive]; dp++){ | |
| 1991/0727 | if(dp->confused == 0) floppyrecal(dp); | |
| 1991/0730/sys/src/9/pc/devfloppy.c:378,396 – 1991/0731/sys/src/9/pc/devfloppy.c:514,522 | ||
| 1991/0727 | } | |
| 1991/0731 | static long floppyseek(Drive *dp) | |
| 1991/0727 | { | |
| 1991/0730/sys/src/9/pc/devfloppy.c:400,406 – 1991/0731/sys/src/9/pc/devfloppy.c:526,532 | ||
| 1991/0727 | * tell floppy to seek */ if(floppysend(Fseek) < 0 | |
| 1991/0731 | || floppysend((dp->thead<<2) | dp->dev) < 0 | |
| 1991/0727 | || floppysend(dp->tcyl * dp->t->steps) < 0){ print("seek cmd failed\n"); floppy.confused = 1; | |
| 1991/0730/sys/src/9/pc/devfloppy.c:410,416 – 1991/0731/sys/src/9/pc/devfloppy.c:536,542 | ||
| 1991/0727 | /* * wait for interrupt */ | |
| 1991/0731 | sleep(&floppy.r, interrupted, 0); | |
| 1991/0727 | /* * get floppy status | |
| 1991/0730/sys/src/9/pc/devfloppy.c:441,482 – 1991/0731/sys/src/9/pc/devfloppy.c:567,613 | ||
| 1991/0727 | return dp->offset; } | |
| 1991/0731 | static long | |
| 1991/0727 | floppyxfer(Drive *dp, int cmd, void *a, long n) { | |
| 1991/0731 | qlock(&floppy); qlock(dp); if(waserror){ qunlock(&floppy); qunlock(dp); } | |
| 1991/0727 | /* | |
| 1991/0731 | * get floppy reset and spinning | |
| 1991/0727 | */ | |
| 1991/0731 | if(floppy.confused || dp->confused) floppyrevive(); if(!dp->motoron) motoron(dp); | |
| 1991/0727 | ||
| 1991/0731 | /* * calculate new position and seek to it (dp->len may be trimmed) */ | |
| 1991/0727 | dp->len = n; | |
| 1991/0731 | floppypos(dp); if(floppyseek(dp) < 0) errors("seeking floppy"); | |
| 1991/0727 |
| |
| 1991/0731 | print("tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", | |
| 1991/0727 | dp->tcyl, dp->thead, dp->tsec, addr, n);/**/ /* | |
| 1991/0731 | * set up the dma (dp->len may be trimmed) | |
| 1991/0727 | */ | |
| 1991/0731 | dp->len = dmasetup(2, a, dp->len, cmd==Fread); | |
| 1991/0727 | /* | |
| 1991/0731 | * start operation | |
| 1991/0727 | */ cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0); if(floppysend(cmd) < 0 | |
| 1991/0730/sys/src/9/pc/devfloppy.c:484,507 – 1991/0731/sys/src/9/pc/devfloppy.c:615,638 | ||
| 1991/0727 | || floppysend(dp->tcyl * dp->t->steps) < 0 || floppysend(dp->thead) < 0 || floppysend(dp->tsec) < 0 | |
| 1991/0731 | || floppysend(dp->t->bcode) < 0 | |
| 1991/0727 | || floppysend(dp->t->sectors) < 0 || floppysend(dp->t->gpl) < 0 || floppysend(0xFF) < 0){ print("xfer cmd failed\n"); floppy.confused = 1; | |
| 1991/0731 | errors("floppy command failed"); | |
| 1991/0727 | } | |
| 1991/0731 | sleep(&floppy.r, interrupted, 0); | |
| 1991/0727 | /* * get status */ | |
| 1991/0731 | if(floppyresult(7) < 0){ print("xfer status failed\n"); | |
| 1991/0727 | floppy.confused = 1; | |
| 1991/0731 | errors("floppy result failed"); | |
| 1991/0727 | } if((floppy.stat[0] & Codemask)!=0 || floppy.stat[1] || floppy.stat[2]){ | |
| 1991/0730/sys/src/9/pc/devfloppy.c:508,547 – 1991/0731/sys/src/9/pc/devfloppy.c:639,667 | ||
| 1991/0727 | print("xfer failed %lux %lux %lux\n", floppy.stat[0], floppy.stat[1], floppy.stat[2]); dp->confused = 1; | |
| 1991/0731 | errors("floppy drive lost"); | |
| 1991/0727 | } offset = (floppy.stat[3]/dp->t->steps) * dp->t->heads + floppy.stat[4]; offset = offset*dp->t->sectors + floppy.stat[5] - 1; | |
| 1991/0731 | offset = offset * c2b[floppy.stat[6]]; | |
| 1991/0727 | if(offset != dp->offset+n){ | |
| 1991/0731 | print("new offset %d instead of %d\n", offset, dp->offset+dp->len); | |
| 1991/0727 | dp->confused = 1; | |
| 1991/0731 | errors("floppy drive lost"); | |
| 1991/0727 | } | |
| 1991/0731 | qunlock(&floppy); qunlock(dp); poperror(); | |
| 1991/0727 | dp->offset += dp->len; return dp->len; } | |
| 1991/0731 | static void | |
| 1991/0727 | floppyintr(Ureg *ur) { floppy.intr = 1; | |
| 1991/0731 | wakeup(&floppy.r); | |
| 1991/0727 | } | |