📄 atapi.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 + -