📄 fdcdrv.c
字号:
/* fdcDrv.c - Floppy Disk Controller (FDC) Input/Output Driver Module */
/* Copyright 1984-2001 Wind River Systems, Inc. */
/* Copyright 1996,1997,1998 Motorola, Inc., All Rights Reserved */
/*
modification history
--------------------
01d,16sep01,dat Use of WRS_ASM macro
01c,15may01,pch Rename local floppy driver to fix clash with generic in
project facility
01b,15apr98,dat added INCLUDE_FD, using macros FD_BASE_ADDR and
FD_DMA_CHAN to match old API for fdDrv().
01a,12dec97,rbb created by Motorola.
*/
/*
DESCRIPTION
This is the I/O driver for a standard PS2 floppy device controller (FDC).
This driver is normally included as a source file, and expects the macro
INCLUDE_FDC to be defined if any code is to be compiled.
USER CALLABLE ROUTINES
Most of the routines in this driver are accessible only through the I/O
system. Two routines, however, must be called directly: fdcDrv() to
initialize the driver, and fdcDevCreate() to create devices.
Before using the driver, it must be initialized by calling the fdcDrv().
The macros FD_BASE_ADDR and FD_DMA_CHAN are needed to provide the base
address of the floppy disk controller device and the DMA channel number
to be used. (This is to maintain compatibility with the existing API for
fdcDrv() ).
.CS
STATUS fdcDrv
(
UINT intVector, // interrupt vector
UINT intLevel // interrupt level
)
.CE
This routine initializes the floppy disk controller driver, sets up
interrupt vectors, and performs hardware initialization of the floppy
disk controller chip.
This routine should be called exactly once, before any reads, writes,
or calls to fdcDevCreate(). Normally, it is called from usrRoot() in
usrConfig.c.
CREATING DISK DEVICES
Before a disk device can be used, it must be created. This is done
with the fdcDevCreate() call. Each floppy disk drive to be used may
have one or more devices associated with it, by calling this routine.
The way the device is created with this call determines the floppy
diskette type, and whether it covers the whole disk or just part of
it.
fdcDevCreate() - create a device for a floppy disk
.CS
BLK_DEV *fdcDevCreate
(
UINT driveNumber, // drive number (0 to 3)
UINT fdcType, // type of floppy disk (table index)
UINT nBlocks, // device size in blocks (0 = whole disk)
UINT blkOffset // offset from start of device
)
.CE
This routine creates a device for a specified floppy disk.
The driveNumber parameter is the drive number of the floppy disk; valid
values are 0 to 3.
The fdcType parameter specifies the type of diskette, which is described
in the structure table fdcTypes[] in fdcDrv.c. fdcType is an index
into the table. Currently the table contains two diskette types:
- An fdcType of 0 indicates the first entry in the table (3.5" 2HD, 1.44MB);
- An fdcType of 1 indicates the second entry in the table (3.5" 2HD, 720KB);
Members of the fdcTypes[] structure are:
UINT numberofheads; // number of heads (sides)
UINT numberoftracks; // number of tracks
UINT sectorstrack; // sectors (blocks) per track
UINT sectorsize; // sector (block) size in bytes
UINT ratestep; // step rate
UINT ratedata; // data rate
UINT gaprw; // read/write sector gap
UINT gapformat; // format gap
The nBlocks parameter specifies the size of the device, in blocks. If
nBlocks is zero, the whole disk is used.
The blkOffset parameter specifies an offset, in blocks, from the start
of the device to be used when writing or reading the floppy disk. This
offset is added to the block numbers passed by the file system during
disk accesses. (VxWorks file systems always use block numbers beginning
at zero for the start of a device.) Normally, blkOffset is 0.
For instance, to create a rawFs compatible device, covering the whole
disk (3.5" 2HD, 1.44MB) on drive 0, the proper call would be:
.CS
fdcDevCreate (0, 0, 0, 0);
.CE
IOCTL
This driver responds to all the same ioctl codes as a normal block
device driver. To format a disk use FIODISKFORMAT.
CAVEATS
No mechanism exists for detecting the change of media. The driver
does not support the concurrent operation of multiple drives. This
is due to the fact that all drives share the same DMA channel.
*/
/*
* includes
*
* include file paths are dependent on makefile
*/
#include "vxWorks.h" /* vxWorks generics */
#include "taskLib.h" /* taskLib functions */
#include "ioLib.h" /* input/output generics */
#include "blkIo.h" /* block input/output specifics */
#include "semLib.h" /* semaphore operations */
#include "cacheLib.h" /* cache control */
#include "intLib.h" /* interrupt control */
#include "errnoLib.h" /* error number */
#include "string.h"
#include "fdc.h" /* floppy disk controller (FDC) */
#include "fdcDrv.h" /* floppy disk controller (FDC) driver header */
#include "i8237.h" /* i8237 DMA controller device */
#ifdef INCLUDE_FDC /* do nothing, if not defined */
/* defines */
#ifndef EIEIO_SYNC
# define EIEIO_SYNC WRS_ASM (" eieio; sync")
#endif /* EIEIO_SYNC */
/* typedefs */
/* globals */
LOCAL UINT fdcDrvInitFlag = 0; /* driver initialization flag */
LOCAL UINT fdcDrvBaseAddress = 0; /* base address of FDC */
LOCAL UINT fdcDrvIntVector = (UINT)-1; /* interrupt vector number */
LOCAL UINT fdcDrvIntLevel = (UINT)-1; /* interrupt level number */
LOCAL UINT fdcDrvDmaChannel = (UINT)-1; /* DMA channel number */
LOCAL SEM_ID fdcDrvSemId; /* driver ownership semaphore */
LOCAL FDC_IARGS fdcDrvIArgs; /* interrupt handler arguments */
LOCAL UINT fdcDrvIntCount[FDC_NDRIVES] = { 0 };
/* locals */
LOCAL FDC_TYPE fdcTypes[] = {
{ 2, 80, 18, 512, 0, 500, 0x1B, 0x6C }, /* 1.44MB */
{ 2, 80, 9, 512, 0, 250, 0x2A, 0x50 } /* 720KB */
};
#define FDC_TYPES_TABLESIZE (sizeof(fdcTypes)/sizeof(FDC_TYPE))
/* forward declarations */
extern STATUS fdcDrv();
extern BLK_DEV *fdcDevCreate();
LOCAL STATUS fdcIoctl();
LOCAL STATUS fdcRead();
LOCAL STATUS fdcWrite();
LOCAL STATUS fdcStatusChk();
LOCAL UINT fdcCheck(); /* check state */
LOCAL UINT fdcClearReset(); /* clear reset state */
LOCAL void fdcDelay(); /* delay (sleep) in milli-seconds */
LOCAL UINT fdcDrvMain(); /* fdc driver main entry point */
LOCAL UINT fdcFormat(); /* format track/disk */
LOCAL UCHAR fdcDRCode(); /* return data-rate code */
LOCAL UINT fdcInit(); /* initialize operating parameters */
LOCAL void fdcInt(); /* interrupt handler */
LOCAL void fdcSetAES(); /* setup additional error status information */
LOCAL UINT fdc_clsn(); /* calculate logical sector number */
LOCAL void fdcCP(); /* calculate position */
LOCAL UINT fdcRxd(); /* receive byte from data FIFO */
LOCAL UINT fdcRxdEp(); /* receive data from FIFO, execution phase */
LOCAL UINT fdcSeek(); /* seek to track */
LOCAL void fdcStat(); /* retrieve command execution status (results) */
LOCAL UINT fdcTxd(FDC *, UCHAR); /* transmit (send) byte to data FIFO */
LOCAL UINT fdcTxdEp(); /* transmit data to FIFO, execution phase */
LOCAL void fdcExeCmd(); /* execute command */
LOCAL UINT fdcXfer(); /* read/write transfer */
LOCAL UINT fdcXfrcheck(); /* sanity check on block size/number of blocks/sector size parameters */
LOCAL UINT fdcSCode(); /* return sector code */
/* externals */
extern void bzero(); /* zero or clear memory routine */
extern void *calloc(); /* memory allocate and clear */
extern void *memalign(); /* aligned memory allocate */
extern int sysClkRateGet(); /* system clock rate */
extern void isaDmaInit(); /* initialize DMA (global configuration) */
extern void isaDmaStart(); /* initialize DMA channel for transfer */
extern void isaDmaStop(); /* disable DMA channel */
extern UINT isaDmaStatus(); /* query DMA channel for transfer status */
/*******************************************************************************
*
* fdcDrv - initialize the floppy disk driver
*
* This function's purpose is to the initialize the floppy disk
* controller device for operation.
*
* The macros FD_BASE_ADDR and FD_DMA_CHAN must be defined for this driver
* to compile correctly.
*
* RETURNS: OK, or ERROR if driver initialization fails
*/
STATUS fdcDrv
(
register UINT interruptVector, /* interrupt vector */
register UINT interruptLevel /* interrupt level */
)
{
register UINT baseAddress = FD_BASE_ADDR; /* base address of FDC */
register UINT dmaChannel = FD_DMA_CHAN; /* DMA channel number */
/* initialize driver, if initialized, return ERROR */
if (fdcDrvInitFlag)
{
return (ERROR);
}
/* make some sanity of the desired mode */
if (interruptVector != (UINT)-1)
{
if (dmaChannel == (UINT)-1)
{
return (ERROR);
}
}
/* create semaphore to interlock access to the FDC */
if ((fdcDrvSemId = semBCreate(SEM_Q_PRIORITY, SEM_FULL)) == (SEM_ID)NULL)
{
return (ERROR);
}
/* connect/enable interrupt handler */
if (interruptVector != (UINT)-1)
{
intConnect( (VOIDFUNCPTR *)interruptVector,
(VOIDFUNCPTR)fdcInt,
(int)((FDC_IARGS *)&fdcDrvIArgs) );
intEnable(interruptVector);
}
/*
* initialize the base address of FDC variable, user may override
* if the value is not zero
*/
if (!fdcDrvBaseAddress)
{
fdcDrvBaseAddress = baseAddress;
}
/*
* initialize the DMA channel number for this FDC
* initialize the interrupt vector/level
*/
fdcDrvDmaChannel = dmaChannel;
fdcDrvIntVector = interruptVector;
fdcDrvIntLevel = interruptLevel;
/* set the driver initialization flag to a true state */
fdcDrvInitFlag = (UINT)-1;
return (OK);
}
/*******************************************************************************
*
* fdcDevCreate - create a device for a floppy disk
*
* This function's purpose is to create a device for a specified
* floppy disk.
*
* RETURNS: pointer to BLK_DEV structure
*/
BLK_DEV * fdcDevCreate
(
register UINT driveNumber, /* drive number (0 to 3) */
register UINT fdcType, /* type of floppy disk (table index) */
register UINT nBlocks, /* device size in blocks (0 = whole disk) */
register UINT blkOffset /* offset from start of device */
)
{
register FDC_DEV *pDev; /* device descriptor pointer */
register UINT dmaBufferAddress; /* DMA buffer address */
register UINT realBlocks; /* real number of blocks */
/* do not create device if the driver has not been initialized */
if (!fdcDrvInitFlag)
{
return ((BLK_DEV *)NULL);
}
/* validate floppy disk drive number */
if (driveNumber > (FDC_NDRIVES - 1))
{
return ((BLK_DEV *)NULL);
}
/* validate floppy device/disk type */
if (fdcType >= FDC_TYPES_TABLESIZE)
{
return ((BLK_DEV *)NULL);
}
/* allocate memory for device descriptor */
pDev = calloc(1, sizeof(FDC_DEV));
if (pDev == (FDC_DEV *)NULL)
{
return ((BLK_DEV *)NULL);
}
/* allocate DMA buffer */
dmaBufferAddress = (UINT)memalign(FDC_DMAALIGN, FDC_DMAALIGN);
if (dmaBufferAddress == (UINT)NULL)
{
return ((BLK_DEV *)NULL);
}
pDev->dmaBuffer = dmaBufferAddress;
/* create interrupt level to task level semaphore */
if ((pDev->intSemId = semBCreate(SEM_Q_FIFO, SEM_EMPTY)) == (SEM_ID)NULL)
{
return ((BLK_DEV *)NULL);
}
/* initialize device specific data structures */
pDev->driveNumber = driveNumber;
pDev->fdcType = fdcTypes[fdcType];
/*
* initialize block information, perfrom some sanity
* checks on the blkOffset and nBlocks arguments
*/
pDev->blockSize = pDev->fdcType.sectorsize;
pDev->blockOffset = blkOffset;
realBlocks = pDev->fdcType.numberofheads *
pDev->fdcType.numberoftracks *
pDev->fdcType.sectorstrack;
if ((nBlocks > realBlocks) ||
(blkOffset >= realBlocks) ||
((blkOffset + nBlocks) > realBlocks))
{
return ((BLK_DEV *)NULL);
}
if (!nBlocks)
{
pDev->blockTotal = realBlocks - blkOffset;
}
else
{
pDev->blockTotal = nBlocks;
}
/* initialize device block descriptor */
pDev->fdcBlockDev.bd_blkRd = fdcRead;
pDev->fdcBlockDev.bd_blkWrt = fdcWrite;
pDev->fdcBlockDev.bd_ioctl = fdcIoctl;
pDev->fdcBlockDev.bd_reset = NULL;
pDev->fdcBlockDev.bd_statusChk = fdcStatusChk;
pDev->fdcBlockDev.bd_removable = TRUE;
pDev->fdcBlockDev.bd_nBlocks = realBlocks;
pDev->fdcBlockDev.bd_bytesPerBlk = pDev->fdcType.sectorsize;
pDev->fdcBlockDev.bd_blksPerTrack = pDev->fdcType.sectorstrack;
pDev->fdcBlockDev.bd_nHeads = pDev->fdcType.numberofheads;
pDev->fdcBlockDev.bd_retry = 0;
pDev->fdcBlockDev.bd_mode = O_RDWR;
pDev->fdcBlockDev.bd_readyChanged = TRUE;
/* initialize the system clock rate */
pDev->sysClkRate = sysClkRateGet();
return ((BLK_DEV *)pDev);
}
/*******************************************************************************
*
* fdcRead - fdc read blocks
*
* This function's purpose is to read the specified number of
* blocks from the specified device.
*
* RETURNS: OK, or ERROR if the read failed
*/
LOCAL STATUS fdcRead
(
register FDC_DEV *pDev, /* pointer to device descriptor */
register UINT startBlk, /* starting block to read */
register UINT numBlks, /* number of blocks to read */
register char *pBuf /* pointer to buffer to receive 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_READOP;
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));
}
/*******************************************************************************
*
* fdcWrite - fdc write blocks
*
* This function's purpose is to write the specified number of
* blocks to the specified device.
*
* RETURNS: OK, or ERROR if the write failed
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -