📄 oofdc.cxx
字号:
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::StartIO(uint8_t unit){ DiskUnit& du = GetUnit(unit); uint8_t hd, sec, cyl; uint32_t secsPerCyl; assert(du.curReq); DiskIoReq* ioReq = du.curReq->ioReq; #ifdef FDCDEBUG Diag::printf("FDC::StartIO(%d): enter. status=%d req = %x, cmd == %s)\n", unit, (int) du.ioState, du.curReq, du.curReq->cmdName());#endif if (!du.attached) Diag::fatal(0,"Attempt to access detached/absent unit %s\n", du.Name()); for (;;) { /* If we are actually going to do some work, configure the * controller appropriately: */ switch (du.ioState) { case IosReady: case IosNeedRecal: case IosRecalDone: case IosSeekDone: ConfigureFDC(); /* set up for I/O */ /* Activate the drive control pins: */ dor &= ~3; dor |= unit; outb(NECREG::DOR, dor); Stall(100); } switch (du.ioState) { case IosSpunDown: case IosSpinUpWait:#ifdef FDCDEBUG Diag::printf("FDC::startCurrentOp(): still spinning up\n");#endif /* nothing to do at the moment */ return; case IosSpinDownWait: du.timer.Cancel(); case IosReady: if (!du.curReq) { du.ioState = IosSpinDownWait; du.timer.SleepFor(MOTOR_SHUT_WAIT); return; } case IosNeedRecal: case IosRecalWait: case IosRecalDone: case IosSeekWait: case IosSeekDone: case IosReadWait: case IosReadDone: case IosWriteWait: case IosWriteDone: case IosFormatWait: case IosFormatDone: } } char cmdstr[9]; /* command string to send */ char *cmdbyte = cmdstr; /* Media is present and spinning. If not calibrated, do so: */ if (!du.calibrated) {#ifdef FDCDEBUG Diag::printf("FDC::startCurrentOp(): Recalibrate\n");#endif /* recall the floppy arm to track 0: */ lastCmd = CmdRecal; *cmdbyte++ = NECCMD::RECALIBRATE; *cmdbyte++ = unit; goto sendcmd; } /* 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 = start; cyl = sec / secsPerCyl; sec -= (cyl * secsPerCyl); hd = sec/curParams->nSec; sec -= hd * curParams->nSec; #ifdef FDCDEBUG2 Diag::printf("FDC::startCurrentOp(): start %d nsec %d " "[cyl %d hd %d sec %d]\n", start, nsec, cyl, hd, sec);#endif /* if necessary, seek to the appropriate cylinder. It appears * that if the seek does not actually move the arm, the head value * does not get updated, so only check the cylinder, not the head. */ if (du.curcyl != cyl ) {#ifdef FDCDEBUG Diag::printf("FDC::startCurrentOp(): Seek\n");#endif lastCmd = CmdSeek; *cmdbyte++ = NECCMD::SEEK; *cmdbyte++ = (hd<<2)|unit; *cmdbyte++ = cyl; goto sendcmd; } else { /* Seek has completed, so any pending errors should be * canceled: */ nError = 0; } #if 0 /* If the operation was merely a seek command, we should not get * 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]);}#if 0class FDC : public DiskCtrlr { enum { NUM_UNITS = 2, /* floppy controller has up to 4 */ /* units, but for now support only 2 */ }; #if 0 enum UnitCommands { CmdNone, CmdReset, CmdRecal, CmdSeek, CmdRead, CmdWrite, };#endif DiskUnit units[NUM_UNITS]; /* Because the floppy has removable media, the media parameters * can change, and may change from use to use. */ FloppyInfo *unitParams[4]; /* Current media parameters */ FloppyInfo *curParams; /* How FDC is currently programmed */ DiskUnit& GetUnit(uint8_t whichUnit); void StartRequest(uint8_t unit); /* COMMANDS */ void Reset(); /* CONTROLLER IO */ uint8_t dor; uint32_t secsToXfer; /* used in read/write operations */ int nresults; /* number of results from last operation */ uint8_t results[8]; /* actual result values */ void OutFDC(uint8_t); int GetResults(); void ConfigureFDC(); /* INTERRUPT HANDLING */ virtual void OnEvent(Event&); void ResetIntr(FixRegs *); void SeekIntr(FixRegs *); void RwIntr(FixRegs *); /* MOTOR CONTROL */ enum { MOTOR_SHUT_WAIT = 10000, MOTOR_START_WAIT = 40, }; virtual void Spinup(uint8_t unit); virtual void Spindown(uint8_t unit); virtual bool Attach(uint8_t unit); /* return true if succeeded */ virtual void Detach(uint8_t unit); void OnIdle(uint8_t unit); public: FDC(AutoConf::ID id); virtual void Probe(); virtual void Attach(); virtual const char* UnitName(uint8_t unit); uint32_t GetCylinder(uint8_t unit, uint32_t sec);};FDC TheFDC(AutoConf::FDCA);static Timer timer(&TheFDC);DiskUnit& FDC::GetUnit(uint8_t whichUnit){ assert(whichUnit < NUM_UNITS); return units[whichUnit];}FDC::FDC(AutoConf::ID id): DiskCtrlr(id, NUM_UNITS, McMem1M){ int i; dor = 0; for(i = 0; i < NUM_UNITS; i++) { units[i].unitNo = i; units[i].ctrlr = this; }}voidFDC::Reset(){#ifdef FDCDEBUG Diag::printf("FDC::reset(): enter\n");#endif ctrlrStatus = CtrlrBusy; IDT::Disable(); /* CRITICAL REGION */ lastCmd = CmdReset; dor = 0; /* Reset FDC, Motors off */ outb(NECREG::DOR, dor); Stall(100); dor = DOR::Reset|DOR::DmaGate; /* re-enable the part */ outb(NECREG::DOR, dor); IDT::Enable(); /* END CRITICAL REGION */}void FDC::Probe(){ /* FIX: This may or may not actually be present. A real probe * routine is called for! */ present = true;}void FDC::Attach(){ int i; ctrlrStatus = CtrlrIdle; IDT::RegisterHandler(IntFloppy, this);/* IDT::EnableIRQ(IRQ6); */ /* For the moment, we do not support more than 2 floppy drives. * Someday I will have to fix this. */ for (i = 0; i < NUM_UNITS; i++) { uint32_t type = CMOS::fdType(i); DiskUnit& du = GetUnit(i); du.type = type; if (du.type) { du.unitState = DiskCtrlr::UsPresent; du.isRemovable = true; /* Floppies only automount if they are the boot drive. */ du.bootAttach = (i == SysConfig.boot.drive) ? true : false; du.multiFormat = true; } Diag::printf("%s: %s\n", UnitName(i), FloppyParams[type].name); } Reset(); attached = true; Diag::printf("FDC::init() complete\n");}/* FIX: a lot of this strategy routine is very disk-centric. When we * get around to tapes we need to do something about this. *//* The generic controller logic has committed us to doing something, * and has properly initialized the request block. Start the actual * operation. Controller is already marked "busy". */void FDC::StartRequest(){ assert(unit < NUM_UNITS); uint8_t hd, sec, cyl; uint32_t secsPerCyl; assert(req); DiskIoReq* ioReq = req->ioReq; DiskUnit& du = GetUnit(unit); #ifdef FDCDEBUG Diag::printf("FDC::startRequest(): enter. unit=%d status=%d req = %x, cmd == %s)\n", unit, (int) du.status, req, req->cmdName());#endif if (!du.unitState < DiskCtrlr::UsAttached) Diag::fatal(0,"Attempt to access detached/absent unit %s\n", UnitName(unit));#if 0 if (!du.mediaPresent) Diag::printf("No media in drive %s\n", UnitName(unit));#endif if (du.status == DiskUnit::UnitIdle) { /* We are racing with the disk motor logic to cancel the * spindown. If we win, we end up in the ready state. If not, * the motor logic will place the drive in the Offline state. */ IDT::Disable(); if (du.spinning) du.status = DiskUnit::UnitActive; else Spinup(unit); IDT::Enable();#ifdef FDCMOTOR Diag::printf("FDC::startCurrentOp(): Unit %d Spindown canceled\n", unit);#endif } /* At this point, drive is either spinning up or we are ready to * initiate. */ /* OK if unit is still spinning up. */ if (du.status == DiskUnit::UnitSpinUp) {#ifdef FDCDEBUG Diag::printf("FDC::startCurrentOp(): still spinning up\n");#endif return; } ConfigureFDC(); /* set up for I/O */ /* Activate the drive control pins: */ dor &= ~3; dor |= unit; outb(NECREG::DOR, dor); Stall(100); char cmdstr[9]; /* command string to send */ char *cmdbyte = cmdstr; /* Media is present and spinning. If not calibrated, do so: */ if (!du.calibrated) {#ifdef FDCDEBUG Diag::printf("FDC::startCurrentOp(): Recalibrate\n");#endif /* recall the floppy arm to track 0: */ lastCmd = CmdRecal; *cmdbyte++ = NECCMD::RECALIBRATE; *cmdbyte++ = unit; goto sendcmd; } /* 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 = start; cyl = sec / secsPerCyl; sec -= (cyl * secsPerCyl); hd = sec/curParams->nSec; sec -= hd * curParams->nSec; #ifdef FDCDEBUG2 Diag::printf("FDC::startCurrentOp(): start %d nsec %d " "[cyl %d hd %d sec %d]\n", start, nsec, cyl, hd, sec);#endif /* if necessary, seek to the appropriate cylinder. It appears * that if the seek does not actually move the arm, the head value * does not get updated, so only check the cylinder, not the head. */ if (du.curcyl != cyl ) {#ifdef FDCDEBUG Diag::printf("FDC::startCurrentOp(): Seek\n");#endif lastCmd = CmdSeek; *cmdbyte++ = NECCMD::SEEK; *cmdbyte++ = (hd<<2)|unit; *cmdbyte++ = cyl; goto sendcmd; } else { /* Seek has completed, so any pending errors should be * canceled: */ nError = 0; } #if 0 /* If the operation was merely a seek command, we should not get
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -