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

📄 main.cpp

📁 使用ASPI控制CDROM旋转速度的程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:
        (AnsiString)ASC +
        (AnsiString)" ASCQ " +
        (AnsiString)ASCQ).c_str() );
  }

//speed is stored in bytes 22 & 23 of mode page 0x2A
return (int)((b[22] << 8) + b[23]);
}

int __fastcall TMainWindow::getMAXCDSpeed()
{
SRB_ExecSCSICmd s;
unsigned char b[256];

memset( &s, 0, sizeof( s ) );
memset( b, 0xFF, 256 );
s.SRB_Cmd      = SC_EXEC_SCSI_CMD;
s.SRB_HaId     = gbyCurrentHostAdapter;
s.SRB_Target   = gbyCurrentTarget;
s.SRB_Lun      = 0;
s.SRB_Flags    = SRB_DIR_IN | SRB_EVENT_NOTIFY;
s.SRB_BufLen   = 256;
s.SRB_BufPointer = b;
s.SRB_CDBLen   = 12;
s.CDBByte[0]   = SCSI_MODESENSE;
s.CDBByte[2]   = 0x2A;    //mode page 0x2A contains the max speed
s.CDBByte[7]   = 0x01;
s.CDBByte[8]   = 0x00;

BYTE byStatus = ExecSCSICommand(&s);

if( byStatus != SS_COMP )
  log( ((AnsiString)"getMAXCDSpeed returned status " +
        LookupASPIStatus(byStatus) +
        (AnsiString)" with HaStat " +
        (AnsiString)s.SRB_HaStat +
        (AnsiString)" TargStat " +
        (AnsiString)s.SRB_TargStat).c_str() );

if( byStatus == SS_ERR && s.SRB_TargStat == STATUS_CHKCOND )
  {
  BYTE SenseKey = s.SenseArea[2] & (BYTE)15;
  BYTE ASC = s.SenseArea[12];
  BYTE ASCQ = s.SenseArea[13];
  log( ((AnsiString)"   Check Condition: Sense Key " +
        (AnsiString)SenseKey +
        (AnsiString)" ASC " +
        (AnsiString)ASC +
        (AnsiString)" ASCQ " +
        (AnsiString)ASCQ).c_str() );
  }

//bytes 16 & 17 in mode page 0x2A represent the max speed
return (int)((b[16] << 8) + b[17]);
}

//----------------------------------
//Rounds a float to the closest int
//----------------------------------
int __fastcall TMainWindow::round( float num )
{
int roundnum = (int)num;
if( (num - roundnum) >= .5 )
  return roundnum+1;
else
  return roundnum;
}

//----------------------------------------------------
//Given a read speed in kilobytes, this function
// returns an integer saying how fast this is in
// the common CD-ROM convention of [Speed]x
//----------------------------------------------------
int __fastcall TMainWindow::LookupX( int KB )
{
return round((float)KB/(float)176);
}

//----------------------------------------------------
//Given an integer representing "Speed" in the [Speed]x
// CD-ROM transfer rate notation, this function finds
// and returns the read speed of the currently selected
// CD-ROM drive corresponding to that X value
//----------------------------------------------------
int __fastcall TMainWindow::LookupKB( int X )
{
//Here's the thing -- different drives report different
// speeds for the same X rating.  My ASUS34x reports
// 4x speeds to be exactly 176*4 = 704 kb/s, but my Creative
// 4224 reports 4x to be 706 kb/s.  Instead of simply looking
// up the kb/s using multiple of 176, I must scan the "area"
// around the multiple a few kb/s in either direction until
// I hit on one that the drive accepts.  That is the speed
// corresponding to that x for this particular drive.
// Pretty screwy, huh?

//TOLERANCE is the number of kb/s this function scans on either
// side of the multiple of 176
const int TOLERANCE = ToleranceEdit->Text.ToInt();

//since I'll be issuing read speed set commands in order
// to determine which transfer rate the drive accepts, I
// save the speed at which the drive is currently set
int rememberspeed = getCDSpeed();

//test all speeds +/- [TOLERANCE] kb/s from [X rating]*176:
//1) attempt the set the drive's speed
//2) get the drive's speed
//3) if the gotten speed equals the set speed, that's
//     the tranfer rate corresponding to the X rating
//     for this drive
for( int j = 0; j < TOLERANCE*2; j++ )
   {
   setCDSpeed( X1*X - TOLERANCE + j );
   if( getCDSpeed() == X1*X - TOLERANCE+j )
      {
      log( ((AnsiString)"Found speed " +
            (AnsiString)(X1*X - TOLERANCE + j)).c_str() );
      //restore the drive's original speed
      setCDSpeed( rememberspeed );
      return X1*X - TOLERANCE + j;
      }
   }
//restore the drive's original speed
setCDSpeed( rememberspeed );

//if it gets this far, then no corresponding kb/s value was found
// for this drive, and the function returns 0
return 0;
}

