原创 DOS下BIOS中断INT13H、IO端口直接编程读取IDE、SATA硬盘的参数和TC语言程序5

2015-4-23 17:20 2154 17 17 分类: 工程师职场 文集: 学以致用

int main( int argc, char *argv[] )

{

 

  HBA_MEM myHBAMEM;

  HBA_PORT myHBAPORT;

  BYTE tempbuff1[1024],  *databuff;

  unsigned long tmpADDR,  HBA_addr, PORT_addr;

  BYTE tempbuff2[1024],  *tablebuff;

  HBA_CMD_TBL *myCMDTABLE;

  HBA_CMD_HEADER myCMDHEADER;

  FIS_REG_H2D  *myCFIS;

  HBA_PRDT_ENTRY *myPRDT;

  int myPORTnum;

  int i;

  unsigned char ctemp;

    

  memset(tempbuff1, 0xAA, 1024);

  memset(tempbuff2, 0, 1024);

  memset(&myCMDHEADER, 0, sizeof(HBA_CMD_HEADER));

 

 

//命令头CMDHEADER 

  myCMDHEADER.cfl= sizeof(FIS_REG_H2D)/sizeof(DWORD);  // Command FIS size

  myCMDHEADER.w= 0;               // Read from device 从设备读

  myCMDHEADER.prdtl = 1;      // PRDT entries count   1表示1个

  tmpADDR=(unsigned long)FP_SEG(tempbuff2)*16+(unsigned long)FP_OFF(tempbuff2);

  tmpADDR=(tmpADDR & 0xffffff00) + 0x100 ;  //tmpADDR 要128字节对齐,这里取256字节

  myCMDHEADER.ctba=tmpADDR;

  tablebuff=MK_FP((unsigned int)(tmpADDR>>4), (unsigned int)(tmpADDR & 0xf) );    // 一定要加(unsigned int),不然生成的地址为0

  printf("tablebuff  SEG=%04X   OFF=%04X    FLAT ADDR=%08lX \n",  FP_SEG(tablebuff),  FP_OFF(tablebuff) , tmpADDR);

 

//命令表CMDTABLE

  //命令包  

  myCMDTABLE=(HBA_CMD_TBL *)(tablebuff);

         //注意“线性地址”与 “指针地址” 的不同,这里tablebuff(指针地址) 不能写成 tmpADDR(线性地址)

  myCFIS=(FIS_REG_H2D *) (myCMDTABLE);

  myCFIS->fis_type = 0x27;  //FIS_TYPE_REG_H2D

  myCFIS->command =0xec ;  // 0xEC  ATA_CMD_IDENTIFY

  myCFIS->device = 0;         // Master device

  myCFIS->c = 1;              // Write command register  1表示这是一个命令

 

  //PRDT ENTRY

  myPRDT=(HBA_PRDT_ENTRY *)(myCMDTABLE->prdt_entry);

  tmpADDR=(unsigned long)FP_SEG(tempbuff1)*16+(unsigned long)FP_OFF(tempbuff1);

  tmpADDR=(tmpADDR & 0xfffffff0) + 0x10 ;          //tmpADDR 要2字节对齐,这里取多一些

  databuff=MK_FP((unsigned int)(tmpADDR>>4), (unsigned int)(tmpADDR & 0xf) );    // 一定要加(unsigned int),不然生成的地址为0

  printf("databuff  SEG=%04X   OFF=%04X    FLAT ADDR=%08lX \n",  FP_SEG(databuff),  FP_OFF(databuff) , tmpADDR);

 

  myPRDT->dba= tmpADDR;

  myPRDT->dbc1= 999;    //表示长度是1000字节

  myPRDT->dbc2= 0;     

  myPRDT->i= 1;

 

  printf("COMMAND HEADER in hex is:\n");

  mydisplay( (unsigned char *)&myCMDHEADER, 32 );

  printf("COMMAND TABLE in hex is:\n");

  mydisplay( (unsigned char *)myCMDTABLE, 144 );

  printf("press a key...\n");getchar();

 

 

//读HBA MEM

  if(argc<3)

  {

     printf("you must input HBA addr, port number!");

     return 0;

  }

 

  //得到命令行的HBA ADDR

  if(strlen(argv[1]) != 8) { printf("HBA ADDR must be 8 chars long!"); return 0;}

  HBA_addr=0;

  for(i=0;i< 8;i++)

  {

     argv[1] = toupper(argv[1]);      //转大写

     ctemp=(unsigned char)argv[1];

 

     if (ctemp>=0x30 && ctemp<=0x39)

     {

         ctemp=ctemp-0x30;

     }

     else if (ctemp>=0x41 && ctemp<=0x46)

     {

         ctemp=ctemp-55;

     }

     else

     { printf("HBA ADDR char error");       return 0;  }

 

     HBA_addr+=((unsigned long)ctemp) << (4*(7-i));

  }

 

  //得到命令行的PORT口

  myPORTnum= atoi(argv[2]);

  if(myPORTnum<0 || myPORTnum>31 ) {printf("PORT NUMBER error!"); return 0; }

  PORT_addr= HBA_addr + 256 + myPORTnum*128;

  printf ("HBA addr=%08lXH  PORT addr=%08lXH \n",HBA_addr,  PORT_addr);

 

  //读和显示MEM

  memmove( HBA_addr ,   (unsigned long)FP_SEG(&myHBAMEM)*16+(unsigned long)FP_OFF(&myHBAMEM), 256 );  //源,目的,字节数(应为偶数)

  memmove( PORT_addr ,  (unsigned long)FP_SEG(&myHBAPORT)*16+(unsigned long)FP_OFF(&myHBAPORT), 128 );  //源,目的,字节数(应为偶数)

  printf("HBA MEM in hex is:\n");

  mydisplay( (unsigned char *)&myHBAMEM,  256);

  printf("press a key...\n");getchar();

 

  printf("PORT MEM in hex is:\n");

  mydisplay( (unsigned char *)&myHBAPORT,  128);

  printf("press a key...\n");getchar();

 

 

//判断各个取值是否正常 

  if( !(myHBAMEM.ghc >> 31) ) { printf(" ERROR, AHCI NOT ENABLE "); return 0;}

  if( myHBAMEM.bohc ) { printf(" ERROR, BIOS OR OS is controling HBA"); return 0;}

  if( !( myHBAMEM.pi & ((DWORD)1 << myPORTnum) ) ) { printf(" ERROR, NO DEVICE ON THAT PORT"); return 0;}

  if( myHBAPORT.clbu || myHBAPORT.fbu ) { printf(" ERROR, clbu or fbu ERROR"); return 0;}

  if( (!myHBAPORT.clb) || (!myHBAPORT.fb) ) { printf(" ERROR, clb or fb ERROR"); return 0;}

  if( myHBAPORT.is ) { printf(" ERROR, PxIS NOT ZERO"); return 0;}

  if( myHBAPORT.serr ) { printf(" ERROR, PxSERR NOT ZERO"); return 0;}

  if( myHBAPORT.tfd & 0x89 ) { printf(" ERROR, ERR or DRQ or BSY NOT ZERO"); return 0;} 

                          //PxTFD.STS.BSY(bit7)=0,PxTFD.STS.DRQ(bit3)=0,PxTFD.STS.ERR(bit0)=0

  if( (myHBAPORT.ssts & 0x0f) !=3  ) { printf(" ERROR, PxSSTS.DET is not 3"); return 0;}      //PxSSTS.DET(bit3:0) = 3

  if( (myHBAPORT.cmd & 0x8000)   ) { printf(" ERROR, PxCMD.CR a command is running"); return 0;}    //PxCMD.CR(bit15)=0,FR(bit14)=0

  if( (myHBAPORT.cmd & 0x4000)   ) { printf(" ERROR, PxCMD.FR RFIS is receiving"); return 0;}

  if( myHBAPORT.ci || myHBAPORT.sact   ) { printf(" ERROR, command slot is not all free"); return 0;}

            //这里为简单起见,需SLOT全部空闲!即要使用SLOT0

 

 

//把COMMAND HEADER拷入SLOT

  memmove( (unsigned long)FP_SEG(&myCMDHEADER)*16+(unsigned long)FP_OFF(&myCMDHEADER) ,   myHBAPORT.clb,  32 );  //源,目的,字节数(应为偶数)

  printf("HAVE COPY COMMAND HEADER TO SLOT0     press a key...\n");   getchar();

 

 

//发送命令

 

  myWRITEMEM_DWORD( PORT_addr+0x18,  myREADMEM_DWORD( PORT_addr+0x18) | 0x10   );  //设置PxCMD.FRE(bit4)=1  使能接收FIS 

  printf("HAVE SET PxCMD.FRE     press a key...\n");   getchar();

  printf("PxCMD is %08lX\n",  myREADMEM_DWORD( PORT_addr+0x18));

    

  myWRITEMEM_DWORD( PORT_addr+0x18,  myREADMEM_DWORD( PORT_addr+0x18) | 0x01   );  //设置PxCMD.ST(bit0)=1  使能命令运行

  printf("HAVE SET PxCMD.ST      press a key...\n");   getchar();

  printf("PxCMD is %08lX\n",  myREADMEM_DWORD( PORT_addr+0x18));

 

  myWRITEMEM_DWORD( PORT_addr+0x38,  myHBAPORT.ci | 0x01   );  //写PxCI.CI相应位,让HBA发送命令。这里是SLOT0

 

//判断命令完成

  delay(1000);  //延时1S

  if( myREADMEM_DWORD(PORT_addr+0x38) )  {printf(" ERROR, PxCI.CI not return zero"); return 0; }  //PxCI.CI必须清零

  if( myREADMEM_DWORD(PORT_addr+0x10) & 0x40000000  ) {printf(" ERROR, PxIS.TFES is 1"); return 0; } //PxIS.TFES(bit30) 不能为1

 

//显示收到的数据

  printf("data buff in hex is:\n");

  mydisplay(databuff, 256);

  printf("press a key...\n");getchar(); 

  mydisplay(databuff+256, 256);

 

  return 0;

}

 

文章评论0条评论)

登录后参与讨论
我要评论
0
17
关闭 站长推荐上一条 /2 下一条