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

📄 ide_ide.cxx

📁 C++ 编写的EROS RTOS
💻 CXX
📖 第 1 页 / 共 2 页
字号:
/* * 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. */#include <kerninc/kernel.hxx>#include <kerninc/MsgLog.hxx>#include <kerninc/AutoConf.hxx>#include <kerninc/IoRegion.hxx>#include <kerninc/IntAction.hxx>#include <kerninc/IRQ.hxx>#include <kerninc/BlockDev.hxx>#include <kerninc/IoRequest.hxx>#include <eros/Device.h>#include <arch/i486/kernel/SysConfig.hxx>#include <arch/i486/kernel/CMOS.hxx>static bool Probe(AutoConf *ac);static bool Attach(AutoConf *ac);struct Driver ac_ide = {  "hd", Probe, Attach} ;#include "io.h"/* #define IDE_DEBUG *//* Driver for IDE interface devices and (also) older ST506 devices. * According to the ATA Faq, these interfaces are assigned as follows: * (REF: ATA Faq) *  *  Interface   CS0-decode   CS1-decode   IRQ *  1           0x1F0-0x1F7  0x3F6-0x3F7  14 *  2           0x170-0x177  0x376-0x377  15 or 10 -- usually 15 *  3           0x1E8-0x1EF  0x3EE-0x3EF  12 or 11 *  4           0x168-0x16F  0x36E-0x36F  10 or 9 *  * The current implementation does not configure interfaces 3 and 4, * because there is no real standard for port assignments on * interfaces 3 and 4, and I am reluctant to deploy what I cannot * test. */const uint16_t ide_cs0[] = { 0x1F0, 0x170, 0x1E8, 0x168 };const uint16_t ide_irq[] = { 14, 15, 12, 10 };#include "ide_ide.hxx"const char *ide_name[MAX_HWIF] = { "ide0", "ide1" };#include "ide_drive.hxx"#include "ide_hwif.hxx"#include "ide_group.hxx"	      #define BIOS_HD_BASE	 0x1F0#define OK_TO_RESET_CONTROLLER 0/* In theory, these should not be statically allocated, but it * complexifies things to do otherwise, and they don't really take up * all that much space. */ide_group group_tbl[MAX_HWIF];ide_hwif  hwif_tbl[MAX_HWIF];ide_hwif::ide_hwif(){  uint32_t hwifno = this - hwif_tbl;    ndx = hwifno;  irq = 0;		/* probe for this */  ioBase = ide_cs0[hwifno];  /*  ctlBase = ide_cs1[hwifno]; */  chipset = IDE::cs_unknown;  noprobe = (hwifno > 1) ? true : false;  present = false;  /* Second unit may be present even if first unit isn't, so... */  nUnits = MAX_DRIVE;  devClass = DEV_DISK_IDE;  name = "ide";    group = &group_tbl[hwifno];  group->hwif[0] = this;#if 0  /* Given the number of bone-headed IDE controller chips out there,   * and the fact that more are being discovered daily, proceed on the   * assumption that the IDE interface chip is brain damaged until   * proven otherwise.   */    serialized = true;#endif  int_handler = 0;  dma_handler = 0;    for (int drv = 0; drv < MAX_DRIVE; drv++) {    drive[drv].ndx = drv;    drive[drv].hwif = this;    drive[drv].select.all = (drv << 4) | 0xa0;    drive[drv].name[0] = 'h';    drive[drv].name[1] = 'd';    drive[drv].name[2] = 'a' + hwifno;    drive[drv].name[3] = '0' + drv;    drive[drv].name[4] = 0;  }}voidide_hwif::SetHandler(uint8_t unit, bool (ide_hwif::*handler)()){  assert (unit == cur_drive);  assert(int_handler == 0);    int_handler = handler;#ifdef IDE_DEBUG  MsgLog::printf("Set int handler to 0x%08x\n", &handler);#endif}/* Issue a simple drive command */voidide_hwif::DoCmd(uint8_t unit, uint8_t cmd, uint8_t nsec, bool (ide_hwif::*handler)()){  SetHandler(unit, handler);  Put8(IDE_CTL_ALTSTATUS, drive[unit].ctl);  Put8(IDE_NSECS, nsec);  Put8(IDE_CMD, cmd);}/* * ide_do_reset() is the entry point to the drive/interface reset code. */voidide_hwif::DoReset(uint8_t unit){  DoReset1(unit, false);#ifdef CONFIG_BLK_DEV_IDETAPE  if (drive->media == ide_tape)    drive->tape.reset_issued=1;#endif /* CONFIG_BLK_DEV_IDETAPE */}/* * do_reset1() attempts to recover a confused drive by resetting it. * Unfortunately, resetting a disk drive actually resets all devices on * the same interface, so it can really be thought of as resetting the * interface rather than resetting the drive. * * ATAPI devices have their own reset mechanism which allows them to be * individually reset without clobbering other devices on the same interface. * * Unfortunately, the IDE interface does not generate an interrupt to let * us know when the reset operation has finished, so we must poll for this. * Equally poor, though, is the fact that this may a very long time to complete, * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it, * we set a timer to poll at 50ms intervals. */voidide_hwif::DoReset1(uint8_t unit, bool /* suppressAtapi */){#ifdef CONFIG_BLK_DEV_IDEATAPI  /* Interrupts may need to be disabled here... */    /* For an ATAPI device, first try an ATAPI SRST. */  if (drive[unit].media != IDE::med_disk) {    MsgLog::fatal("Reset1 on non-disk not implemented\n");        if (!suppressAtapi) {      if (!keep_settings)	unmask = 0;      SelectDrive(unit);      Machine::SpinWait(20);      Put8(IDE_CMD, WIN_SRST);#if 0      hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;      ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20);#endif      return;    }  }#endif /* CONFIG_BLK_DEV_IDEATAPI */  /*   * First, reset any device state data we were maintaining   * for any of the drives on this interface.   */  for (unit = 0; unit < MAX_DRIVE; ++unit) {    ide_drive *pUnit = &drive[unit];    pUnit->flags.all = 0;    pUnit->flags.b.setGeom = 1;    pUnit->flags.b.recal  = 1;    if (OK_TO_RESET_CONTROLLER)      pUnit->multCount = 0;#if 0    if (!pUnit->keep_settings) {      pUnit->mult_req = 0;      pUnit->unmask = 0;      if (pUnit->using_dma) {	pUnit->using_dma = 0;	MsgLog::printf("%s: disabled DMA\n", pUnit->name);      }    }#endif#if 0    if (pUnit->mult_req != pUnit->mult_count)      pUnit->special.b.set_multmode = 1;#endif  }#if OK_TO_RESET_CONTROLLER  /*   * Note that we also set nIEN while resetting the device,   * to mask unwanted interrupts from the interface during the reset.   * However, due to the design of PC hardware, this will cause an   * immediate interrupt due to the edge transition it produces.   * This single interrupt gives us a "fast poll" for drives that   * recover from reset very quickly, saving us the first 50ms wait time.   */  OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG);	/* set SRST and nIEN */  udelay(5);			/* more than enough time */  OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG);	/* clear SRST, leave nIEN */  hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;  ide_set_handler (drive, &reset_pollfunc, HZ/20);#endif	/* OK_TO_RESET_CONTROLLER */}voidide_hwif::SelectDrive(uint32_t unit){  Put8(IDE_DRV_HD, drive[unit].select.all);}/*  * FUNCTIONS FOR THE EROS BLOCK DEVICE INTERFACE *  */voidide_hwif::MountUnit(uint8_t unit){  assert (unit < MAX_DRIVE);  assert (drive[unit].present);  assert (drive[unit].needsMount);  assert (drive[unit].mounted == false);  if (drive[unit].removable) {    MsgLog::fatal("Removable unit locking not yet implemented\n");  }    drive[unit].mounted = true;  drive[unit].needsMount = false;  totalMountedUnits++;}voidide_hwif::GetUnitInfo(uint8_t unit, BlockUnitInfo& ui){  assert (unit < MAX_DRIVE);  if (drive[unit].present == false) {    ui.isDisk = false;  }  else {    ui.b_geom = drive[unit].b_chs;    ui.d_geom = drive[unit].l_chs;    ui.nSecs = drive[unit].Capacity();    ui.isEros = true;		/* if any partition might be EROS */    ui.isDisk = (drive[unit].media == IDE::med_disk) ? true : false;    ui.isMounted = drive[unit].mounted;    ui.needsMount = drive[unit].needsMount;    ui.hasPartitions = true;    ui.isBoot = false;        /* FIX: If we're not on a DOS machine.... */        if (ioBase == BIOS_HD_BASE && ((unit | 0x80) == unit))      ui.isBoot = true;  }}voidide_hwif::InsertRequest(Request *req){#if 0  MsgLog::printf("Request ior=0x%08x inserted on hwif=0x%08x\n",		 req, this);#endif    assert (req->unit < MAX_DRIVE);  assert (drive[req->unit].mounted == true);  drive[req->unit].rq.InsertRequest(req);  StartIO();}/* INTERRUPT HANDLERS: */boolide_hwif::SetMultmodeIntr(){  uint8_t status = Get8(IDE_STATUS);  if (OK_STAT(status, READY_STAT, BAD_STAT)) {    drive[cur_drive].multCount = drive[cur_drive].multReq;  }  else {    drive[cur_drive].multCount = 0;    drive[cur_drive].multReq = 0;    drive[cur_drive].flags.b.recal = 1;    drive[cur_drive].DumpStatus("Multmode interrupt", status, 0);  }  #ifdef IDE_DEBUG  MsgLog::printf("SetMultMode: xfer in %d sec blocks\n",		 drive[cur_drive].multCount);#endif  return true;}boolide_hwif::RecalibrateIntr(){  uint8_t status = Get8(IDE_STATUS);  if (!OK_STAT(status,READY_STAT,BAD_STAT))    drive[cur_drive].Error("recalibrate interrupt", status);#ifdef IDE_DEBUG  MsgLog::printf("RecalIntr(): Set int handler to 0\n");#endif  int_handler = 0;  return true;}boolide_hwif::SetGeometryIntr(){  uint8_t status = Get8(IDE_STATUS);  if (!OK_STAT(status,READY_STAT,BAD_STAT))    drive[cur_drive].Error("set geometry intr", status);#ifdef IDE_DEBUG  MsgLog::printf("SetGeomIntr(): Set int handler to 0\n");#endif  int_handler = 0;    return true;}/* When using IDE drives, we always issue a request for the total * desired number of sectors.  If the drive supports READ MULTIPLE we * use it to reduce the number of generated interrupts, else we live * with taking one interrupt per sector. */boolide_hwif::ReadIntr(){  uint8_t status = Get8(IDE_STATUS);  if (!OK_STAT(status,DATA_READY,BAD_R_STAT)) {    drive[cur_drive].Error("read intr", status);    return true;  }  uint32_t max_xfer = drive[cur_drive].multCount;  if (max_xfer == 0) max_xfer = 1;    /* What follows is really the same code as in MultWrite, and it   * isn't clear to me why it is replicated here.   */    Request *req = group->curReq;    uint32_t nsec = req->nsec;  if (nsec > max_xfer)    nsec = max_xfer;  #ifdef IDE_DEBUG  MsgLog::printf("Transfer was 0x%08x: %d sectors at %d nsec %d\n",		 req->req_ioaddr, req->req_nsec, req->req_start, req->nsec);  MsgLog::printf("Transferring %d sectors of data\n", nsec);#endif    drive[cur_drive].InputData((void*) req->req_ioaddr, nsec *			     EROS_SECTOR_SIZE >> 2);

⌨️ 快捷键说明

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