//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
//CD Spindown Commands
//---------------------------------------------------------------------------
#define SPINDOWN_VENDOR_SPECIFIC 0x00
#define SPINDOWN_125MS 0x01
#define SPINDOWN_250MS 0x02
#define SPINDOWN_500MS 0x03
#define SPINDOWN_1S    0x04
#define SPINDOWN_2S    0x05
#define SPINDOWN_4S    0x06
#define SPINDOWN_8S    0x07
#define SPINDOWN_16S   0x08
#define SPINDOWN_32S   0x09
#define SPINDOWN_1MIN  0x0A
#define SPINDOWN_2MIN  0x0B
#define SPINDOWN_4MIN  0x0C
#define SPINDOWN_8MIN  0x0D
#define SPINDOWN_16MIN 0x0E
#define SPINDOWN_32MIN 0x0F
//----------------------------------------------------
//Given one of the above codes, this function returns
// a string indicating what the corresponding spindown
// time is
//----------------------------------------------------
AnsiString LookupSpindownText( BYTE code )
{
AnsiString returnstring;
switch( code )
  {
  case SPINDOWN_VENDOR_SPECIFIC: returnstring = "VS"; break;
  case SPINDOWN_125MS  : returnstring = "125 ms"; break;
  case SPINDOWN_250MS  : returnstring = "250 ms"; break;
  case SPINDOWN_500MS  : returnstring = "500 ms"; break;
  case SPINDOWN_1S     : returnstring = "1 s";    break;
  case SPINDOWN_2S     : returnstring = "2 s";    break;
  case SPINDOWN_4S     : returnstring = "4 s";    break;
  case SPINDOWN_8S     : returnstring = "8 s";    break;
  case SPINDOWN_16S    : returnstring = "16 s";   break;
  case SPINDOWN_32S    : returnstring = "32 s";   break;
  case SPINDOWN_1MIN   : returnstring = "1 min";  break;
  case SPINDOWN_2MIN   : returnstring = "2 min";  break;
  case SPINDOWN_4MIN   : returnstring = "4 min";  break;
  case SPINDOWN_8MIN   : returnstring = "8 min";  break;
  case SPINDOWN_16MIN  : returnstring = "16 min"; break;
  case SPINDOWN_32MIN  : returnstring = "32 min"; break;
  }
return returnstring;
}

//----------------------------------------------------
//Give one of the strings that the above function
// returns, this returns the above code that
// corresponds to this string
//----------------------------------------------------
BYTE LookupSpindownCode( AnsiString Text )
{
if( Text == "125 ms" ) return SPINDOWN_125MS;
if( Text == "250 ms" ) return SPINDOWN_250MS;
if( Text == "500 ms" ) return SPINDOWN_500MS;
if( Text == "1 s" )    return SPINDOWN_1S;
if( Text == "2 s" )    return SPINDOWN_2S;
if( Text == "4 s" )    return SPINDOWN_4S;
if( Text == "8 s" )    return SPINDOWN_8S;
if( Text == "16 s" )   return SPINDOWN_16S;
if( Text == "32 s" )   return SPINDOWN_32S;
if( Text == "1 min" )  return SPINDOWN_1MIN;
if( Text == "2 min" )  return SPINDOWN_2MIN;
if( Text == "4 min" )  return SPINDOWN_4MIN;
if( Text == "8 min" )  return SPINDOWN_8MIN;
if( Text == "16 min" ) return SPINDOWN_16MIN;
if( Text == "32 min" ) return SPINDOWN_32MIN;
else return 0;
}

//----------------------------------------------------
//Issues a mode sense command to obtain the current
// spindown time of the current drive
//----------------------------------------------------
BYTE __fastcall TMainWindow::getCDSpindown()
{
SRB_ExecSCSICmd s;
unsigned char b[256];

memset( &s, 0, sizeof( s ) );
memset( b, 0xFF, 256 );
s.SRB_Cmd      = SC_EXEC_SCSI_CMD;
s.SRB_HaId     = gbyCurrentHostAdapter;
s.SRB_Target   = gbyCurrentTarget;
s.SRB_Lun      = 0;
s.SRB_Flags    = SRB_DIR_IN | SRB_EVENT_NOTIFY;
s.SRB_BufLen   = 256;
s.SRB_BufPointer = b;
s.SRB_CDBLen   = 12;
s.CDBByte[0]   = SCSI_MODESENSE;
s.CDBByte[2]   = 0x0D;    //spindown timer is on the 0x0D mode page
s.CDBByte[7]   = 0x01;
s.CDBByte[8]   = 0x00;

BYTE byStatus = ExecSCSICommand(&s);

if( byStatus != SS_COMP )
  log( ((AnsiString)"getCDSpindown returned status " +
        LookupASPIStatus(byStatus) +
        (AnsiString)" with HaStat " +
        (AnsiString)s.SRB_HaStat +
        (AnsiString)" TargStat " +
        (AnsiString)s.SRB_TargStat).c_str() );

if( byStatus == SS_ERR && s.SRB_TargStat == STATUS_CHKCOND )
  {
  BYTE SenseKey = s.SenseArea[2] & (BYTE)15;
  BYTE ASC = s.SenseArea[12];
  BYTE ASCQ = s.SenseArea[13];
  log( ((AnsiString)"   Check Condition: Sense Key " +
        (AnsiString)SenseKey +
        (AnsiString)" ASC " +
        (AnsiString)ASC +
        (AnsiString)" ASCQ " +
        (AnsiString)ASCQ).c_str() );
  }

//the byte corresponding to spindown time is 11
return b[11];
}

//----------------------------------------------------
//Issues a mode select command to set the current
// spindown time of the current drive
//----------------------------------------------------
BYTE __fastcall TMainWindow::setCDSpindown( BYTE code )
{
SRB_ExecSCSICmd s;

memset( &s, 0, sizeof( s ) );

unsigned char b[16];
memset( &b, 0, 16 );

b[8] = 0x0D;  //I'm doing a mode select on page 0x0D
b[9] = 0x06;  //The length of this page is 0x06
b[11]= code;  //The code representing spindown time goes here
b[13]= 0x3C;  //other defaults that have nothing
b[15]= 0x4B;  // to do with the spindown time

s.SRB_Cmd      = SC_EXEC_SCSI_CMD;
s.SRB_HaId     = gbyCurrentHostAdapter;
s.SRB_Target   = gbyCurrentTarget;
s.SRB_Lun      = 0;
s.SRB_Flags    = SRB_DIR_OUT | SRB_EVENT_NOTIFY;
s.SRB_SenseLen = SENSE_LEN;
s.SRB_BufPointer = b;
s.SRB_BufLen   = 16;
s.SRB_CDBLen   = 12;
s.CDBByte[0]   = SCSI_MODESELECT;
s.CDBByte[1]   = 0x10;              //a default from the ATAPI specs
s.CDBByte[8]   = (BYTE)16;

BYTE byStatus = ExecSCSICommand(&s);

if( byStatus != SS_COMP )
  log( ((AnsiString)"setCDSpindown returned status " +
        LookupASPIStatus(byStatus) +
        (AnsiString)" with HaStat " +
        (AnsiString)s.SRB_HaStat +
        (AnsiString)" TargStat " +
        (AnsiString)s.SRB_TargStat).c_str() );

if( byStatus == SS_ERR && s.SRB_TargStat == STATUS_CHKCOND )
  {
  BYTE SenseKey = s.SenseArea[2] & (BYTE)15;
  BYTE ASC = s.SenseArea[12];
  BYTE ASCQ = s.SenseArea[13];
  log( ((AnsiString)"   Check Condition: Sense Key " +
        (AnsiString)SenseKey +
        (AnsiString)" ASC " +
        (AnsiString)ASC +
        (AnsiString)" ASCQ " +
        (AnsiString)ASCQ).c_str() );
  }

return byStatus;
}

//---------------------------------------------------------------------------
//Translates ASPI status codes into meaningful text
//---------------------------------------------------------------------------
AnsiString __fastcall TMainWindow::LookupASPIStatus( BYTE code )
{
switch( code )
  {
  case SS_ILLEGAL_MODE:
     return (AnsiString)"SS_ILLEGAL_MODE";
  case SS_NO_ASPI:
     return (AnsiString)"SS_NO_ASPI";
  case SS_MISMATCHED_COMPONENTS:
     return (AnsiString)"SS_MISMATCHED_COMPONENTS";
  case SS_INSUFFICIENT_RESOURCES:
     return (AnsiString)"SS_INSUFFICIENT_RESOURCES";
  case SS_FAILED_INIT:
     return (AnsiString)"SS_FAILED_INIT";
  case SS_NO_ADAPTERS:
     return (AnsiString)"SS_NO_ADAPTERS";
  case SS_COMP:
     return (AnsiString)"SS_COMP";
  case SS_INVALID_HA:
     return (AnsiString)"SS_INVALID_HA";
  case SS_NO_DEVICE:
     return (AnsiString)"SS_NO_DEVICE";
  case SS_ERR:
     return (AnsiString)"SS_ERR";

  default:
     char buffer[50];
     sprintf( buffer, "Unknown Status Code: 0x%X", code );
     return (AnsiString)buffer;
  }
}
//---------------------------------------------------------------------------

⌨️ 快捷键说明

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