📄 fdd.c
字号:
Wait for the head to settle after a seek for write.
MicroDelay is in 15 us increments, while settle value
is in milliseconds, so we turn millies into micros and
divide by 15 to get value for MicroDelay call.
-------------------------------------------------------*/
void wait_for_head(void)
{
U32 wait;
if (fwrite) {
wait = GetParm(9); /* Head settle for write in milliseconds */
wait = (wait * 1000) / 15;
MicroDelay(wait); /* delay in 15 us increments */
}
}
/*=========================================================
Checks for a media change for selected drive.
Returns:
0, or ErcNewMedia
-------------------------------------------------------*/
U32 med_change(void)
{
/* if no disk change indicated return OK */
if (InByte(DIR_PORT) & DSKCHANGE_BIT) {
fdstatus.fNewMedia = 1;
xprintf("Diskette Change High\r\n");
return (ErcNewMedia);
}
else {
fdstatus.fNewMedia = 0;
return (ok);
}
}
/***********************************************************
Wait until an operation is complete, then accept the status
from the controller.
************************************************************/
U32 get_fdc_status(void)
{
U32 erc;
if (erc = wait_int()) return(erc);
if (erc = results(7)) return(erc);
if (!(FDC_STATUS[0] & 0xc0)) return(ok);
if ((FDC_STATUS[0] & 0xc0) == 0x80) return(ErcBadCmd);
if ((FDC_STATUS[0] & 0xc0) == 0xC0) return(ErcReadyLine);
/* If we got here, get controller error status */
if (FDC_STATUS[1] & BIT7)
erc = ErcSectNotFound;
else if (FDC_STATUS[1] & BIT5)
erc = ErcCRC;
else if (FDC_STATUS[1] & BIT4)
erc = ErcOverRun;
else if (FDC_STATUS[1] & BIT2)
erc = ErcSectNotFound;
else if (FDC_STATUS[1] & BIT1)
erc = ErcReadOnly;
else if (FDC_STATUS[1] & BIT0)
erc = ErcAddrMark;
else fdstatus.erc = ErcBadFDC;
return(erc);
}
/*************************************************************
This is called for Read, Write or Verify commmands. The only
differences in these 3 commands is the DMA type/direction and
a single byte FDC command.
*************************************************************/
U32 RdWrtVerf(U32 op)
{
U32 erc;
S8 dmatype; /* 0 = Verify, 1 = IN, 2 = Out */
S8 retrys;
U32 count;
erc = 0;
retrys = 5;
count = fd_nr_sectors * 512;
while ((fd_nr_sectors) && (!erc)) {
switch(op) {
case(CmdRead): /* Read */
dmatype = 1;
fd_fdc_command = FDC_READ;
break;
case(2): /* Write */
fwrite = 1;
dmatype = 2;
CopyData(fd_pData, sectbuf, 512);
fd_fdc_command = FDC_WRITE;
break;
case(3): /* Verify */
dmatype = 0;
fd_fdc_command = FDC_READ;
}
/* nBytes ch Type Mode */
erc = DmaSetUp(sectbuf, 512, 2, dmatype, 1 );
if (!erc) {
while(retrys--)
{
if (!erc) erc = seek();
if (!erc) erc = send_fdc(fd_fdc_command);
if (!erc) erc = send_fdc(((fd_head <<2) & BIT2) | fd_drive);
if (!erc) erc = send_fdc(fd_track);
if (!erc) erc = send_fdc(fd_head);
if (!erc) erc = send_fdc(fd_sector);
if (!erc) erc = send_fdc(GetParm(3));
if (!erc) erc = send_fdc(GetParm(4));
if (!erc) erc = send_fdc(GetParm(5));
if (!erc) erc = send_fdc(GetParm(6));
if (!erc) erc = get_fdc_status();
if (!erc) break; /* exit loop with good operation */
MicroDelay(200); /* wait 3 milliseconds... */
} /* While statement for 5 retrys */
}
if (!erc) {
if (op==CmdRead)
CopyData(sectbuf, fd_pData, 512);
fdstatus.blocks_done++;
fd_pData+=512;
--fd_nr_sectors; /* One less sector */
++fd_sector; /* Next sector please */
if (fd_sector > fdisk_table[fdstatus.type_now][4]) {
fd_sector = 1; /* back to sect one */
++fd_head; /* next head please */
}
if (fd_head > 1) {
fd_head = 0; /* back to head 0 */
++fd_track; /* next track please */
}
}
} /* while */
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 (usually 9 or 15).
*************************************************************/
U32 format_track(void)
{
U32 erc;
fd_fdc_command = FDC_FORMAT;
fwrite = 1; /* indicate write operation */
erc = DmaSetUp(fd_pData, 512, 2, 1, 1);
if (!erc) erc = send_fdc(3); /* specify command */
if (!erc) erc = send_fdc(GetParm(0));
if (!erc) erc = send_fdc(GetParm(1));
if (!erc) erc = seek();
if (!erc) erc = send_fdc(fd_fdc_command);
if (!erc) erc = send_fdc(((fd_head <<2) & BIT2) | fd_drive);
if (!erc) erc = send_fdc(GetParm(3));
if (!erc) erc = send_fdc(GetParm(4));
if (!erc) erc = send_fdc(GetParm(7));
if (!erc) erc = send_fdc(GetParm(8));
if (!erc) erc = get_fdc_status();
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 Floppy, 5=0
and 6=1. This will check to make sure a
drive type is assigned then calc physical
head, cly, sector from dLBA.
*******************************************/
U32 dev_op(U32 dDevice,
U32 dOpNum,
U32 dLBA,
U32 dnBlocks,
S8 *pData)
{
U32 erc, j;
fd_pData = pData;
fwrite = 0;
fdstatus.blocks_done = 0; /* Reset values in Status record */
fdstatus.erc = 0;
/* Set internal drive number */
if (dDevice == 10)
fd_drive = 0;
else
fd_drive = 1;
/* Check to see if we have a leftover interrupt message from last
command. If so then we eat it (do nothing)
*/
erc = CheckMsg(fd_exch, fd_msg);
if (fd_drive==0){
if (!type0) return(fdstatus.erc = ErcDriveType);
fdstatus.type_now = type0;
}
else {
if (!type1) return(fdstatus.erc = ErcDriveType);
fdstatus.type_now = type1;
}
if (dLBA > fdstatus.BlocksMax)
return(fdstatus.erc = ErcBadLBA);
fd_select(fd_drive); /* turn motor on and select drive */
/* set the data rate register to value the drive */
OutByte(fdisk_table[fdstatus.type_now][12], DRR_PORT); /* Rate Cmd */
/* make sure any residual status is unloaded */
purge_fdc();
/* if a media change sensed, update status */
/*
erc = med_change();
if (erc) {
erc = recal();
fd_motoroff(fd_drive);
if (erc) {
return(fdstatus.erc=erc);
}
else
return(fdstatus.erc=ErcNewMedia);
}
*/
fdstatus.BlocksMax = rgSectorMax[fdstatus.type_now]; /* set max sectors */
fd_nr_sectors = dnBlocks;
/* calculate the cylinder, head and sector from LBA */
/* 3 = nHeads, 4 = sectors/track */
fd_track = dLBA / (GetParm(3) * GetParm(4));
j = dLBA % (GetParm(3) * GetParm(4));
/* We now know what cylinder, calc head and sector */
fd_head = j / GetParm(4);
fd_sector = j % GetParm(4) + 1; /* sector numbers start at 1 !!!! */
/*
xprintf("\r\nDevice: %d, dLBA: %d, dOpNum: %d\r\n", dDevice, dLBA, dOpNum);
*/
xprintf("CYL %d, HD %d, SEC %d\r\n", fd_track, fd_head, fd_sector);
switch(dOpNum) {
case(CmdNull):
fdstatus.erc = ok; /* Null Command */
break;
case(CmdRead): /* Read */
case(CmdWrite): /* Write */
case(CmdVerify): /* Verify */
fdstatus.erc = RdWrtVerf(dOpNum);
break;
case(CmdFmtBlk): /* Format Block */
fdstatus.erc = ErcBadOp;
break;
case(CmdFmtTrk):
break; /* Format Track */
case(CmdSeekTrk): /* Seek Track */
break;
default:
fdstatus.erc = ErcBadOp;
break;
}
fd_motoroff(fd_drive);
return(fdstatus.erc);
}
/******************************************
Called for indepth status report on ctrlr
and drive specified. Returns 80 byte block
of data including the drive parameter
block (a 16 byte structure with all the
timing and size params of the drive).
This is called by the PUBLIC call DeviceStat!
*******************************************/
U32 dev_stat(U32 dDevice,
S8 * pStatRet,
U32 dStatusMax,
U32 *pdStatusRet)
{
S32 i, j;
S8 *pStat;
/* Set internal drive number */
if (dDevice == 10)
fd_drive=0;
else fd_drive = 1;
if (fd_drive==0){
if (type0==0) return(fdstatus.erc = ErcDriveType);
fdstatus.type_now = type0;
fdstatus.nCyl = fdisk_table[type0][11]+1; /* total physical cyls */
fdstatus.nHead = 2; /* total heads on device */
fdstatus.nSectors= fdisk_table[type0][4]; /* Sectors per track */
fdstatus.nBPS = 512; /* Bytes per sect */
}
else {
if (type1==0) return(fdstatus.erc = ErcDriveType);
fdstatus.type_now = type1;
fdstatus.nCyl = fdisk_table[type1][11]+1; /* total physical cyls */
fdstatus.nHead = 2; /* total heads on device */
fdstatus.nSectors= fdisk_table[type1][4]; /* Sectors per track */
fdstatus.nBPS = 512; /* Bytes per sect */
}
/* set max sectors in status record */
fdstatus.BlocksMax = rgSectorMax[fdstatus.type_now];
/* copy in the 16 bytes of floppy specific data */
CopyData(&fdisk_table[fdstatus.type_now], &fdstatus.params, 16);
/* Update disk status bytes for status return */
CopyData(&FDC_STATUS, &fdstatus.STATUS, 8);
if (dStatusMax < sStatus) j = dStatusMax;
else j = sStatus;
CopyData(&fdstatus, pStatRet, j); /* copy the status data */
*pdStatusRet = j; /* give em the size returned */
return(0);
}
/******************************************
Called to reset the floppy disk controller
and to set the TYPE. The type is one byte
of the 64 byte status record passed to
dev_init (offset 13). See the fdstatus struct.
This should be called once for each floppy
before it is used the first time after
the driver is loaded, or after a fatal
error is received (timeout etc.).
This is called by the PUBLIC call DeviceInit!
*******************************************/
S32 dev_init(U32 dDevice,
S8 *pInitData,
U32 sdInitData)
{
U32 i;
/* Read the init status block in */
if (sdInitData > sStatus) i = sStatus; /* no more than 64 bytes! */
else i = sdInitData;
CopyData(pInitData, &FDStatTmp, i); /* copy in their init data */
if (dDevice == 10)
fd_drive=0; /* Set internal drive number */
else
fd_drive = 1;
if (fd_drive==0){ /* set up for drive 0 */
type0 = FDStatTmp.type_now;
if (type0==0) return(fdstatus.erc = ErcDriveType);
fdstatus.type_now = type0;
}
else {
type1 = FDStatTmp.type_now;
if (type1==0) return(fdstatus.erc = ErcDriveType);
fdstatus.type_now = type1;
}
fd_select(fd_drive);
fdstatus.erc = FDC_reset();
fd_motoroff(fd_drive);
return(fdstatus.erc);
}
/*=========== THE END =========================================*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -