|
SPTIとは
SPTIとは、SCSI Pass Through Interfaceの略称で、SCSIデバイスを制御する
インタフェースです。
SPTIを用いるにはDDK(Driver Development Kits)が必要ですが、現在は、
Microsoftのホームページからダウンロード出来ず、WindowsXPのDDKに限り、注文し、
取り寄せることが出来るようです。
Disc情報を取得するには
SPTIを利用し、Disc情報を取得する際には、デバイスドライバへコマンドを
送信する必要があります。
下記フローがコマンドを送信する際の基本的な手順になります。
下記図中に、"コマンドを送信"とありますが、このコマンドを変更するだけで、
多種多様な制御ができます。
|
|
コマンドとは?
まずコマンドの打ち方ですが、下記のAPIをコールすることにより、
デバイスドライバへ直接コマンド送信できます。
BOOL DeviceIoControl(
HANDLE hDevice, // デバイス、ファイル、ディレクトリいずれかのハンドル
DWORD dwIoControlCode, // 実行する動作の制御コード
LPVOID lpInBuffer, // 入力データを供給するバッファへのポインタ
DWORD nInBufferSize, // 入力バッファのバイト単位のサイズ
LPVOID lpOutBuffer, // 出力データを受け取るバッファへのポインタ
DWORD nOutBufferSize, // 出力バッファのバイト単位のサイズ
LPDWORD lpBytesReturned, // バイト数を受け取る変数へのポインタ
LPOVERLAPPED lpOverlapped // 非同期動作を表す構造体へのポインタ
);
SPTIでのコマンド指定は、以下の2パターンあります。
(1)DeviceIoControl関数の第2引数に、直接コマンドを設定する。
(2)DeviceIoControl関数の第3引数にあたる、SRB32_ExecSCSICmd構造体の
sptメンバにコマンドを設定する。
以下に、Drive・Discを制御する為の基本コマンドを列挙(私が知っている範囲で)します。
| コマンド |
(1)の場合 |
(2)の場合 |
| Drive Lock |
FSCTL_LOCK_VOLUME |
CDB[0]=0x1E CDB[4]=0x01 |
| Drive Unlock |
FSCTL_UNLOCK_VOLUME |
CDB[0]=0x1E CDB[4]=0x00 |
| Media Eject ON/OFF |
IOCTL_STORAGE_MEDIA_REMOVAL |
不明 |
| Volume Dismount |
FSCTL_DISMOUNT_VOLUME |
不明 |
| Drive Open |
IOCTL_STORAGE_EJECT_MEDIA |
CDB[0]=0x1B CDB[1]=0x01 CDB[4]=0x20 |
| Drive Close |
IOCTL_STORAGE_LOAD_MEDIA |
CDB[0]=0x1B CDB[1]=0x01 CDB[4]=0x21 |
| InquiryData取得 |
IOCTL_SCSI_GET_INQUIRY_DATA |
不明 |
| Capabilities取得 |
IOCTL_SCSI_GET_CAPABILITIES |
不明 |
| Drive情報取得 |
IOCTL_CDROM_GET_DRIVE_GEOMETRY |
不明 |
| Discタイプ取得 |
IOCTL_CDROM_DISK_TYPE |
CDB[0]=0x46 CDB[8]=8 |
| Disc情報取得 |
不明 |
CDB[0]=0x51 CDB[7]=Disc情報サイズ |
| TOC情報取得 |
IOCTL_CDROM_READ_TOC |
CDB[0]=0x43 CDB[1]=0x02 CDB[2]=0x02 CDB[7]=session no. CDB[8]=取得サイズ(byte) |
| Qサブコード取得 |
IOCTL_CDROM_READ_Q_CHANNEL |
CDB[0]=0xBE CDB[2]-[5]=LBA CDB[6]-[7]=取得セクタサイズ CDB[10]=2 |
| データ取得 |
IOCTL_CDROM_RAW_READ |
CDB[0]=0xBE CDB[2]-[5]=LBA CDB[6]-[7]=取得セクタサイズ CDB[9]=0xF8 |
ディスク情報取得手順
Disc情報を取得するには、以下の順番にコマンドを発行します。
- ドライブハンドルを取得する。
- ディスクタイプを取得する。
- ドライブをBlock(Prevent allow)する。
- セッション・トラック情報を取得する。
- ディスクに合わせて、最終LBAを確認する。
- 最終LBAまでリードする。
- ドライブをUnblock(Prevent allow)する。
- ドライブハンドルをクローズする。
ドライブハンドル取得
ドライブハンドルの取得は、CreateFile関数にて行います。
どうやってドライブハンドルを取得するの?と思う方もいらっしゃると思いますが、
答えは簡単です。
以下のように引数していすればハンドル取得できます。
ファイル名 :"\\\\.\\ドライブレター:"
アクセスモード :GENERIC_WRITE|GENERIC_READ
共有モード :FILE_SHARE_WRITE
セキュリティ記述子 :NULL
作成方法 :OPEN_EXISTING
ファイル属性 :0
テンプレートファイルのハンドル:NULL
ディスクタイプ取得
ディスクタイプの取得は、上記コマンドのDiscタイプ取得コマンドを利用します。
ディスクタイプは、CD-ROM・CD-R・DVD-ROM・DVD-R・DVD-RAM・DVR-RW(フォーマット済み)・
DVR-RW(シーケンシャル記録)・DVD+R・DVD+RWが取れます。
DVD系は、最終セッションの最終LBAまで取得するだけで、全ディスク情報を取れます。
DVD-RAMに関しては、最終LBAが読めない場合があるので、読めるLBAまで遡る必要が
あるかもしれません。
CD系のCD-ROMの場合は、TOC情報から総再生時間を取得し、この時間から最終LBAを取得すれば、
全ディスク情報を取れます。
それ以外のCDは、TOC情報から取れる総再生時間から最終LBAを算出すると、ファースト・
セッションしか取得出来ないので、気を付けて下さい。
ドライブをBlock
ドライブのBlockは、上記コマンドDrive lockで行います。
特記するほどのことはない、簡単な手順ですが、重要です。
セッション・トラック情報取得
DVD系の場合は、必須手順です。上記のDisc情報取得コマンドで取得出来ます。
CD系の場合は、TOC情報を取得(付録参照)し、最終LBAを求めます。最終LBAは、
TOC情報の内、
POINT=0xA2のMIN・SEC・FRAMEをLBAに変換すれば取得出来ます。
最終LBA確認
私もはっきりとしたところは分からないのですが、データCDや、DVD-RAMの場合、
上記手順で取得した最終LBAはリード出来ず、もう少し遡ったLBAまでリード出来ない
ことがあり、最終LBAのリードテストを行い、調整します。
本当は、微調整する為の正式手順があるかも知れません。もし、ご存知の方が
いらっしゃったら、教えてください!!
データをリード
データのリードは、ファイルのリードとは違い、トラック毎のモードに合わせて
コマンドを送信する必要があります。モードは、以下は通りです。
・AUDIO :オーディオ
・CDG :カラオケCD+G
・MODE1/2048:CDROM Mode1 DATA
・MODE1/2352:CDROM Mode1 DATA(RAW)
・MODE2/2336:CDROM Mode2 DATA
・MODE2/2352:CDROM Mode2 DATA(RAW)
・CDI/2336 :CDI Mode2 DATA
・CDI/2352 :CDI Mode2 DATA(RAW)
上記のモード毎のコマンドでリードして下さい。
(コマンドは分かり次第、コマンド表に記載予定です。)
ドライブをUnblock
ドライブのUnblockは、上記コマンドDrive unlockで行います。
特記するほどのことはない、簡単な手順ですが、これまた重要です。
ハンドルをクローズする
最後は、オープンしたハンドルを、CloseHandleでクローズします。
このへんは、ファイルI/Oと同じですね。
※現在、CD-DA情報の取得方法について調査中です。調査結果は、随時上げる
つもりですので、暫くお待ち下さい。
(その伏線として、付録だけ先にアップしておきます)
<付録>
CDROMのデータ構造
CDROMのデータの最小単位はフレームで、このフレームを98ブロック集めたものを、
サブコーディング・フレームといいます。
これは、Qサブチャネルが98ビットで意味を持つ為です。
CDROMのデータ構造では、このQサブチャネルのデータと、TOC(Table of Contents)の
情報が非常に重要です。
TOC情報の構造
| | | | | | | | |
TNO
8 |
POINT
8 |
MIN
8 |
SEC
8 |
FRAME
8 |
ZERO
8 |
PMIN
8 |
PSEC
8 |
PFRAME
8 |
TOC情報は、上記のようになっています。左から順に、
・TNO :トラック番号
・POINT:0〜99:PMIN, PSEC, PFRAME は、各トラックの開始する絶対時間を示す。
A0H :PMIN は、最初のトラックのトラック番号を示す。PSEC、PFRAMEは0。
A1H :PMIN は、最終トラックのトラック番号を示す。PSEC、PFRAMEは0。
A2H :PMIN, PSEC, PFRAME は、リードアウトの始まる絶対時間を示す。
・MIN :トラック先頭からの相対時間(分)を示す。
・SEC :トラック先頭からの相対時間(秒)を示す。
・FRAME:トラック先頭からの相対時間(フレーム)を示す。
・ZERO :0。
Qサブコードの構造
| | | | | | | | |
TNO
8 |
INDEX
8 |
MIN
8 |
SEC
8 |
FRAME
8 |
ZERO
8 |
PMIN
8 |
PSEC
8 |
PFRAME
8 |
Qサブコードは、上記のようになっています。左から順に、
・TNO :トラック番号
・INDEX :無音部分:0。
・MIN :トラック先頭からの相対時間(分)を示す。
・SEC :トラック先頭からの相対時間(秒)を示す。
・FRAME :トラック先頭からの相対時間(フレーム)を示す。
・ZERO :0。
・PMIN :Disc先頭からの絶対時間(分)を示す。
・PSEC :Disc先頭からの絶対時間(秒)を示す。
・PFRAME:Disc先頭からの絶対時間(フレーム)を示す。
<質問・要望など>
上記内容に対しての質問、要望などは常に受け付けております。
以下のメールフォームか、掲示板へ書き込みをお願いします。
メール送信フォーム
掲示板
|