⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 oofdc.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (C) 1998, 1999, Jonathan S. Shapiro. * * This file is part of the EROS Operating System. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* Low-level floppy controller implementation. * FIX - don't start the motor shutdown timer until the operation * queue is empty! */#include <kernel/Diag.hxx>#include "kernel.hxx"#include "lostart.hxx"#include <kernel/io.h>#include "IDT.hxx"#include "CMOS.hxx"#include "KernThread.hxx"#include "CoreObject.hxx"#include "IoReq.hxx"#include "DMA.hxx"#include "UserMem.hxx"#include "SysConfig.hxx"#include "SysTimer.hxx"#include "DiskCtrlr.hxx"#include "DiskVolume.hxx"/* #define FDCDEBUG * #define FDCDEBUG2 * #define PARANOID * #define FDCMOTOR */struct FloppyInfo {  uint16_t totSectors;  uint8_t     nSec;  uint8_t	   nHd;  uint8_t	   nCyl;  uint8_t	   doubleStep;    uint8_t	   gap;  uint8_t	   dataRate;  uint8_t	   spec1;  uint8_t	   fmt_gap;  char *   name;  uint8_t	   nextToTry;};/* Formatting parameters for various media in various drives. * Note that the order of these is chosen so that the first five * entries match the drive type encodings returned by the CMOS NVRAM. */static FloppyInfo FloppyParams[] = {    {    0, 0,0, 0,0,0x00,0x00,0x00,0x00,"None", 0 }, /* no testing */    {  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k", 0 }, /* 360kB PC diskettes */    /* Following entry used to have '6' in its nextToTry slot: */    { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"1.2M", 0 }, /* 1.2 MB AT-diskettes */    { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720K", 0 }, /* 720kB diskette */    { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"1.44M", 3 }, /* 1.44MB diskette */#if 0    /* we do not support these ancient pieces of crap.  Actually, we     * only support 360 kb and 720 kb because it's easier than     * adjusting what the BIOS tells us.     */        {  720, 9,2,40,1,0x2A,0x02,0xDF,0x50,NULL, 0 }, /* 360kB in 720kB drive */    {  720, 9,2,40,1,0x23,0x01,0xDF,0x50,NULL, 0 }, /* 360kB in 1.2MB drive */    { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,NULL, 0 }, /* 720kB in 1.2MB drive */#endif};#define NUM_UNITS 2class FDC : public DiskCtrlr {  /* Ports on the NEC 765 controller: */  struct NECREG {    enum {      DOR    = 0x2,		/* digital output register */      TDR    = 0x3,		/* tape drive register (not on NEC 765) */      STATUS = 0x4,		/* status register */      DATA   = 0x5,		/* data register */      DIR    = 0x7,		/* digital input register: read only */      DCR    = 0x7,		/* Diskette control register: write only */    };  };  /* bits in the DOR register: */  struct DOR {    enum {      Motor3  = 0x80,		/* set if indicated motor is spinning */      Motor2  = 0x40,      Motor1  = 0x20,      Motor0  = 0x10,      DmaGate = 0x08,		/* set for most commands */      Reset   = 0x04,		/* set for most commands */      DrvSel1 = 0x02,      DrvSel0 = 0x01,    };  };  struct STATUS {    enum {      Master    = 0x80,	/* host can send if set to 1 */      ReqRead   = 0x40,	/* 1 indicates read */      NonDMA    = 0x20,	/* set in specify command */      CmdBusy   = 0x10,	/* 1 if command in progress */      Drv3Busy  = 0x08,      Drv2Busy  = 0x04,      Drv1Busy  = 0x02,      Drv0Busy  = 0x01,    };  };  /* NEC Commands that we use: */  struct NECCMD {    enum {      VERSION = 0x10,      CONFIGURE = 0x13,      SPECIFY = 0x03,      RECALIBRATE = 0x07,      SENSEI = 0x08,      SEEK = 0x0f,      /* Floppy I/O operations */      READ = 0xc6, /* with MT, MFM.  0xE6 with skip deleted */      WRITE = 0xc5, /* with MT, MFM */      FORMAT = 0x4d, /* with MFM */    };  };  /* Masks and values for Status Register 0: */  struct SR0 {    enum {      IC         = 0xC0,	/* interrupt code mask */      ICnormal   = 0x00,	/* normal completion */      ICabnormal = 0x40,	/* failed */      ICbadcmd   = 0x80,	/* bad command */      ICpolled   = 0xC0,	/* interrupted by a poll operation. */      SeekEnd    = 0x20,	/* Seek completed */      EquipChk   = 0x10,	/* Equipment Check - 1 if recalibrate */				/* did not make it to track 0 or a				 * relative seek overran track 0				 */      Head       = 0x04,	/* Head address mask */      Head0      = 0x00,      Head1      = 0x04,      DrvSel     = 0x03,	/* Drive select mask. Values are 0..3 */    };  };  struct SR1 {    enum {      CylEnd     = 0x80,	/* Hit end of cylinder */      BadCrc     = 0x20,	/* CRC on data or ID failed */      Overrun    = 0x10,	/* DMA service too slow */      NoData     = 0x04,	/* sector may have been deleted */      WriteProt  = 0x02,	/* Write Protected */      NoAddr     = 0x01,	/* Missing address mark */    };  };  protected:  uint8_t dor;  /* controller state holders: */  int nresults;			/* number of results from last operation */  uint8_t results[8];		/* actual result values */  void Reset();  void OutFDC(uint8_t);  int GetResults();    void ConfigureFDC();  FloppyInfo *curParams;	/* How FDC is currently programmed */  /* UNIT OPERATIONS   *    * These are here so that only one new class needs to be defined for   * a new controller type.  The unit and the controller are   * incestuously related anyway.   */    DiskUnit* units[NUM_UNITS];  DiskUnit& GetUnit(uint8_t whichUnit);  void StartIO(uint8_t unit);  void StartMount(uint8_t unit);  bool CanSchedule(uint8_t unit);  void OnEvent(Event& event);  void OnKeyCall();  void OnEvent(uint8_t unit, Event& event);  bool Probe(uint8_t unit);  void Attach(uint8_t unit);  void OnKeyCall(uint8_t unit);public:  FDC(AutoConf::ID id, io_t ioaddr);    virtual void Probe();  virtual void Attach();};FDC fdca(AutoConf::FDCA, (io_t) 0x3f0);DiskUnit fdca0(AutoConf::FDCA0, &fdca, 0);DiskUnit fdca1(AutoConf::FDCA1, &fdca, 1);DiskUnit fdca2(AutoConf::FDCA2, &fdca, 2);DiskUnit fdca3(AutoConf::FDCA3, &fdca, 3);#if 0/* G++ is broken - it doesn't support this. */DiskUnit* FDCAunits[4] = {  { AutoConf::FDCA0, fdca, 0 },  { AutoConf::FDCA1, fdca, 1 },  { AutoConf::FDCA2, fdca, 2 },  { AutoConf::FDCA3, fdca, 3 }};#endifFDC::FDC(AutoConf::ID id, io_t ioaddr): DiskCtrlr(id, NUM_UNITS, ioaddr, (kva_t)0, McMem1M){  int i;  dor = 0;    if (id == AutoConf::FDCA) {    units[0] = &fdca0;    units[1] = &fdca1;#if (NUM_UNITS > 2)    units[2] = &fdca2;#endif#if (NUM_UNITS > 3)    units[3] = &fdca3;#endif  }}voidFDC::Probe(){  present = CMOS::HaveFDC();}voidFDC::Attach(){  IDT::RegisterHandler(IntFloppy, this);  Reset();}boolFDC::Probe(uint8_t unit){  DiskUnit& du = GetUnit(unit);  uint32_t type = CMOS::fdType(unit);  du.type = type;  if (du.type) {    du.isRemovable = true;    du.bootAttach = (unit == SysConfig.boot.drive) ? true : false;    du.multiFormat = true;        Diag::printf("%s: %s\n", du.Name(), FloppyParams[type].name);  }  return (du.type != 0);}voidFDC::Attach(uint8_t unit){  /* FIX: this needs to change! */  if (present)    attached = true;}voidFDC::Reset(){  dor = 0;			/* Reset FDC, Motors off */    outb(NECREG::DOR, dor);  Stall(100);    state = CsResetWait;  dor = DOR::Reset|DOR::DmaGate; /* re-enable the part */  outb(ioBase + NECREG::DOR, dor);  while (state == CsResetWait)    Stall(100);  assert(state == CsActive);}voidFDC::OnEvent(Event& e){  switch(state) {  case CsActive:    OnEvent(curUnit, e);    return;  case CsResetWait:    {      assert(e.kind == Event::Interrupt);        curParams = 0;      curUnit = 0;      /* Controller comes back in polling mode.  Must run four SENSEI       * operations to clear this mode.       */          int i;        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");	/* The unit is now spun down. */	du.ioState = IosSpunDown;      }        state = CsActive;        KernThread::SetReady(Thread::DiskDaemon);        return;    }  }}voidFDC::OnEvent(uint8_t unit, Event& e){  DiskUnit& du = GetUnit(unit);    if (e.kind == Event::Interrupt) {    switch(du.ioState) {    case IosRecalWait:      du.ioState = IosRecalDone;      break;    case IosSeekWait:      du.ioState = IosSeekDone;      break;    case IosReadWait:      du.ioState = IosReadDone;      break;    case IosWriteWait:      du.ioState = IosWriteDone;      break;    case IosFormatWait:      du.ioState = IosFormatDone;      break;    default:      Diag::fatal(0, "%s: Unexpected interrupt\n", Name());    }    KernThread::SetReady(Thread::DiskDaemon);  }  if (e.kind == Event::Timer) {    switch(du.ioState) {    case IosSpinUpWait:      du.ioState = IosNeedRecal;      KernThread::SetReady(Thread::DiskDaemon);      break;    case IosSpinDownWait:      dor &= ~(DOR::Motor0 << unit);      outb(NECREG::DOR, dor);      du.ioState = IosSpunDown;      break;    default:      Diag::fatal(0, "%s: Unexpected watchdog timer\n", Name());    }  }}boolFDC::CanSchedule(uint8_t unit){  DiskUnit& du = GetUnit(unit);  /* If we have nothing to do, pass the token. Note that the effect of   * 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");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -