📄 mindrvr.c
字号:
DELAY400NS;
// Command packet transfer...
// Poll Alternate Status for BSY=0.
while ( 1 )
{
status = pio_inbyte( CB_ASTAT ); // poll for not busy
if ( ( status & CB_STAT_BSY ) == 0 )
break;
if ( tmr_chk_timeout() ) // time out yet ?
{
reg_cmd_info.to = 1;
reg_cmd_info.ec = 51;
dir = -1; // command done
break;
}
}
// Command packet transfer...
// Check for protocol failures... no interrupt here please!
// Command packet transfer...
// If no error, transfer the command packet.
if ( reg_cmd_info.ec == 0 )
{
// Command packet transfer...
// Read the primary status register and the other ATAPI registers.
status = pio_inbyte( CB_STAT );
// Command packet transfer...
// check status: must have BSY=0, DRQ=1 now
if ( ( status & ( CB_STAT_BSY | CB_STAT_DRQ | CB_STAT_ERR ) )
!= CB_STAT_DRQ
)
{
reg_cmd_info.ec = 52;
dir = -1; // command done
}
else
{
// Command packet transfer...
// xfer the command packet (the cdb)
pio_drq_block_out( CB_DATA, cdbBufAddr, cpbc >> 1 );
DELAY400NS; // delay so device can get the status updated
}
}
// Data transfer loop...
// If there is no error, enter the data transfer loop.
while ( reg_cmd_info.ec == 0 )
{
// Data transfer loop...
// Wait for interrupt -or- wait for not BUSY -or- wait for time out.
sub_wait_poll( 53, 54 );
// Data transfer loop...
// If there was a time out error, exit the data transfer loop.
if ( reg_cmd_info.ec )
{
dir = -1; // command done
break;
}
// Data transfer loop...
// If using interrupts get the status read by the interrupt
// handler, otherwise read the status register.
if ( int_use_intr_flag )
status = int_ata_status;
else
status = pio_inbyte( CB_STAT );
// Data transfer loop...
// Exit the read data loop if the device indicates this
// is the end of the command.
if ( ( status & ( CB_STAT_BSY | CB_STAT_DRQ ) ) == 0 )
{
dir = -1; // command done
break;
}
// Data transfer loop...
// The device must want to transfer data...
// check status: must have BSY=0, DRQ=1 now.
if ( ( status & ( CB_STAT_BSY | CB_STAT_DRQ ) ) != CB_STAT_DRQ )
{
reg_cmd_info.ec = 55;
dir = -1; // command done
break;
}
// Data transfer loop...
// get the byte count, check for zero...
byteCnt = ( pio_inbyte( CB_CH ) << 8 ) | pio_inbyte( CB_CL );
if ( byteCnt < 1 )
{
reg_cmd_info.ec = 59;
dir = -1; // command done
break;
}
// Data transfer loop...
// increment number of DRQ packets
reg_cmd_info.drqPackets ++ ;
// Data transfer loop...
// transfer the data and update the i/o buffer address
// and the number of bytes transfered.
wordCnt = ( byteCnt >> 1 ) + ( byteCnt & 0x0001 );
reg_cmd_info.totalBytesXfer += ( wordCnt << 1 );
if ( dir )
pio_drq_block_out( CB_DATA, dataBufAddr, wordCnt );
else
pio_drq_block_in( CB_DATA, dataBufAddr, wordCnt );
dataBufAddr = dataBufAddr + byteCnt;
DELAY400NS; // delay so device can get the status updated
}
// End of command...
// Wait for interrupt or poll for BSY=0,
// but don't do this if there was any error or if this
// was a commmand that did not transfer data.
if ( ( reg_cmd_info.ec == 0 ) && ( dir >= 0 ) )
{
sub_wait_poll( 56, 57 );
}
// Final status check, only if no previous error.
if ( reg_cmd_info.ec == 0 )
{
// Final status check...
// If using interrupts get the status read by the interrupt
// handler, otherwise read the status register.
if ( int_use_intr_flag )
status = int_ata_status;
else
status = pio_inbyte( CB_STAT );
// Final status check...
// check for any error.
if ( status & ( CB_STAT_BSY | CB_STAT_DRQ | CB_STAT_ERR ) )
{
reg_cmd_info.ec = 58;
}
}
// Done...
// Final status check
// BMIDE Error=1?
if ( pio_readBusMstrStatus() & BM_SR_MASK_ERR )
{
reg_cmd_info.ec = 78; // yes
}
// All done. The return values of this function are described in
// MINDRVR.H.
if ( reg_cmd_info.ec )
return 1;
return 0;
}
#endif // INCLUDE_ATAPI
#if INCLUDE_ATA_DMA
//***********************************************************
//
// Some notes about PCI bus mastering DMA...
//
// !!! The DMA support in MINDRVR is based on x86 PCI bus mastering
// !!! ATA controller design as described by the T13 document
// !!! '1510 Host Controller Standard' (in sections 1-6).
//
// Note that the T13 1510D document also describes a
// complex DMA engine called ADMA. While ADMA is a good idea it
// will probably never be popular or widely implemented. MINDRVR
// does not support ADMA.
//
// The base address of the Bus Master Control Registers (BMIDE) is
// found in the PCI Configuration space for the ATA controller (at
// offset 0x20 in the config space data). This is normally an I/O
// address.
//
// The BMIDE data is 16 bytes of data starting at the BMIDE base
// address. The first 8 bytes is for the primary ATA channel and
// the second 8 bytes is for the secondary ATA channel. The 8 bytes
// contain a "command" byte and a "status" byte and a 4 byte
// (32-bit) physical memory address pointing to the Physical Region
// Descriptor (PRD) list. Each PRD entry describes an area of
// memory or data buffer for the DMA transfer. A region described
// by a PRD may not cross a 64K byte boundary in physical memory.
// Also, the PRD list must not cross a 64K byte boundary.
//
//***********************************************************
//***********************************************************
//
// pci bus master registers and PRD list buffer,
// see the dma_pci_config() and set_up_xfer() functions.
//
// !!! Note that the PRD buffer is statically allocated here
// !!! but the actual address of the buffer is adjusted by
// !!! the dma_pci_config() function.
//
//***********************************************************
static unsigned long * dma_pci_prd_ptr; // current PRD buffer address
static int dma_pci_num_prd; // current number of PRD entries
static unsigned char statReg; // save BM status reg bits
static unsigned char rwControl; // read/write control bit setting
#define MAX_TRANSFER_SIZE 262144L // max transfer size (in bytes,
// should be multiple of 65536)
#define MAX_SEG ((MAX_TRANSFER_SIZE/65536L)+2L) // number physical segments
#define MAX_PRD (MAX_SEG*4L) // number of PRDs required
#define PRD_BUF_SIZE (48+(2*MAX_PRD*8)) // size of PRD list buffer
static unsigned char prdBuf[PRD_BUF_SIZE]; // PRD buffer
static unsigned long * prdBufPtr; // first PRD addr
//***********************************************************
//
// dma_pci_config() - configure/setup for Read/Write DMA
//
// The caller must call this function before attempting
// to use any ATA or ATAPI commands in PCI DMA mode.
//
// !!! MINDRVR assumes the entire DMA data transfer is contained
// !!! within a single contiguous I/O buffer. You may not need
// !!! the dma_pci_config() function depending on how your system
// !!! allocates the PRD buffer.
//
// !!! This function shows an example of PRD buffer allocation.
// !!! The PRD buffer must be aligned
// !!! on a 8 byte boundary and must not cross a 64K byte
// !!! boundary in memory.
//
//***********************************************************
int dma_pci_config( void )
{
unsigned long lw;
// Set up the PRD entry list buffer address - the PRD entry list
// may not span a 64KB boundary in physical memory. Space is
// allocated (above) for this buffer such that it will be
// aligned on a seqment boundary
// and such that the PRD list will not span a 64KB boundary...
lw = (unsigned long) prdBuf;
// ...move up to an 8 byte boundary.
lw = lw + 15;
lw = lw & 0xfffffff8L;
// ...check for 64KB boundary in the first part of the PRD buffer,
// ...if so just move the buffer to that boundary.
if ( ( lw & 0xffff0000L )
!=
( ( lw + ( MAX_PRD * 8L ) - 1L ) & 0xffff0000L )
)
lw = ( lw + ( MAX_PRD * 8L ) ) & 0xffff0000L;
// ... return the address of the first PRD
dma_pci_prd_ptr = prdBufPtr = (unsigned long *) lw;
// ... return the current number of PRD entries
dma_pci_num_prd = 0;
// read the BM status reg and save the upper 3 bits.
statReg = (unsigned char) ( pio_readBusMstrStatus() & 0x60 );
return 0;
}
//***********************************************************
//
// set_up_xfer() -- set up the PRD entry list
//
// !!! MINDRVR assumes the entire DMA data transfer is contained
// !!! within a single contiguous I/O buffer. You may not need
// !!! a much more complex set_up_xfer() function to support
// !!! true scatter/gather lists.
//
// The PRD list must be aligned on an 8 byte boundary and the
// list must not cross a 64K byte boundary in memory.
//
//***********************************************************
static int set_up_xfer( int dir, long bc, unsigned char * bufAddr );
static int set_up_xfer( int dir, long bc, unsigned char * bufAddr )
{
int numPrd; // number of PRD required
int maxPrd; // max number of PRD allowed
unsigned long temp;
unsigned long phyAddr; // physical memory address
unsigned long * prdPtr; // pointer to PRD entry list
// disable/stop the dma channel, clear interrupt and error bits
pio_writeBusMstrCmd( BM_CR_MASK_STOP );
pio_writeBusMstrStatus( (unsigned char) ( statReg | BM_SR_MASK_INT | BM_SR_MASK_ERR ) );
// setup to build the PRD list...
// ...max PRDs allowed
maxPrd = (int) MAX_PRD;
// ...PRD buffer address
prdPtr = prdBufPtr;
dma_pci_prd_ptr = prdPtr;
// ... convert I/O buffer address to an physical memory address
phyAddr = (unsigned long) bufAddr;
// build the PRD list...
// ...PRD entry format:
// +0 to +3 = memory address
// +4 to +5 = 0x0000 (not EOT) or 0x8000 (EOT)
// +6 to +7 = byte count
// ...zero number of PRDs
numPrd = 0;
// ...loop to build each PRD
while ( bc > 0 )
{
if ( numPrd >= maxPrd )
return 1;
// set this PRD's address
prdPtr[0] = phyAddr;
// set count for this PRD
temp = 65536L; // max PRD length
if ( temp > bc ) // count to large?
temp = bc; // yes - use actual count
// check if count will fit
phyAddr = phyAddr + temp;
if ( ( phyAddr & 0xffff0000L ) != ( prdPtr[0] & 0xffff0000L ) )
{
phyAddr = phyAddr & 0xffff0000L;
temp = phyAddr - prdPtr[0];
}
// set this PRD's count
prdPtr[1] = temp & 0x0000ffffL;
// update byte count
bc = bc - temp;
// set the end bit in the prd list
if ( bc < 1 )
prdPtr[1] = prdPtr[1] | 0x80000000L;
prdPtr ++ ;
prdPtr ++ ;
numPrd ++ ;
}
// return the current PRD list size and
// write into BMIDE PRD address registers.
dma_pci_num_prd = numPrd;
* (unsigned long *) (pio_bmide_base_addr + BM_PRD_ADDR_LOW )
= (unsigned long) prdBufPtr;
// set the read/write control:
// PCI reads for ATA Write DMA commands,
// PCI writes for ATA Read DMA commands.
if ( dir )
rwControl = BM_CR_MASK_READ; // ATA Write DMA
else
rwControl = BM_CR_MASK_WRITE; // ATA Read DMA
pio_writeBusMstrCmd( rwControl );
return 0;
}
//***********************************************************
//
// exec_pci_ata_cmd() - PCI Bus Master for ATA R/W DMA commands
//
//***********************************************************
static int exec_pci_ata_cmd( unsigned char dev,
unsigned char * bufAddr,
long numSect );
static int exec_pci_ata_cmd( unsigned char dev,
unsigned char * bufAddr,
long numSect )
{
unsigned char status;
// Quit now if the command is incorrect.
if ( ( reg_cmd_info.cmd != CMD_READ_DMA )
&& ( reg_cmd_info.cmd != CMD_READ_DMA_EXT )
&& ( reg_cmd_info.cmd != CMD_WRITE_DMA )
&& ( reg_cmd_info.cmd != CMD_WRITE_DMA_EXT ) )
{
reg_cmd_info.ec = 77;
return 1;
}
// Set up the dma transfer
if ( set_up_xfer( ( reg_cmd_info.cmd == CMD_WRITE_DMA )
||
( reg_cmd_info.cmd == CMD_WRITE_DMA_EXT ),
numSect * 512L, bufAddr ) )
{
reg_cmd_info.ec = 61;
return 1;
}
// Set command time out.
tmr_set_timeout();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -