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

📄 hdd.c

📁 MMURTL(tm) Computer Operating System Ver x0.8, source code.
💻 C
📖 第 1 页 / 共 3 页
字号:
			if ((statbyte & SEEKOK) == 0) erc =	ErcBadSeek;
		break;
	  case HDC_SET_PARAMS:
	  case HDC_VERIFY:
	  case HDC_FORMAT:
	  case HDC_DIAG:
		break;
	  default:
		break;
	}
    return(erc);
	}
  else {
	erc = check_busy();
	if (!erc)
	  errbyte = InByte(HD_PORT+1);
	else return(erc);

	if (hd_drive)
	    hdstatus.LastErcByte1 = errbyte;
	else
	    hdstatus.LastErcByte0 = errbyte;

	if (errbyte & BAD_ADDRESS) erc = ErcAddrMark;
	else if (errbyte & BAD_SEEK) erc = ErcBadSeek;
	else if (errbyte & BAD_CMD) erc = ErcBadCmd;
	else if (errbyte & BAD_IDMARK) erc = ErcSectNotFound;
	else if (errbyte & BAD_ECC) erc = ErcBadECC;
	else if (errbyte & BAD_SECTOR) erc = ErcBadBlock;
	else erc = ErcBadHDC; /* no error bits found but should have been! */
  }
 return erc;
}

/*************************************************************
 This is called for the DeviceOp code Read.
 This reads 1 or more whole sectors from the calculated values
 in hd_head, hd_sector, and hd_cyl
*************************************************************/

U32  hd_read(U32 dLBA, U32 dnBlocks, U8 *pDataRet)
{
U32 erc, nleft, nBPS;

  nBPS = hdcb[hd_drive].nBPB;			/* From nBytesPerBlock in DCB */
  nleft = dnBlocks;
  erc = setupseek(dLBA, dnBlocks);		/* sets up for implied seek */
  if (!erc) erc = send_command(HDC_READ);

  while ((nleft) && (!erc)) {
	  erc = hd_wait();					/* wait for interrupt */
	  if (!erc)
	  	erc = hd_status(HDC_READ);
	  if (!erc)		/* && (statbyte & DATA_REQ))  */ {
	  	InWords(HD_PORT, pDataRet, nBPS);
	  	pDataRet+=nBPS;
	  	--nleft;
	  	}
  }
  return(erc);
}

/*************************************************************
 This is called for the DeviceOp code Write.
 This writes 1 or more whole sectors from the calculated values
 in hd_head, hd_sector, and hd_cyl
*************************************************************/

U32  hd_write(U32 dLBA, U32 dnBlocks, U8 *pDataOut)
{
U32 erc, nSoFar, nBPS;

  nBPS = hdcb[hd_drive].nBPB;			/* From n BytesPerBlock in DCB */
  nSoFar = 0;
  erc = setupseek(dLBA, dnBlocks);		/* sets up for implied seek */
  erc = send_command(HDC_WRITE);
  erc = check_busy();			/* No INT occurs for first sector of write */

  if ((!erc) && (statbyte & DATA_REQ)) {
	OutWords(HD_PORT, pDataOut, nBPS);
	pDataOut+=nBPS;
	nSoFar++;
	}

  while ((nSoFar < dnBlocks ) && (erc==ok)) {
	  erc = hd_wait();					/* wait for interrupt */
      if (erc==ok) erc = hd_status(HDC_WRITE);
	  if ((erc==ok) && (statbyte & DATA_REQ)) {
		  OutWords(HD_PORT, pDataOut, nBPS);
		  pDataOut+=nBPS;
		  nSoFar++;
		  }
  }
  if (!erc) erc = hd_wait();			/* wait for final interrupt */
  if (!erc) erc = hd_status(HDC_WRITE);

  return(erc);
}


/*************************************************************
 This formats the track beginning at the block address given
 in dLBA. dLBA must always be a multiple of the number of
 sectors per track minus 1 for the disk type.
*************************************************************/

U32  hd_format_track(U32 dLBA, U32 dnBlocks)
{
U32  erc;
  erc = setupseek(dLBA, dnBlocks);		/* sets up for implied seek */
  erc = send_command(HDC_FORMAT);
  erc = hd_wait();						/* wait for interrupt */
  if (erc==ok)
      erc = hd_status(HDC_FORMAT);
  return(erc);
}

/******************************************************************
   ReadSector is the only device specific call in the IDE/MFM hard
   disk device driver.  This allows you to read ONE sector
   specified by Cylinder, head and Sector number.
   Cylinder is LoWord of dLBA in DeviceOp call,
   Head is LoWord of dnBlocks in DeviceOp call, and
   Sector number is HiWord in dnBlocks.
*******************************************************************/

U32 ReadSector(U32 Cylinder, U32 HdSect, U8 *pDataRet)
{
U32 erc;
U16  cyl;

  cyl = Cylinder;
  hd_head = HdSect & 0xffff;
  hd_sector = (HdSect >> 16) & 0xffff;

/*
 xprintf("\r\nCYL %d, HD %d, SEC %d\r\n", cyl, hd_head, hd_sector);
*/

  hd_Cmd[2] = 1;						/* How many sectors */
  hd_Cmd[3] = hd_sector;				/* Which sector to start on */
  hd_Cmd[4] = cyl & 0xff;				/* cylinder lobyte */
  hd_Cmd[5] = (cyl >> 8) & 0xff;		/* cylinder hibyte */
  hd_Cmd[6] = (hd_drive << 4) | (hd_head & 0x0f) | 0xa0;

  erc = send_command(HDC_READ);
  erc = hd_wait();					/* wait for interrupt */
  if (!erc) erc = hd_status(HDC_READ);
  if (!erc)
  	InWords(HD_PORT, pDataRet, 512);
  return(erc);
}

/***************************************************************************
Now begins the PUBLIC routines that are interfaced to for all DEVICE DRIVERS
*/

/******************************************
Called for all device operations.  This
assigns physical device from logical number
that outside callers use. For Hard disk,
10=0 and 11=1. This will check to make sure a
drive type is assigned then calc physical
head, cly, sector from dLBA.
*******************************************/

U32  hddev_op(U32  dDevice,
 		      U32  dOpNum,
		      U32  dLBA,
		      U32  dnBlocks,
		      U8  *pData)
{
U32  erc;

 hdstatus.blocks_done = 0;	/* Reset values in Status record */

 erc = 0;

 /* Set drive internal drive number */

 if (dDevice == 12)
 	hd_drive = 0;
 else
 	hd_drive = 1;

 /* check to see if we have a leftover interrupt message from last
    command.  If so then we eat it (and do nothing) */

  CheckMsg(hd_exch, &hd_msg);		/* Ignore error */

 if (hd_drive==0) {
	if (hd0_type==0)
		erc = ErcInvalidDrive;
	}
 else {
	if (hd1_type==0)
		erc = ErcInvalidDrive;
	}

 /* make sure they don't exceed max blocks */

 if (!erc)
   if (dLBA > hdcb[hd_drive].nBlocks) erc = ErcBadLBA;

 if (!erc) {

   switch(dOpNum) {
 	  case(CmdNull):
		erc = ok;					/* Null Command */
		break;
	  case(CmdRead): 										/* Read */
		erc = hd_read(dLBA, dnBlocks, pData);
/*
		if (erc==ErcHDCTimeOut)
			erc = hd_read(dLBA, dnBlocks, pData);
*/
		break;
	  case(CmdWrite): 									/* Write */
		erc = hd_write(dLBA, dnBlocks, pData);
		break;
	  case(CmdVerify): 									/* Verify */
/*		erc = hd_verify(dLBA, dnBlocks, pData); */
		break;
	  case(CmdSeekTrk): 								/* Seek Track */
		erc = hd_seek(dLBA);
		break;
	  case(CmdFmtTrk):                                  /* Format Track */
		erc = ErcNotSupported;
		break;
	  case(CmdResetHdw): 								/* Reset Ctrlr */
		hd_reset();
		erc = 0;
		break;
	  case(CmdReadSect): 								/* Read Sector */
		erc = ReadSector(dLBA, dnBlocks, pData);
		break;
	  default:
		erc = ErcBadOp;
		break;
	}
 }
 hdcb[hd_drive].last_erc = erc;			/* update DCB erc */
 return(erc);
}


/******************************************
Called for indepth status report on ctrlr
and drive specified. Returns 64 byte block
of data including current drive geometery.
This is called by the PUBLIC call DeviceStat!
*******************************************/

U32 hddev_stat(U32  dDevice,
			   S8 * pStatRet,
			   U32  dStatusMax,
			   U32  *pdStatusRet)
{
U32 i;

 /* Set status for proper device */

 if (dDevice == 12) {
	hdstatus.erc = hdcb[0].last_erc;
 	hdstatus.type_now = hd0_type;
 	hdstatus.nCyl = hd0_cyls;
 	hdstatus.nHead = hd0_heads;
 	hdstatus.nSectors = hd0_secpertrk;
	hdstatus.nBPS = hdcb[0].nBPB;
 }
 else {
	hdstatus.erc = hdcb[1].last_erc;
 	hdstatus.type_now = hd1_type;
 	hdstatus.nCyl = hd1_cyls;
 	hdstatus.nHead = hd1_heads;
 	hdstatus.nSectors = hd1_secpertrk;
	hdstatus.nBPS = hdcb[1].nBPB;
 }

 /* Calculate size of status to return. Return no more than asked for! */

 if (dStatusMax <= sStatus) i = dStatusMax;
 else i = sStatus;

 CopyData(&hdstatus, pStatRet, i);		/* copy to their status block */

 *pdStatusRet = i;						/* tell em how much it was */

 return ok;
}

/******************************************
Called to reset the hard disk controller
and set drive parameters.  The Initdata
is a copy of the 64 byte status block
that is read from status.  The caller
normally reads the block (DeviceStat),
makes changes to certain fields and
calls DeviceInit pointing to the block
for the changes to take effect.
This should ONLY be called once for each HD
to set it's parameters before it is used
the first time after the driver is loaded,
or after a fatal error is received that
indicates the controller may need to be
reset (multiple timeouts etc.).
The DCB values are updated if this is
successful.
This is called by the PUBLIC call DeviceInit.
*******************************************/

U32  hddev_init(U32  dDevice,
			  S8  *pInitData,
			  U32   sdInitData)

{
U32 erc, i;

  erc = 0;

 /* Read the init status block in */

 if (sdInitData > sStatus) i = sStatus;		/* no more than 64 bytes! */
 else i = sdInitData;

 CopyData(pInitData, &HDStatTmp, i);		/* copy in their init data */

 /* Set internal drive number */
 if (dDevice == 12) hd_drive=0;
 else hd_drive = 1;

 if (hd_drive==0){
 	hd0_type  = HDStatTmp.type_now;
	if (hd0_type) {
 	  hd0_cyls  = HDStatTmp.nCyl;
 	  hd0_heads = HDStatTmp.nHead;
 	  hd0_secpertrk = HDStatTmp.nSectors;
 	}
 	else erc = ErcInvalidDrive;
 }
 else {
 	hd1_type  = HDStatTmp.type_now;
	if (hd1_type) {
		hd1_cyls  = HDStatTmp.nCyl;
	 	hd1_heads = HDStatTmp.nHead;
	 	hd1_secpertrk = HDStatTmp.nSectors;
	 	}
 	else erc = ErcInvalidDrive;
 }

/* If no error, initialize it and recal */

 if (!erc) erc = hd_init(hd_drive);
 if (!erc) erc = hd_recal(hd_drive);

/* If no error, update corresponding DCB values */

 if (!erc) {
	hdcb[hd_drive].nBPB = HDStatTmp.nBPS;
	hdcb[hd_drive].last_erc = 0;
	hdcb[hd_drive].nBlocks =
				HDStatTmp.nCyl * HDStatTmp.nSectors * HDStatTmp.nHead;
 }

 hdcb[hd_drive].last_erc = erc;			/* update DCB erc */

 return(erc);
}

/*===========  THE END  =========================================*/

⌨️ 快捷键说明

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