📄 ofdc.cxx
字号:
* this is that the token runs just ahead of the unit index in * DiskCtrlr::StartIO(). */ if (!du.GetNextRequest()) { curUnit ++; if (curUnit == nUnits) curUnit -= nUnits; return false; } /* If we have something to do, we can start it if we have the token * or if we need to start the motor. */ if (unit == curUnit) return true; if (du.ioState == DiskCtrlr::IosSpunDown) return true; return false;}voidFDC::OnKeyCall(){ Diag::fatal(0, "FDC::OnKeyCall called\n");}voidFDC::OnKeyCall(uint8_t unit){ Diag::fatal(0, "FDC::OnKeyCall(%d) called\n", unit);}DiskUnit& FDC::GetUnit(uint8_t whichUnit){ assert(whichUnit < NUM_UNITS); return *(units[whichUnit]);}voidFDC::OutFDC(uint8_t b){#ifdef FDCIODEBUG Diag::printf("FDC::OutFDC(%x)\n", b);#endif uint8_t r; for (int i = 0; i < 10000; i++) { r = inb(NECREG::STATUS); r &= (STATUS::Master | STATUS::ReqRead); if (r == STATUS::Master) { outb(NECREG::DATA, b); return; } } Diag::fatal(0,"FDC::OutFDC() failed. Status Reg = %x\n", r);}intFDC::GetResults(){ int i, n = 0; for (i = 0 ; i < 1000 ; i++) { uint8_t r = inb(NECREG::STATUS); r &= (STATUS::Master|STATUS::ReqRead|STATUS::CmdBusy); if (r == STATUS::Master) { /* not busy, ready for commands */ return n; } if (r == (STATUS::Master|STATUS::ReqRead|STATUS::CmdBusy)) { if (n >= 8) { Diag::fatal(0,"FDC::GetResults(): too many answers\n"); break; } results[n] = inb(NECREG::DATA);#ifdef FDCIODEBUG Diag::printf("results[%d] = 0x%x\n", n, results[n]);#endif n++; } } Diag::fatal(0,"FDC::getStatus(): couldn't get status\n"); return -1;}void FDC::StartMount(uint8_t unit){ Diag::fatal(0, "FDC::StartMount(unit) not yet implemented\n");}void FDC::StartIO(uint8_t unit){ DiskUnit& du = GetUnit(unit); bool iswrite = true; uint8_t hd, sec, cyl; uint32_t secsPerCyl; UnitIoReq* req = du.GetNextRequest(); DiskIoReq* ioReq = req->ioReq; #ifdef FDCDEBUG Diag::printf("FDC::StartIO(%d): enter. status=%d req = %x, cmd == %s)\n", unit, (int) du.ioState, req, req->cmdName());#endif if (!du.IsAttached()) Diag::fatal(0,"Attempt to access detached/absent unit %s\n", du.Name()); /* compute the head, cyl, and sec for this operation. We need * to recompute this in every pass because the last operation * may have been a partially complete I/O operation that hit the * end of a cylinder boundary. */ secsPerCyl = curParams->nHd * curParams->nSec; sec = du.start; cyl = sec / secsPerCyl; sec -= (cyl * secsPerCyl); hd = sec/curParams->nSec; sec -= hd * curParams->nSec; /* Compute number of sectors to transfer: */ uint32_t secsToXfer = min(du.nsec, curParams->nSec - sec); for (;;) { /* If we are actually going to start an I/O action, configure the * controller appropriately: */ switch (du.ioState) { case IosStartRecal: case IosStartSense: case IosStartSeek: case IosStartRead: case IosStartWrite:#if 0 case IosStartFormat:#endif ConfigureFDC(unit); /* set up for I/O */ /* Activate the drive control pins: */ dor &= ~3; dor |= unit; outb(NECREG::DOR, dor); Stall(100); } switch (du.ioState) { case IosRecalWait: case IosSenseWait: case IosSeekWait: case IosReadWait: case IosWriteWait:#if 0 case IosFormatWait:#endif case IosSpinUpWait: return; case IosSpinDownWait: /* If we are starting an operation, and the drive is waiting to * spin down, cancel the spindown timer and hope we get there * before the spindown happens. From here, we'll either end up * in the IosReady state or the */ du.timer.Cancel(); /* If we beat the spindown, we still know the cylinder position, * so go ahead and do the seek. */ if (du.ioState == IosSpinDownWait) du.ioState = IosStartIO; break; case IosSpunDown: du.ioState = IosSpinUpWait; dor |= (0x10 << unit); outb(NECREG::DOR, dor); du.timer.SleepFor(MOTOR_START_WAIT); return; case IosReady: if (!req) { du.ioState = IosSpinDownWait; du.timer.SleepFor(MOTOR_SHUT_WAIT); return; } case IosStartIO: if (du.curCyl != cyl) { du.ioState = IosSeekWait; } else { switch(ioReq->cmd) { case IoReq::OpObjectRead: case IoReq::OpFormatDetect: du.ioState = IosStartRead; break; case IoReq::OpObjectWrite: du.ioState = IosStartWrite; break;#if 0 case IoReq::OpFormatTrack: du.ioState = IosStartFormat; break;#endif } } break; case IosStartRecal: OutFDC(NECCMD::RECALIBRATE); OutFDC(unit); break; case IosStartSense: OutFDC(NECCMD::READID); OutFDC((hd<<2)|unit); du.ioState = IosSenseWait; break; case IosStartSeek: OutFDC(NECCMD::SEEK); OutFDC((hd<<2)|unit); OutFDC(cyl); du.ioState = IosSeekWait; break; case IosStartRead: iswrite = false; /* FALL THROUGH */ case IosStartWrite: { dmakva = DMA::setup(DMAC::FLOPPY, iokva, secsToXfer * EROS_SECTOR_SIZE, iswrite ? DMA::WRITE : DMA::READ); OutFDC(iswrite ? NECCMD::WRITE : NECCMD::READ); OutFDC((hd<<2)|unit); OutFDC(cyl); OutFDC(hd); OutFDC(sec+1); OutFDC(0x2u); /* 512 byte sector size */ OutFDC(curParams->nSec); /* sectors per track */ OutFDC(curParams->fmt_gap); OutFDC(0xff); /* DTL?? */ }#if 0 case IosStartFormat:#endif case IosSenseDone: { if (GetResults() != 7) { /* controller is hosed - resetting it should restart the requests. */ Reset(); Diag::fatal(0,"FDC::rw_intr(): Floppy not responding"); } du.ioState = IosStartIO; Word sr0 = results[0]; if ((sr0 & SR0::IC) == 0) { du.nError += 4; du.ioState = IosStartRecal; } break; } case IosRecalDone: case IosSeekDone: { 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"); } Word sr0 = results[0]; if ((sr0 & (SR0::EquipChk | SR0::IC | SR0::SeekEnd)) == SR0::SeekEnd) { /* Completed successfully */ du.curCyl = results[1]; du.ioState = IosStartIO; } else { /* Seek did not complete, so bump the error count for that: */ du.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)) du.nError += 4; du.ioState = IosStartSeek; } break; } case IosReadDone: case IosWriteDone: { if (GetResults() != 7) { /* controller is hosed - resetting it should restart the requests. */ Reset(); Diag::fatal(0,"FDC::rw_intr(): Floppy not responding"); } /* Assume we completed this operation until we determine otherwise: */ du.ioState = IosCompleted; Word 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: */ du.nsec -= secsToXfer; if (du.nsec) { du.ioState = IosStartIO; du.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)) { du.nError += 2; /* allow five retries */ du.ioState = IosStartIO; } /* An overrun or going past end of cylinder is (for the moment) * 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 0 case IosFormatDone:#endif case IosXferData:#if 0 /* 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);#endif case IosError: case IosCompleted: break; } if (du.nError > MAX_ERROR) du.ioState = IosError; }}voidFDC::ConfigureFDC(uint8_t unit){ DiskUnit& du = GetUnit(unit); if (curParams == &FloppyParams[du.format]) return; curParams = &FloppyParams[du.format]; #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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -