📄 oofdc.cxx
字号:
* this far before the interrupt handler declares it done. */ assert (ioReq->cmd != DiskIoReq::OpSeek);#endif /* START THE I/O OPERATION: */ /* Compute number of sectors to transfer: */ secsToXfer = min(nsec, curParams->nSec - sec); #ifdef FDCDEBUG Diag::printf("FDC::startCurrentOp(): xfer %d secs\n", secsToXfer);#endif assert(iokva); assert (ioReq->cmd == IoReq::OpObjectRead || ioReq->cmd == IoReq::OpObjectWrite); { int iswrite = (ioReq->cmd == IoReq::OpObjectWrite); dmakva = DMA::setup(DMAC::FLOPPY, iokva, secsToXfer * EROS_SECTOR_SIZE, iswrite ? DMA::WRITE : DMA::READ); lastCmd = iswrite ? CmdWrite : CmdRead; *cmdbyte++ = iswrite ? NECCMD::WRITE : NECCMD::READ; *cmdbyte++ = (hd<<2)|unit; *cmdbyte++ = cyl; *cmdbyte++ = hd; *cmdbyte++ = sec+1; *cmdbyte++ = 0x2u; /* 512 byte sector size */ *cmdbyte++ = curParams->nSec; /* sectors per track */ *cmdbyte++ = curParams->fmt_gap; /* sectors per track */ *cmdbyte++ = 0xff; /* DTL?? */ } sendcmd: int count = cmdbyte - cmdstr; int i; for (i = 0; i < count; i++) OutFDC(cmdstr[i]);}voidFDC::ConfigureFDC(){ assert(unitParams[unit]); if (curParams == unitParams[unit]) return; curParams = unitParams[unit]; #ifdef FDCDEBUG2 Diag::printf("Specify drive parameters\n");#endif OutFDC(NECCMD::SPECIFY); OutFDC(curParams->spec1); OutFDC(6); /* head unload time */ #ifdef FDCDEBUG2 Diag::printf("And data rate\n");#endif outb(NECREG::DCR, curParams->dataRate & 3);}const char*FDC::UnitName(uint8_t unit){ static char *name = "fdXX\0"; name[2] = ConfigTable[id].name[2]; name[3] = '0' + unit; return name;}voidFDC::OnEvent(Event& e){ if (e.kind == Event::Interrupt) { /* Reset is not really an operation. */ if (lastCmd == CmdReset) ResetIntr(e.fr); else { if (!req) Diag::fatal(0,"Unexpected floppy interrupt\n"); assert(req); switch(lastCmd) { case CmdReset: Diag::fatal(0,"Fielded FDC reset interrupt in wrong place\n"); break; case CmdRecal: case CmdSeek: SeekIntr(e.fr); break; case CmdRead: case CmdWrite: RwIntr(e.fr); break; } /* if command has completed. call the completion routine: */ if (ioReq->cmd == IoReq::OpDone) {#ifdef FDCDEBUG Diag::printf("FDC::do_intr(): command complete. cte= 0x%x\n", ioReq->cte);#endif ctrlrStatus = CtrlrIdle; KernThread::SetReady(ioReq->ioThread); } else ctrlrStatus = CtrlrMore; /* retry the current op */ KernThread::SetReady(Thread::DiskDaemon); } } else { /* timer went off */#ifdef FDCMOTOR Diag::printf("FDC::OnTimer(): Motor timer went off\n");#endif uint8_t u; for (u = 0; u < NUM_UNITS; u++) { DiskUnit& du = GetUnit(u); /* No need to check if unit present. If not present, cannot be * in spinup state. If not present, cannot be spinning. */ if (du.status == DiskUnit::UnitSpinUp) { du.spinning = true; du.calibrated = false; du.status = DiskUnit::UnitActive; assert(du.unitPresent); #ifdef FDCMOTOR Diag::printf("FDC::OnTimer(): unit %d spun up\n", u);#endif ctrlrStatus = CtrlrMore; KernThread::SetReady(Thread::DiskDaemon); } else if (du.status == DiskUnit::UnitIdle && du.spinning) {#ifdef FDCMOTOR Diag::printf("FDC::OnTimer(): unit %d spun down\n", u);#endif assert(du.unitPresent); Spindown(u); } }#if 0 dor &= ~(DOR::Motor0|DOR::Motor1|DOR::Motor2|DOR::Motor3); outb(NECREG::DOR, dor); for (u = 0; u < NUM_UNITS; u++) { DiskUnit& du = GetUnit(u); du.status = DiskUnit::Offline; } #endif }}voidFDC::ResetIntr(FixRegs *fr){ int i; #ifdef FDCDEBUG2 Diag::printf("FDC::reset_intr(): Run a sensei after RESET\n");#endif for (i = 0; i < NUM_UNITS; i++) { DiskUnit& du = GetUnit(i); /* sense the drive status */ OutFDC(NECCMD::SENSEI); if (GetResults() != 2) Diag::fatal(0,"Improper results from FDC reset\n"); /* if the unit is present, it is now offline */ if (units[i].unitPresent) units[i].spinning = false; /* set floppy parameters to the default for the particular * media type. */ unitParams[i] = &FloppyParams[du.type]; } unit = 0; curParams = 0; ctrlrStatus = CtrlrIdle; KernThread::SetReady(Thread::DiskDaemon); /* IDT::ResetPIC(); */ return;}voidFDC::SeekIntr(FixRegs *fr){#ifdef FDCDEBUG Diag::printf("FDC::seek_intr(): curcmd == %d\n", lastCmd);#endif OutFDC(NECCMD::SENSEI); if (GetResults() != 2) { /* controller is hosed - resetting it should restart the requests. */ Reset(); Diag::fatal(0,"FDC::seek_intr(): Floppy not responding"); } uint32_t sr0 = results[0]; /* We should have completed the seek: */ if (!(sr0 & SR0::SeekEnd)) nError += 2; /* We should not have aborted or run off the end of the * drive. In the event that we did, give it one more try * because we might be recalibrating a drive with > 80 * cylinders someday: */ if (sr0 & (SR0::EquipChk | SR0::IC)) nError += 4; if (nError > MAX_ERROR) { Diag::fatal(0, "Error count exceeded\n"); req->OnIntrCompletion(IOR::Range); } if (nError) return; DiskUnit& du = GetUnit(unit); du.curcyl = results[1];#if 0 du.curhd = (results[0] & 0x4) ? 1 : 0;#endif #ifdef FDCDEBUG Diag::printf("Post seek: unit %d curcyl=%d\n", unit, du.curcyl);#endif if (du.calibrated == false) { assert(du.curcyl == 0); du.calibrated = true; }#if 0 if (ioReq->cmd == DiskIoReq::OpSeek) req->Completed();#endif}voidFDC::RwIntr(FixRegs *fr){#ifdef FDCDEBUG Diag::printf("FDC::rw_intr(): curcmd == %d\n", lastCmd);#endif if (GetResults() != 7) { /* controller is hosed - resetting it should restart the requests. */ Reset(); Diag::fatal(0,"FDC::rw_intr(): Floppy not responding"); } uint32_t sr0 = results[0]; /* We should not have interrupted or run off the end of the * drive. We should not have needed to seek. */ if ((sr0 & SR0::IC) == 0) { /* We now need to decide if we are done with the operation or * not. If the operation went over a track boundary, we need * to hack track, head, sector, and nsec and start over: */ /* Bounce buffer copy. Probably shouldn't be done with interrupts * disabled, but until I rebuild the I/O subsystem this is * the simplest solution. */ if (dmakva != iokva) bcopy(dmakva, iokva, nsec * EROS_SECTOR_SIZE); nsec -= secsToXfer; start += secsToXfer; iokva += (secsToXfer * EROS_SECTOR_SIZE); } /* FIX: Seeking is probably panicworthy. */ if (sr0 & (SR0::EquipChk | SR0::SeekEnd | SR0::IC)) Diag::fatal(0,"FDC: Unexpected seek\n"); uint8_t sr1 = results[1]; /* A CRC error just means a bad sector. We should retry: */ if (sr1 & (SR1::BadCrc | SR1::NoData)) nError += 2; /* allow five retries */ if (nError > MAX_ERROR) { req->OnIntrCompletion(IOR::Range); return; } /* An overrun or going past end of cylinder is a fatal * problem. Something is wrong with the kernel: */ if (DMA::get_residue(DMAC::FLOPPY) || (sr1 & (SR1::Overrun | SR1::CylEnd))) Diag::fatal(0,"DMA Overrun by fd%d\n", unit); if (!nsec) {#ifdef FDCDEBUG Diag::printf("Op completed\n");#ifdef PARANOID uint32_t* puint32_t = (Word *) UserMem.CTEtoPage(req->cte); int i; for (i = 0; i < 8; i++) Diag::printf("0x%x ", *pWord++); Diag::printf("\n");#endif#endif req->OnIntrCompletion(IOR::OK); KernThread::SetReady(Thread::DiskDaemon); }} /* MOTOR CONTROL * * An FDC has some number of associated diskettes, each of which has a * motor whose state must unfortunately be modeled. * * The spin variable has the following values: * * 1 Motor is spinning * 0 Motor is off * -1 Motor will be spinning when the timer goes off * */voidFDC::Spinup(uint8_t unit){ /* Because the spinup timer could go off while we are here, this * is a critical region: */ #ifdef FDCMOTOR Diag::printf("FDC::SpinUp(%d): enter\n", unit);#endif DiskUnit& du = GetUnit(unit); assert(du.spinning == false); #ifdef FDCMOTOR Diag::printf("FDC::SpinUp(): %s: spinning up\n", UnitName(unit));#endif du.status = DiskUnit::UnitSpinUp; dor |= (0x10 << unit); /* Spin control. Bet you thought only marketing did that. */ outb(NECREG::DOR, dor); timer.SleepFor(MOTOR_START_WAIT);}voidFDC::OnIdle(uint8_t unit){#ifdef FDCMOTOR Diag::printf("FDC::OnIdle(): OnIdle called.\n");#endif DiskUnit& du = GetUnit(unit); if (du.unitPresent == false) Diag::fatal(0, "FDC::OnIdle(): Tried to idle offline unit %d\n", unit); IDT::Disable(); /* CRITICAL REGION */ if (!timer.active) timer.SleepFor(MOTOR_SHUT_WAIT); du.status = DiskUnit::UnitIdle; IDT::Enable(); /* END CRITICAL REGION */}voidFDC::Spindown(uint8_t unit){ DiskUnit& du = GetUnit(unit); dor &= ~(DOR::Motor0 << unit); outb(NECREG::DOR, dor); du.spinning = false;}/* Since floppies are not partitionable, this is fairly simple. */boolFDC::Attach(uint8_t unit){ DiskUnit& du = GetUnit(unit); /* Attaching media that are not present should succeed trivially. */ if (!du.unitPresent) { Diag::printf("unit %d is not present\n", unit); return true; } if (!du.mediaPresent) { Diag::printf("unit %d - no media\n", unit); return true; } /* do not attach redundantly... */ if (du.attached) { Diag::printf("unit %d is attached\n", unit); return true; } /* Force a read of sector 0, whose side effect will be to do * autoformat detection: */ Diag::printf("Reading raw page 0 from unit %d\n", du.unitNo); CoreObject* bootSector = du.ReadRawPage(0); if (!bootSector) return false; UserMem.releasePage(bootSector); Diag::printf("Released raw page 0 from unit %d\n", du.unitNo); DiskVolume* pVol = DiskVolume::AllocVolume(); Diag::printf("DiskVolume structure allocated\n"); pVol->diskUnit = &units[unit]; pVol->start = 0; pVol->hostPartition = 0; pVol->isErosVolume = false; /* until we know otherwise */ if (unit == SysConfig.boot.drive) pVol->isBootVolume = true; pVol->Announce(); du.attached = true; return true;}voidFDC::Detach(uint8_t unit){ Diag::fatal(0, "FDC::detach() not implemented yet\n");}uint32_tFDC::GetCylinder(uint8_t unit, uint32_t sec){ uint32_t secsPerCyl = unitParams[unit]->nHd * unitParams[unit]->nSec; return sec/secsPerCyl;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -