⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide_ata.c

📁 IDE 驱动程序对开发硬盘驱动很有用,对学习LINUX驱动开发有帮助
💻 C
📖 第 1 页 / 共 5 页
字号:
		if (retval == ATA_FAIL)
		{
			TRACE_ERROR("retval 5: 0x%x\n", retval);
			LOG_DIAG_ERROR("retval 5: 0x%x\n", retval);
		}

		// lba low
		retval = ATA_WriteRegister(cmd->driveID, ATA_REG_LBA_LOW, lba_low);
		if (retval == ATA_FAIL)
		{
			TRACE_ERROR("retval 6: 0x%x\n", retval);
			LOG_DIAG_ERROR("retval 6: 0x%x\n", retval);
		}

		// lba mid
		retval = ATA_WriteRegister(cmd->driveID, ATA_REG_LBA_MID, lba_mid);
		if (retval == ATA_FAIL)
		{
			TRACE_ERROR("retval 7: 0x%x\n", retval);
			LOG_DIAG_ERROR("retval 7: 0x%x\n", retval);
		}

		// lba high
		retval = ATA_WriteRegister(cmd->driveID, ATA_REG_LBA_HIGH, lba_high);
		if (retval == ATA_FAIL)
		{
			TRACE_ERROR("retval 8: 0x%x\n", retval);
			LOG_DIAG_ERROR("retval 8: 0x%x\n", retval);
		}
		
		// device
		retval = ATA_WriteRegister(cmd->driveID, ATA_REG_DRIVE_SEL, device);
		if (retval == ATA_FAIL)
		{
			TRACE_ERROR("retval 9: 0x%x\n", retval);
			LOG_DIAG_ERROR("retval 9: 0x%x\n", retval);
		}
	}

	// command
	retval = ATA_WriteRegister(cmd->driveID, ATA_REG_COMMAND, hd_cmd);
	if (retval == ATA_FAIL)
	{
		TRACE_ERROR("retval 10: 0x%x\n", retval);
		LOG_DIAG_ERROR("retval 10: 0x%x\n", retval);
	}
	
	// Better not be an ATAPI command
	if (ATA_WaitDriveDRdy(cmd->driveID, HD_WAIT_TIMEOUT) == ATA_FAIL) 
	{
		status = ATA_ReadRegister(cmd->driveID, ATA_REG_STATUS);
		TRACE_ERROR("Drive Busy, status = %x 11\n", status);
		LOG_DIAG_ERROR("Drive Busy, status = %x 11\n", status);
		return (IDE_ERRORCODE_TIMEOUT);
	}

	status = ATA_ReadRegister(cmd->driveID, ATA_REG_STATUS);
	if (status & ATA_STATUS_ERR) {
		error = ATA_ReadRegister(cmd->driveID, ATA_REG_ERROR);
		//TRACE_ERROR("ATA_STATUS_CHECK status = %x, error: %x 12\n", status, error);
		//LOG_DIAG_ERROR("ATA_STATUS_CHECK status = %x, error: %x 12\n", status, error);
		return error;
	}
	
	if ((cmd->cmdCode == IDE_CMD_DIAG) ||
		(cmd->cmdCode == IDE_CMD_STANDBY_IMMEDIATE))
	{
		error = ATA_ReadRegister(cmd->driveID, ATA_REG_ERROR);

		if (cmd->cmdCode == IDE_CMD_STANDBY_IMMEDIATE)
		{
			TRACE_STDBY("!!!!!!!!!!!!!!!!!!!!!!!! Done standby immediate\n");
		}

		if (error == 0x01) // Everything is good
			return 0;
		else {
			//DEBUG_OUT("Diagnostics failed %x\n", error);
			return 0;
		}
	}
	if (!cmd->readWrite)
		return 0;

	switch (cmd->cmdCode) { // get the maximum number of sector to transfer at a time before checking for DRQ or BSY again
	case IDE_CMD_READM :
	case IDE_CMD_READM_EXT:
		soft_assert(buf != NULL);
		maxTransfer = MAX_READ_DMA_SIZE / HD_SECTOR_SIZE;
		if (diskDesc[cmd->driveID].currentMultipleTransfer < maxTransfer)
			maxTransfer = diskDesc[cmd->driveID].currentMultipleTransfer;
		break;
	case IDE_CMD_WRITEM :
	case IDE_CMD_WRITEM_EXT:
		if (buf == NULL)
		{
			// for DMA from RIO, we always do 32K chunk
			maxTransfer = 32 * 1024;
		}
		else
		{
			maxTransfer = MAX_WRITE_DMA_SIZE / HD_SECTOR_SIZE;
			if (diskDesc[cmd->driveID].currentMultipleTransfer < maxTransfer)
				maxTransfer = diskDesc[cmd->driveID].currentMultipleTransfer;
		}
		break;
	case IDE_CMD_WRITEDMA:
	case IDE_CMD_WRITEDMA_EXT:
		// tango to do this should be a define
		maxTransfer = 32 * 1024;
		soft_assert((cmd->sectorCntReg * HD_SECTOR_SIZE) <= maxTransfer);
		break;
	default :
		maxTransfer = 1;
		break;
	}

	//DbgPrint2("cmd %x, max %d\n", cmd->cmdCode, maxTransfer);
		
	//DEBUG_OUT("ATA_Send() code: %x, LBA: %x, secNum: %x\n", cmd->cmdCode, cmd->lba, cmd->sectorCntReg);
	if (ATA_WaitDriveRdy(cmd->driveID, ATA_STATUS_DRQ, HD_WAIT_TIMEOUT) == ATA_FAIL) {
		status = ATA_ReadRegister (cmd->driveID, ATA_REG_STATUS);
		
		if (status & ATA_STATUS_ERR) {
			error = ATA_ReadRegister(cmd->driveID, ATA_REG_ERROR);
			//TRACE_ERROR("ATA_STATUS_CHECK status = %x, error: %x 13\n", status, error);
			//LOG_DIAG_ERROR("ATA_STATUS_CHECK status = %x, error: %x 13\n", status, error);
			return error;
		}
		DEBUG_OUT("Waiting for data, DRQ = 0, status = %x\n", status);
		
		return 0;
	}

	byteCnt = cmd->sectorCntReg * HD_SECTOR_SIZE;
	if ((byteCnt > cmd->maxDataSize) && (cmd->readWrite & IDE_CMD_READ))
	{
		TRACE_ERROR("ATA_Send(%x) data requested(0x%x) > maxDataSize(0x%x) 14\n", cmd->cmdCode, byteCnt, cmd->maxDataSize);
		LOG_DIAG_ERROR("ATA_Send(%x) data requested(0x%x) > maxDataSize(0x%x) 14\n", cmd->cmdCode, byteCnt, cmd->maxDataSize);
		return IDE_ERRORCODE_INSUFFICIENT_BUF_SIZE;
	}

	// make some adjustment: If the cmd->sectorCntReg is zero, the IDE device actually expects
	// 256 sectors of data. Set the totalSecNum to 256.
	totalSecNum = (cmd->sectorCntReg == 0) ? 256 : cmd->sectorCntReg;
	
	i = 0;				
	while ( i < totalSecNum ) {

		if (ATA_WaitDriveRdy(cmd->driveID, ATA_STATUS_DRQ, HD_WAIT_TIMEOUT) == ATA_FAIL) {
			TRACE_ERROR("Missing some data 15\n");
			LOG_DIAG_ERROR("Missing some data 15\n");
			return -1;
		}

		if ((totalSecNum - i) >= maxTransfer)
			byteCnt = maxTransfer * HD_SECTOR_SIZE;
		else
			byteCnt = (totalSecNum - i) * HD_SECTOR_SIZE;
		
		// here
		if (cmd->readWrite & IDE_CMD_READ) 
		{
			ATA_ReadDataDMA(cmd->driveID, (void *)(buf + byteTx), byteCnt);
		}
		else 
		{ 
#ifdef STREAM_ENABLE
			if (buf == NULL)
			{
				// Do FPGA dma transfer
#ifndef RIO_APP
				StartFPGADMATransfer(byteCnt);
#else	
#ifdef RIO_PIO_MODE				           
				if (1)
				{
					int i;

					soft_assert((byteCnt % 0x2000) == 0);
					for (i = 0; i < (byteCnt / 0x2000); i++)
					{
						if (i)
						{
							if (ATA_WaitNotBusy(cmd->driveID, HD_WAIT_TIMEOUT) == ATA_FAIL) {
								TRACE_ERROR("Drive Busy after reading data: 18\n");
								LOG_DIAG_ERROR("Drive Busy after reading data 18\n");
								return -1;
							}
											
							if (ATA_WaitDriveRdy(cmd->driveID, ATA_STATUS_DRQ, HD_WAIT_TIMEOUT) == ATA_FAIL) {
								TRACE_ERROR("Missing some data 19\n");
								LOG_DIAG_ERROR("Missing some data 19\n");
								return -1;
							}
						}
						StartDMATransfer(0x2000);	
					}
				}
#else
				StartDMATransfer(byteCnt);
#endif	// RIO_PIO_MODE
#endif
			}
			else
#endif
			{
				// it's a write
				ATA_WriteDataDMA(cmd->driveID, (void *)(buf + byteTx), byteCnt);
			}
		}
		
		byteTx += byteCnt;
		i += byteCnt / HD_SECTOR_SIZE;
		
		if (ATA_WaitNotBusy(cmd->driveID, HD_WAIT_TIMEOUT) == ATA_FAIL) {
			TRACE_ERROR("Drive Busy after reading data 16\n");
			LOG_DIAG_ERROR("Drive Busy after reading data 16\n");
			return -1;
		}
	}
	
	while (ATA_WaitDriveRdy(cmd->driveID, 0, HD_WAIT_TIMEOUT) == ATA_FAIL) {
		TRACE_ERROR("Still some data ... 17\n");
		LOG_DIAG_ERROR("Still some data ... 17\n");
		return -1;
	}
	
	cmd->dataSize = byteTx;
	return 0;
}

