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

📄 atapi.c

📁 bootloader源代码
💻 C
字号:
/***************************************** Copyright (c) 2001-2002  Sigma Designs, Inc. All Rights Reserved Proprietary and Confidential *****************************************//* This is file is part of the Jasper DVD boot loader */#include "config.h"#ifdef SUPPORT_BOOT_FROM_CD#include "specific.h"#include "atapi.h"#include "uart.h"char dummy[128];void atapi_send_cmd (packet_command *pc);/* * Wait uninterruptibly until controller is not busy and certain * status bits are set. * The wait is usually short unless it is for the controller to process * an entire critical command. * Return 1 for (possibly stale) controller errors, -1 for timeout errors, * or 0 for no errors. */int atapi_wait (IOPORT port, unsigned char bits_wanted){	long cnt;	unsigned char s;	// Wait 5 sec for BUSY deassert.//	for (cnt=500000L; cnt>0; --cnt)	while (1)	{		s = ATA_READ_UCHAR (port + AR_STATUS);		if (! (s & ARS_BSY))			break;		DELAY (10);	}//	PrintUart("BUSY deassert\r\n Bits wanted = ",40);//	PrintShort(bits_wanted);//	PrintUart("\r\n",2);//	if (cnt <= 0)//		return (-1);	if (!bits_wanted)		return (s & ARS_CHECK);	// Wait 50 msec for bits wanted.	for (cnt=5000; cnt>0; --cnt)//	while (1)	{		s = ATA_READ_UCHAR (port + AR_STATUS);		if ((s & bits_wanted) == bits_wanted)			return (s & ARS_CHECK);		DELAY (10);	}//	PrintShort(s);//	PrintUart(" - timeout\r\n",40);	return (s);}// Wait for DRQ before sending packet cmd. Returns -1 on errorsint atapi_wait_cmd (packet_command *pc){	// Wait for DRQ from 50 usec to 3 msec for slow devices	int cnt = 500;	int ireason = 0, phase = 0;	// Wait for command phase.	for (; cnt>0; cnt-=1)	{		ireason = ATA_READ_UCHAR (pc->Port + AR_IREASON);		pc->stat = ATA_READ_UCHAR (pc->Port + AR_STATUS);		phase = (ireason & (ARI_CMD | ARI_IN)) |			(pc->stat & (ARS_DRQ | ARS_BSY));		if (phase == PHASE_CMDOUT)			break;		DELAY (10);	}	if (phase != PHASE_CMDOUT)	{		pc->error = ATA_READ_UCHAR (pc->Port + AR_ERROR);/*		PrintUart("wait_cmd: ireason= ",20);		PrintLong(ireason);		PrintUart("\tstat= ",20);		PrintLong(pc->stat);		PrintUart("\r\n",20);*/		return (-1);	}	return (0);}// write a packet command to the data registervoid atapi_send_cmd (packet_command *pc){	int i;	for(i=0;i<sizeof(pc->c); i+=2) {		ATA_WRITE_USHORT (pc->Port + AR_DATA, *(unsigned short *)(pc->c+i));	}}// Process the i/o phase, transferring the command/data to/from the device.// Return 1 if op continues, and we are waiting for new interrupt.// Return 0 when idle.int atapi_io (packet_command *pc){	unsigned char ireason;	unsigned short len, i;	if (atapi_wait (pc->Port, 0) < 0)	{		pc->stat = ATA_READ_UCHAR (pc->Port + AR_STATUS);		pc->error = ATA_READ_UCHAR (pc->Port + AR_ERROR);		return 0;	}	pc->stat = ATA_READ_UCHAR (pc->Port + AR_STATUS);	pc->error = ATA_READ_UCHAR (pc->Port + AR_ERROR);	len = ATA_READ_UCHAR (pc->Port + AR_CNTLO);	len |= ATA_READ_UCHAR (pc->Port + AR_CNTHI) << 8;	ireason = ATA_READ_UCHAR (pc->Port + AR_IREASON);	switch ((ireason & (ARI_CMD | ARI_IN)) | (pc->stat & ARS_DRQ))	{	default:		PrintUart ("atapi_io: default\r\n\0", 128);		pc->stat = RES_ERR;		break;	case PHASE_CMDOUT://		PrintUart ("atapi_io: PHASE_CMDOUT\r\n\0", 128);		// Send packet command.		if (!(pc->stat & ARS_DRQ))		{			pc->stat = RES_NODRQ;			break;		}		atapi_send_cmd (pc);		return (1);	case PHASE_DATAOUT://		PrintUart ("atapi_io: PHASE_DATAOUT\r\n\0", 128);		// Write data		if (pc->data_direction > 0)		{			pc->stat = RES_INVDIR;			break;		}		if (pc->count < len)		{			pc->stat = RES_UNDERRUN;			ATA_WRITE_USHORT_STRING (pc->Port + AR_DATA, (short *)pc->addr,				pc->count / sizeof(short));			for (i = pc->count; i<len; i += sizeof(short))				ATA_WRITE_USHORT (pc->Port + AR_DATA, 0);		}		else		{			ATA_WRITE_USHORT_STRING (pc->Port + AR_DATA, (short *)pc->addr,				len / sizeof(short));		}		pc->addr += len;		pc->count -= len;		return 1;	case PHASE_DATAIN:/*		PrintUart ("atapi_io: PHASE_DATAIN (for len =", 128);		PrintLong(len);		PrintUart(")\r\n",8);*/		// Read data		if (pc->data_direction < 0)		{			pc->stat = RES_INVDIR;			break;		}		if (pc->count < len)		{			pc->stat = RES_OVERRUN;			if (pc->count > 0)			{				ATA_READ_USHORT_STRING (pc->Port + AR_DATA, (short *)pc->addr,					pc->count / sizeof(short));			}			for (i=pc->count; i<len; i += sizeof(short))				ATA_READ_USHORT (pc->Port + AR_DATA);		}		else		{			// I think all devices can accept a long transfers			// if not, we can always revert back to using short transfers#define SLOW_IO_READ#ifdef SLOW_IO_READ			ATA_READ_USHORT_STRING (pc->Port + AR_DATA, (short *)pc->addr,				len / sizeof(short));#else			if ((len % 4) == 0)			{				ATA_READ_ULONG_STRING (pc->Port + AR_DATA, (long *)pc->addr,					len / sizeof(long));			}			else			{				ATA_READ_USHORT_STRING (pc->Port + AR_DATA, (short *)pc->addr,					len / sizeof(short));			}#endif			pc->addr += len;		}		pc->count -= len;/*		PrintUart("Count left: ",16);		PrintLong(pc->count);		PrintUart("\r\n",4);*/		return (1);	case PHASE_ABORTED:	case PHASE_COMPLETED://		PrintUart ("atapi_io: PHASE_COMPLETED\r\n\0", 128);		if (pc->stat & (ARS_CHECK | ARS_DF))		{			pc->stat = RES_ERR;		}		else if (pc->count != 0)		{			if (pc->data_direction < 0)			{				pc->error = RES_OVERRUN;				pc->stat = RES_OK;			}			else			{				pc->error = RES_UNDERRUN;				pc->stat = RES_OK;			}		}		else		{			pc->stat = RES_OK;		}		break;	}	return 0;}int Ata_Command_NonData (IOPORT Port, int Drive, int cmd){	unsigned int p = (unsigned int)Port;//	vfdnum(p);	PrintShort(p&0xFFFF);//	PrintShort(((unsigned int)Port)&0xFFFF);//	PrintUart(" : Select Drive and Wait\r\n",80);	// select drive	ATA_WRITE_UCHAR (Port + AR_DRIVE, Drive ? ARD_DRIVE1 : ARD_DRIVE0);	// Wait for controller not busy.	if (atapi_wait (Port, 0) < 0)	{		return 1;	}//	PrintUart("Issue ATA Command\r\n",80);	// Issue ATA command.	ATA_WRITE_UCHAR (Port + ATA_DRIVE, Drive ? ARD_DRIVE1 : ARD_DRIVE0);	ATA_WRITE_UCHAR (Port + ATA_FEATURE, 0);	ATA_WRITE_UCHAR (Port + ATA_CYL_LSB, 0);	ATA_WRITE_UCHAR (Port + ATA_CYL_MSB, 0);	ATA_WRITE_UCHAR (Port + ATA_SECTOR, 0);	ATA_WRITE_UCHAR (Port + ATA_COUNT, 0);	ATA_WRITE_UCHAR (Port + ATA_COMMAND, (char)cmd);	if (atapi_wait (Port, 0) < 0)	{		return 1;	}	return 0;}int Ata_Command_DataIn (IOPORT Port, int Drive, int cmd, unsigned char *pBuffer, int Length){	unsigned int p = (unsigned int)Port;//	vfdnum(p);	PrintShort(p&0xFFFF);//	PrintShort(((unsigned int)Port)&0xFFFF);//	PrintUart(" : Select Drive and Wait\r\n",80);	// select drive	ATA_WRITE_UCHAR (Port + AR_DRIVE, Drive ? ARD_DRIVE1 : ARD_DRIVE0);	// Wait for controller not busy.	if (atapi_wait (Port, 0) < 0)	{		return 1;	}//	PrintUart("Issue ATA Command\r\n",80);	// Issue ATA command.	ATA_WRITE_UCHAR (Port + ATA_DRIVE, Drive ? ARD_DRIVE1 : ARD_DRIVE0);	ATA_WRITE_UCHAR (Port + ATA_FEATURE, 0);	ATA_WRITE_UCHAR (Port + ATA_CYL_LSB, 0);	ATA_WRITE_UCHAR (Port + ATA_CYL_MSB, 0);	ATA_WRITE_UCHAR (Port + ATA_SECTOR, 0);	ATA_WRITE_UCHAR (Port + ATA_COUNT, 0);	//	DELAY(1);	ATA_WRITE_UCHAR (Port + ATA_COMMAND, (char)cmd);	// Check that device is present.	if (ATA_READ_UCHAR (Port + AR_STATUS) == 0xff)	{		return 2;	}	// Wait for data ready//	PrintUart("Wait after device present\r\n",80);	if (atapi_wait (Port, ARS_DRQ) != 0)	{		return 3;	}	// check that DRQ is not a fake one	if (ATA_READ_UCHAR (Port + AR_STATUS) == 0xff)	{		return 4;	}	// Do the IO//	PrintUart("Lets do the IO\r\n",80);	if (Length)	{		int i;		short buffer[256];		unsigned char *pS, *pD;		ATA_READ_USHORT_STRING (Port+ AR_DATA, buffer, 256);		pS = (unsigned char *)buffer;		pD = (unsigned char *)pBuffer;		for (i=0; i<Length; i++)			pD[i] = pS[i];	}	//	PrintUart("Wait before end\r\n",80);	if (atapi_wait (Port, 0) < 0)	{		return 5;	}	return 0;}int Atapi_Command (packet_command *pc){	int wait_idle;	int cnt;	// select drive	ATA_WRITE_UCHAR (pc->Port + AR_DRIVE, pc->Drive ? ARD_DRIVE1 : ARD_DRIVE0);	// wait for controller to be idle	//	PrintUart ("Waiting for controller to be idle\r\n", 128);	wait_idle = atapi_wait (pc->Port, 0);	if (wait_idle < 0)	{		PrintUart ("atapi_wait timeout\r\n\0", 128);		return 1;	}	pc->addr = pc->buffer;	pc->count = pc->buflen;//	DELAY(10);	// program atapi registers	ATA_WRITE_UCHAR (pc->Port + AR_FEATURES, 0);	ATA_WRITE_UCHAR (pc->Port + AR_IREASON, 0);	ATA_WRITE_UCHAR (pc->Port + AR_TAG, 0);	ATA_WRITE_UCHAR (pc->Port + AR_CNTLO, (unsigned char)(pc->buflen & 0xff));	ATA_WRITE_UCHAR (pc->Port + AR_CNTHI, (unsigned char)(pc->buflen >> 8));	ATA_WRITE_UCHAR (pc->Port + AR_COMMAND, (unsigned char)ATAPIC_PACKET);	// wait for DRQ to be set	if (atapi_wait_cmd (pc) < 0) {		PrintUart("atapi_wait_command FAILED\r\n",40);		return -1;	}	// send the packet command	atapi_send_cmd (pc);	// wait for data i/o phase	for (cnt=20000; cnt>0; --cnt)	{		if (((ATA_READ_UCHAR (pc->Port + AR_IREASON) & (ARI_CMD | ARI_IN)) |			 (ATA_READ_UCHAR (pc->Port + AR_STATUS) & ARS_DRQ)) != PHASE_CMDOUT)			break;	}	// Do all needed i/o (using PIO)//	PrintUart("Do the IO\r\n",20);	while (atapi_io (pc))	{		// Wait for DRQ deassert.		for (cnt=2000; cnt>0; --cnt)		{			if (!(ATA_READ_UCHAR (pc->Port + AR_STATUS) & ARS_DRQ))				break;			DELAY (10);		}	}	if (pc->stat != 0)		return pc->stat;	return 0;}//#define CPU_WR_32BIT_REG(base, port, value) do { *(unsigned int *)(base+port)=value; } while(0)void IdeInit(void){	unsigned short idbuffer[256];	CPU_WR_32BIT_REG(DVD_BASE, DVD_AV_CTRL, 0x00);		//0x00 select IDE over DVD-loader	CPU_WR_32BIT_REG(IDE_BASE, IDE_TIM, 0x8000);		//0x40 IDE decode enable	if(Ata_Command_DataIn((unsigned char *)IDE_BASE + IDE_PRI_DATA,0, ATAPIC_PIDENTIFY,(char *)idbuffer,512))		PrintUart("IDENTIFY FAILED\r\n",40);	//	dump(idbuffer,256);}int IdeReadSense(char *sensedata){	packet_command pc;	int s;	int timeout=10;//	PrintUart("Getting sense data\r\n",40);	do {		pc.buffer=(char *)sensedata;		pc.buflen = 18;		pc.data_direction=1;		pc.Port=(IOPORT) (IDE_BASE + IDE_PRI_DATA);		pc.Drive=0;		pc.stat=0;		pc.count=0;		pc.error=0;				pc.c[0]=0x03;		pc.c[1]=0;		pc.c[2]=0;		pc.c[3]=0;		pc.c[4]=18;		pc.c[5]=0;		pc.c[6]=0;		pc.c[7]=0;		pc.c[8]=0;		pc.c[9]=0;		pc.c[10]=0;		pc.c[11]=0;				s=Atapi_Command(&pc);		timeout--;	} while(s && timeout);	if(timeout==0)		PrintUart("IdeReadSense TIMEOUT\r\n",30);	return s;}int IdeWaitReady(unsigned int timeout){		packet_command pc;	int s;	char sensedata[18];	unsigned short asc,asq;	PrintUart("IdeWaitReady .....\r\n",30);	do {		pc.buffer=0;		pc.buflen=0;		pc.data_direction=0;		pc.Port=(IOPORT) (IDE_BASE + IDE_PRI_DATA);		pc.Drive=0;		pc.stat=0;		pc.count=0;		pc.error=0;		pc.c[0]=0x00;		pc.c[1]=0;		pc.c[2]=0;		pc.c[3]=0;		pc.c[4]=0;		pc.c[5]=0;		pc.c[6]=0;		pc.c[7]=0;		pc.c[8]=0;		pc.c[9]=0;		pc.c[10]=0;		pc.c[11]=0;		timeout--;				s=Atapi_Command(&pc);/*		PrintUart("\r\nStatus:\t",20);		PrintLong(s);		PrintUart("\r\nError:\t",20);	   		PrintLong(pc.error);*/		if(pc.error>>4==2) {						IdeReadSense(sensedata);			asc=sensedata[12];			asq=sensedata[13];			if(asc != 0x4 && asc !=0x28 ) {				// Failed - force exit				timeout=0; 				PrintUart(" SK : ",20);				PrintShort(pc.error>>4);				PrintUart(" - ASC : ",20);				PrintShort(asc);				PrintUart(" - ASQ:",20); 				PrintShort(asq);				PrintUart("\r\n",20); 			}		}	   	} while(s && timeout);	if(timeout==0)		PrintUart("IdeWaitReady TIMEOUT\r\n",30);	else		PrintUart("IdeWaitReady OK\r\n",30);	return s;}int IdeReadSectors(char *buffer, unsigned long  first, unsigned short nsectors){	packet_command pc;	int s;	int timeout = 10000;	do {		pc.buffer=buffer;		pc.buflen = nsectors*2048;		pc.data_direction=1;		pc.Port=(IOPORT) (IDE_BASE + IDE_PRI_DATA);		pc.Drive=0;		pc.stat=0;		pc.count=0;		pc.c[0]=0x28;		pc.c[1]=0;		pc.c[2]=(first>>24) & 0xFF;		pc.c[3]=(first>>16) & 0xFF;		pc.c[4]=(first>>8 ) & 0xFF;		pc.c[5]=(first    ) & 0xFF;		pc.c[6]=0;		pc.c[7]=(nsectors>>8) & 0xFF;		pc.c[8]=(nsectors   ) & 0xFF;		pc.c[9]=0;		pc.c[10]=0;		pc.c[11]=0;				s=Atapi_Command(&pc);		timeout--;	} while(s && timeout);	if(timeout==0)		PrintUart("IdeReadSectors TIMEOUT\r\n",30);	PrintLong(s);	PrintUart(" : read sectors status\r\n",30);	return s;}int IdeTray(int open){	packet_command pc;	int s;	int timeout = 100;	do {		pc.buffer=0;		pc.buflen = 0;		pc.data_direction=0;		pc.Port=(IOPORT) (IDE_BASE + IDE_PRI_DATA);		pc.Drive=0;		pc.stat=0;		pc.count=0;				pc.c[0] = 0x1b;		pc.c[1] = 0x00; // 1; 1= immediate return		pc.c[2] = 0x00;		pc.c[3] = 0x00;		if(open)			pc.c[4] = 0x02;		else			pc.c[4] = 0x03;		pc.c[5] = 0x00;		pc.c[6] = 0x00;		pc.c[7] = 0x00;		pc.c[8] = 0x00;		pc.c[9] = 0x00;		pc.c[10] = 0x00;		pc.c[11] = 0x00;				s=Atapi_Command(&pc);		timeout--;	} while(s && timeout);		if(timeout==0)		PrintUart("IdeEject TIMEOUT\r\n",30);	return s;}#endif // SUPPORT_BOOT_FROM_CD

⌨️ 快捷键说明

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