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

📄 fdd.c

📁 MMURTL(tm) Computer Operating System Ver x0.8, source code.
💻 C
📖 第 1 页 / 共 3 页
字号:
			fsend = TRUE;
			fdelay = TRUE;
			dor_crnt |= FD_MOTOR0;	/* motor 0 on */
		}
	}

	if (fsend) {

		disable_ints();

		OutByte( dor_crnt, DOR_PORT);

		enable_ints();

		if (fdelay)
			Sleep(33);  /* delay 1/3th second if not already on! */
	}

}


/*******************************************
 Sets motor_want bit for specified motor.
*******************************************/

void fd_motoroff(U32 motor)
{
/* Set what we want so motor task will know */

if (motor)
	motor1_want = FALSE;
else
	motor0_want = FALSE;
}

/*********************************************************
    This is called ONCE to initialize the Driver.
*********************************************************/

U32 fdisk_setup(void)
{
U32 erc;

fdcb[0].Name[0] = 'F';
fdcb[0].Name[1] = 'D';
fdcb[0].Name[2] = '0';
fdcb[0].sbName  = 3;
fdcb[0].type    = 1;
fdcb[0].fDevReent = 0;	/* not reentrant */
fdcb[0].fSingleUser = 0;

fdcb[1].Name[0] = 'F';
fdcb[1].Name[1] = 'D';
fdcb[1].Name[2] = '1';
fdcb[1].sbName  = 3;
fdcb[1].type    = 1;	/* this is set set to zero if not installed */
fdcb[1].fDevReent = 0;	/* not reentrant */
fdcb[1].fSingleUser = 0;

 dor_crnt |= (FD_INTS | FD_RESET);	 /* set ints & reset bits high */
 motor0_want = FALSE;
 motor1_want = FALSE;
 seek_status = 0;   /* clear seek status */
 fdstatus.erc = 0;  		/* clear global disk error */

 erc = AllocExch(&fd_exch);		/* allocates exchanges for messaging */

 /* Set up the motor task */

 SpawnTask( &fdmotor_task, 18, 0, &MotorStkTop, 1);

 SetIRQVector(6, &fdisk_isr);
 UnMaskIRQ(6);    /*  unmask IRQ 6 */

 type0 = cmos_type(0);
 if (type0) {
    fdcb[0].nBPB    = 512;
    fdcb[0].nBlocks = rgSectorMax[type0];
  }

 type1 = cmos_type(1);
 if (type1) {
    fdcb[1].nBPB    = 512;
    fdcb[1].nBlocks = rgSectorMax[type1];
  }

/* reset the FDC */

 if (fdstatus.erc= FDC_reset())
 	return (fdstatus.erc);

/* now we attempt to select and recal both drives */

 if (type0) {
	fd_drive = 0;		/* select drive 0 */
 	fd_select(0);
	if (erc = recal())
		erc = recal();		/* try twice */
 	fd_motoroff(0);
	if (erc) return (fdstatus.erc = erc);
 	}

 if (type1) {
	fd_drive = 1;		/* select drive 1 */
 	fd_select(1);
	if (erc = recal())
		erc = recal();		/* try twice */
	if (erc) fdcb[1].type = 0;
 	fd_motoroff(1);
 	}

 fdcb[0].pDevOp = &dev_op;
 fdcb[0].pDevInit = &dev_init;
 fdcb[0].pDevSt = &dev_stat;

 fdcb[1].pDevOp = &dev_op;
 fdcb[1].pDevInit = &dev_init;
 fdcb[1].pDevSt = &dev_stat;

 return(erc = InitDevDr(10, &fdcb, 2, 1));

}

/************************************************************
 Reset the disk system
*************************************************************/

U32 FDC_reset(void)
{
 U32 erc;

 seek_status = 0;					 /* Set to Recal on next seek */

 disable_ints();

 OutByte(0x08, DOR_PORT);	 /* Drop reset signal on disk controller */
 MicroDelay(75);			 /* Wait 1ms */
 OutByte(0x0C, DOR_PORT);	 /* Raise reset line on disk controller */

 enable_ints();

 /* wait for interrupt and return if error (timeout...?) */

 if (erc = wait_int())
 	return(erc);

  /* Send sense command to current drive to see if reset took.
     If this is the first system reset it defaults to drive 0,
     Head 0.
  */


 if (erc = send_fdc(8)) return(erc);

  /* check results */

 if (erc = results(2)) return(erc);

 if (((FDC_STATUS[0] & 0xc0) == 0xc0 ) ||
    ((FDC_STATUS[0] & 0xc0) == 0)) {

     /* Send Specify command to controller */
	 send_fdc(3);
	 send_fdc(GetParm(0));
	 send_fdc(GetParm(1));
	 return(ok);
 }
 return(ErcBadFDC);
}

/*************************************************************
 The ISR is very simple.
 It just waits for an interrupt then sends a message to the
 exchange where the FD Driver will be waiting.
 The call that caused an interrupt to be generated reads the status
 codes from the controller to determine if the last status was OK.
****************************************************************/
void interrupt fdisk_isr(void)
{
	ISendMsg(fd_exch, 0xfffffffd, 0xfffffffd);
	EndOfIRQ(6);
}

/*=========================================================
Return the drive type for a specified drive.
---------------------------------------------------------*/

U8 cmos_type (U8 drive_nr)
{
 U8 drive_type;
 drive_type = 0;
 if (drive_nr)
 	drive_type = ReadCMOS(0x10) & 0x0f;
 else
 	drive_type = (ReadCMOS(0x10) >> 4) & 0x0f;
 return(drive_type);
}

/*========================================================
Send a byte to the FDC.
--------------------------------------------------------*/

U32 send_fdc(U8 parm)
{
U32 i;
U8  b, bjunk;

i = 100;  /* try 100 times to send FDC command */
do
{
	b = InByte(MSR_PORT);				/* Get I/O status byte */
	MicroDelay(100);					/* 1.5 milliseconds between tries */
	if (b & RQM) {
		if (b & DIO) {  				/* He has something to send us... */
			bjunk = InByte(DATA_PORT);	/* Eat it! */
			MicroDelay(100);			/* 1.5 milliseconds between I/O */
		}
		else {							/* OK to send to him */
			OutByte(parm,DATA_PORT);
			MicroDelay(100);			/* 1.5 milliseconds between I/O */
			return (ok);				/* Sent it OK */
		}
	}
 }
 while (i--);
 return (ErcSendFDC);		/* return ERROR */
}

/*==========================================================
Get the indexed value from the disk parameter table.
-------------------------------------------------------*/

U8 GetParm(U8 index)
{
 return( fdisk_table [fdstatus.type_now][index]);
}


/******************************************
Wait for the hardware interrupt to occur.
Time-out and return if no interrupt.
********************************************/

U32 wait_int(void)
{
U32 erc;

/* Set alarm for 3 seconds */
erc = Alarm(fd_exch, 300);

erc = WaitMsg(fd_exch, fd_msg);  /* Wait for message from ISR or Alarm */
if (erc) {
	KillAlarm(fd_exch);
	return(erc); /* BAD NEWS FROM KERNEL!!! */
	}

if (fd_msg[0] != 0xfffffffd)
	return(fdstatus.erc = ErcFDCTimeOut);
else {
	KillAlarm(fd_exch);
	return(fdstatus.erc = ok);
	}
}


/*******************************
    Recalibrate the drive.
********************************/

U32 recal(void)
{
U32 erc;

 erc = send_fdc(7);							/* recal command (2 bytes) */
 if (!erc) erc = send_fdc(fd_drive);		/* second byte is drive */

 /* wait for int on recal */
 if (!erc) erc = wait_int();
 if (!erc) erc = send_fdc(8);				/* Sense command */
 if (!erc) erc = results(2);				/* expect 2 bytes */
 if (!erc) {
   if (FDC_STATUS[0] & 0x20)   				/* Check seek-Ok bit */
   {
    if (FDC_STATUS[1]) return(ErcBadRecal);	/* Was it track 0? */
    return(ok);
   }
   else return (ErcBadSeek);       			/* Seek bit NOT set */
 }
 return(erc);
}
/*******************************************************
 Move the head to the selected track.
*********************************************************/

U32 seek(void)
{
U32 erc;

 if ((seek_status & (1 << fd_drive)) == 0)	/* need recal */
 {

  /* try 2 attemps at recalibrate, then error out */
  if (recal())
  	if (erc = recal()) return (erc);  		/* try again */

  seek_status |= (1 << fd_drive); 			/* recal was done */

  LAST_TRACK[fd_drive] = 0; 				/* clear track number */

  /* if we want track zero, then just wait for head and exit */

  if (fd_track == 0) {
  	wait_for_head();
  	return (ok);
  	}
 }

 if (fdisk_table[fdstatus.type_now][14] != 0)
	fd_track *= 2;
 if (LAST_TRACK[fd_drive] == fd_track)		/* already there */
	 return(ok);

  /* update new position */
 LAST_TRACK[fd_drive] = fd_track;

 erc = send_fdc(0x0f);						/*Seek Cmd */
 if (!erc) erc = send_fdc((fd_head << 2) | fd_drive);
 if (!erc) erc = send_fdc(fd_track);

  /* wait for int on seek command */
 if (!erc) erc = wait_int();
 if (!erc) erc = send_fdc(8);				/* Sense command */
 if (!erc) erc = results(2);				/* expect 2 bytes */
 if (!erc)
 	if (!(FDC_STATUS[0] & 0x20))			/* Look for seek-Ok bit */
 	{
     seek_status &= ~(1 << fd_drive);		/* needs recal! */
  	 erc = ErcBadSeek;
  	 return (erc);
 	}
 wait_for_head();
 return (ok);
}

/*=======================================================
Read a single byte from the data port (for status).
Returns TRUE if it got one.
--------------------------------------------------------*/

U32 read_data(U8 *pDataRet)
{
U16 tries;
U8 status;

	/* try 100 times while Busy */

	for (tries=0; tries<1000; tries++) {
		status = InByte(MSR_PORT);
		MicroDelay(100);
		if (status & RQM) {						/* RQM set */
			if (status & DIO) {					/* Direction IN if set */
				*pDataRet = InByte(DATA_PORT);	/* Get the data byte */
				MicroDelay(100);				/* digest it...*/
				return(TRUE);
			}
		}
	}
	return(FALSE);
}


/*=======================================================
Read anything from the controller following an interrupt.
This may include up to seven bytes of status.
--------------------------------------------------------*/

U32 results(U32 expect)
{
unsigned count, indx;
U8 status;

	indx = 0;
	while (indx < expect) {
		if (read_data(&status)) {
			FDC_STATUS[indx++] = status;		/* save status */
		 	MicroDelay(100);
		}
		else return(ErcResults);
	}
	return(0);
}



/****************************************************
  Purge the FDC of any status it is waiting to send.
*****************************************************/

void purge_fdc (void)
{
 unsigned count;
 U8 b;

	do {
		b = InByte(MSR_PORT);
		if (b & RQM) {
		  	if (b & DIO) {
				InByte(DATA_PORT);  /* eat the byte */
				MicroDelay(100);   	/* Breath (1.5ms) */
			 }
			 else return;
		}
		else return;
	}
	while (1);
}

/*======================================================

⌨️ 快捷键说明

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