Int32 ide_command_standby_immediate(Uint8 driveID)
{
	IDE_Cmd cmd;

	cmd.cmdCode = IDE_CMD_STANDBY_IMMEDIATE;
	cmd.sectorCntReg = 0;
	cmd.lba = 0;
	cmd.driveID = driveID;
	cmd.featureReg = 0x0;
	cmd.pktCmd = NULL;
	cmd.pktCmdSize = 0;
	cmd.data = NULL;
	cmd.deviceReg = 0;
	cmd.readWrite = 0;
	cmd.maxDataSize = 0;

	if(IDE_SendCmd(&cmd)) 
		return IDE_IO_ERROR;
	else
		return SUCCESS;
}

Int32 ide_command_check_power_mode(Uint8 driveID, Uint8* mode)
{
	IDE_Cmd cmd;

	cmd.cmdCode = IDE_CMD_CHECK_POWER_MODE;
	cmd.sectorCntReg = 0;
	cmd.lba = 0;
	cmd.driveID = driveID;
	cmd.featureReg = 0;
	cmd.pktCmd = NULL;
	cmd.pktCmdSize = 0;
	cmd.data = NULL;
	cmd.deviceReg = 0;
	cmd.readWrite = 0;
	cmd.maxDataSize = 0;
	cmd.ext_cmd = FALSE;

	if (IDE_SendCmd(&cmd))
	{
		*mode  = 0;
		return ATA_FAIL;
	}
	else
	{
		*mode  = ATA_ReadRegister(driveID, ATA_REG_SECTOR_CNT) & 0xFF;
		return ATA_SUCCESS;
	}
}

Int32 ide_command_idle_immediate(Uint8 driveID)
{
	Uint32  status;

	ATA_LockBus (driveID);
	ATA_LockDevice(driveID);
	
	// Select the appropriate drive
	ATA_WriteRegister (
			driveID, 					//
			ATA_REG_DRIVE_SEL,          //
			ATA_DRIVE_SELECT(driveID)   //
		);

	if (ATA_WaitDriveDRdy(driveID, HD_WAIT_TIMEOUT) == ATA_FAIL) 
	{
		TRACE_ERROR("<ide_command_idle_immediate> Timeout Waiting For Drive Drdy driveID %d\n", driveID);
		ATA_ReleaseDevice(driveID);
		ATA_ReleaseBus (driveID);
		return (IDE_ERRORCODE_TIMEOUT);
	}

	// issue the command
	ATA_WriteRegister (
			driveID, 					//
			ATA_REG_COMMAND,            //
			IDE_CMD_IDLE_IMMEDIATE      //
		);

	// Better not be an ATAPI command
	if (ATA_WaitDriveDRdy(driveID, HD_WAIT_TIMEOUT * 20) == ATA_FAIL) 
	{
		status = ATA_ReadRegister(driveID, ATA_REG_STATUS);
		TRACE_ERROR("<ide_command_idle_immediate> Drive Busy,driveID = %d status = %x\n", driveID, status);
		ATA_ReleaseDevice(driveID);
		ATA_ReleaseBus (driveID);
		return (IDE_ERRORCODE_TIMEOUT);
	}

	ATA_ReleaseDevice(driveID);
	ATA_ReleaseBus (driveID);

	return SUCCESS;
}

//-----------------------------------------------------------------------------
//  Function: ide_command_identify
//
//  Description:
//      Read drive characteristics
//
//      This routine requests the drive parameters from the IDE drive at
//      driveno and places them in the buffer at address. See an IDE drive
//      data for a description of the command. 
//    
//      Note: buffer must be at least 512 bytes.
//    
//      This routine is optional. It is not needed by the device driver interface.
//    
//      This routine is portable
//          
//
//
//-----------------------------------------------------------------------------
Int32 ide_command_identify (Uint8 driveID, Uint8 * address)
{
    IDE_Cmd cmd;

	cmd.cmdCode = IDE_CMD_IDENT;
	cmd.sectorCntReg = 1;
	cmd.lba = 0;
	cmd.driveID = driveID;
	cmd.featureReg = 0;
	cmd.pktCmd = NULL;
	cmd.pktCmdSize = 0;
	cmd.data = address;
	cmd.deviceReg = 0;
	cmd.readWrite = IDE_CMD_READ;
	cmd.maxDataSize = 512;
	cmd.ext_cmd =FALSE;

	if(IDE_SendCmd(&cmd)) 
		return IDE_IO_ERROR;
	else
		return SUCCESS;
}

 
//-----------------------------------------------------------------------------
//  Function: ide_command_diags
//
//  Description:
//		Execute drive diagnostics
//
//      This routine execute a diagnostic request. If the diagnostic succeeds
//      it returns SUCCESS
//
//-----------------------------------------------------------------------------
static Int32 ide_command_diags(Uint8 driveID)
{
	IDE_Cmd cmd;

	if (( diskDesc[driveID].MediaDeviceBrand == MEDIADEVICE_BRAND_SAIN) ||
		( diskDesc[driveID].MediaDeviceBrand == MEDIADEVICE_BRAND_ONSPEC))
	{
		return SUCCESS;
	}

	cmd.cmdCode = IDE_CMD_DIAG;
	cmd.sectorCntReg = 0;
	cmd.lba = 0;
	cmd.driveID = driveID;
	cmd.featureReg = 0;
	cmd.pktCmd = NULL;
	cmd.pktCmdSize = 0;
	cmd.data = NULL;
	cmd.deviceReg = 0;
	cmd.readWrite = 0;
	cmd.maxDataSize = 0;
	cmd.ext_cmd = FALSE;

	if(IDE_SendCmd(&cmd)) 
		return IDE_IO_ERROR;
	else
		return SUCCESS;
}

 

Int32 ide_command_seek(Uint8 driveID)
{
	IDE_Cmd cmd;

	cmd.cmdCode = IDE_CMD_SEEK;
	cmd.sectorCntReg = 0;
	cmd.lba = 0;
	cmd.driveID = driveID;
	cmd.featureReg = 0;
	cmd.pktCmd = NULL;
	cmd.pktCmdSize = 0;
	cmd.data = NULL;
	cmd.deviceReg = 0;
	cmd.readWrite = 0;
	cmd.maxDataSize = 0;
	cmd.ext_cmd =FALSE;

	if(IDE_SendCmd(&cmd)) 
		return IDE_IO_ERROR;
	else
		return SUCCESS;
}

#if 1
Int32 ide_command_media(Uint8 driveID)
{
	Int32   retVal;
	Uint32  status;
	Uint32  tickCnt;

	ATA_LockBus (driveID);
	ATA_LockDevice(driveID);
	
	// Select the appropriate drive
	ATA_WriteRegister (
			driveID, 					//
			ATA_REG_DRIVE_SEL,          //
			ATA_DRIVE_SELECT(driveID)   //
		);

	if (ATA_WaitDriveDRdy(driveID, HD_WAIT_TIMEOUT * 2) == ATA_FAIL) 
	{
		TRACE_ERROR("<ide_command_media> Timeout Waiting For Drive Drdy 1\n");
		//soft_assert(0);
		ATA_WriteRegister(driveID, ATA_REG_DEVICE_CONTROL, ATA_DEVICE_CTRL_SRT_BIT | ATA_DEVICE_CTRL_nIEN_BIT);
		ATA_ReleaseDevice(driveID);
		ATA_ReleaseBus (driveID);
		return (IDE_ERRORCODE_TIMEOUT);
	}

	if( diskDesc[driveID].MediaDeviceBrand == MEDIADEVICE_BRAND_ONSPEC)
	{
		ATA_WriteRegister(driveID, ATA_REG_FEATURE, 0);
	}
	else
	{
		ATA_WriteRegister(driveID, ATA_REG_FEATURE, 1);
	}
	// issue the command
	ATA_WriteRegister (
			driveID, 					//
			ATA_REG_COMMAND,            //
			IDE_CMD_MEDIA               //
		);

	tickCnt = tickGet();

	while (1)
	{
		status = ATA_ReadRegister (
				driveID, 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -