📄 devfloppy.c
字号:
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"#include "floppy.h"/* Intel 82077A (8272A compatible) floppy controller *//* This module expects the following functions to be defined * elsewhere: * * inb() * outb() * floppyexec() * floppyeject() * floppysetup0() * floppysetup1() * dmainit() * dmasetup() * dmaend() * * On DMA systems, floppyexec() should be an empty function; * on non-DMA systems, dmaend() should be an empty function; * dmasetup() may enforce maximum transfer sizes. */enum { /* file types */ Qdir= 0, Qdata= (1<<2), Qctl= (2<<2), Qmask= (3<<2), DMAchan= 2, /* floppy dma channel */};#define DPRINT if(floppydebug)printint floppydebug = 0;/* * types of drive (from PC equipment byte) */enum{ Tnone= 0, T360kb= 1, T1200kb= 2, T720kb= 3, T1440kb= 4,};FType 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, }, { "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, }, { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },};/* * 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,};FController fl;#define MOTORBIT(i) (1<<((i)+4))/* * predeclared */static int cmddone(void*);static void floppyformat(FDrive*, char*);static void floppykproc(void*);static void floppypos(FDrive*,long);static int floppyrecal(FDrive*);static int floppyresult(void);static void floppyrevive(void);static long floppyseek(FDrive*, long);static int floppysense(void);static void floppywait(void);static long floppyxfer(FDrive*, int, void*, long, long);Dirtab floppydir[]={ "fd0disk", {Qdata + 0}, 0, 0660, "fd0ctl", {Qctl + 0}, 0, 0660, "fd1disk", {Qdata + 1}, 0, 0660, "fd1ctl", {Qctl + 1}, 0, 0660, "fd2disk", {Qdata + 2}, 0, 0660, "fd2ctl", {Qctl + 2}, 0, 0660, "fd3disk", {Qdata + 3}, 0, 0660, "fd3ctl", {Qctl + 3}, 0, 0660,};#define NFDIR 2 /* directory entries/drive */static voidfldump(void){ DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb), inb(Pdor), inb(Pmsr), inb(Pdir));}/* * set floppy drive to its default type */static voidfloppysetdef(FDrive *dp){ FType *t; for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++) if(dp->dt == t->dt){ dp->t = t; floppydir[NFDIR*dp->dev].length = dp->t->cap; break; }}static voidfloppyreset(void){ FDrive *dp; FType *t; ulong maxtsize; floppysetup0(&fl); if(fl.ndrive == 0) return; /* * init dependent parameters */ maxtsize = 0; for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){ t->cap = t->bytes * t->heads * t->sectors * t->tracks; t->bcode = b2c[t->bytes/128]; t->tsize = t->bytes * t->sectors; if(maxtsize < t->tsize) maxtsize = t->tsize; } dmainit(DMAchan, maxtsize); /* * allocate the drive storage */ fl.d = xalloc(fl.ndrive*sizeof(FDrive)); fl.selected = fl.d; /* * stop the motors */ fl.motor = 0; delay(10); outb(Pdor, fl.motor | Fintena | Fena); delay(10); /* * init drives */ for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){ dp->dev = dp - fl.d; dp->dt = T1440kb; floppysetdef(dp); dp->cyl = -1; /* because we don't know */ dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024); dp->ccyl = -1; dp->vers = 0; } /* * first operation will recalibrate */ fl.confused = 1; floppysetup1(&fl);}static Chan*floppyattach(char *spec){ static int kstarted; if(fl.ndrive == 0) error(Enodev); if(kstarted == 0){ /* * watchdog to turn off the motors */ kstarted = 1; kproc("floppy", floppykproc, 0); } return devattach('f', spec);}static intfloppywalk(Chan *c, char *name){ return devwalk(c, name, floppydir, fl.ndrive*NFDIR, devgen);}static voidfloppystat(Chan *c, char *dp){ devstat(c, dp, floppydir, fl.ndrive*NFDIR, devgen);}static Chan*floppyopen(Chan *c, int omode){ return devopen(c, omode, floppydir, fl.ndrive*NFDIR, devgen);}static voidfloppyclose(Chan *){}static voidislegal(ulong offset, long n, FDrive *dp){ if(offset % dp->t->bytes) error(Ebadarg); if(n % dp->t->bytes) error(Ebadarg);}/* * check if the floppy has been replaced under foot. cause * an error if it has. * * a seek and a read clears the condition. this was determined * experimentally, there has to be a better way. * * if the read fails, cycle through the possible floppy * density till one works or we've cycled through all * possibilities for this drive. */static voidchanged(Chan *c, FDrive *dp){ ulong old; FType *start; /* * if floppy has changed or first time through */ if((inb(Pdir)&Fchange) || dp->vers == 0){ DPRINT("changed\n"); fldump(); dp->vers++; floppysetdef(dp); start = dp->t; dp->confused = 1; /* make floppyon recal */ floppyon(dp); floppyseek(dp, dp->t->heads*dp->t->tsize); while(waserror()){ while(++dp->t){ if(dp->t == &floppytype[nelem(floppytype)]) dp->t = floppytype; if(dp->dt == dp->t->dt) break; } floppydir[NFDIR*dp->dev].length = dp->t->cap; floppyon(dp); DPRINT("changed: trying %s\n", dp->t->name); fldump(); if(dp->t == start) nexterror(); } floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize); poperror(); } old = c->qid.vers; c->qid.vers = dp->vers; if(old && old != dp->vers) error(Eio);}static intreadtrack(FDrive *dp, int cyl, int head){ int i, nn, sofar; ulong pos; nn = dp->t->tsize; if(dp->ccyl==cyl && dp->chead==head) return nn; pos = (cyl*dp->t->heads+head) * nn; for(sofar = 0; sofar < nn; sofar += i){ dp->ccyl = -1; i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar); if(i <= 0) return -1; } dp->ccyl = cyl; dp->chead = head; return nn;}static longfloppyread(Chan *c, void *a, long n, vlong off){ FDrive *dp; long rv; int sec, head, cyl; long len; uchar *aa; ulong offset = off; if(c->qid.path == CHDIR) return devdirread(c, a, n, floppydir, fl.ndrive*NFDIR, devgen); rv = 0; dp = &fl.d[c->qid.path & ~Qmask]; switch ((int)(c->qid.path & Qmask)) { case Qdata: islegal(offset, n, dp); aa = a; qlock(&fl); if(waserror()){ qunlock(&fl); nexterror(); } floppyon(dp); changed(c, dp); for(rv = 0; rv < n; rv += len){ /* * all xfers come out of the track cache */ dp->len = n - rv; floppypos(dp, offset+rv); cyl = dp->tcyl; head = dp->thead; len = dp->len; sec = dp->tsec; if(readtrack(dp, cyl, head) < 0) break; memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len); } qunlock(&fl); poperror(); break; case Qctl: return readstr(offset, a, n, dp->t->name); default: panic("floppyread: bad qid"); } return rv;}#define SNCMP(a, b) strncmp(a, b, sizeof(b)-1)static longfloppywrite(Chan *c, void *a, long n, vlong off){ FDrive *dp; long rv, i; char *aa = a; char ctlmsg[64]; ulong offset = off; rv = 0; dp = &fl.d[c->qid.path & ~Qmask]; switch ((int)(c->qid.path & Qmask)) { case Qdata: islegal(offset, n, dp); qlock(&fl); if(waserror()){ qunlock(&fl); nexterror(); } floppyon(dp); changed(c, dp); for(rv = 0; rv < n; rv += i){ floppypos(dp, offset+rv); if(dp->tcyl == dp->ccyl) dp->ccyl = -1; i = floppyxfer(dp, Fwrite, aa+rv, offset+rv, n-rv); if(i < 0) break; if(i == 0) error(Eio); } qunlock(&fl); poperror(); break; case Qctl: rv = n; qlock(&fl); if(waserror()){ qunlock(&fl); nexterror(); } if(n >= sizeof(ctlmsg)) n = sizeof(ctlmsg) - 1; memmove(ctlmsg, aa, n); ctlmsg[n] = 0; if(SNCMP(ctlmsg, "eject") == 0){ floppyeject(dp); } else if(SNCMP(ctlmsg, "reset") == 0){ fl.confused = 1; floppyon(dp); } else if(SNCMP(ctlmsg, "format") == 0){ floppyformat(dp, ctlmsg); } else if(SNCMP(ctlmsg, "debug") == 0){ floppydebug = 1; } else error(Ebadctl); poperror(); qunlock(&fl); break; default: panic("floppywrite: bad qid"); } return rv;}static voidfloppykproc(void *){ FDrive *dp; while(waserror()) ; for(;;){ for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){ if((fl.motor&MOTORBIT(dp->dev)) && TK2SEC(m->ticks - dp->lasttouched) > 5 && canqlock(&fl)){ if(TK2SEC(m->ticks - dp->lasttouched) > 5) floppyoff(dp); qunlock(&fl); } } tsleep(&fl.kr, return0, 0, 1000); }}/* * start a floppy drive's motor. */static voidfloppyon(FDrive *dp){ int alreadyon; int tries; if(fl.confused) floppyrevive(); /* start motor and select drive */ alreadyon = fl.motor & MOTORBIT(dp->dev); fl.motor |= MOTORBIT(dp->dev); outb(Pdor, fl.motor | Fintena | Fena | dp->dev); if(!alreadyon){ /* wait for drive to spin up */ tsleep(&dp->r, return0, 0, 750); /* clear any pending interrupts */ floppysense(); } /* 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 = m->ticks; fl.selected = dp;}/* * stop the floppy if it hasn't been used in 5 seconds */static voidfloppyoff(FDrive *dp){ fl.motor &= ~MOTORBIT(dp->dev); outb(Pdor, fl.motor | Fintena | Fena | dp->dev);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -