📄 mindrvr.c
字号:
// Select the drive - call the sub_select function.
// Quit now if this fails.
if ( sub_select( dev ) )
{
return 1;
}
// Set up all the registers except the command register.
sub_setup_command();
// Start the command by setting the Command register. The drive
// should immediately set BUSY status.
pio_outbyte( CB_CMD, reg_cmd_info.cmd );
// The drive should start executing the command including any
// data transfer.
// Data transfer...
// read the BMIDE regs
// enable/start the dma channel.
// read the BMIDE regs again
pio_readBusMstrCmd();
pio_readBusMstrStatus();
pio_writeBusMstrCmd( (unsigned char) ( rwControl | BM_CR_MASK_START ) );
pio_readBusMstrCmd();
pio_readBusMstrStatus();
// Data transfer...
// the device and dma channel transfer the data here while we start
// checking for command completion...
// wait for the PCI BM Interrupt=1 (see ATAIOINT.C)...
if ( SYSTEM_WAIT_INTR_OR_TIMEOUT() ) // time out ?
{
reg_cmd_info.to = 1;
reg_cmd_info.ec = 73;
}
// End of command...
// disable/stop the dma channel
status = int_bmide_status; // read BM status
status &= ~ BM_SR_MASK_ACT; // ignore Active bit
pio_writeBusMstrCmd( BM_CR_MASK_STOP ); // shutdown DMA
pio_readBusMstrCmd(); // read BM cmd (just for trace)
status |= pio_readBusMstrStatus(); // read BM status again
if ( reg_cmd_info.ec == 0 )
{
if ( status & BM_SR_MASK_ERR ) // bus master error?
{
reg_cmd_info.ec = 78; // yes
}
}
if ( reg_cmd_info.ec == 0 )
{
if ( status & BM_SR_MASK_ACT ) // end of PRD list?
{
reg_cmd_info.ec = 71; // no
}
}
// End of command...
// If no error use the Status register value that was read
// by the interrupt handler. If there was an error
// read the Status register because it may not have been
// read by the interrupt handler.
if ( reg_cmd_info.ec )
status = pio_inbyte( CB_STAT );
else
status = int_ata_status;
// Final status check...
// if no error, check final status...
// Error if BUSY, DEVICE FAULT, DRQ or ERROR status now.
if ( reg_cmd_info.ec == 0 )
{
if ( status & ( CB_STAT_BSY | CB_STAT_DF | CB_STAT_DRQ | CB_STAT_ERR ) )
{
reg_cmd_info.ec = 74;
}
}
// Final status check...
// if any error, update total bytes transferred.
if ( reg_cmd_info.ec == 0 )
reg_cmd_info.totalBytesXfer = numSect * 512L;
else
reg_cmd_info.totalBytesXfer = 0L;
// All done. The return values of this function are described in
// MINDRVR.H.
if ( reg_cmd_info.ec )
return 1;
return 0;
}
//***********************************************************
//
// dma_pci_lba28() - DMA in PCI Multiword for ATA R/W DMA
//
//***********************************************************
int dma_pci_lba28( unsigned char dev, unsigned char cmd,
unsigned int fr, unsigned int sc,
unsigned long lba,
unsigned char * bufAddr,
long numSect )
{
// Setup current command information.
reg_cmd_info.cmd = cmd;
reg_cmd_info.fr = fr;
reg_cmd_info.sc = sc;
reg_cmd_info.dh = (unsigned char) ( CB_DH_LBA | ( dev ? CB_DH_DEV1 : CB_DH_DEV0 ) );
reg_cmd_info.dc = 0x00; // nIEN=0 required on PCI !
reg_cmd_info.ns = numSect;
reg_cmd_info.lbaSize = LBA28;
reg_cmd_info.lbaHigh = 0L;
reg_cmd_info.lbaLow = lba;
// Execute the command.
return exec_pci_ata_cmd( dev, bufAddr, numSect );
}
//***********************************************************
//
// dma_pci_lba48() - DMA in PCI Multiword for ATA R/W DMA
//
//***********************************************************
int dma_pci_lba48( unsigned char dev, unsigned char cmd,
unsigned int fr, unsigned int sc,
unsigned long lbahi, unsigned long lbalo,
unsigned char * bufAddr,
long numSect )
{
// Setup current command information.
reg_cmd_info.cmd = cmd;
reg_cmd_info.fr = fr;
reg_cmd_info.sc = sc;
reg_cmd_info.dh = (unsigned char) ( CB_DH_LBA | ( dev ? CB_DH_DEV1 : CB_DH_DEV0 ) );
reg_cmd_info.dc = 0x00; // nIEN=0 required on PCI !
reg_cmd_info.ns = numSect;
reg_cmd_info.lbaSize = LBA48;
reg_cmd_info.lbaHigh = lbahi;
reg_cmd_info.lbaLow = lbalo;
// Execute the command.
return exec_pci_ata_cmd( dev, bufAddr, numSect );
}
#endif // INCLUDE_ATA_DMA
#if INCLUDE_ATAPI_DMA
//***********************************************************
//
// dma_pci_packet() - PCI Bus Master for ATAPI Packet command
//
//***********************************************************
int dma_pci_packet( unsigned char dev,
unsigned int cpbc,
unsigned char * cdbBufAddr,
int dir,
long dpbc,
unsigned char * dataBufAddr )
{
unsigned char status;
// Make sure the command packet size is either 12 or 16
// and save the command packet size and data.
cpbc = cpbc < 12 ? 12 : cpbc;
cpbc = cpbc > 12 ? 16 : cpbc;
// Setup current command information.
reg_cmd_info.cmd = CMD_PACKET;
reg_cmd_info.fr = 0x01; // packet DMA mode !
reg_cmd_info.sc = 0;
reg_cmd_info.sn = 0;
reg_cmd_info.cl = 0; // no Byte Count Limit in DMA !
reg_cmd_info.ch = 0; // no Byte Count Limit in DMA !
reg_cmd_info.dh = (unsigned char) ( dev ? CB_DH_DEV1 : CB_DH_DEV0 );
reg_cmd_info.dc = 0x00; // nIEN=0 required on PCI !
// the data packet byte count must be even
// and must not be zero
if ( dpbc & 1L )
dpbc ++ ;
if ( dpbc < 2L )
dpbc = 2L;
// Set up the dma transfer
if ( set_up_xfer( dir, dpbc, dataBufAddr ) )
{
reg_cmd_info.ec = 61;
return 1;
}
// Set command time out.
tmr_set_timeout();
// Select the drive - call the reg_select function.
// Quit now if this fails.
if ( sub_select( dev ) )
{
return 1;
}
// Set up all the registers except the command register.
sub_setup_command();
// Start the command by setting the Command register. The drive
// should immediately set BUSY status.
pio_outbyte( CB_CMD, CMD_PACKET );
// Waste some time by reading the alternate status a few times.
// This gives the drive time to set BUSY in the status register on
// really fast systems. If we don't do this, a slow drive on a fast
// system may not set BUSY fast enough and we would think it had
// completed the command when it really had not started the
// command yet.
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 = 75;
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 = 76;
}
else
{
// Command packet transfer...
// xfer the command packet (the cdb)
pio_drq_block_out( CB_DATA, cdbBufAddr, cpbc >> 1 );
}
}
// Data transfer...
// The drive should start executing the command
// including any data transfer.
// If no error, set up and start the DMA,
// and wait for the DMA to complete.
if ( reg_cmd_info.ec == 0 )
{
// Data transfer...
// read the BMIDE regs
// enable/start the dma channel.
// read the BMIDE regs again
pio_readBusMstrCmd();
pio_readBusMstrStatus();
pio_writeBusMstrCmd( (unsigned char) ( rwControl | BM_CR_MASK_START ) );
pio_readBusMstrCmd();
pio_readBusMstrStatus();
// Data transfer...
// the device and dma channel transfer the data here while we start
// checking for command completion...
// wait for the PCI BM Active=0 and Interrupt=1 or PCI BM Error=1...
if ( SYSTEM_WAIT_INTR_OR_TIMEOUT() ) // time out ?
{
reg_cmd_info.to = 1;
reg_cmd_info.ec = 73;
}
// End of command...
// disable/stop the dma channel
status = int_bmide_status; // read BM status
status &= ~ BM_SR_MASK_ACT; // ignore Active bit
pio_writeBusMstrCmd( BM_CR_MASK_STOP ); // shutdown DMA
pio_readBusMstrCmd(); // read BM cmd (just for trace)
status |= pio_readBusMstrStatus(); // read BM statu again
}
if ( reg_cmd_info.ec == 0 )
{
if ( status & ( BM_SR_MASK_ERR ) ) // bus master error?
{
reg_cmd_info.ec = 78; // yes
}
if ( ( status & BM_SR_MASK_ACT ) ) // end of PRD list?
{
reg_cmd_info.ec = 71; // no
}
}
// End of command...
// If no error use the Status register value that was read
// by the interrupt handler. If there was an error
// read the Status register because it may not have been
// read by the interrupt handler.
if ( reg_cmd_info.ec )
status = pio_inbyte( CB_STAT );
else
status = int_ata_status;
// Final status check...
// if no error, check final status...
// Error if BUSY, DRQ or ERROR status now.
if ( reg_cmd_info.ec == 0 )
{
if ( status & ( CB_STAT_BSY | CB_STAT_DRQ | CB_STAT_ERR ) )
{
reg_cmd_info.ec = 74;
}
}
// Final status check...
// if any error, update total bytes transferred.
if ( reg_cmd_info.ec == 0 )
reg_cmd_info.totalBytesXfer = dpbc;
else
reg_cmd_info.totalBytesXfer = 0L;
// 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_DMA
//*************************************************************
//
// sub_setup_command() -- setup the command parameters
// in FR, SC, SN, CL, CH and DH.
//
//*************************************************************
static void sub_setup_command( void )
{
// output DevCtrl - same for all devices and commands
pio_outbyte( CB_DC, reg_cmd_info.dc );
// output command parameters
if ( reg_cmd_info.lbaSize == LBA28 )
{
// in ATA LBA28 mode
pio_outbyte( CB_FR, (unsigned char) reg_cmd_info.fr );
pio_outbyte( CB_SC, (unsigned char) reg_cmd_info.sc );
pio_outbyte( CB_SN, (unsigned char) reg_cmd_info.lbaLow );
pio_outbyte( CB_CL, (unsigned char) ( reg_cmd_info.lbaLow >> 8 ) );
pio_outbyte( CB_CH, (unsigned char) ( reg_cmd_info.lbaLow >> 16 ) );
pio_outbyte( CB_DH, (unsigned char) ( ( reg_cmd_info.dh & 0xf0 )
| ( ( reg_cmd_info.lbaLow >> 24 ) & 0x0f ) ) );
}
else
if ( reg_cmd_info.lbaSize == LBA48 )
{
// in ATA LBA48 mode
pio_outbyte( CB_FR, (unsigned char) ( reg_cmd_info.fr >> 8 ) );
pio_outbyte( CB_SC, (unsigned char) ( reg_cmd_info.sc >> 8 ) );
pio_outbyte( CB_SN, (unsigned char) ( reg_cmd_info.lbaLow >> 24 ) );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -