📄 fdcdrv.c
字号:
LOCAL STATUS fdcWrite
(
register FDC_DEV *pDev, /* pointer to device descriptor */
register UINT startBlk, /* starting block to write */
register UINT numBlks, /* number of blocks to write */
register char *pBuf /* pointer to buffer of send data */
)
{
register UINT localStatus; /* local status variable */
FDC_CMDPCKT fdcCmdPacket; /* command packet */
/*
* verify the request against the logical block parameters (all
* or nothing)
*/
if ((startBlk + pDev->blockOffset + numBlks) > pDev->blockTotal)
{
return (ERROR);
}
/* check for a NOP request */
if (!numBlks)
{
errno = S_ioLib_DEVICE_ERROR;
return (ERROR);
}
/* build command packet */
fdcCmdPacket.command = FDC_WRITOP;
fdcCmdPacket.status = 0;
fdcCmdPacket.memaddr = (UINT)pBuf;
fdcCmdPacket.blcknum = startBlk + pDev->blockOffset;
fdcCmdPacket.nblcks = numBlks;
fdcCmdPacket.tdflg = 0;
fdcCmdPacket.aescount = 0;
/* take ownership, call driver, release ownership */
semTake(fdcDrvSemId, WAIT_FOREVER);
localStatus = fdcDrvMain(pDev, (FDC_CMDPCKT *)&fdcCmdPacket);
semGive(fdcDrvSemId);
return ((localStatus ? ERROR : OK));
}
/*******************************************************************************
*
* fdcIoctl - fdc i/o control
*
* This function's purpose is to perform the specified I/O control
* operation.
*
* RETURNS: OK, or ERROR if ioctl request failed
*/
LOCAL STATUS fdcIoctl
(
register FDC_DEV *pDev, /* pointer to device descriptor */
register int funcCode, /* ioctl() function code */
register int arg /* function-specific argument */
)
{
register UINT localStatus; /* local status variable */
FDC_CMDPCKT fdcCmdPacket; /* command packet */
switch (funcCode)
{
case FIODISKFORMAT:
/* build command packet */
fdcCmdPacket.command = FDC_FRMTOP;
fdcCmdPacket.status = 0;
fdcCmdPacket.memaddr = 0;
fdcCmdPacket.blcknum = 0;
fdcCmdPacket.nblcks = 0;
fdcCmdPacket.tdflg = 'D';
fdcCmdPacket.aescount = 0;
/* take ownership, call driver, release ownership */
semTake(fdcDrvSemId, WAIT_FOREVER);
localStatus = fdcDrvMain(pDev, (FDC_CMDPCKT *)&fdcCmdPacket);
semGive(fdcDrvSemId);
break;
default:
errno = S_ioLib_UNKNOWN_REQUEST;
localStatus = ERROR;
break;
}
return ((localStatus ? ERROR : OK));
}
/*******************************************************************************
*
* fdcStatusChk - fdc status check
*
* This function's purpose is to perform a status check on the
* specified device. The status check basically checks to see
* if the disk has been changed.
*
* RETURNS: OK, or ERROR if check fails
*/
LOCAL STATUS fdcStatusChk
(
register FDC_DEV *pDev /* pointer to device descriptor */
)
{
register STATUS lstatus; /* local error status */
register FDC *pFdc; /* FDC registers pointer */
FDC_CMDPCKT fdcCmdPacket; /* command packet */
FDC_CRDATA fdc_crdata;
/*
* initialize pointer to FDC registers
* initialize local error status variable
*/
pFdc = (FDC *)fdcDrvBaseAddress;
lstatus = OK;
/* take ownership */
semTake(fdcDrvSemId, WAIT_FOREVER);
/* motor on */
pFdc->dor |= (pDev->driveNumber | (0x10 << pDev->driveNumber));
EIEIO_SYNC;
/*
* query the digital input register for a disk change status, if
* a disk change has occurred, set the "ready change" flag
*/
if (pFdc->dir_ccr & FDC_DIR_PS2_DSKCHG)
{
/* set the "ready change" flag */
pDev->fdcBlockDev.bd_readyChanged = TRUE;
/* build command packet */
fdcCmdPacket.command = FDC_CHCKOP;
fdcCmdPacket.status = 0;
fdcCmdPacket.memaddr = 0;
fdcCmdPacket.blcknum = 0;
fdcCmdPacket.nblcks = 0;
fdcCmdPacket.tdflg = 0;
fdcCmdPacket.aescount = 0;
/* initialize interrupt handler arguments data structure */
fdcDrvIArgs.pDev = pDev;
fdcDrvIArgs.pCmd = (FDC_CMDPCKT *)&fdcCmdPacket;
fdcDrvIArgs.pFdc = pFdc;
fdcDrvIArgs.cr_data_p = (FDC_CRDATA *)&fdc_crdata;
/* check state (take to known state) */
if (fdcCheck(pDev, (FDC_DEV *)&fdcCmdPacket, pFdc, fdc_crdata, 1))
{
lstatus = ERROR;
}
}
/* motor off */
pFdc->dor &= (FDC_DOR_DMAEN|FDC_DOR_RESET);
/* release ownership */
semGive(fdcDrvSemId);
return (lstatus);
}
/*******************************************************************************
*
* fdcDrvMain - fdc driver main entry point
*
* This function's purpose is the main entry point into the FDC
* Floppy Disk I/O driver.
*
* RETURNS: 0 if OK, non-zero for error condition which means the status
* word in the command packet is set.
*/
LOCAL UINT fdcDrvMain
(
register FDC_DEV *pDev, /* device descriptor pointer */
register FDC_CMDPCKT *pCmd /* command packet pointer */
)
{
register UINT lstatus; /* local error status */
FDC_CRDATA fdc_crdata;
/* setup local error status (error condition) */
lstatus = (UINT)-1;
/* initialize interrupt handler arguments data structure */
fdcDrvIArgs.pDev = pDev;
fdcDrvIArgs.pCmd = pCmd;
fdcDrvIArgs.pFdc = (FDC *)fdcDrvBaseAddress;
fdcDrvIArgs.cr_data_p = (FDC_CRDATA *)&fdc_crdata;
/* perform the requested action */
switch (pCmd->command)
{
case FDC_READOP:
case FDC_WRITOP:
/*
* sanity check of block size/number of blocks/physical
* sector size
*/
if ((pCmd->command == FDC_READOP) || (pCmd->command == FDC_WRITOP))
{
if (fdcXfrcheck(pDev, pCmd, 0))
{
break;
}
}
if (!(fdcXfer(pDev, pCmd, (FDC *)fdcDrvBaseAddress, fdc_crdata)))
{
lstatus = 0;
}
break;
case FDC_FRMTOP:
if (!(fdcFormat(pDev, pCmd, (FDC *)fdcDrvBaseAddress, fdc_crdata)))
{
lstatus = 0;
}
break;
}
if (lstatus)
errno = S_ioLib_DEVICE_ERROR;
return (lstatus);
}
/*******************************************************************************
*
* fdcXfer - read/write transfer
*
* This function's purpose is to perform the specified data
* transfers with the specified device. The data requests
* are blocked to a track size, only a one track can be
* read/written at a time.
*
* RETURNS: 0 if OK, non-zero for error condition which means the status
* word in the command packet is set.
*/
LOCAL UINT fdcXfer
(
register FDC_DEV *pDev, /* device descriptor pointer */
register FDC_CMDPCKT *pCmd, /* command packet pointer */
register FDC *pFdc, /* FDC registers pointer */
register FDC_CRDATA *cr_data_p /* command/result data pointer */
)
{
register UINT bufadd; /* starting address of data transfer */
register UINT t_count, m_count; /* data count variables */
register UINT d_count, x_count; /* data count variables */
register UINT l_count; /* loop count variable */
register UINT lstatus; /* local status flag */
register UCHAR statusx; /* status register copy */
register UINT e_sector; /* ending sector numbner */
register UCHAR *pd_p; /* phase data pointer */
struct fdc_pos pos;
/* setup the return status */
lstatus = 0;
/*
* calculate starting logical sector number of data
* transfer, this is only done once
*/
pos.lsector =
fdc_clsn( pCmd->blcknum, pDev->fdcType.sectorsize,
pDev->blockSize, pDev->fdcType.sectorstrack, 1 );
/*
* calculate the number of bytes in a track, this is the
* maximum number of bytes that can be transferred at one
* given time
*
* calculate the number of bytes that the user specified
*/
t_count = pDev->fdcType.sectorsize * pDev->fdcType.sectorstrack;
m_count = pCmd->nblcks * pDev->blockSize;
/* check the sanity of number of blocks requested */
if (((pos.lsector * pDev->fdcType.sectorsize) + m_count) >
(t_count * pDev->fdcType.numberofheads * pDev->fdcType.numberoftracks))
{
pCmd->status = FDC_ERROR_ILLDREQ;
return ((UINT)-1);
}
/* check state (take to known state) */
if (fdcCheck(pDev, pCmd, pFdc, cr_data_p, 0))
{
lstatus = (UINT)-1;
m_count = 0;
}
/*
* setup starting address of data transfer
* read/write data tracks loop
*/
bufadd = pCmd->memaddr;
for (l_count = 0; m_count; l_count++)
{
/* calculate floppy disk address from logical sector number */
fdcCP( pDev->fdcType.numberofheads,
pDev->fdcType.sectorstrack,
(struct fdc_pos *)&pos );
/*
* seek to track for initial data transfer
*
* if the seek to track call fails, post error status and
* terminate for loop
*/
if (l_count == 0)
{
if (fdcSeek(pDev, pCmd, pFdc, cr_data_p, pos.headno, pos.cylndrno))
{
lstatus = (UINT)-1;
break;
}
}
/*
* calculate the size (number of bytes) for this transfer
* calculate the ending sector number for this transfer
*/
if (pos.sectorno > 1)
{
d_count =
((pDev->fdcType.sectorstrack -
(pos.sectorno - 1)) * pDev->fdcType.sectorsize);
if (d_count >= m_count)
{
d_count = m_count;
e_sector =
((d_count / pDev->fdcType.sectorsize) - 1) + pos.sectorno;
}
else
{
e_sector = pDev->fdcType.sectorstrack;
}
}
else
{
if (m_count >= t_count)
{
d_count = t_count;
}
else
{
d_count = m_count;
}
e_sector = d_count / pDev->fdcType.sectorsize;
}
/* setup the "read-data" or "write-data" command structure */
pd_p = (UCHAR *)&cr_data_p->c_data.c_justdata.databytes[0];
bzero((UCHAR *)cr_data_p, sizeof(FDC_CRDATA));
pd_p[0] = FDC_CP_MFM |
((pCmd->command == FDC_READOP) ?
FDC_CS_READDATA : FDC_CS_WRITEDATA);
pd_p[1] = pDev->driveNumber | (pos.headno ? FDC_ST0_HDS : 0);
pd_p[2] = pos.cylndrno;
pd_p[3] = pos.headno;
pd_p[4] = pos.sectorno;
pd_p[5] = fdcSCode(pDev->fdcType.sectorsize);
pd_p[6] = (UCHAR)e_sector;
pd_p[7] = (UCHAR)pDev->fdcType.gaprw;
pd_p[8] = 0xFF;
/* setup/start DMA controller */
if (fdcDrvDmaChannel != (UINT)-1)
{
/* copy caller's buffer to internal buffer */
if (pCmd->command == FDC_WRITOP)
{
memcpy((void *) pDev->dmaBuffer, (void *) bufadd, d_count);
cacheFlush(DATA_CACHE, (void *)pDev->dmaBuffer, d_count);
}
/* initialize DMA controller for DMA data transfer */
isaDmaStart( fdcDrvDmaChannel,
I8237_MODE_TM_DEMAND,
((pCmd->command == FDC_READOP) ?
I8237_MODE_TT_WRITE : I8237_MODE_TT_READ),
pDev->dmaBuffer, d_count );
}
/* issue the "read-data" or the "write-data" command */
fdcExeCmd(pFdc, pd_p, sizeof(cr_data_p->c_data.c_readdata));
/* wait for interrupt, or poll for completion */
if (fdcDrvIntVector != (UINT)-1)
{
if (semTake(pDev->intSemId, pDev->sysClkRate * 2) == ERROR)
{
pFdc->fifo = 0x00;
EIEIO_SYNC;
isaDmaStop(fdcDrvDmaChannel);
x_count = 0;
}
else
{
x_count = d_count;
}
}
else
{
/* poll DMA controller for completion (terminal count) */
if (fdcDrvDmaChannel != (UINT)-1)
{
for (x_count = 0;; x_count++)
{
/* sleep for a bit (10ms) */
fdcDelay(10);
/* retrieve DMA controller status */
if ((statusx =
(UCHAR)isaDmaStatus(fdcDrvDmaChannel)) == 1)
{
x_count = d_count;
break;
}
else
{
if (x_count >= (2000/10))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -