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

📄 main.cpp

📁 使用ASPI控制CDROM旋转速度的程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*
CD-ROM Tool - Allows you to set the read speed and spindown time
 time of a CD-ROM drive.
Copyright (C) 1999-2000 Jesse Carroll

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/


//---------------------------------------------------------------------------
#include <vcl.h>
#include "registry.hpp"
#include "main.h"
#include "aboutcode.h"
#include "splashcode.h"
#include <stdio.h>
#pragma hdrstop

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

//-----defines for SCSI commands------------------
#define SCSI_SETSPEED   0xBB
#define SCSI_INQUIRY    0x12
#define SCSI_MODESENSE  0x5A
#define SCSI_MODESELECT 0x55

//-----SCSI device type define------------------
#define DTYPE_CDROM     0x05

#define STATUS_CHKCOND 0x02

//according to the ASPI docs, a host adapter can support up to 16 targets
#define MAX_SCSI_TARGETS 16

//transfer rate in kilobytes of the 1x CD-ROM read speed
#define X1   176

//Causes debug info to be written to c:\\cdromtool.txt if set to true
//In the Main Window's OnCreate event, this is set to true if the
// command line was "-debug" or shift is held when the program is run.
// It is otherwise set to false.
bool LOG;

//the handle for the ASPI32 DLL
HMODULE ASPIDLL;

//used to store the proc addresses of the ASPI DLL functions
DWORD           (*gpfnGetASPI32SupportInfo)( VOID );
DWORD           (*gpfnSendASPI32Command)( LPSRB );

//variable to make the command line globally available
extern AnsiString CommandLineGlobal;

TMainWindow *MainWindow;
//---------------------------------------------------------------------------
__fastcall TMainWindow::TMainWindow(TComponent* Owner)
  : TForm(Owner)
{
}

//-------------------------------------------------------
//simple function that checks to see if a key is pressed
//-------------------------------------------------------
inline bool isKeyDown( int keycode )
  {
  if( (GetAsyncKeyState(keycode) & 0x8000) == 0x8000 )
    return TRUE;
  else
    return FALSE;
  }

//----------------------------------------------------
//simple function that appends text to a log file
//----------------------------------------------------
inline void log(char *string)
  {
  if( LOG )
    {
    FILE *fp=fopen("c:\\cdromtool.txt", "a+");
    fprintf( fp, "%s\n", string);
    fclose( fp );
    }
  }

//----------------------------------------------------------------------------
//Used for debugging, this dumps the entire mode pages 2A & 0D to the log file
//----------------------------------------------------------------------------
void __fastcall TMainWindow::ModeSenseDump()
{
if( LOG )
  {
  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;
  s.CDBByte[7]   = 0x01;
  s.CDBByte[8]   = 0x00;

  ExecSCSICommand(&s);

  log( "Mode Page 2A Dump" );
  FILE *fp=fopen("c:\\cdromtool.txt", "a+");
  for( int i = 0; i < 256; i++ )
    fprintf( fp, "%c", b[i]);
  fclose( fp );

  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;
  s.CDBByte[7]   = 0x01;
  s.CDBByte[8]   = 0x00;

  ExecSCSICommand(&s);

  log( "Mode Page 0D Dump" );
  fp=fopen("c:\\cdromtool.txt", "a+");
  for( int i = 0; i < 256; i++ )
    fprintf( fp, "%c", b[i]);
  fclose( fp );
  }
}

//---------------------------------------------------------------------------
//Executes SCSI Command specified in the structure "s"
//Returns the final SRB (SCSI request block) status
//---------------------------------------------------------------------------
BYTE __fastcall TMainWindow::ExecSCSICommand( SRB_ExecSCSICmd* s )
{
//use the event method for determining completion
HANDLE heventSRB = CreateEvent( NULL, TRUE, FALSE, NULL );
ResetEvent( heventSRB );
s->SRB_PostProc = (LPVOID)heventSRB;

//issue the command
DWORD dwStatus = gpfnSendASPI32Command( s );

//sendASPI32Command is asynchronous, so if the operation
// is still pending, wait for it to return
if ( dwStatus == SS_PENDING )
  WaitForSingleObject( heventSRB, INFINITE );

CloseHandle( heventSRB );

//return the final SRB status
return s->SRB_Status;
}

//---------------------------------------------------------
//Gets the name of the drive
//Returns the final SRB (SCSI request block) status
//---------------------------------------------------------
BYTE __fastcall TMainWindow::getDriveName( BYTE hostadapter, BYTE target, char* stringbuffer )
{
SRB_ExecSCSICmd s;
BYTE buf[100];

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

s.SRB_Cmd        = SC_EXEC_SCSI_CMD;
s.SRB_HaId       = hostadapter;
s.SRB_Target     = target;
s.SRB_Lun        = 0;
s.SRB_Flags      = SRB_DIR_IN | SRB_EVENT_NOTIFY;
s.SRB_BufLen     = 100;
s.SRB_BufPointer = buf;
s.SRB_SenseLen   = SENSE_LEN;
s.SRB_CDBLen     = 6;
s.CDBByte[0]     = SCSI_INQUIRY;
s.CDBByte[4]     = 100;

BYTE byStatus = ExecSCSICommand(&s);

if( byStatus != SS_COMP )
  log( ((AnsiString)"getDriveName 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() );
  }

//if the command was successful
if( byStatus == SS_COMP )
  {
  //extract the whole string identifying the drive
  for( int i = 8; i < 36; i++ )
    stringbuffer[i-8] = buf[i];

  //the part I wish to extract is 28 characters long
  stringbuffer[28] = NULL;
  }

return byStatus;
}

//---------------------------------------------------------------------------
//CD Speed Commands
//---------------------------------------------------------------------------
BYTE __fastcall TMainWindow::setCDSpeed( DWORD speed )
{
//if the requested speed is less than 1x speed (176 kb/s),
// this command *will* return an error (it's part of the
// ATAPI specs).  Therefore, stop this function here if
// speed < 1x (176)
if( speed < X1 ) return 0;

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

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_CDBLen   = 12;
s.CDBByte[0]   = SCSI_SETSPEED;

//bytes 2 & 3 represent the desired read speed
s.CDBByte[2]   = (BYTE)(speed >> 8);
s.CDBByte[3]   = (BYTE)speed;

//bytes 4 & 5 represent the desired write speed
//THIS CAUSED ME A LOT OF GRIEF - it seems that with
// some drives, YOU MUST set the write speed to a
// non-zero value, or this call will return with
// an error. This applies even if you don't want to
// change the write speed! For instance, I could get
// away with not setting these bytes when sending
// this command to my old 4x drive, but I *had* to
// put *something* in here when sending the command
// to my Creative CDRW
s.CDBByte[4]   = (BYTE)(706 >> 8);
s.CDBByte[5]   = (BYTE)706;

BYTE byStatus = ExecSCSICommand(&s);

if( byStatus != SS_COMP )
  log( ((AnsiString)"setCDSpeed returned status " +
        LookupASPIStatus(byStatus) +
        (AnsiString)" with HaStat " +
        (AnsiString)s.SRB_HaStat +
        (AnsiString)" TargStat " +
        (AnsiString)s.SRB_TargStat +
        (AnsiString)" attempting " +
        (AnsiString)(unsigned int)speed +
        (AnsiString)" kb/s").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;
}

int __fastcall TMainWindow::getCDSpeed()
{
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 speed
s.CDBByte[7]   = 0x01;
s.CDBByte[8]   = 0x00;

BYTE byStatus = ExecSCSICommand(&s);

if( byStatus != SS_COMP )
  log( ((AnsiString)"getCDSpeed 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 " +

⌨️ 快捷键说明

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