mirror of
https://github.com/akuker/RASCSI.git
synced 2024-06-13 23:29:30 +00:00
9714 lines
201 KiB
C++
9714 lines
201 KiB
C++
//---------------------------------------------------------------------------
|
||
//
|
||
// X68000 EMULATOR "XM6"
|
||
//
|
||
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
||
// Copyright (C) 2014-2020 GIMONS
|
||
//
|
||
// XM6i
|
||
// Copyright (C) 2010-2015 isaki@NetBSD.org
|
||
// Copyright (C) 2010 Y.Sugahara
|
||
//
|
||
// Imported sava's Anex86/T98Next image and MO format support patch.
|
||
// Imported NetBSD support and some optimisation patch by Rin Okuyama.
|
||
//
|
||
// [ ディスク ]
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
|
||
#include "os.h"
|
||
#include "xm6.h"
|
||
#include "filepath.h"
|
||
#include "fileio.h"
|
||
#ifdef RASCSI
|
||
#include "gpiobus.h"
|
||
#ifndef BAREMETAL
|
||
#include "ctapdriver.h"
|
||
#endif // BAREMETAL
|
||
#include "cfilesystem.h"
|
||
#include "disk.h"
|
||
#else
|
||
#include "vm.h"
|
||
#include "disk.h"
|
||
#include "windrv.h"
|
||
#include "ctapdriver.h"
|
||
#include "mfc_com.h"
|
||
#include "mfc_host.h"
|
||
#endif // RASCSI
|
||
|
||
//===========================================================================
|
||
//
|
||
// ディスク
|
||
//
|
||
//===========================================================================
|
||
//#define DISK_LOG
|
||
|
||
#ifdef RASCSI
|
||
#define BENDER_SIGNATURE "RaSCSI"
|
||
#else
|
||
#define BENDER_SIGNATURE "XM6"
|
||
#endif
|
||
|
||
//===========================================================================
|
||
//
|
||
// ディスクトラック
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
DiskTrack::DiskTrack()
|
||
{
|
||
// 内部情報の初期化
|
||
dt.track = 0;
|
||
dt.size = 0;
|
||
dt.sectors = 0;
|
||
dt.raw = FALSE;
|
||
dt.init = FALSE;
|
||
dt.changed = FALSE;
|
||
dt.length = 0;
|
||
dt.buffer = NULL;
|
||
dt.maplen = 0;
|
||
dt.changemap = NULL;
|
||
dt.imgoffset = 0;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// デストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
DiskTrack::~DiskTrack()
|
||
{
|
||
// メモリ解放は行うが、自動セーブはしない
|
||
if (dt.buffer) {
|
||
free(dt.buffer);
|
||
dt.buffer = NULL;
|
||
}
|
||
if (dt.changemap) {
|
||
free(dt.changemap);
|
||
dt.changemap = NULL;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 初期化
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL DiskTrack::Init(
|
||
int track, int size, int sectors, BOOL raw, off64_t imgoff)
|
||
{
|
||
ASSERT(track >= 0);
|
||
ASSERT((size >= 8) && (size <= 11));
|
||
ASSERT((sectors > 0) && (sectors <= 0x100));
|
||
ASSERT(imgoff >= 0);
|
||
|
||
// パラメータを設定
|
||
dt.track = track;
|
||
dt.size = size;
|
||
dt.sectors = sectors;
|
||
dt.raw = raw;
|
||
|
||
// 初期化されていない(ロードする必要あり)
|
||
dt.init = FALSE;
|
||
|
||
// 変更されていない
|
||
dt.changed = FALSE;
|
||
|
||
// 実データまでのオフセット
|
||
dt.imgoffset = imgoff;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ロード
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL DiskTrack::Load(const Filepath& path)
|
||
{
|
||
Fileio fio;
|
||
off64_t offset;
|
||
int i;
|
||
int length;
|
||
|
||
ASSERT(this);
|
||
|
||
// 既にロードされていれば不要
|
||
if (dt.init) {
|
||
ASSERT(dt.buffer);
|
||
ASSERT(dt.changemap);
|
||
return TRUE;
|
||
}
|
||
|
||
// オフセットを計算(これ以前のトラックは256セクタ保持とみなす)
|
||
offset = ((off64_t)dt.track << 8);
|
||
if (dt.raw) {
|
||
ASSERT(dt.size == 11);
|
||
offset *= 0x930;
|
||
offset += 0x10;
|
||
} else {
|
||
offset <<= dt.size;
|
||
}
|
||
|
||
// 実イメージまでのオフセットを追加
|
||
offset += dt.imgoffset;
|
||
|
||
// レングスを計算(このトラックのデータサイズ)
|
||
length = dt.sectors << dt.size;
|
||
|
||
// バッファのメモリを確保
|
||
ASSERT((dt.size >= 8) && (dt.size <= 11));
|
||
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||
|
||
if (dt.buffer == NULL) {
|
||
#if defined(RASCSI) && !defined(BAREMETAL)
|
||
posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512);
|
||
#else
|
||
dt.buffer = (BYTE *)malloc(length * sizeof(BYTE));
|
||
#endif // RASCSI && !BAREMETAL
|
||
dt.length = length;
|
||
}
|
||
|
||
if (!dt.buffer) {
|
||
return FALSE;
|
||
}
|
||
|
||
// バッファ長が異なるなら再確保
|
||
if (dt.length != (DWORD)length) {
|
||
free(dt.buffer);
|
||
#if defined(RASCSI) && !defined(BAREMETAL)
|
||
posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512);
|
||
#else
|
||
dt.buffer = (BYTE *)malloc(length * sizeof(BYTE));
|
||
#endif // RASCSI && !BAREMETAL
|
||
dt.length = length;
|
||
}
|
||
|
||
// 変更マップのメモリを確保
|
||
if (dt.changemap == NULL) {
|
||
dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL));
|
||
dt.maplen = dt.sectors;
|
||
}
|
||
|
||
if (!dt.changemap) {
|
||
return FALSE;
|
||
}
|
||
|
||
// バッファ長が異なるなら再確保
|
||
if (dt.maplen != (DWORD)dt.sectors) {
|
||
free(dt.changemap);
|
||
dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL));
|
||
dt.maplen = dt.sectors;
|
||
}
|
||
|
||
// 変更マップクリア
|
||
memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL));
|
||
|
||
// ファイルから読み込む
|
||
#if defined(RASCSI) && !defined(BAREMETAL)
|
||
if (!fio.OpenDIO(path, Fileio::ReadOnly)) {
|
||
#else
|
||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||
#endif // RASCSI && !BAREMETAL
|
||
return FALSE;
|
||
}
|
||
if (dt.raw) {
|
||
// 分割読み
|
||
for (i = 0; i < dt.sectors; i++) {
|
||
// シーク
|
||
if (!fio.Seek(offset)) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
|
||
// 読み込み
|
||
if (!fio.Read(&dt.buffer[i << dt.size], 1 << dt.size)) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
|
||
// 次のオフセット
|
||
offset += 0x930;
|
||
}
|
||
} else {
|
||
// 連続読み
|
||
if (!fio.Seek(offset)) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
if (!fio.Read(dt.buffer, length)) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
}
|
||
fio.Close();
|
||
|
||
// フラグを立て、正常終了
|
||
dt.init = TRUE;
|
||
dt.changed = FALSE;
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// セーブ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL DiskTrack::Save(const Filepath& path)
|
||
{
|
||
off64_t offset;
|
||
int i;
|
||
int j;
|
||
Fileio fio;
|
||
int length;
|
||
int total;
|
||
|
||
ASSERT(this);
|
||
|
||
// 初期化されていなければ不要
|
||
if (!dt.init) {
|
||
return TRUE;
|
||
}
|
||
|
||
// 変更されていなければ不要
|
||
if (!dt.changed) {
|
||
return TRUE;
|
||
}
|
||
|
||
// 書き込む必要がある
|
||
ASSERT(dt.buffer);
|
||
ASSERT(dt.changemap);
|
||
ASSERT((dt.size >= 8) && (dt.size <= 11));
|
||
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||
|
||
// RAWモードでは書き込みはありえない
|
||
ASSERT(!dt.raw);
|
||
|
||
// オフセットを計算(これ以前のトラックは256セクタ保持とみなす)
|
||
offset = ((off64_t)dt.track << 8);
|
||
offset <<= dt.size;
|
||
|
||
// 実イメージまでのオフセットを追加
|
||
offset += dt.imgoffset;
|
||
|
||
// セクタあたりのレングスを計算
|
||
length = 1 << dt.size;
|
||
|
||
// ファイルオープン
|
||
if (!fio.Open(path, Fileio::ReadWrite)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 部分書き込みループ
|
||
for (i = 0; i < dt.sectors;) {
|
||
// 変更されていれば
|
||
if (dt.changemap[i]) {
|
||
// 書き込みサイズ初期化
|
||
total = 0;
|
||
|
||
// シーク
|
||
if (!fio.Seek(offset + ((off64_t)i << dt.size))) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
|
||
// 連続するセクタ長
|
||
for (j = i; j < dt.sectors; j++) {
|
||
// 途切れたら終了
|
||
if (!dt.changemap[j]) {
|
||
break;
|
||
}
|
||
|
||
// 1セクタ分加算
|
||
total += length;
|
||
}
|
||
|
||
// 書き込み
|
||
if (!fio.Write(&dt.buffer[i << dt.size], total)) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
|
||
// 未変更のセクタへ
|
||
i = j;
|
||
} else {
|
||
// 次のセクタ
|
||
i++;
|
||
}
|
||
}
|
||
|
||
// クローズ
|
||
fio.Close();
|
||
|
||
// 変更フラグを落とし、終了
|
||
memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL));
|
||
dt.changed = FALSE;
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// リードセクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL DiskTrack::Read(BYTE *buf, int sec) const
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
ASSERT((sec >= 0) & (sec < 0x100));
|
||
|
||
// 初期化されていなければエラー
|
||
if (!dt.init) {
|
||
return FALSE;
|
||
}
|
||
|
||
// セクタが有効数を超えていればエラー
|
||
if (sec >= dt.sectors) {
|
||
return FALSE;
|
||
}
|
||
|
||
// コピー
|
||
ASSERT(dt.buffer);
|
||
ASSERT((dt.size >= 8) && (dt.size <= 11));
|
||
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||
memcpy(buf, &dt.buffer[(off64_t)sec << dt.size], (off64_t)1 << dt.size);
|
||
|
||
// 成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ライトセクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL DiskTrack::Write(const BYTE *buf, int sec)
|
||
{
|
||
int offset;
|
||
int length;
|
||
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
ASSERT((sec >= 0) & (sec < 0x100));
|
||
ASSERT(!dt.raw);
|
||
|
||
// 初期化されていなければエラー
|
||
if (!dt.init) {
|
||
return FALSE;
|
||
}
|
||
|
||
// セクタが有効数を超えていればエラー
|
||
if (sec >= dt.sectors) {
|
||
return FALSE;
|
||
}
|
||
|
||
// オフセット、レングスを計算
|
||
offset = sec << dt.size;
|
||
length = 1 << dt.size;
|
||
|
||
// 比較
|
||
ASSERT(dt.buffer);
|
||
ASSERT((dt.size >= 8) && (dt.size <= 11));
|
||
ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100));
|
||
if (memcmp(buf, &dt.buffer[offset], length) == 0) {
|
||
// 同じものを書き込もうとしているので、正常終了
|
||
return TRUE;
|
||
}
|
||
|
||
// コピー、変更あり
|
||
memcpy(&dt.buffer[offset], buf, length);
|
||
dt.changemap[sec] = TRUE;
|
||
dt.changed = TRUE;
|
||
|
||
// 成功
|
||
return TRUE;
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// ディスクキャッシュ
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
DiskCache::DiskCache(
|
||
const Filepath& path, int size, int blocks, off64_t imgoff)
|
||
{
|
||
int i;
|
||
|
||
ASSERT((size >= 8) && (size <= 11));
|
||
ASSERT(blocks > 0);
|
||
ASSERT(imgoff >= 0);
|
||
|
||
// キャッシュワーク
|
||
for (i = 0; i < CacheMax; i++) {
|
||
cache[i].disktrk = NULL;
|
||
cache[i].serial = 0;
|
||
}
|
||
|
||
// その他
|
||
serial = 0;
|
||
sec_path = path;
|
||
sec_size = size;
|
||
sec_blocks = blocks;
|
||
cd_raw = FALSE;
|
||
imgoffset = imgoff;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// デストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
DiskCache::~DiskCache()
|
||
{
|
||
// トラックをクリア
|
||
Clear();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// RAWモード設定
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL DiskCache::SetRawMode(BOOL raw)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(sec_size == 11);
|
||
|
||
// 設定
|
||
cd_raw = raw;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// セーブ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL DiskCache::Save()
|
||
{
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
|
||
// トラックを保存
|
||
for (i = 0; i < CacheMax; i++) {
|
||
// 有効なトラックか
|
||
if (cache[i].disktrk) {
|
||
// 保存
|
||
if (!cache[i].disktrk->Save(sec_path)) {
|
||
return FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ディスクキャッシュ情報取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL DiskCache::GetCache(int index, int& track, DWORD& aserial) const
|
||
{
|
||
ASSERT(this);
|
||
ASSERT((index >= 0) && (index < CacheMax));
|
||
|
||
// 未使用ならFALSE
|
||
if (!cache[index].disktrk) {
|
||
return FALSE;
|
||
}
|
||
|
||
// トラックとシリアルを設定
|
||
track = cache[index].disktrk->GetTrack();
|
||
aserial = cache[index].serial;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// クリア
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL DiskCache::Clear()
|
||
{
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
|
||
// キャッシュワークを解放
|
||
for (i = 0; i < CacheMax; i++) {
|
||
if (cache[i].disktrk) {
|
||
delete cache[i].disktrk;
|
||
cache[i].disktrk = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// セクタリード
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL DiskCache::Read(BYTE *buf, int block)
|
||
{
|
||
int track;
|
||
DiskTrack *disktrk;
|
||
|
||
ASSERT(this);
|
||
ASSERT(sec_size != 0);
|
||
|
||
// 先に更新
|
||
Update();
|
||
|
||
// トラックを算出(256セクタ/トラックに固定)
|
||
track = block >> 8;
|
||
|
||
// そのトラックデータを得る
|
||
disktrk = Assign(track);
|
||
if (!disktrk) {
|
||
return FALSE;
|
||
}
|
||
|
||
// トラックに任せる
|
||
return disktrk->Read(buf, (BYTE)block);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// セクタライト
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL DiskCache::Write(const BYTE *buf, int block)
|
||
{
|
||
int track;
|
||
DiskTrack *disktrk;
|
||
|
||
ASSERT(this);
|
||
ASSERT(sec_size != 0);
|
||
|
||
// 先に更新
|
||
Update();
|
||
|
||
// トラックを算出(256セクタ/トラックに固定)
|
||
track = block >> 8;
|
||
|
||
// そのトラックデータを得る
|
||
disktrk = Assign(track);
|
||
if (!disktrk) {
|
||
return FALSE;
|
||
}
|
||
|
||
// トラックに任せる
|
||
return disktrk->Write(buf, (BYTE)block);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// トラックの割り当て
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
DiskTrack* FASTCALL DiskCache::Assign(int track)
|
||
{
|
||
int i;
|
||
int c;
|
||
DWORD s;
|
||
DiskTrack *disktrk;
|
||
|
||
ASSERT(this);
|
||
ASSERT(sec_size != 0);
|
||
ASSERT(track >= 0);
|
||
|
||
// まず、既に割り当てされていないか調べる
|
||
for (i = 0; i < CacheMax; i++) {
|
||
if (cache[i].disktrk) {
|
||
if (cache[i].disktrk->GetTrack() == track) {
|
||
// トラックが一致
|
||
cache[i].serial = serial;
|
||
return cache[i].disktrk;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 次に、空いているものがないか調べる
|
||
for (i = 0; i < CacheMax; i++) {
|
||
if (!cache[i].disktrk) {
|
||
// ロードを試みる
|
||
if (Load(i, track)) {
|
||
// ロード成功
|
||
cache[i].serial = serial;
|
||
return cache[i].disktrk;
|
||
}
|
||
|
||
// ロード失敗
|
||
return NULL;
|
||
}
|
||
}
|
||
|
||
// 最後に、シリアル番号の一番若いものを探し、削除する
|
||
|
||
// インデックス0を候補cとする
|
||
s = cache[0].serial;
|
||
c = 0;
|
||
|
||
// 候補とシリアルを比較し、より小さいものへ更新する
|
||
for (i = 0; i < CacheMax; i++) {
|
||
ASSERT(cache[i].disktrk);
|
||
|
||
// 既に存在するシリアルと比較、更新
|
||
if (cache[i].serial < s) {
|
||
s = cache[i].serial;
|
||
c = i;
|
||
}
|
||
}
|
||
|
||
// このトラックを保存
|
||
if (!cache[c].disktrk->Save(sec_path)) {
|
||
return NULL;
|
||
}
|
||
|
||
// このトラックを削除
|
||
disktrk = cache[c].disktrk;
|
||
cache[c].disktrk = NULL;
|
||
|
||
// ロード
|
||
if (Load(c, track, disktrk)) {
|
||
// ロード成功
|
||
cache[c].serial = serial;
|
||
return cache[c].disktrk;
|
||
}
|
||
|
||
// ロード失敗
|
||
return NULL;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// トラックのロード
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL DiskCache::Load(int index, int track, DiskTrack *disktrk)
|
||
{
|
||
int sectors;
|
||
|
||
ASSERT(this);
|
||
ASSERT((index >= 0) && (index < CacheMax));
|
||
ASSERT(track >= 0);
|
||
ASSERT(!cache[index].disktrk);
|
||
|
||
// このトラックのセクタ数を取得
|
||
sectors = sec_blocks - (track << 8);
|
||
ASSERT(sectors > 0);
|
||
if (sectors > 0x100) {
|
||
sectors = 0x100;
|
||
}
|
||
|
||
// ディスクトラックを作成
|
||
if (disktrk == NULL) {
|
||
disktrk = new DiskTrack();
|
||
}
|
||
|
||
// ディスクトラックを初期化
|
||
disktrk->Init(track, sec_size, sectors, cd_raw, imgoffset);
|
||
|
||
// ロードを試みる
|
||
if (!disktrk->Load(sec_path)) {
|
||
// 失敗
|
||
delete disktrk;
|
||
return FALSE;
|
||
}
|
||
|
||
// 割り当て成功、ワークを設定
|
||
cache[index].disktrk = disktrk;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// シリアル番号の更新
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL DiskCache::Update()
|
||
{
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
|
||
// 更新して、0以外は何もしない
|
||
serial++;
|
||
if (serial != 0) {
|
||
return;
|
||
}
|
||
|
||
// 全キャッシュのシリアルをクリア(32bitループしている)
|
||
for (i = 0; i < CacheMax; i++) {
|
||
cache[i].serial = 0;
|
||
}
|
||
}
|
||
|
||
|
||
//===========================================================================
|
||
//
|
||
// ディスク
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
Disk::Disk()
|
||
{
|
||
// ワーク初期化
|
||
disk.id = MAKEID('N', 'U', 'L', 'L');
|
||
disk.ready = FALSE;
|
||
disk.writep = FALSE;
|
||
disk.readonly = FALSE;
|
||
disk.removable = FALSE;
|
||
disk.lock = FALSE;
|
||
disk.attn = FALSE;
|
||
disk.reset = FALSE;
|
||
disk.size = 0;
|
||
disk.blocks = 0;
|
||
disk.lun = 0;
|
||
disk.code = 0;
|
||
disk.dcache = NULL;
|
||
disk.imgoffset = 0;
|
||
|
||
// その他
|
||
cache_wb = TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// デストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
Disk::~Disk()
|
||
{
|
||
// ディスクキャッシュの保存
|
||
if (disk.ready) {
|
||
// レディの場合のみ
|
||
if (disk.dcache) {
|
||
disk.dcache->Save();
|
||
}
|
||
}
|
||
|
||
// ディスクキャッシュの削除
|
||
if (disk.dcache) {
|
||
delete disk.dcache;
|
||
disk.dcache = NULL;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// リセット
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL Disk::Reset()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// ロックなし、アテンションなし、リセットあり
|
||
disk.lock = FALSE;
|
||
disk.attn = FALSE;
|
||
disk.reset = TRUE;
|
||
}
|
||
|
||
#ifndef RASCSI
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// セーブ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Save(Fileio *fio, int ver)
|
||
{
|
||
DWORD sz;
|
||
DWORD padding;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fio);
|
||
|
||
// サイズをセーブ
|
||
sz = 52;
|
||
if (!fio->Write(&sz, sizeof(sz))) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 実体をセーブ
|
||
PROP_EXPORT(fio, disk.id);
|
||
PROP_EXPORT(fio, disk.ready);
|
||
PROP_EXPORT(fio, disk.writep);
|
||
PROP_EXPORT(fio, disk.readonly);
|
||
PROP_EXPORT(fio, disk.removable);
|
||
PROP_EXPORT(fio, disk.lock);
|
||
PROP_EXPORT(fio, disk.attn);
|
||
PROP_EXPORT(fio, disk.reset);
|
||
PROP_EXPORT(fio, disk.size);
|
||
PROP_EXPORT(fio, disk.blocks);
|
||
PROP_EXPORT(fio, disk.lun);
|
||
PROP_EXPORT(fio, disk.code);
|
||
PROP_EXPORT(fio, padding);
|
||
|
||
// パスをセーブ
|
||
if (!diskpath.Save(fio, ver)) {
|
||
return FALSE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ロード
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Load(Fileio *fio, int ver)
|
||
{
|
||
DWORD sz;
|
||
disk_t buf;
|
||
DWORD padding;
|
||
Filepath path;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fio);
|
||
|
||
// version2.03より前は、ディスクはセーブしていない
|
||
if (ver <= 0x0202) {
|
||
return TRUE;
|
||
}
|
||
|
||
// 現在のディスクキャッシュを削除
|
||
if (disk.dcache) {
|
||
disk.dcache->Save();
|
||
delete disk.dcache;
|
||
disk.dcache = NULL;
|
||
}
|
||
|
||
// サイズをロード、照合
|
||
if (!fio->Read(&sz, sizeof(sz))) {
|
||
return FALSE;
|
||
}
|
||
if (sz != 52) {
|
||
return FALSE;
|
||
}
|
||
|
||
// バッファへロード
|
||
PROP_IMPORT(fio, buf.id);
|
||
PROP_IMPORT(fio, buf.ready);
|
||
PROP_IMPORT(fio, buf.writep);
|
||
PROP_IMPORT(fio, buf.readonly);
|
||
PROP_IMPORT(fio, buf.removable);
|
||
PROP_IMPORT(fio, buf.lock);
|
||
PROP_IMPORT(fio, buf.attn);
|
||
PROP_IMPORT(fio, buf.reset);
|
||
PROP_IMPORT(fio, buf.size);
|
||
PROP_IMPORT(fio, buf.blocks);
|
||
PROP_IMPORT(fio, buf.lun);
|
||
PROP_IMPORT(fio, buf.code);
|
||
PROP_IMPORT(fio, padding);
|
||
|
||
// パスをロード
|
||
if (!path.Load(fio, ver)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// IDが一致した場合のみ、移動
|
||
if (disk.id == buf.id) {
|
||
// NULLなら何もしない
|
||
if (IsNULL()) {
|
||
return TRUE;
|
||
}
|
||
|
||
// セーブした時と同じ種類のデバイス
|
||
disk.ready = FALSE;
|
||
if (Open(path)) {
|
||
// Open内でディスクキャッシュは作成されている
|
||
// プロパティのみ移動
|
||
if (!disk.readonly) {
|
||
disk.writep = buf.writep;
|
||
}
|
||
disk.lock = buf.lock;
|
||
disk.attn = buf.attn;
|
||
disk.reset = buf.reset;
|
||
disk.lun = buf.lun;
|
||
disk.code = buf.code;
|
||
|
||
// 正常にロードできた
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
// ディスクキャッシュ再作成
|
||
if (!IsReady()) {
|
||
disk.dcache = NULL;
|
||
} else {
|
||
disk.dcache = new DiskCache(diskpath, disk.size, disk.blocks);
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
#endif // RASCSI
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// NULLチェック
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::IsNULL() const
|
||
{
|
||
ASSERT(this);
|
||
|
||
if (disk.id == MAKEID('N', 'U', 'L', 'L')) {
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// SASIチェック
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::IsSASI() const
|
||
{
|
||
ASSERT(this);
|
||
|
||
if (disk.id == MAKEID('S', 'A', 'H', 'D')) {
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// オープン
|
||
// ※派生クラスで、オープン成功後の後処理として呼び出すこと
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Open(const Filepath& path, BOOL /*attn*/)
|
||
{
|
||
Fileio fio;
|
||
|
||
ASSERT(this);
|
||
ASSERT((disk.size >= 8) && (disk.size <= 11));
|
||
ASSERT(disk.blocks > 0);
|
||
|
||
// レディ
|
||
disk.ready = TRUE;
|
||
|
||
// キャッシュ初期化
|
||
ASSERT(!disk.dcache);
|
||
disk.dcache =
|
||
new DiskCache(path, disk.size, disk.blocks, disk.imgoffset);
|
||
|
||
// 読み書きオープン可能か
|
||
if (fio.Open(path, Fileio::ReadWrite)) {
|
||
// 書き込み許可、リードオンリーでない
|
||
disk.writep = FALSE;
|
||
disk.readonly = FALSE;
|
||
fio.Close();
|
||
} else {
|
||
// 書き込み禁止、リードオンリー
|
||
disk.writep = TRUE;
|
||
disk.readonly = TRUE;
|
||
}
|
||
|
||
// ロックされていない
|
||
disk.lock = FALSE;
|
||
|
||
// パス保存
|
||
diskpath = path;
|
||
|
||
// 成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// イジェクト
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL Disk::Eject(BOOL force)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// リムーバブルでなければイジェクトできない
|
||
if (!disk.removable) {
|
||
return;
|
||
}
|
||
|
||
// レディでなければイジェクト必要ない
|
||
if (!disk.ready) {
|
||
return;
|
||
}
|
||
|
||
// 強制フラグがない場合、ロックされていないことが必要
|
||
if (!force) {
|
||
if (disk.lock) {
|
||
return;
|
||
}
|
||
}
|
||
|
||
// ディスクキャッシュを削除
|
||
disk.dcache->Save();
|
||
delete disk.dcache;
|
||
disk.dcache = NULL;
|
||
|
||
// ノットレディ、アテンションなし
|
||
disk.ready = FALSE;
|
||
disk.writep = FALSE;
|
||
disk.readonly = FALSE;
|
||
disk.attn = FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 書き込み禁止
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL Disk::WriteP(BOOL writep)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// レディであること
|
||
if (!disk.ready) {
|
||
return;
|
||
}
|
||
|
||
// Read Onlyの場合は、プロテクト状態のみ
|
||
if (disk.readonly) {
|
||
ASSERT(disk.writep);
|
||
return;
|
||
}
|
||
|
||
// フラグ設定
|
||
disk.writep = writep;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 内部ワーク取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL Disk::GetDisk(disk_t *buffer) const
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buffer);
|
||
|
||
// 内部ワークをコピー
|
||
*buffer = disk;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// パス取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL Disk::GetPath(Filepath& path) const
|
||
{
|
||
path = diskpath;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// フラッシュ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Flush()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// キャッシュがなければ何もしない
|
||
if (!disk.dcache) {
|
||
return TRUE;
|
||
}
|
||
|
||
// キャッシュを保存
|
||
return disk.dcache->Save();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// レディチェック
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::CheckReady()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// リセットなら、ステータスを返す
|
||
if (disk.reset) {
|
||
disk.code = DISK_DEVRESET;
|
||
disk.reset = FALSE;
|
||
return FALSE;
|
||
}
|
||
|
||
// アテンションなら、ステータスを返す
|
||
if (disk.attn) {
|
||
disk.code = DISK_ATTENTION;
|
||
disk.attn = FALSE;
|
||
return FALSE;
|
||
}
|
||
|
||
// ノットレディなら、ステータスを返す
|
||
if (!disk.ready) {
|
||
disk.code = DISK_NOTREADY;
|
||
return FALSE;
|
||
}
|
||
|
||
// エラーなしに初期化
|
||
disk.code = DISK_NOERROR;
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// INQUIRY
|
||
// ※常時成功する必要がある
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::Inquiry(
|
||
const DWORD* /*cdb*/, BYTE* /*buf*/, DWORD /*major*/, DWORD /*minor*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// デフォルトはINQUIRY失敗
|
||
disk.code = DISK_INVALIDCMD;
|
||
return 0;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// REQUEST SENSE
|
||
// ※SASIは別処理
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::RequestSense(const DWORD *cdb, BYTE *buf)
|
||
{
|
||
int size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(buf);
|
||
|
||
// エラーがない場合に限り、ノットレディをチェック
|
||
if (disk.code == DISK_NOERROR) {
|
||
if (!disk.ready) {
|
||
disk.code = DISK_NOTREADY;
|
||
}
|
||
}
|
||
|
||
// サイズ決定(アロケーションレングスに従う)
|
||
size = (int)cdb[4];
|
||
ASSERT((size >= 0) && (size < 0x100));
|
||
|
||
// SCSI-1では、サイズ0のときに4バイト転送する(SCSI-2ではこの仕様は削除)
|
||
if (size == 0) {
|
||
size = 4;
|
||
}
|
||
|
||
// バッファをクリア
|
||
memset(buf, 0, size);
|
||
|
||
// 拡張センスデータを含めた、18バイトを設定
|
||
buf[0] = 0x70;
|
||
buf[2] = (BYTE)(disk.code >> 16);
|
||
buf[7] = 10;
|
||
buf[12] = (BYTE)(disk.code >> 8);
|
||
buf[13] = (BYTE)disk.code;
|
||
|
||
// コードをクリア
|
||
disk.code = 0x00;
|
||
|
||
return size;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MODE SELECTチェック
|
||
// ※disk.codeの影響を受けない
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::SelectCheck(const DWORD *cdb)
|
||
{
|
||
int length;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
|
||
// SCSIHDでなくセーブパラメータが設定されていればエラー
|
||
if (disk.id != MAKEID('S', 'C', 'H', 'D')) {
|
||
// セーブパラメータが設定されていればエラー
|
||
if (cdb[1] & 0x01) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
// パラメータレングスで指定されたデータを受け取る
|
||
length = (int)cdb[4];
|
||
return length;
|
||
}
|
||
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MODE SELECT(10)チェック
|
||
// ※disk.codeの影響を受けない
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::SelectCheck10(const DWORD *cdb)
|
||
{
|
||
DWORD length;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
|
||
// SCSIHDでなくセーブパラメータが設定されていればエラー
|
||
if (disk.id != MAKEID('S', 'C', 'H', 'D')) {
|
||
if (cdb[1] & 0x01) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
// パラメータレングスで指定されたデータを受け取る
|
||
length = cdb[7];
|
||
length <<= 8;
|
||
length |= cdb[8];
|
||
if (length > 0x800) {
|
||
length = 0x800;
|
||
}
|
||
|
||
return (int)length;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MODE SELECT
|
||
// ※disk.codeの影響を受けない
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::ModeSelect(
|
||
const DWORD* /*cdb*/, const BYTE *buf, int length)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
ASSERT(length >= 0);
|
||
|
||
// 設定できない
|
||
disk.code = DISK_INVALIDPRM;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MODE SENSE
|
||
// ※disk.codeの影響を受けない
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::ModeSense(const DWORD *cdb, BYTE *buf)
|
||
{
|
||
int page;
|
||
int length;
|
||
int size;
|
||
BOOL valid;
|
||
BOOL change;
|
||
int ret;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(buf);
|
||
ASSERT(cdb[0] == 0x1a);
|
||
|
||
// レングス取得、バッファクリア
|
||
length = (int)cdb[4];
|
||
ASSERT((length >= 0) && (length < 0x100));
|
||
memset(buf, 0, length);
|
||
|
||
// 変更可能フラグ取得
|
||
if ((cdb[2] & 0xc0) == 0x40) {
|
||
change = TRUE;
|
||
} else {
|
||
change = FALSE;
|
||
}
|
||
|
||
// ページコード取得(0x00は最初からvalid)
|
||
page = cdb[2] & 0x3f;
|
||
if (page == 0x00) {
|
||
valid = TRUE;
|
||
} else {
|
||
valid = FALSE;
|
||
}
|
||
|
||
// 基本情報
|
||
size = 4;
|
||
|
||
// MEDIUM TYPE
|
||
if (disk.id == MAKEID('S', 'C', 'M', 'O')) {
|
||
buf[1] = 0x03; // optical reversible or erasable
|
||
}
|
||
|
||
// DEVICE SPECIFIC PARAMETER
|
||
if (disk.writep) {
|
||
buf[2] = 0x80;
|
||
}
|
||
|
||
// DBDが0なら、ブロックディスクリプタを追加
|
||
if ((cdb[1] & 0x08) == 0) {
|
||
// モードパラメータヘッダ
|
||
buf[3] = 0x08;
|
||
|
||
// レディの場合に限り
|
||
if (disk.ready) {
|
||
// ブロックディスクリプタ(ブロック数)
|
||
buf[5] = (BYTE)(disk.blocks >> 16);
|
||
buf[6] = (BYTE)(disk.blocks >> 8);
|
||
buf[7] = (BYTE)disk.blocks;
|
||
|
||
// ブロックディスクリプタ(ブロックレングス)
|
||
size = 1 << disk.size;
|
||
buf[9] = (BYTE)(size >> 16);
|
||
buf[10] = (BYTE)(size >> 8);
|
||
buf[11] = (BYTE)size;
|
||
}
|
||
|
||
// サイズ再設定
|
||
size = 12;
|
||
}
|
||
|
||
// ページコード1(read-write error recovery)
|
||
if ((page == 0x01) || (page == 0x3f)) {
|
||
size += AddError(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
|
||
// ページコード3(format device)
|
||
if ((page == 0x03) || (page == 0x3f)) {
|
||
size += AddFormat(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
|
||
// ページコード4(drive parameter)
|
||
if ((page == 0x04) || (page == 0x3f)) {
|
||
size += AddDrive(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
|
||
// ページコード6(optical)
|
||
if (disk.id == MAKEID('S', 'C', 'M', 'O')) {
|
||
if ((page == 0x06) || (page == 0x3f)) {
|
||
size += AddOpt(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
}
|
||
|
||
// ページコード8(caching)
|
||
if ((page == 0x08) || (page == 0x3f)) {
|
||
size += AddCache(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
|
||
// ページコード13(CD-ROM)
|
||
if (disk.id == MAKEID('S', 'C', 'C', 'D')) {
|
||
if ((page == 0x0d) || (page == 0x3f)) {
|
||
size += AddCDROM(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
}
|
||
|
||
// ページコード14(CD-DA)
|
||
if (disk.id == MAKEID('S', 'C', 'C', 'D')) {
|
||
if ((page == 0x0e) || (page == 0x3f)) {
|
||
size += AddCDDA(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
}
|
||
|
||
// ページ(ベンダ特殊)
|
||
ret = AddVendor(page, change, &buf[size]);
|
||
if (ret > 0) {
|
||
size += ret;
|
||
valid = TRUE;
|
||
}
|
||
|
||
// モードデータレングスを最終設定
|
||
buf[0] = (BYTE)(size - 1);
|
||
|
||
// サポートしていないページか
|
||
if (!valid) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return 0;
|
||
}
|
||
|
||
// MODE SENSE成功
|
||
disk.code = DISK_NOERROR;
|
||
return length;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MODE SENSE(10)
|
||
// ※disk.codeの影響を受けない
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::ModeSense10(const DWORD *cdb, BYTE *buf)
|
||
{
|
||
int page;
|
||
int length;
|
||
int size;
|
||
BOOL valid;
|
||
BOOL change;
|
||
int ret;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(buf);
|
||
ASSERT(cdb[0] == 0x5a);
|
||
|
||
// レングス取得、バッファクリア
|
||
length = cdb[7];
|
||
length <<= 8;
|
||
length |= cdb[8];
|
||
if (length > 0x800) {
|
||
length = 0x800;
|
||
}
|
||
ASSERT((length >= 0) && (length < 0x800));
|
||
memset(buf, 0, length);
|
||
|
||
// 変更可能フラグ取得
|
||
if ((cdb[2] & 0xc0) == 0x40) {
|
||
change = TRUE;
|
||
} else {
|
||
change = FALSE;
|
||
}
|
||
|
||
// ページコード取得(0x00は最初からvalid)
|
||
page = cdb[2] & 0x3f;
|
||
if (page == 0x00) {
|
||
valid = TRUE;
|
||
} else {
|
||
valid = FALSE;
|
||
}
|
||
|
||
// 基本情報
|
||
size = 4;
|
||
if (disk.writep) {
|
||
buf[2] = 0x80;
|
||
}
|
||
|
||
// DBDが0なら、ブロックディスクリプタを追加
|
||
if ((cdb[1] & 0x08) == 0) {
|
||
// モードパラメータヘッダ
|
||
buf[3] = 0x08;
|
||
|
||
// レディの場合に限り
|
||
if (disk.ready) {
|
||
// ブロックディスクリプタ(ブロック数)
|
||
buf[5] = (BYTE)(disk.blocks >> 16);
|
||
buf[6] = (BYTE)(disk.blocks >> 8);
|
||
buf[7] = (BYTE)disk.blocks;
|
||
|
||
// ブロックディスクリプタ(ブロックレングス)
|
||
size = 1 << disk.size;
|
||
buf[9] = (BYTE)(size >> 16);
|
||
buf[10] = (BYTE)(size >> 8);
|
||
buf[11] = (BYTE)size;
|
||
}
|
||
|
||
// サイズ再設定
|
||
size = 12;
|
||
}
|
||
|
||
// ページコード1(read-write error recovery)
|
||
if ((page == 0x01) || (page == 0x3f)) {
|
||
size += AddError(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
|
||
// ページコード3(format device)
|
||
if ((page == 0x03) || (page == 0x3f)) {
|
||
size += AddFormat(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
|
||
// ページコード4(drive parameter)
|
||
if ((page == 0x04) || (page == 0x3f)) {
|
||
size += AddDrive(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
|
||
// ページコード6(optical)
|
||
if (disk.id == MAKEID('S', 'C', 'M', 'O')) {
|
||
if ((page == 0x06) || (page == 0x3f)) {
|
||
size += AddOpt(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
}
|
||
|
||
// ページコード8(caching)
|
||
if ((page == 0x08) || (page == 0x3f)) {
|
||
size += AddCache(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
|
||
// ページコード13(CD-ROM)
|
||
if (disk.id == MAKEID('S', 'C', 'C', 'D')) {
|
||
if ((page == 0x0d) || (page == 0x3f)) {
|
||
size += AddCDROM(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
}
|
||
|
||
// ページコード14(CD-DA)
|
||
if (disk.id == MAKEID('S', 'C', 'C', 'D')) {
|
||
if ((page == 0x0e) || (page == 0x3f)) {
|
||
size += AddCDDA(change, &buf[size]);
|
||
valid = TRUE;
|
||
}
|
||
}
|
||
|
||
// ページ(ベンダ特殊)
|
||
ret = AddVendor(page, change, &buf[size]);
|
||
if (ret > 0) {
|
||
size += ret;
|
||
valid = TRUE;
|
||
}
|
||
|
||
// モードデータレングスを最終設定
|
||
buf[0] = (BYTE)(size - 1);
|
||
|
||
// サポートしていないページか
|
||
if (!valid) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return 0;
|
||
}
|
||
|
||
// MODE SENSE成功
|
||
disk.code = DISK_NOERROR;
|
||
return length;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// エラーページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::AddError(BOOL change, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x01;
|
||
buf[1] = 0x0a;
|
||
|
||
// 変更可能領域はない
|
||
if (change) {
|
||
return 12;
|
||
}
|
||
|
||
// リトライカウントは0、リミットタイムは装置内部のデフォルト値を使用
|
||
return 12;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// フォーマットページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::AddFormat(BOOL change, BYTE *buf)
|
||
{
|
||
int size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x80 | 0x03;
|
||
buf[1] = 0x16;
|
||
|
||
// 物理セクタのバイト数は変更可能に見せる(実際には変更できないが)
|
||
if (change) {
|
||
buf[0xc] = 0xff;
|
||
buf[0xd] = 0xff;
|
||
return 24;
|
||
}
|
||
|
||
if (disk.ready) {
|
||
// 1ゾーンのトラック数を8に設定(TODO)
|
||
buf[0x3] = 0x08;
|
||
|
||
// セクタ/トラックを25に設定(TODO)
|
||
buf[0xa] = 0x00;
|
||
buf[0xb] = 0x19;
|
||
|
||
// 物理セクタのバイト数を設定
|
||
size = 1 << disk.size;
|
||
buf[0xc] = (BYTE)(size >> 8);
|
||
buf[0xd] = (BYTE)size;
|
||
}
|
||
|
||
// リムーバブル属性を設定
|
||
if (disk.removable) {
|
||
buf[20] = 0x20;
|
||
}
|
||
|
||
return 24;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ドライブページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::AddDrive(BOOL change, BYTE *buf)
|
||
{
|
||
DWORD cylinder;
|
||
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x04;
|
||
buf[1] = 0x16;
|
||
|
||
// 変更可能領域はない
|
||
if (change) {
|
||
return 24;
|
||
}
|
||
|
||
if (disk.ready) {
|
||
// シリンダ数を設定(総ブロック数を25セクタ/トラックと8ヘッドで除算)
|
||
cylinder = disk.blocks;
|
||
cylinder >>= 3;
|
||
cylinder /= 25;
|
||
buf[0x2] = (BYTE)(cylinder >> 16);
|
||
buf[0x3] = (BYTE)(cylinder >> 8);
|
||
buf[0x4] = (BYTE)cylinder;
|
||
|
||
// ヘッドを8で固定
|
||
buf[0x5] = 0x8;
|
||
}
|
||
|
||
return 24;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// オプティカルページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::AddOpt(BOOL change, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x06;
|
||
buf[1] = 0x02;
|
||
|
||
// 変更可能領域はない
|
||
if (change) {
|
||
return 4;
|
||
}
|
||
|
||
// 更新ブロックのレポートは行わない
|
||
return 4;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// キャッシュページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::AddCache(BOOL change, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x08;
|
||
buf[1] = 0x0a;
|
||
|
||
// 変更可能領域はない
|
||
if (change) {
|
||
return 12;
|
||
}
|
||
|
||
// 読み込みキャッシュのみ有効、プリフェッチは行わない
|
||
return 12;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// CD-ROMページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::AddCDROM(BOOL change, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x0d;
|
||
buf[1] = 0x06;
|
||
|
||
// 変更可能領域はない
|
||
if (change) {
|
||
return 8;
|
||
}
|
||
|
||
// インアクティブタイマは2sec
|
||
buf[3] = 0x05;
|
||
|
||
// MSF倍数はそれぞれ60, 75
|
||
buf[5] = 60;
|
||
buf[7] = 75;
|
||
|
||
return 8;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// CD-DAページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::AddCDDA(BOOL change, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x0e;
|
||
buf[1] = 0x0e;
|
||
|
||
// 変更可能領域はない
|
||
if (change) {
|
||
return 16;
|
||
}
|
||
|
||
// オーディオは操作完了を待ち、 複数トラックにまたがるPLAYを許可する
|
||
return 16;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Vendor特殊ページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::AddVendor(int /*page*/, BOOL /*change*/, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
return 0;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// READ DEFECT DATA(10)
|
||
// ※disk.codeの影響を受けない
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::ReadDefectData10(const DWORD *cdb, BYTE *buf)
|
||
{
|
||
DWORD length;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(buf);
|
||
ASSERT(cdb[0] == 0x37);
|
||
|
||
// レングス取得、バッファクリア
|
||
length = cdb[7];
|
||
length <<= 8;
|
||
length |= cdb[8];
|
||
if (length > 0x800) {
|
||
length = 0x800;
|
||
}
|
||
ASSERT((length >= 0) && (length < 0x800));
|
||
memset(buf, 0, length);
|
||
|
||
// P/G/FORMAT
|
||
buf[1] = (cdb[1] & 0x18) | 5;
|
||
buf[3] = 8;
|
||
|
||
buf[4] = 0xff;
|
||
buf[5] = 0xff;
|
||
buf[6] = 0xff;
|
||
buf[7] = 0xff;
|
||
|
||
buf[8] = 0xff;
|
||
buf[9] = 0xff;
|
||
buf[10] = 0xff;
|
||
buf[11] = 0xff;
|
||
|
||
// リスト無し
|
||
disk.code = DISK_NODEFECT;
|
||
return 4;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コマンド
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// TEST UNIT READY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::TestUnitReady(const DWORD* /*cdb*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return FALSE;
|
||
}
|
||
|
||
// TEST UNIT READY成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// REZERO UNIT
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Rezero(const DWORD* /*cdb*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return FALSE;
|
||
}
|
||
|
||
// REZERO成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// FORMAT UNIT
|
||
// ※SASIはオペコード$06、SCSIはオペコード$04
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Format(const DWORD *cdb)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return FALSE;
|
||
}
|
||
|
||
// FMTDATA=1はサポートしない(但しDEFECT LISTが無いならOK)
|
||
if ((cdb[1] & 0x10) != 0 && cdb[4] != 0) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return FALSE;
|
||
}
|
||
|
||
// FORMAT成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// REASSIGN BLOCKS
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Reassign(const DWORD* /*cdb*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return FALSE;
|
||
}
|
||
|
||
// REASSIGN BLOCKS成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// READ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::Read(BYTE *buf, DWORD block)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return 0;
|
||
}
|
||
|
||
// トータルブロック数を超えていればエラー
|
||
if (block >= disk.blocks) {
|
||
disk.code = DISK_INVALIDLBA;
|
||
return 0;
|
||
}
|
||
|
||
// キャッシュに任せる
|
||
if (!disk.dcache->Read(buf, block)) {
|
||
disk.code = DISK_READFAULT;
|
||
return 0;
|
||
}
|
||
|
||
// 成功
|
||
return (1 << disk.size);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// WRITEチェック
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::WriteCheck(DWORD block)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return 0;
|
||
}
|
||
|
||
// トータルブロック数を超えていればエラー
|
||
if (block >= disk.blocks) {
|
||
return 0;
|
||
}
|
||
|
||
// 書き込み禁止ならエラー
|
||
if (disk.writep) {
|
||
disk.code = DISK_WRITEPROTECT;
|
||
return 0;
|
||
}
|
||
|
||
// 成功
|
||
return (1 << disk.size);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// WRITE
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Write(const BYTE *buf, DWORD block)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// レディでなければエラー
|
||
if (!disk.ready) {
|
||
disk.code = DISK_NOTREADY;
|
||
return FALSE;
|
||
}
|
||
|
||
// トータルブロック数を超えていればエラー
|
||
if (block >= disk.blocks) {
|
||
disk.code = DISK_INVALIDLBA;
|
||
return FALSE;
|
||
}
|
||
|
||
// 書き込み禁止ならエラー
|
||
if (disk.writep) {
|
||
disk.code = DISK_WRITEPROTECT;
|
||
return FALSE;
|
||
}
|
||
|
||
// キャッシュに任せる
|
||
if (!disk.dcache->Write(buf, block)) {
|
||
disk.code = DISK_WRITEFAULT;
|
||
return FALSE;
|
||
}
|
||
|
||
// 成功
|
||
disk.code = DISK_NOERROR;
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// SEEK
|
||
// ※LBAのチェックは行わない(SASI IOCS)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Seek(const DWORD* /*cdb*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return FALSE;
|
||
}
|
||
|
||
// SEEK成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ASSIGN
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Assign(const DWORD* /*cdb*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// SPECIFY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Specify(const DWORD* /*cdb*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// START STOP UNIT
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::StartStop(const DWORD *cdb)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(cdb[0] == 0x1b);
|
||
|
||
// イジェクトビットを見て、必要ならイジェクト
|
||
if (cdb[4] & 0x02) {
|
||
if (disk.lock) {
|
||
// ロックされているので、イジェクトできない
|
||
disk.code = DISK_PREVENT;
|
||
return FALSE;
|
||
}
|
||
|
||
// イジェクト
|
||
Eject(FALSE);
|
||
}
|
||
|
||
// OK
|
||
disk.code = DISK_NOERROR;
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// SEND DIAGNOSTIC
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::SendDiag(const DWORD *cdb)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(cdb[0] == 0x1d);
|
||
|
||
// PFビットはサポートしない
|
||
if (cdb[1] & 0x10) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return FALSE;
|
||
}
|
||
|
||
// パラメータリストはサポートしない
|
||
if ((cdb[3] != 0) || (cdb[4] != 0)) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return FALSE;
|
||
}
|
||
|
||
// 常に成功
|
||
disk.code = DISK_NOERROR;
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// PREVENT/ALLOW MEDIUM REMOVAL
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Removal(const DWORD *cdb)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(cdb[0] == 0x1e);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return FALSE;
|
||
}
|
||
|
||
// ロックフラグを設定
|
||
if (cdb[4] & 0x01) {
|
||
disk.lock = TRUE;
|
||
} else {
|
||
disk.lock = FALSE;
|
||
}
|
||
|
||
// REMOVAL成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// READ CAPACITY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::ReadCapacity(const DWORD* /*cdb*/, BYTE *buf)
|
||
{
|
||
DWORD blocks;
|
||
DWORD length;
|
||
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// バッファクリア
|
||
memset(buf, 0, 8);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return 0;
|
||
}
|
||
|
||
// 論理ブロックアドレスの終端(disk.blocks - 1)を作成
|
||
ASSERT(disk.blocks > 0);
|
||
blocks = disk.blocks - 1;
|
||
buf[0] = (BYTE)(blocks >> 24);
|
||
buf[1] = (BYTE)(blocks >> 16);
|
||
buf[2] = (BYTE)(blocks >> 8);
|
||
buf[3] = (BYTE)blocks;
|
||
|
||
// ブロックレングス(1 << disk.size)を作成
|
||
length = 1 << disk.size;
|
||
buf[4] = (BYTE)(length >> 24);
|
||
buf[5] = (BYTE)(length >> 16);
|
||
buf[6] = (BYTE)(length >> 8);
|
||
buf[7] = (BYTE)length;
|
||
|
||
// 返送サイズを返す
|
||
return 8;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// VERIFY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::Verify(const DWORD *cdb)
|
||
{
|
||
DWORD record;
|
||
DWORD blocks;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(cdb[0] == 0x2f);
|
||
|
||
// パラメータ取得
|
||
record = cdb[2];
|
||
record <<= 8;
|
||
record |= cdb[3];
|
||
record <<= 8;
|
||
record |= cdb[4];
|
||
record <<= 8;
|
||
record |= cdb[5];
|
||
blocks = cdb[7];
|
||
blocks <<= 8;
|
||
blocks |= cdb[8];
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return 0;
|
||
}
|
||
|
||
// パラメータチェック
|
||
if (disk.blocks < (record + blocks)) {
|
||
disk.code = DISK_INVALIDLBA;
|
||
return FALSE;
|
||
}
|
||
|
||
// 成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// READ TOC
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL Disk::ReadToc(const DWORD *cdb, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(cdb[0] == 0x43);
|
||
ASSERT(buf);
|
||
|
||
// このコマンドはサポートしない
|
||
disk.code = DISK_INVALIDCMD;
|
||
return FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// PLAY AUDIO
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::PlayAudio(const DWORD *cdb)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(cdb[0] == 0x45);
|
||
|
||
// このコマンドはサポートしない
|
||
disk.code = DISK_INVALIDCMD;
|
||
return FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// PLAY AUDIO MSF
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::PlayAudioMSF(const DWORD *cdb)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(cdb[0] == 0x47);
|
||
|
||
// このコマンドはサポートしない
|
||
disk.code = DISK_INVALIDCMD;
|
||
return FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// PLAY AUDIO TRACK
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL Disk::PlayAudioTrack(const DWORD *cdb)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(cdb[0] == 0x48);
|
||
|
||
// このコマンドはサポートしない
|
||
disk.code = DISK_INVALIDCMD;
|
||
return FALSE;
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// SASI ハードディスク
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
SASIHD::SASIHD() : Disk()
|
||
{
|
||
// SASI ハードディスク
|
||
disk.id = MAKEID('S', 'A', 'H', 'D');
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// リセット
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIHD::Reset()
|
||
{
|
||
// ロック状態解除、アテンション解除
|
||
disk.lock = FALSE;
|
||
disk.attn = FALSE;
|
||
|
||
// リセットなし、コードをクリア
|
||
disk.reset = FALSE;
|
||
disk.code = 0x00;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// オープン
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SASIHD::Open(const Filepath& path, BOOL /*attn*/)
|
||
{
|
||
Fileio fio;
|
||
off64_t size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(!disk.ready);
|
||
|
||
// 読み込みオープンが必要
|
||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// ファイルサイズの取得
|
||
size = fio.GetFileSize();
|
||
fio.Close();
|
||
|
||
#if defined(USE_MZ1F23_1024_SUPPORT)
|
||
// MZ-2500/MZ-2800用 MZ-1F23(SASI 20M/セクタサイズ1024)専用
|
||
// 20M(22437888 BS=1024 C=21912)
|
||
if (size == 0x1566000) {
|
||
// セクタサイズとブロック数
|
||
disk.size = 10;
|
||
disk.blocks = (DWORD)(size >> 10);
|
||
|
||
// 基本クラス
|
||
return Disk::Open(path);
|
||
}
|
||
#endif // USE_MZ1F23_1024_SUPPORT
|
||
|
||
#if defined(REMOVE_FIXED_SASIHD_SIZE)
|
||
// 256バイト単位であること
|
||
if (size & 0xff) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 10MB以上
|
||
if (size < 0x9f5400) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 512MB程度に制限しておく
|
||
if (size > 512 * 1024 * 1024) {
|
||
return FALSE;
|
||
}
|
||
#else
|
||
// 10MB, 20MB, 40MBのみ
|
||
switch (size) {
|
||
// 10MB(10441728 BS=256 C=40788)
|
||
case 0x9f5400:
|
||
break;
|
||
|
||
// 20MB(20748288 BS=256 C=81048)
|
||
case 0x13c9800:
|
||
break;
|
||
|
||
// 40MB(41496576 BS=256 C=162096)
|
||
case 0x2793000:
|
||
break;
|
||
|
||
// その他(サポートしない)
|
||
default:
|
||
return FALSE;
|
||
}
|
||
#endif // REMOVE_FIXED_SASIHD_SIZE
|
||
|
||
// セクタサイズとブロック数
|
||
disk.size = 8;
|
||
disk.blocks = (DWORD)(size >> 8);
|
||
|
||
// 基本クラス
|
||
return Disk::Open(path);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// REQUEST SENSE
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SASIHD::RequestSense(const DWORD *cdb, BYTE *buf)
|
||
{
|
||
int size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(buf);
|
||
|
||
// サイズ決定
|
||
size = (int)cdb[4];
|
||
ASSERT((size >= 0) && (size < 0x100));
|
||
|
||
// サイズ0のときに4バイト転送する(Shugart Associates System Interface仕様)
|
||
if (size == 0) {
|
||
size = 4;
|
||
}
|
||
|
||
// SASIは非拡張フォーマットに固定
|
||
memset(buf, 0, size);
|
||
buf[0] = (BYTE)(disk.code >> 16);
|
||
buf[1] = (BYTE)(disk.lun << 5);
|
||
|
||
// コードをクリア
|
||
disk.code = 0x00;
|
||
|
||
return size;
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// SCSI ハードディスク
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
SCSIHD::SCSIHD() : Disk()
|
||
{
|
||
// SCSI ハードディスク
|
||
disk.id = MAKEID('S', 'C', 'H', 'D');
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// リセット
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIHD::Reset()
|
||
{
|
||
// ロック状態解除、アテンション解除
|
||
disk.lock = FALSE;
|
||
disk.attn = FALSE;
|
||
|
||
// リセットなし、コードをクリア
|
||
disk.reset = FALSE;
|
||
disk.code = 0x00;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// オープン
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSIHD::Open(const Filepath& path, BOOL /*attn*/)
|
||
{
|
||
Fileio fio;
|
||
off64_t size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(!disk.ready);
|
||
|
||
// 読み込みオープンが必要
|
||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// ファイルサイズの取得
|
||
size = fio.GetFileSize();
|
||
fio.Close();
|
||
|
||
// 512バイト単位であること
|
||
if (size & 0x1ff) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 10MB以上
|
||
if (size < 0x9f5400) {
|
||
return FALSE;
|
||
}
|
||
// xm6iに準じて2TB
|
||
// よく似たものが wxw/wxw_cfg.cpp にもある
|
||
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
|
||
return FALSE;
|
||
}
|
||
|
||
// セクタサイズとブロック数
|
||
disk.size = 9;
|
||
disk.blocks = (DWORD)(size >> 9);
|
||
|
||
// 基本クラス
|
||
return Disk::Open(path);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// INQUIRY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIHD::Inquiry(
|
||
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
|
||
{
|
||
char vendor[32];
|
||
char product[32];
|
||
char rev[32];
|
||
int size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(buf);
|
||
ASSERT(cdb[0] == 0x12);
|
||
|
||
// EVPDチェック
|
||
if (cdb[1] & 0x01) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return 0;
|
||
}
|
||
|
||
// レディチェック(イメージファイルがない場合、エラーとする)
|
||
if (!disk.ready) {
|
||
disk.code = DISK_NOTREADY;
|
||
return 0;
|
||
}
|
||
|
||
// 基本データ
|
||
// buf[0] ... Direct Access Device
|
||
// buf[2] ... SCSI-2準拠のコマンド体系
|
||
// buf[3] ... SCSI-2準拠のInquiryレスポンス
|
||
// buf[4] ... Inquiry追加データ
|
||
memset(buf, 0, 8);
|
||
|
||
// SCSI-2 本の p.104 4.4.3 不当なロジカルユニットの処理
|
||
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
|
||
buf[0] = 0x7f;
|
||
}
|
||
|
||
buf[2] = 0x02;
|
||
buf[3] = 0x02;
|
||
buf[4] = 122 + 3; // 実HDDに近い値
|
||
|
||
// 空白で埋める
|
||
memset(&buf[8], 0x20, buf[4] - 3);
|
||
|
||
// ベンダ名/製品名を決定
|
||
sprintf(vendor, BENDER_SIGNATURE);
|
||
size = disk.blocks >> 11;
|
||
if (size < 300)
|
||
sprintf(product, "PRODRIVE LPS%dS", size);
|
||
else if (size < 600)
|
||
sprintf(product, "MAVERICK%dS", size);
|
||
else if (size < 800)
|
||
sprintf(product, "LIGHTNING%dS", size);
|
||
else if (size < 1000)
|
||
sprintf(product, "TRAILBRAZER%dS", size);
|
||
else if (size < 2000)
|
||
sprintf(product, "FIREBALL%dS", size);
|
||
else
|
||
sprintf(product, "FBSE%d.%dS", size / 1000, (size % 1000) / 100);
|
||
|
||
// ベンダ名
|
||
memcpy(&buf[8], vendor, strlen(vendor));
|
||
|
||
// 製品名
|
||
memcpy(&buf[16], product, strlen(product));
|
||
|
||
// リビジョン
|
||
sprintf(rev, "0%01d%01d%01d",
|
||
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
|
||
memcpy(&buf[32], rev, 4);
|
||
|
||
// 返却できるデータのサイズ
|
||
size = (buf[4] + 5);
|
||
|
||
// 相手のバッファが少なければ制限する
|
||
if (size > (int)cdb[4]) {
|
||
size = (int)cdb[4];
|
||
}
|
||
|
||
// 成功
|
||
disk.code = DISK_NOERROR;
|
||
return size;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MODE SELECT
|
||
// ※disk.codeの影響を受けない
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSIHD::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
|
||
{
|
||
int page;
|
||
int size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
ASSERT(length >= 0);
|
||
|
||
// PF
|
||
if (cdb[1] & 0x10) {
|
||
// Mode Parameter header
|
||
if (length >= 12) {
|
||
// ブロックレングスのバイト数をチェック
|
||
size = 1 << disk.size;
|
||
if (buf[9] != (BYTE)(size >> 16) ||
|
||
buf[10] != (BYTE)(size >> 8) ||
|
||
buf[11] != (BYTE)size) {
|
||
// 今のところセクタ長の変更は許さない
|
||
disk.code = DISK_INVALIDPRM;
|
||
return FALSE;
|
||
}
|
||
buf += 12;
|
||
length -= 12;
|
||
}
|
||
|
||
// ページの解析
|
||
while (length > 0) {
|
||
// ページの取得
|
||
page = buf[0];
|
||
|
||
switch (page) {
|
||
// format device
|
||
case 0x03:
|
||
// 物理セクタのバイト数をチェック
|
||
size = 1 << disk.size;
|
||
if (buf[0xc] != (BYTE)(size >> 8) ||
|
||
buf[0xd] != (BYTE)size) {
|
||
// 今のところセクタ長の変更は許さない
|
||
disk.code = DISK_INVALIDPRM;
|
||
return FALSE;
|
||
}
|
||
break;
|
||
|
||
// その他ページ
|
||
default:
|
||
break;
|
||
}
|
||
|
||
// 次のページへ
|
||
size = buf[1] + 2;
|
||
length -= size;
|
||
buf += size;
|
||
}
|
||
}
|
||
|
||
// とりあえずエラーは発生させない(MINIX)
|
||
disk.code = DISK_NOERROR;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// SCSI ハードディスク(PC-9801-55 NEC純正/Anex86/T98Next)
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
SCSIHD_NEC::SCSIHD_NEC() : SCSIHD()
|
||
{
|
||
// ワーク初期化
|
||
cylinders = 0;
|
||
heads = 0;
|
||
sectors = 0;
|
||
sectorsize = 0;
|
||
imgoffset = 0;
|
||
imgsize = 0;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// リトルエンディアンと想定したワードを取り出す
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
static inline WORD getWordLE(const BYTE *b)
|
||
{
|
||
return ((WORD)(b[1]) << 8) | b[0];
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// リトルエンディアンと想定したロングワードを取り出す
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
static inline DWORD getDwordLE(const BYTE *b)
|
||
{
|
||
return ((DWORD)(b[3]) << 24) | ((DWORD)(b[2]) << 16) |
|
||
((DWORD)(b[1]) << 8) | b[0];
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// オープン
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSIHD_NEC::Open(const Filepath& path, BOOL /*attn*/)
|
||
{
|
||
Fileio fio;
|
||
off64_t size;
|
||
BYTE hdr[512];
|
||
LPCTSTR ext;
|
||
|
||
ASSERT(this);
|
||
ASSERT(!disk.ready);
|
||
|
||
// 読み込みオープンが必要
|
||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// ファイルサイズの取得
|
||
size = fio.GetFileSize();
|
||
|
||
// ヘッダー読み込み
|
||
if (size >= (off64_t)sizeof(hdr)) {
|
||
if (!fio.Read(hdr, sizeof(hdr))) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
}
|
||
fio.Close();
|
||
|
||
// 512バイト単位であること
|
||
if (size & 0x1ff) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 10MB以上
|
||
if (size < 0x9f5400) {
|
||
return FALSE;
|
||
}
|
||
// xm6iに準じて2TB
|
||
// よく似たものが wxw/wxw_cfg.cpp にもある
|
||
if (size > 2LL * 1024 * 1024 * 1024 * 1024) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 拡張子別にパラメータを決定
|
||
ext = path.GetFileExt();
|
||
if (xstrcasecmp(ext, _T(".HDN")) == 0) {
|
||
// デフォルト設定としてセクタサイズ512,セクタ数25,ヘッド数8を想定
|
||
imgoffset = 0;
|
||
imgsize = size;
|
||
sectorsize = 512;
|
||
sectors = 25;
|
||
heads = 8;
|
||
cylinders = (int)(size >> 9);
|
||
cylinders >>= 3;
|
||
cylinders /= 25;
|
||
} else if (xstrcasecmp(ext, _T(".HDI")) == 0) { // Anex86 HD image?
|
||
imgoffset = getDwordLE(&hdr[4 + 4]);
|
||
imgsize = getDwordLE(&hdr[4 + 4 + 4]);
|
||
sectorsize = getDwordLE(&hdr[4 + 4 + 4 + 4]);
|
||
sectors = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4]);
|
||
heads = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4 + 4]);
|
||
cylinders = getDwordLE(&hdr[4 + 4 + 4 + 4 + 4 + 4 + 4]);
|
||
} else if (xstrcasecmp(ext, _T(".NHD")) == 0 &&
|
||
memcmp(hdr, "T98HDDIMAGE.R0\0", 15) == 0) { // T98Next HD image?
|
||
imgoffset = getDwordLE(&hdr[0x10 + 0x100]);
|
||
cylinders = getDwordLE(&hdr[0x10 + 0x100 + 4]);
|
||
heads = getWordLE(&hdr[0x10 + 0x100 + 4 + 4]);
|
||
sectors = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2]);
|
||
sectorsize = getWordLE(&hdr[0x10 + 0x100 + 4 + 4 + 2 + 2]);
|
||
imgsize = (off64_t)cylinders * heads * sectors * sectorsize;
|
||
}
|
||
|
||
// セクタサイズは256または512をサポート
|
||
if (sectorsize != 256 && sectorsize != 512) {
|
||
return FALSE;
|
||
}
|
||
|
||
// イメージサイズの整合性チェック
|
||
if (imgoffset + imgsize > size || (imgsize % sectorsize != 0)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// セクタサイズ
|
||
for(disk.size = 16; disk.size > 0; --(disk.size)) {
|
||
if ((1 << disk.size) == sectorsize)
|
||
break;
|
||
}
|
||
if (disk.size <= 0 || disk.size > 16) {
|
||
return FALSE;
|
||
}
|
||
|
||
// ブロック数
|
||
disk.blocks = (DWORD)(imgsize >> disk.size);
|
||
disk.imgoffset = imgoffset;
|
||
|
||
// 基本クラス
|
||
return Disk::Open(path);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// INQUIRY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIHD_NEC::Inquiry(
|
||
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
|
||
{
|
||
int size;
|
||
|
||
// 基底クラス
|
||
size = SCSIHD::Inquiry(cdb, buf, major, minor);
|
||
|
||
// 基底クラスでエラーなら終了
|
||
if (size == 0) {
|
||
return 0;
|
||
}
|
||
|
||
// SCSI1相当に変更
|
||
buf[2] = 0x01;
|
||
buf[3] = 0x01;
|
||
|
||
// ベンダー名差し替え
|
||
buf[8] = 'N';
|
||
buf[9] = 'E';
|
||
buf[10] = 'C';
|
||
|
||
return size;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// エラーページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIHD_NEC::AddError(BOOL change, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x01;
|
||
buf[1] = 0x06;
|
||
|
||
// 変更可能領域はない
|
||
if (change) {
|
||
return 8;
|
||
}
|
||
|
||
// リトライカウントは0、リミットタイムは装置内部のデフォルト値を使用
|
||
return 8;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// フォーマットページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIHD_NEC::AddFormat(BOOL change, BYTE *buf)
|
||
{
|
||
int size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x80 | 0x03;
|
||
buf[1] = 0x16;
|
||
|
||
// 物理セクタのバイト数は変更可能に見せる(実際には変更できないが)
|
||
if (change) {
|
||
buf[0xc] = 0xff;
|
||
buf[0xd] = 0xff;
|
||
return 24;
|
||
}
|
||
|
||
if (disk.ready) {
|
||
// 1ゾーンのトラック数を設定(PC-9801-55はこの値を見ているようだ)
|
||
buf[0x2] = (BYTE)(heads >> 8);
|
||
buf[0x3] = (BYTE)heads;
|
||
|
||
// 1トラックのセクタ数を設定
|
||
buf[0xa] = (BYTE)(sectors >> 8);
|
||
buf[0xb] = (BYTE)sectors;
|
||
|
||
// 物理セクタのバイト数を設定
|
||
size = 1 << disk.size;
|
||
buf[0xc] = (BYTE)(size >> 8);
|
||
buf[0xd] = (BYTE)size;
|
||
}
|
||
|
||
// リムーバブル属性を設定(昔の名残)
|
||
if (disk.removable) {
|
||
buf[20] = 0x20;
|
||
}
|
||
|
||
return 24;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ドライブページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIHD_NEC::AddDrive(BOOL change, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x04;
|
||
buf[1] = 0x12;
|
||
|
||
// 変更可能領域はない
|
||
if (change) {
|
||
return 20;
|
||
}
|
||
|
||
if (disk.ready) {
|
||
// シリンダ数を設定
|
||
buf[0x2] = (BYTE)(cylinders >> 16);
|
||
buf[0x3] = (BYTE)(cylinders >> 8);
|
||
buf[0x4] = (BYTE)cylinders;
|
||
|
||
// ヘッド数を設定
|
||
buf[0x5] = (BYTE)heads;
|
||
}
|
||
|
||
return 20;
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// SCSI ハードディスク(Macintosh Apple純正)
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
SCSIHD_APPLE::SCSIHD_APPLE() : SCSIHD()
|
||
{
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// INQUIRY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIHD_APPLE::Inquiry(
|
||
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
|
||
{
|
||
int size;
|
||
char vendor[32];
|
||
char product[32];
|
||
|
||
// 基底クラス
|
||
size = SCSIHD::Inquiry(cdb, buf, major, minor);
|
||
|
||
// 基底クラスでエラーなら終了
|
||
if (size == 0) {
|
||
return 0;
|
||
}
|
||
|
||
// ベンダ名
|
||
sprintf(vendor, " SEAGATE");
|
||
memcpy(&buf[8], vendor, strlen(vendor));
|
||
|
||
// 製品名
|
||
sprintf(product, " ST225N");
|
||
memcpy(&buf[16], product, strlen(product));
|
||
|
||
return size;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Vendor特殊ページ追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIHD_APPLE::AddVendor(int page, BOOL change, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// ページコード48
|
||
if ((page != 0x30) && (page != 0x3f)) {
|
||
return 0;
|
||
}
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x30;
|
||
buf[1] = 0x1c;
|
||
|
||
// 変更可能領域はない
|
||
if (change) {
|
||
return 30;
|
||
}
|
||
|
||
// APPLE COMPUTER, INC.
|
||
memcpy(&buf[0xa], "APPLE COMPUTER, INC.", 20);
|
||
|
||
return 30;
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// SCSI 光磁気ディスク
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
SCSIMO::SCSIMO() : Disk()
|
||
{
|
||
// SCSI 光磁気ディスク
|
||
disk.id = MAKEID('S', 'C', 'M', 'O');
|
||
|
||
// リムーバブル
|
||
disk.removable = TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// オープン
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSIMO::Open(const Filepath& path, BOOL attn)
|
||
{
|
||
Fileio fio;
|
||
off64_t size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(!disk.ready);
|
||
|
||
// 読み込みオープンが必要
|
||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// ファイルサイズの取得
|
||
size = fio.GetFileSize();
|
||
fio.Close();
|
||
|
||
switch (size) {
|
||
// 128MB
|
||
case 0x797f400:
|
||
disk.size = 9;
|
||
disk.blocks = 248826;
|
||
break;
|
||
|
||
// 230MB
|
||
case 0xd9eea00:
|
||
disk.size = 9;
|
||
disk.blocks = 446325;
|
||
break;
|
||
|
||
// 540MB
|
||
case 0x1fc8b800:
|
||
disk.size = 9;
|
||
disk.blocks = 1041500;
|
||
break;
|
||
|
||
// 640MB
|
||
case 0x25e28000:
|
||
disk.size = 11;
|
||
disk.blocks = 310352;
|
||
break;
|
||
|
||
// その他(エラー)
|
||
default:
|
||
return FALSE;
|
||
}
|
||
|
||
// 基本クラス
|
||
Disk::Open(path);
|
||
|
||
// レディならアテンション
|
||
if (disk.ready && attn) {
|
||
disk.attn = TRUE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
#ifndef RASCSI
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ロード
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSIMO::Load(Fileio *fio, int ver)
|
||
{
|
||
DWORD sz;
|
||
disk_t buf;
|
||
DWORD padding;
|
||
Filepath path;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fio);
|
||
ASSERT(ver >= 0x0200);
|
||
|
||
// version2.03より前は、ディスクはセーブしていない
|
||
if (ver <= 0x0202) {
|
||
return TRUE;
|
||
}
|
||
|
||
// サイズをロード、照合
|
||
if (!fio->Read(&sz, sizeof(sz))) {
|
||
return FALSE;
|
||
}
|
||
if (sz != 52) {
|
||
return FALSE;
|
||
}
|
||
|
||
// バッファへロード
|
||
PROP_IMPORT(fio, buf.id);
|
||
PROP_IMPORT(fio, buf.ready);
|
||
PROP_IMPORT(fio, buf.writep);
|
||
PROP_IMPORT(fio, buf.readonly);
|
||
PROP_IMPORT(fio, buf.removable);
|
||
PROP_IMPORT(fio, buf.lock);
|
||
PROP_IMPORT(fio, buf.attn);
|
||
PROP_IMPORT(fio, buf.reset);
|
||
PROP_IMPORT(fio, buf.size);
|
||
PROP_IMPORT(fio, buf.blocks);
|
||
PROP_IMPORT(fio, buf.lun);
|
||
PROP_IMPORT(fio, buf.code);
|
||
PROP_IMPORT(fio, padding);
|
||
|
||
// パスをロード
|
||
if (!path.Load(fio, ver)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 必ずイジェクト
|
||
Eject(TRUE);
|
||
|
||
// IDが一致した場合のみ、移動
|
||
if (disk.id != buf.id) {
|
||
// セーブ時にMOでなかった。イジェクト状態を維持
|
||
return TRUE;
|
||
}
|
||
|
||
// 再オープンを試みる
|
||
if (!Open(path, FALSE)) {
|
||
// 再オープンできない。イジェクト状態を維持
|
||
return TRUE;
|
||
}
|
||
|
||
// Open内でディスクキャッシュは作成されている。プロパティのみ移動
|
||
if (!disk.readonly) {
|
||
disk.writep = buf.writep;
|
||
}
|
||
disk.lock = buf.lock;
|
||
disk.attn = buf.attn;
|
||
disk.reset = buf.reset;
|
||
disk.lun = buf.lun;
|
||
disk.code = buf.code;
|
||
|
||
// 正常にロードできた
|
||
return TRUE;
|
||
}
|
||
#endif // RASCSI
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// INQUIRY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIMO::Inquiry(
|
||
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
|
||
{
|
||
int size;
|
||
char rev[32];
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(buf);
|
||
ASSERT(cdb[0] == 0x12);
|
||
|
||
// EVPDチェック
|
||
if (cdb[1] & 0x01) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return FALSE;
|
||
}
|
||
|
||
// 基本データ
|
||
// buf[0] ... Optical Memory Device
|
||
// buf[1] ... リムーバブル
|
||
// buf[2] ... SCSI-2準拠のコマンド体系
|
||
// buf[3] ... SCSI-2準拠のInquiryレスポンス
|
||
// buf[4] ... Inquiry追加データ
|
||
memset(buf, 0, 8);
|
||
buf[0] = 0x07;
|
||
|
||
// SCSI-2 本の p.104 4.4.3 不当なロジカルユニットの処理
|
||
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
|
||
buf[0] = 0x7f;
|
||
}
|
||
|
||
buf[1] = 0x80;
|
||
buf[2] = 0x02;
|
||
buf[3] = 0x02;
|
||
buf[4] = 36 - 5; // 必須
|
||
|
||
// 空白で埋める
|
||
memset(&buf[8], 0x20, buf[4] - 3);
|
||
|
||
// ベンダ
|
||
memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE));
|
||
|
||
// 製品名
|
||
memcpy(&buf[16], "M2513A", 6);
|
||
|
||
// リビジョン(XM6のバージョンNo)
|
||
sprintf(rev, "0%01d%01d%01d",
|
||
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
|
||
memcpy(&buf[32], rev, 4);
|
||
|
||
// 返却できるデータのサイズ
|
||
size = (buf[4] + 5);
|
||
|
||
// 相手のバッファが少なければ制限する
|
||
if (size > (int)cdb[4]) {
|
||
size = (int)cdb[4];
|
||
}
|
||
|
||
// 成功
|
||
disk.code = DISK_NOERROR;
|
||
return size;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MODE SELECT
|
||
// ※disk.codeの影響を受けない
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSIMO::ModeSelect(const DWORD *cdb, const BYTE *buf, int length)
|
||
{
|
||
int page;
|
||
int size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
ASSERT(length >= 0);
|
||
|
||
// PF
|
||
if (cdb[1] & 0x10) {
|
||
// Mode Parameter header
|
||
if (length >= 12) {
|
||
// ブロックレングスのバイト数をチェック
|
||
size = 1 << disk.size;
|
||
if (buf[9] != (BYTE)(size >> 16) ||
|
||
buf[10] != (BYTE)(size >> 8) || buf[11] != (BYTE)size) {
|
||
// 今のところセクタ長の変更は許さない
|
||
disk.code = DISK_INVALIDPRM;
|
||
return FALSE;
|
||
}
|
||
buf += 12;
|
||
length -= 12;
|
||
}
|
||
|
||
// ページの解析
|
||
while (length > 0) {
|
||
// ページの取得
|
||
page = buf[0];
|
||
|
||
switch (page) {
|
||
// format device
|
||
case 0x03:
|
||
// 物理セクタのバイト数をチェック
|
||
size = 1 << disk.size;
|
||
if (buf[0xc] != (BYTE)(size >> 8) ||
|
||
buf[0xd] != (BYTE)size) {
|
||
// 今のところセクタ長の変更は許さない
|
||
disk.code = DISK_INVALIDPRM;
|
||
return FALSE;
|
||
}
|
||
break;
|
||
// vendor unique format
|
||
case 0x20:
|
||
// just ignore, for now
|
||
break;
|
||
|
||
// その他ページ
|
||
default:
|
||
break;
|
||
}
|
||
|
||
// 次のページへ
|
||
size = buf[1] + 2;
|
||
length -= size;
|
||
buf += size;
|
||
}
|
||
}
|
||
|
||
// とりあえずエラーは発生させない(MINIX)
|
||
disk.code = DISK_NOERROR;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// Vendor Unique Format Page 20h (MO)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIMO::AddVendor(int page, BOOL change, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// ページコード20h
|
||
if ((page != 0x20) && (page != 0x3f)) {
|
||
return 0;
|
||
}
|
||
|
||
// コード・レングスを設定
|
||
buf[0] = 0x20;
|
||
buf[1] = 0x0a;
|
||
|
||
// 変更可能領域はない
|
||
if (change) {
|
||
return 12;
|
||
}
|
||
|
||
/*
|
||
mode page code 20h - Vendor Unique Format Page
|
||
format mode XXh type 0
|
||
information: http://h20628.www2.hp.com/km-ext/kmcsdirect/emr_na-lpg28560-1.pdf
|
||
|
||
offset description
|
||
02h format mode
|
||
03h type of format (0)
|
||
04~07h size of user band (total sectors?)
|
||
08~09h size of spare band (spare sectors?)
|
||
0A~0Bh number of bands
|
||
|
||
actual value of each 3.5inches optical medium (grabbed by Fujitsu M2513EL)
|
||
|
||
128M 230M 540M 640M
|
||
---------------------------------------------------
|
||
size of user band 3CBFAh 6CF75h FE45Ch 4BC50h
|
||
size of spare band 0400h 0401h 08CAh 08C4h
|
||
number of bands 0001h 000Ah 0012h 000Bh
|
||
|
||
further information: http://r2089.blog36.fc2.com/blog-entry-177.html
|
||
*/
|
||
|
||
if (disk.ready) {
|
||
unsigned spare = 0;
|
||
unsigned bands = 0;
|
||
|
||
if (disk.size == 9) switch (disk.blocks) {
|
||
// 128MB
|
||
case 248826:
|
||
spare = 1024;
|
||
bands = 1;
|
||
break;
|
||
|
||
// 230MB
|
||
case 446325:
|
||
spare = 1025;
|
||
bands = 10;
|
||
break;
|
||
|
||
// 540MB
|
||
case 1041500:
|
||
spare = 2250;
|
||
bands = 18;
|
||
break;
|
||
}
|
||
|
||
if (disk.size == 11) switch (disk.blocks) {
|
||
// 640MB
|
||
case 310352:
|
||
spare = 2244;
|
||
bands = 11;
|
||
break;
|
||
|
||
// 1.3GB (lpproj: not tested with real device)
|
||
case 605846:
|
||
spare = 4437;
|
||
bands = 18;
|
||
break;
|
||
}
|
||
|
||
buf[2] = 0; // format mode
|
||
buf[3] = 0; // type of format
|
||
buf[4] = (BYTE)(disk.blocks >> 24);
|
||
buf[5] = (BYTE)(disk.blocks >> 16);
|
||
buf[6] = (BYTE)(disk.blocks >> 8);
|
||
buf[7] = (BYTE)disk.blocks;
|
||
buf[8] = (BYTE)(spare >> 8);
|
||
buf[9] = (BYTE)spare;
|
||
buf[10] = (BYTE)(bands >> 8);
|
||
buf[11] = (BYTE)bands;
|
||
}
|
||
|
||
return 12;
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// CDトラック
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
CDTrack::CDTrack(SCSICD *scsicd)
|
||
{
|
||
ASSERT(scsicd);
|
||
|
||
// 親となるCD-ROMデバイスを設定
|
||
cdrom = scsicd;
|
||
|
||
// トラック無効
|
||
valid = FALSE;
|
||
|
||
// その他のデータを初期化
|
||
track_no = -1;
|
||
first_lba = 0;
|
||
last_lba = 0;
|
||
audio = FALSE;
|
||
raw = FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// デストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
CDTrack::~CDTrack()
|
||
{
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 初期化
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL CDTrack::Init(int track, DWORD first, DWORD last)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(!valid);
|
||
ASSERT(track >= 1);
|
||
ASSERT(first < last);
|
||
|
||
// トラック番号を設定、有効化
|
||
track_no = track;
|
||
valid = TRUE;
|
||
|
||
// LBAを記憶
|
||
first_lba = first;
|
||
last_lba = last;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// パス設定
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL CDTrack::SetPath(BOOL cdda, const Filepath& path)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(valid);
|
||
|
||
// CD-DAか、データか
|
||
audio = cdda;
|
||
|
||
// パス記憶
|
||
imgpath = path;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// パス取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL CDTrack::GetPath(Filepath& path) const
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(valid);
|
||
|
||
// パスを返す
|
||
path = imgpath;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// インデックス追加
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL CDTrack::AddIndex(int index, DWORD lba)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(valid);
|
||
ASSERT(index > 0);
|
||
ASSERT(first_lba <= lba);
|
||
ASSERT(lba <= last_lba);
|
||
|
||
// 現在はインデックスはサポートしない
|
||
ASSERT(FALSE);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 開始LBA取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
DWORD FASTCALL CDTrack::GetFirst() const
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(valid);
|
||
ASSERT(first_lba < last_lba);
|
||
|
||
return first_lba;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 終端LBA取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
DWORD FASTCALL CDTrack::GetLast() const
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(valid);
|
||
ASSERT(first_lba < last_lba);
|
||
|
||
return last_lba;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ブロック数取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
DWORD FASTCALL CDTrack::GetBlocks() const
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(valid);
|
||
ASSERT(first_lba < last_lba);
|
||
|
||
// 開始LBAと最終LBAから算出
|
||
return (DWORD)(last_lba - first_lba + 1);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// トラック番号取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL CDTrack::GetTrackNo() const
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(valid);
|
||
ASSERT(track_no >= 1);
|
||
|
||
return track_no;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 有効なブロックか
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL CDTrack::IsValid(DWORD lba) const
|
||
{
|
||
ASSERT(this);
|
||
|
||
// トラック自体が無効なら、FALSE
|
||
if (!valid) {
|
||
return FALSE;
|
||
}
|
||
|
||
// firstより前なら、FALSE
|
||
if (lba < first_lba) {
|
||
return FALSE;
|
||
}
|
||
|
||
// lastより後なら、FALSE
|
||
if (last_lba < lba) {
|
||
return FALSE;
|
||
}
|
||
|
||
// このトラック
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// オーディオトラックか
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL CDTrack::IsAudio() const
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(valid);
|
||
|
||
return audio;
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// CD-DAバッファ
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
CDDABuf::CDDABuf()
|
||
{
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// デストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
CDDABuf::~CDDABuf()
|
||
{
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// SCSI CD-ROM
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
SCSICD::SCSICD() : Disk()
|
||
{
|
||
int i;
|
||
|
||
// SCSI CD-ROM
|
||
disk.id = MAKEID('S', 'C', 'C', 'D');
|
||
|
||
// リムーバブル、書込み禁止
|
||
disk.removable = TRUE;
|
||
disk.writep = TRUE;
|
||
|
||
// RAW形式でない
|
||
rawfile = FALSE;
|
||
|
||
// フレーム初期化
|
||
frame = 0;
|
||
|
||
// トラック初期化
|
||
for (i = 0; i < TrackMax; i++) {
|
||
track[i] = NULL;
|
||
}
|
||
tracks = 0;
|
||
dataindex = -1;
|
||
audioindex = -1;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// デストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
SCSICD::~SCSICD()
|
||
{
|
||
// トラッククリア
|
||
ClearTrack();
|
||
}
|
||
|
||
#ifndef RASCSI
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ロード
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSICD::Load(Fileio *fio, int ver)
|
||
{
|
||
DWORD sz;
|
||
disk_t buf;
|
||
DWORD padding;
|
||
Filepath path;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fio);
|
||
ASSERT(ver >= 0x0200);
|
||
|
||
// version2.03より前は、ディスクはセーブしていない
|
||
if (ver <= 0x0202) {
|
||
return TRUE;
|
||
}
|
||
|
||
// サイズをロード、照合
|
||
if (!fio->Read(&sz, sizeof(sz))) {
|
||
return FALSE;
|
||
}
|
||
if (sz != 52) {
|
||
return FALSE;
|
||
}
|
||
|
||
// バッファへロード
|
||
PROP_IMPORT(fio, buf.id);
|
||
PROP_IMPORT(fio, buf.ready);
|
||
PROP_IMPORT(fio, buf.writep);
|
||
PROP_IMPORT(fio, buf.readonly);
|
||
PROP_IMPORT(fio, buf.removable);
|
||
PROP_IMPORT(fio, buf.lock);
|
||
PROP_IMPORT(fio, buf.attn);
|
||
PROP_IMPORT(fio, buf.reset);
|
||
PROP_IMPORT(fio, buf.size);
|
||
PROP_IMPORT(fio, buf.blocks);
|
||
PROP_IMPORT(fio, buf.lun);
|
||
PROP_IMPORT(fio, buf.code);
|
||
PROP_IMPORT(fio, padding);
|
||
|
||
// パスをロード
|
||
if (!path.Load(fio, ver)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 必ずイジェクト
|
||
Eject(TRUE);
|
||
|
||
// IDが一致した場合のみ、移動
|
||
if (disk.id != buf.id) {
|
||
// セーブ時にCD-ROMでなかった。イジェクト状態を維持
|
||
return TRUE;
|
||
}
|
||
|
||
// 再オープンを試みる
|
||
if (!Open(path, FALSE)) {
|
||
// 再オープンできない。イジェクト状態を維持
|
||
return TRUE;
|
||
}
|
||
|
||
// Open内でディスクキャッシュは作成されている。プロパティのみ移動
|
||
if (!disk.readonly) {
|
||
disk.writep = buf.writep;
|
||
}
|
||
disk.lock = buf.lock;
|
||
disk.attn = buf.attn;
|
||
disk.reset = buf.reset;
|
||
disk.lun = buf.lun;
|
||
disk.code = buf.code;
|
||
|
||
// 再度、ディスクキャッシュを破棄
|
||
if (disk.dcache) {
|
||
delete disk.dcache;
|
||
disk.dcache = NULL;
|
||
}
|
||
disk.dcache = NULL;
|
||
|
||
// 暫定
|
||
disk.blocks = track[0]->GetBlocks();
|
||
if (disk.blocks > 0) {
|
||
// ディスクキャッシュを作り直す
|
||
track[0]->GetPath(path);
|
||
disk.dcache = new DiskCache(path, disk.size, disk.blocks);
|
||
disk.dcache->SetRawMode(rawfile);
|
||
|
||
// データインデックスを再設定
|
||
dataindex = 0;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
#endif // RASCSI
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// オープン
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSICD::Open(const Filepath& path, BOOL attn)
|
||
{
|
||
Fileio fio;
|
||
off64_t size;
|
||
TCHAR file[5];
|
||
|
||
ASSERT(this);
|
||
ASSERT(!disk.ready);
|
||
|
||
// 初期化、トラッククリア
|
||
disk.blocks = 0;
|
||
rawfile = FALSE;
|
||
ClearTrack();
|
||
|
||
// 読み込みオープンが必要
|
||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 物理CDアクセスならクローズして委譲する
|
||
if (path.GetPath()[0] == _T('\\')) {
|
||
// クローズ
|
||
fio.Close();
|
||
|
||
// 物理CDオープン
|
||
if (!OpenPhysical(path)) {
|
||
return FALSE;
|
||
}
|
||
} else {
|
||
// サイズ取得
|
||
size = fio.GetFileSize();
|
||
if (size <= 4) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
|
||
// CUEシートか、ISOファイルかの判定を行う
|
||
fio.Read(file, 4);
|
||
file[4] = '\0';
|
||
fio.Close();
|
||
|
||
// FILEで始まっていれば、CUEシートとみなす
|
||
if (xstrncasecmp(file, _T("FILE"), 4) == 0) {
|
||
// CUEとしてオープン
|
||
if (!OpenCue(path)) {
|
||
return FALSE;
|
||
}
|
||
} else {
|
||
// ISOとしてオープン
|
||
if (!OpenIso(path)) {
|
||
return FALSE;
|
||
}
|
||
}
|
||
}
|
||
|
||
// オープン成功
|
||
ASSERT(disk.blocks > 0);
|
||
disk.size = 11;
|
||
|
||
// 基本クラス
|
||
Disk::Open(path);
|
||
|
||
// RAWフラグを設定
|
||
ASSERT(disk.dcache);
|
||
disk.dcache->SetRawMode(rawfile);
|
||
|
||
// ROMメディアなので、書き込みはできない
|
||
disk.writep = TRUE;
|
||
|
||
// レディならアテンション
|
||
if (disk.ready && attn) {
|
||
disk.attn = TRUE;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// オープン(CUE)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSICD::OpenCue(const Filepath& /*path*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// 常に失敗
|
||
return FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// オープン(ISO)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSICD::OpenIso(const Filepath& path)
|
||
{
|
||
Fileio fio;
|
||
off64_t size;
|
||
BYTE header[12];
|
||
BYTE sync[12];
|
||
|
||
ASSERT(this);
|
||
|
||
// 読み込みオープンが必要
|
||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// サイズ取得
|
||
size = fio.GetFileSize();
|
||
if (size < 0x800) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
|
||
// 最初の12バイトを読み取って、クローズ
|
||
if (!fio.Read(header, sizeof(header))) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
|
||
// RAW形式かチェック
|
||
memset(sync, 0xff, sizeof(sync));
|
||
sync[0] = 0x00;
|
||
sync[11] = 0x00;
|
||
rawfile = FALSE;
|
||
if (memcmp(header, sync, sizeof(sync)) == 0) {
|
||
// 00,FFx10,00なので、RAW形式と推定される
|
||
if (!fio.Read(header, 4)) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
|
||
// MODE1/2048またはMODE1/2352のみサポート
|
||
if (header[3] != 0x01) {
|
||
// モードが違う
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
|
||
// RAWファイルに設定
|
||
rawfile = TRUE;
|
||
}
|
||
fio.Close();
|
||
|
||
if (rawfile) {
|
||
// サイズが2536の倍数で、700MB以下であること
|
||
if (size % 0x930) {
|
||
return FALSE;
|
||
}
|
||
if (size > 912579600) {
|
||
return FALSE;
|
||
}
|
||
|
||
// ブロック数を設定
|
||
disk.blocks = (DWORD)(size / 0x930);
|
||
} else {
|
||
// サイズが2048の倍数で、700MB以下であること
|
||
if (size & 0x7ff) {
|
||
return FALSE;
|
||
}
|
||
if (size > 0x2bed5000) {
|
||
return FALSE;
|
||
}
|
||
|
||
// ブロック数を設定
|
||
disk.blocks = (DWORD)(size >> 11);
|
||
}
|
||
|
||
// データトラック1つのみ作成
|
||
ASSERT(!track[0]);
|
||
track[0] = new CDTrack(this);
|
||
track[0]->Init(1, 0, disk.blocks - 1);
|
||
track[0]->SetPath(FALSE, path);
|
||
tracks = 1;
|
||
dataindex = 0;
|
||
|
||
// オープン成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// オープン(Physical)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSICD::OpenPhysical(const Filepath& path)
|
||
{
|
||
Fileio fio;
|
||
off64_t size;
|
||
|
||
ASSERT(this);
|
||
|
||
// 読み込みオープンが必要
|
||
if (!fio.Open(path, Fileio::ReadOnly)) {
|
||
return FALSE;
|
||
}
|
||
|
||
// サイズ取得
|
||
size = fio.GetFileSize();
|
||
if (size < 0x800) {
|
||
fio.Close();
|
||
return FALSE;
|
||
}
|
||
|
||
// クローズ
|
||
fio.Close();
|
||
|
||
// サイズが2048の倍数で、700MB以下であること
|
||
if (size & 0x7ff) {
|
||
return FALSE;
|
||
}
|
||
if (size > 0x2bed5000) {
|
||
return FALSE;
|
||
}
|
||
|
||
// ブロック数を設定
|
||
disk.blocks = (DWORD)(size >> 11);
|
||
|
||
// データトラック1つのみ作成
|
||
ASSERT(!track[0]);
|
||
track[0] = new CDTrack(this);
|
||
track[0]->Init(1, 0, disk.blocks - 1);
|
||
track[0]->SetPath(FALSE, path);
|
||
tracks = 1;
|
||
dataindex = 0;
|
||
|
||
// オープン成功
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// INQUIRY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSICD::Inquiry(
|
||
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
|
||
{
|
||
char rev[32];
|
||
int size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(buf);
|
||
ASSERT(cdb[0] == 0x12);
|
||
|
||
// EVPDチェック
|
||
if (cdb[1] & 0x01) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return FALSE;
|
||
}
|
||
|
||
// 基本データ
|
||
// buf[0] ... CD-ROM Device
|
||
// buf[1] ... リムーバブル
|
||
// buf[2] ... SCSI-2準拠のコマンド体系
|
||
// buf[3] ... SCSI-2準拠のInquiryレスポンス
|
||
// buf[4] ... Inquiry追加データ
|
||
memset(buf, 0, 8);
|
||
buf[0] = 0x05;
|
||
|
||
// SCSI-2 本の p.104 4.4.3 不当なロジカルユニットの処理
|
||
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
|
||
buf[0] = 0x7f;
|
||
}
|
||
|
||
buf[1] = 0x80;
|
||
buf[2] = 0x02;
|
||
buf[3] = 0x02;
|
||
buf[4] = 36 - 5; // 必須
|
||
|
||
// 空白で埋める
|
||
memset(&buf[8], 0x20, buf[4] - 3);
|
||
|
||
// ベンダ
|
||
memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE));
|
||
|
||
// 製品名
|
||
memcpy(&buf[16], "CD-ROM CDU-55S", 14);
|
||
|
||
// リビジョン(XM6のバージョンNo)
|
||
sprintf(rev, "0%01d%01d%01d",
|
||
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
|
||
memcpy(&buf[32], rev, 4);
|
||
|
||
// 返却できるデータのサイズ
|
||
size = (buf[4] + 5);
|
||
|
||
// 相手のバッファが少なければ制限する
|
||
if (size > (int)cdb[4]) {
|
||
size = (int)cdb[4];
|
||
}
|
||
|
||
// 成功
|
||
disk.code = DISK_NOERROR;
|
||
return size;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// READ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSICD::Read(BYTE *buf, DWORD block)
|
||
{
|
||
int index;
|
||
Filepath path;
|
||
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
// 状態チェック
|
||
if (!CheckReady()) {
|
||
return 0;
|
||
}
|
||
|
||
// トラック検索
|
||
index = SearchTrack(block);
|
||
|
||
// 無効なら、範囲外
|
||
if (index < 0) {
|
||
disk.code = DISK_INVALIDLBA;
|
||
return 0;
|
||
}
|
||
ASSERT(track[index]);
|
||
|
||
// 現在のデータトラックと異なっていれば
|
||
if (dataindex != index) {
|
||
// 現在のディスクキャッシュを削除(Saveの必要はない)
|
||
delete disk.dcache;
|
||
disk.dcache = NULL;
|
||
|
||
// ブロック数を再設定
|
||
disk.blocks = track[index]->GetBlocks();
|
||
ASSERT(disk.blocks > 0);
|
||
|
||
// ディスクキャッシュを作り直す
|
||
track[index]->GetPath(path);
|
||
disk.dcache = new DiskCache(path, disk.size, disk.blocks);
|
||
disk.dcache->SetRawMode(rawfile);
|
||
|
||
// データインデックスを再設定
|
||
dataindex = index;
|
||
}
|
||
|
||
// 基本クラス
|
||
ASSERT(dataindex >= 0);
|
||
return Disk::Read(buf, block);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// READ TOC
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSICD::ReadToc(const DWORD *cdb, BYTE *buf)
|
||
{
|
||
int last;
|
||
int index;
|
||
int length;
|
||
int loop;
|
||
int i;
|
||
BOOL msf;
|
||
DWORD lba;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(cdb[0] == 0x43);
|
||
ASSERT(buf);
|
||
|
||
// レディチェック
|
||
if (!CheckReady()) {
|
||
return 0;
|
||
}
|
||
|
||
// レディであるなら、トラックが最低1つ以上存在する
|
||
ASSERT(tracks > 0);
|
||
ASSERT(track[0]);
|
||
|
||
// アロケーションレングス取得、バッファクリア
|
||
length = cdb[7] << 8;
|
||
length |= cdb[8];
|
||
memset(buf, 0, length);
|
||
|
||
// MSFフラグ取得
|
||
if (cdb[1] & 0x02) {
|
||
msf = TRUE;
|
||
} else {
|
||
msf = FALSE;
|
||
}
|
||
|
||
// 最終トラック番号を取得、チェック
|
||
last = track[tracks - 1]->GetTrackNo();
|
||
if ((int)cdb[6] > last) {
|
||
// ただしAAは除外
|
||
if (cdb[6] != 0xaa) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
// 開始インデックスをチェック
|
||
index = 0;
|
||
if (cdb[6] != 0x00) {
|
||
// トラック番号が一致するまで、トラックを進める
|
||
while (track[index]) {
|
||
if ((int)cdb[6] == track[index]->GetTrackNo()) {
|
||
break;
|
||
}
|
||
index++;
|
||
}
|
||
|
||
// 見つからなければAAか、内部エラー
|
||
if (!track[index]) {
|
||
if (cdb[6] == 0xaa) {
|
||
// AAなので、最終LBA+1を返す
|
||
buf[0] = 0x00;
|
||
buf[1] = 0x0a;
|
||
buf[2] = (BYTE)track[0]->GetTrackNo();
|
||
buf[3] = (BYTE)last;
|
||
buf[6] = 0xaa;
|
||
lba = track[tracks - 1]->GetLast() + 1;
|
||
if (msf) {
|
||
LBAtoMSF(lba, &buf[8]);
|
||
} else {
|
||
buf[10] = (BYTE)(lba >> 8);
|
||
buf[11] = (BYTE)lba;
|
||
}
|
||
return length;
|
||
}
|
||
|
||
// それ以外はエラー
|
||
disk.code = DISK_INVALIDCDB;
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
// 今回返すトラックディスクリプタの個数(ループ数)
|
||
loop = last - track[index]->GetTrackNo() + 1;
|
||
ASSERT(loop >= 1);
|
||
|
||
// ヘッダ作成
|
||
buf[0] = (BYTE)(((loop << 3) + 2) >> 8);
|
||
buf[1] = (BYTE)((loop << 3) + 2);
|
||
buf[2] = (BYTE)track[0]->GetTrackNo();
|
||
buf[3] = (BYTE)last;
|
||
buf += 4;
|
||
|
||
// ループ
|
||
for (i = 0; i < loop; i++) {
|
||
// ADRとControl
|
||
if (track[index]->IsAudio()) {
|
||
// オーディオトラック
|
||
buf[1] = 0x10;
|
||
} else {
|
||
// データトラック
|
||
buf[1] = 0x14;
|
||
}
|
||
|
||
// トラック番号
|
||
buf[2] = (BYTE)track[index]->GetTrackNo();
|
||
|
||
// トラックアドレス
|
||
if (msf) {
|
||
LBAtoMSF(track[index]->GetFirst(), &buf[4]);
|
||
} else {
|
||
buf[6] = (BYTE)(track[index]->GetFirst() >> 8);
|
||
buf[7] = (BYTE)(track[index]->GetFirst());
|
||
}
|
||
|
||
// バッファとインデックスを進める
|
||
buf += 8;
|
||
index++;
|
||
}
|
||
|
||
// アロケーションレングスだけ必ず返す
|
||
return length;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// PLAY AUDIO
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSICD::PlayAudio(const DWORD* /*cdb*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
disk.code = DISK_INVALIDCDB;
|
||
return FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// PLAY AUDIO MSF
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSICD::PlayAudioMSF(const DWORD* /*cdb*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
disk.code = DISK_INVALIDCDB;
|
||
return FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// PLAY AUDIO TRACK
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSICD::PlayAudioTrack(const DWORD* /*cdb*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
disk.code = DISK_INVALIDCDB;
|
||
return FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// LBA→MSF変換
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSICD::LBAtoMSF(DWORD lba, BYTE *msf) const
|
||
{
|
||
DWORD m;
|
||
DWORD s;
|
||
DWORD f;
|
||
|
||
ASSERT(this);
|
||
|
||
// 75、75*60でそれぞれ余りを出す
|
||
m = lba / (75 * 60);
|
||
s = lba % (75 * 60);
|
||
f = s % 75;
|
||
s /= 75;
|
||
|
||
// 基点はM=0,S=2,F=0
|
||
s += 2;
|
||
if (s >= 60) {
|
||
s -= 60;
|
||
m++;
|
||
}
|
||
|
||
// 格納
|
||
ASSERT(m < 0x100);
|
||
ASSERT(s < 60);
|
||
ASSERT(f < 75);
|
||
msf[0] = 0x00;
|
||
msf[1] = (BYTE)m;
|
||
msf[2] = (BYTE)s;
|
||
msf[3] = (BYTE)f;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MSF→LBA変換
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
DWORD FASTCALL SCSICD::MSFtoLBA(const BYTE *msf) const
|
||
{
|
||
DWORD lba;
|
||
|
||
ASSERT(this);
|
||
ASSERT(msf[2] < 60);
|
||
ASSERT(msf[3] < 75);
|
||
|
||
// 1, 75, 75*60の倍数で合算
|
||
lba = msf[1];
|
||
lba *= 60;
|
||
lba += msf[2];
|
||
lba *= 75;
|
||
lba += msf[3];
|
||
|
||
// 基点はM=0,S=2,F=0なので、150を引く
|
||
lba -= 150;
|
||
|
||
return lba;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// トラッククリア
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSICD::ClearTrack()
|
||
{
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
|
||
// トラックオブジェクトを削除
|
||
for (i = 0; i < TrackMax; i++) {
|
||
if (track[i]) {
|
||
delete track[i];
|
||
track[i] = NULL;
|
||
}
|
||
}
|
||
|
||
// トラック数0
|
||
tracks = 0;
|
||
|
||
// データ、オーディオとも設定なし
|
||
dataindex = -1;
|
||
audioindex = -1;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// トラック検索
|
||
// ※見つからなければ-1を返す
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSICD::SearchTrack(DWORD lba) const
|
||
{
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
|
||
// トラックループ
|
||
for (i = 0; i < tracks; i++) {
|
||
// トラックに聞く
|
||
ASSERT(track[i]);
|
||
if (track[i]->IsValid(lba)) {
|
||
return i;
|
||
}
|
||
}
|
||
|
||
// 見つからなかった
|
||
return -1;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// フレーム通知
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSICD::NextFrame()
|
||
{
|
||
ASSERT(this);
|
||
ASSERT((frame >= 0) && (frame < 75));
|
||
|
||
// フレームを0~74の範囲で設定
|
||
frame = (frame + 1) % 75;
|
||
|
||
// 1周したらFALSE
|
||
if (frame != 0) {
|
||
return TRUE;
|
||
} else {
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// CD-DAバッファ取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSICD::GetBuf(
|
||
DWORD* /*buffer*/, int /*samples*/, DWORD /*rate*/)
|
||
{
|
||
ASSERT(this);
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// SCSI ホストブリッジ
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
SCSIBR::SCSIBR() : Disk()
|
||
{
|
||
// ホストブリッジ
|
||
disk.id = MAKEID('S', 'C', 'B', 'R');
|
||
|
||
#if defined(RASCSI) && !defined(BAREMETAL)
|
||
// TAPドライバ生成
|
||
tap = new CTapDriver();
|
||
m_bTapEnable = tap->Init();
|
||
|
||
// MACアドレスを生成
|
||
memset(mac_addr, 0x00, 6);
|
||
if (m_bTapEnable) {
|
||
tap->GetMacAddr(mac_addr);
|
||
mac_addr[5]++;
|
||
}
|
||
|
||
// パケット受信フラグオフ
|
||
packet_enable = FALSE;
|
||
#endif // RASCSI && !BAREMETAL
|
||
|
||
// ホストファイルシステム生成
|
||
fs = new CFileSys();
|
||
fs->Reset();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// デストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
SCSIBR::~SCSIBR()
|
||
{
|
||
#if defined(RASCSI) && !defined(BAREMETAL)
|
||
// TAPドライバ解放
|
||
if (tap) {
|
||
tap->Cleanup();
|
||
delete tap;
|
||
}
|
||
#endif // RASCSI && !BAREMETAL
|
||
|
||
// ホストファイルシステム解放
|
||
if (fs) {
|
||
fs->Reset();
|
||
delete fs;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// INQUIRY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIBR::Inquiry(
|
||
const DWORD *cdb, BYTE *buf, DWORD major, DWORD minor)
|
||
{
|
||
char rev[32];
|
||
int size;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(buf);
|
||
ASSERT(cdb[0] == 0x12);
|
||
|
||
// EVPDチェック
|
||
if (cdb[1] & 0x01) {
|
||
disk.code = DISK_INVALIDCDB;
|
||
return FALSE;
|
||
}
|
||
|
||
// 基本データ
|
||
// buf[0] ... Communication Device
|
||
// buf[2] ... SCSI-2準拠のコマンド体系
|
||
// buf[3] ... SCSI-2準拠のInquiryレスポンス
|
||
// buf[4] ... Inquiry追加データ
|
||
memset(buf, 0, 8);
|
||
buf[0] = 0x09;
|
||
|
||
// SCSI-2 本の p.104 4.4.3 不当なロジカルユニットの処理
|
||
if (((cdb[1] >> 5) & 0x07) != disk.lun) {
|
||
buf[0] = 0x7f;
|
||
}
|
||
|
||
buf[2] = 0x02;
|
||
buf[3] = 0x02;
|
||
buf[4] = 36 - 5 + 8; // 必須 + 8バイト拡張
|
||
|
||
// 空白で埋める
|
||
memset(&buf[8], 0x20, buf[4] - 3);
|
||
|
||
// ベンダ
|
||
memcpy(&buf[8], BENDER_SIGNATURE, strlen(BENDER_SIGNATURE));
|
||
|
||
// 製品名
|
||
memcpy(&buf[16], "RASCSI BRIDGE", 13);
|
||
|
||
// リビジョン(XM6のバージョンNo)
|
||
sprintf(rev, "0%01d%01d%01d",
|
||
(int)major, (int)(minor >> 4), (int)(minor & 0x0f));
|
||
memcpy(&buf[32], rev, 4);
|
||
|
||
// オプション機能有効フラグ
|
||
buf[36] = '0';
|
||
|
||
#if defined(RASCSI) && !defined(BAREMETAL)
|
||
// TAP有効
|
||
if (m_bTapEnable) {
|
||
buf[37] = '1';
|
||
}
|
||
#endif // RASCSI && !BAREMETAL
|
||
|
||
// CFileSys有効
|
||
buf[38] = '1';
|
||
|
||
// 返却できるデータのサイズ
|
||
size = (buf[4] + 5);
|
||
|
||
// 相手のバッファが少なければ制限する
|
||
if (size > (int)cdb[4]) {
|
||
size = (int)cdb[4];
|
||
}
|
||
|
||
// 成功
|
||
disk.code = DISK_NOERROR;
|
||
return size;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// TEST UNIT READY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSIBR::TestUnitReady(const DWORD* /*cdb*/)
|
||
{
|
||
ASSERT(this);
|
||
|
||
// TEST UNIT READY成功
|
||
disk.code = DISK_NOERROR;
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// GET MESSAGE(10)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIBR::GetMessage10(const DWORD *cdb, BYTE *buf)
|
||
{
|
||
int type;
|
||
int phase;
|
||
#if defined(RASCSI) && !defined(BAREMETAL)
|
||
int func;
|
||
int total_len;
|
||
int i;
|
||
#endif // RASCSI && !BAREMETAL
|
||
|
||
ASSERT(this);
|
||
|
||
// タイプ
|
||
type = cdb[2];
|
||
|
||
#if defined(RASCSI) && !defined(BAREMETAL)
|
||
// 機能番号
|
||
func = cdb[3];
|
||
#endif // RASCSI && !BAREMETAL
|
||
|
||
// フェーズ
|
||
phase = cdb[9];
|
||
|
||
switch (type) {
|
||
#if defined(RASCSI) && !defined(BAREMETAL)
|
||
case 1: // イーサネット
|
||
// TAP無効なら処理しない
|
||
if (!m_bTapEnable) {
|
||
return 0;
|
||
}
|
||
|
||
switch (func) {
|
||
case 0: // MACアドレス取得
|
||
return GetMacAddr(buf);
|
||
|
||
case 1: // 受信パケット取得(サイズ/バッファ別)
|
||
if (phase == 0) {
|
||
// パケットサイズ取得
|
||
ReceivePacket();
|
||
buf[0] = (BYTE)(packet_len >> 8);
|
||
buf[1] = (BYTE)packet_len;
|
||
return 2;
|
||
} else {
|
||
// パケットデータ取得
|
||
GetPacketBuf(buf);
|
||
return packet_len;
|
||
}
|
||
|
||
case 2: // 受信パケット取得(サイズ+バッファ同時)
|
||
ReceivePacket();
|
||
buf[0] = (BYTE)(packet_len >> 8);
|
||
buf[1] = (BYTE)packet_len;
|
||
GetPacketBuf(&buf[2]);
|
||
return packet_len + 2;
|
||
|
||
case 3: // 複数パケット同時取得(サイズ+バッファ同時)
|
||
// パケット数の上限は現状10個に決め打ち
|
||
// これ以上増やしてもあまり速くならない?
|
||
total_len = 0;
|
||
for (i = 0; i < 10; i++) {
|
||
ReceivePacket();
|
||
*buf++ = (BYTE)(packet_len >> 8);
|
||
*buf++ = (BYTE)packet_len;
|
||
total_len += 2;
|
||
if (packet_len == 0)
|
||
break;
|
||
GetPacketBuf(buf);
|
||
buf += packet_len;
|
||
total_len += packet_len;
|
||
}
|
||
return total_len;
|
||
}
|
||
break;
|
||
#endif // RASCSI && !BAREMETAL
|
||
|
||
case 2: // ホストドライブ
|
||
switch (phase) {
|
||
case 0: // 結果コード取得
|
||
return ReadFsResult(buf);
|
||
|
||
case 1: // 返却データ取得
|
||
return ReadFsOut(buf);
|
||
|
||
case 2: // 返却追加データ取得
|
||
return ReadFsOpt(buf);
|
||
}
|
||
break;
|
||
}
|
||
|
||
// エラー
|
||
ASSERT(FALSE);
|
||
return 0;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// SEND MESSAGE(10)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSIBR::SendMessage10(const DWORD *cdb, BYTE *buf)
|
||
{
|
||
int type;
|
||
int func;
|
||
int phase;
|
||
int len;
|
||
|
||
ASSERT(this);
|
||
ASSERT(cdb);
|
||
ASSERT(buf);
|
||
|
||
// タイプ
|
||
type = cdb[2];
|
||
|
||
// 機能番号
|
||
func = cdb[3];
|
||
|
||
// フェーズ
|
||
phase = cdb[9];
|
||
|
||
// ライト数を取得
|
||
len = cdb[6];
|
||
len <<= 8;
|
||
len |= cdb[7];
|
||
len <<= 8;
|
||
len |= cdb[8];
|
||
|
||
switch (type) {
|
||
#if defined(RASCSI) && !defined(BAREMETAL)
|
||
case 1: // イーサネット
|
||
// TAP無効なら処理しない
|
||
if (!m_bTapEnable) {
|
||
return FALSE;
|
||
}
|
||
|
||
switch (func) {
|
||
case 0: // MACアドレス設定
|
||
SetMacAddr(buf);
|
||
return TRUE;
|
||
|
||
case 1: // パケット送信
|
||
SendPacket(buf, len);
|
||
return TRUE;
|
||
}
|
||
break;
|
||
#endif // RASCSI && !BAREMETAL
|
||
|
||
case 2: // ホストドライブ
|
||
switch (phase) {
|
||
case 0: // コマンド発行
|
||
WriteFs(func, buf);
|
||
return TRUE;
|
||
|
||
case 1: // 追加データ書き込み
|
||
WriteFsOpt(buf, len);
|
||
return TRUE;
|
||
}
|
||
break;
|
||
}
|
||
|
||
// エラー
|
||
ASSERT(FALSE);
|
||
return FALSE;
|
||
}
|
||
|
||
#if defined(RASCSI) && !defined(BAREMETAL)
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MACアドレス取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIBR::GetMacAddr(BYTE *mac)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(mac);
|
||
|
||
memcpy(mac, mac_addr, 6);
|
||
return 6;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MACアドレス設定
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::SetMacAddr(BYTE *mac)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(mac);
|
||
|
||
memcpy(mac_addr, mac, 6);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// パケット受信
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::ReceivePacket()
|
||
{
|
||
static const BYTE bcast_addr[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||
|
||
ASSERT(this);
|
||
ASSERT(tap);
|
||
|
||
// 前のパケットが受信されていない
|
||
if (packet_enable) {
|
||
return;
|
||
}
|
||
|
||
// パケット受信
|
||
packet_len = tap->Rx(packet_buf);
|
||
|
||
// 受信パケットか検査
|
||
if (memcmp(packet_buf, mac_addr, 6) != 0) {
|
||
if (memcmp(packet_buf, bcast_addr, 6) != 0) {
|
||
packet_len = 0;
|
||
return;
|
||
}
|
||
}
|
||
|
||
// バッファサイズを越えたら捨てる
|
||
if (packet_len > 2048) {
|
||
packet_len = 0;
|
||
return;
|
||
}
|
||
|
||
// 受信バッファに格納
|
||
if (packet_len > 0) {
|
||
packet_enable = TRUE;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// パケット取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::GetPacketBuf(BYTE *buf)
|
||
{
|
||
int len;
|
||
|
||
ASSERT(this);
|
||
ASSERT(tap);
|
||
ASSERT(buf);
|
||
|
||
// サイズ制限
|
||
len = packet_len;
|
||
if (len > 2048) {
|
||
len = 2048;
|
||
}
|
||
|
||
// コピー
|
||
memcpy(buf, packet_buf, len);
|
||
|
||
// 受信済み
|
||
packet_enable = FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// パケット送信
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::SendPacket(BYTE *buf, int len)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(tap);
|
||
ASSERT(buf);
|
||
|
||
tap->Tx(buf, len);
|
||
}
|
||
#endif // RASCSI && !BAREMETAL
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $40 - デバイス起動
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_InitDevice(BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
fs->Reset();
|
||
fsresult = fs->InitDevice((Human68k::argument_t*)buf);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $41 - ディレクトリチェック
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_CheckDir(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
Human68k::namests_t *pNamests;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pNamests = (Human68k::namests_t*)&buf[i];
|
||
i += sizeof(Human68k::namests_t);
|
||
|
||
fsresult = fs->CheckDir(nUnit, pNamests);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $42 - ディレクトリ作成
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_MakeDir(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
Human68k::namests_t *pNamests;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pNamests = (Human68k::namests_t*)&buf[i];
|
||
i += sizeof(Human68k::namests_t);
|
||
|
||
fsresult = fs->MakeDir(nUnit, pNamests);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $43 - ディレクトリ削除
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_RemoveDir(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
Human68k::namests_t *pNamests;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pNamests = (Human68k::namests_t*)&buf[i];
|
||
i += sizeof(Human68k::namests_t);
|
||
|
||
fsresult = fs->RemoveDir(nUnit, pNamests);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $44 - ファイル名変更
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Rename(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
Human68k::namests_t *pNamests;
|
||
Human68k::namests_t* pNamestsNew;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pNamests = (Human68k::namests_t*)&buf[i];
|
||
i += sizeof(Human68k::namests_t);
|
||
|
||
pNamestsNew = (Human68k::namests_t*)&buf[i];
|
||
i += sizeof(Human68k::namests_t);
|
||
|
||
fsresult = fs->Rename(nUnit, pNamests, pNamestsNew);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $45 - ファイル削除
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Delete(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
Human68k::namests_t *pNamests;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pNamests = (Human68k::namests_t*)&buf[i];
|
||
i += sizeof(Human68k::namests_t);
|
||
|
||
fsresult = fs->Delete(nUnit, pNamests);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $46 - ファイル属性取得/設定
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Attribute(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
Human68k::namests_t *pNamests;
|
||
DWORD nHumanAttribute;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pNamests = (Human68k::namests_t*)&buf[i];
|
||
i += sizeof(Human68k::namests_t);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nHumanAttribute = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
fsresult = fs->Attribute(nUnit, pNamests, nHumanAttribute);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $47 - ファイル検索
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Files(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD nKey;
|
||
Human68k::namests_t *pNamests;
|
||
Human68k::files_t *files;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nKey = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pNamests = (Human68k::namests_t*)&buf[i];
|
||
i += sizeof(Human68k::namests_t);
|
||
|
||
files = (Human68k::files_t*)&buf[i];
|
||
i += sizeof(Human68k::files_t);
|
||
|
||
files->sector = ntohl(files->sector);
|
||
files->offset = ntohs(files->offset);
|
||
files->time = ntohs(files->time);
|
||
files->date = ntohs(files->date);
|
||
files->size = ntohl(files->size);
|
||
|
||
fsresult = fs->Files(nUnit, nKey, pNamests, files);
|
||
|
||
files->sector = htonl(files->sector);
|
||
files->offset = htons(files->offset);
|
||
files->time = htons(files->time);
|
||
files->date = htons(files->date);
|
||
files->size = htonl(files->size);
|
||
|
||
i = 0;
|
||
memcpy(&fsout[i], files, sizeof(Human68k::files_t));
|
||
i += sizeof(Human68k::files_t);
|
||
|
||
fsoutlen = i;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $48 - ファイル次検索
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_NFiles(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD nKey;
|
||
Human68k::files_t *files;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nKey = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
files = (Human68k::files_t*)&buf[i];
|
||
i += sizeof(Human68k::files_t);
|
||
|
||
files->sector = ntohl(files->sector);
|
||
files->offset = ntohs(files->offset);
|
||
files->time = ntohs(files->time);
|
||
files->date = ntohs(files->date);
|
||
files->size = ntohl(files->size);
|
||
|
||
fsresult = fs->NFiles(nUnit, nKey, files);
|
||
|
||
files->sector = htonl(files->sector);
|
||
files->offset = htons(files->offset);
|
||
files->time = htons(files->time);
|
||
files->date = htons(files->date);
|
||
files->size = htonl(files->size);
|
||
|
||
i = 0;
|
||
memcpy(&fsout[i], files, sizeof(Human68k::files_t));
|
||
i += sizeof(Human68k::files_t);
|
||
|
||
fsoutlen = i;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $49 - ファイル作成
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Create(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD nKey;
|
||
Human68k::namests_t *pNamests;
|
||
Human68k::fcb_t *pFcb;
|
||
DWORD nAttribute;
|
||
BOOL bForce;
|
||
DWORD *dp;
|
||
BOOL *bp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nKey = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pNamests = (Human68k::namests_t*)&buf[i];
|
||
i += sizeof(Human68k::namests_t);
|
||
|
||
pFcb = (Human68k::fcb_t*)&buf[i];
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nAttribute = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
bp = (BOOL*)&buf[i];
|
||
bForce = ntohl(*bp);
|
||
i += sizeof(BOOL);
|
||
|
||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||
pFcb->mode = ntohs(pFcb->mode);
|
||
pFcb->time = ntohs(pFcb->time);
|
||
pFcb->date = ntohs(pFcb->date);
|
||
pFcb->size = ntohl(pFcb->size);
|
||
|
||
fsresult = fs->Create(nUnit, nKey, pNamests, pFcb, nAttribute, bForce);
|
||
|
||
pFcb->fileptr = htonl(pFcb->fileptr);
|
||
pFcb->mode = htons(pFcb->mode);
|
||
pFcb->time = htons(pFcb->time);
|
||
pFcb->date = htons(pFcb->date);
|
||
pFcb->size = htonl(pFcb->size);
|
||
|
||
i = 0;
|
||
memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t));
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
fsoutlen = i;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $4A - ファイルオープン
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Open(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD nKey;
|
||
Human68k::namests_t *pNamests;
|
||
Human68k::fcb_t *pFcb;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nKey = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pNamests = (Human68k::namests_t*)&buf[i];
|
||
i += sizeof(Human68k::namests_t);
|
||
|
||
pFcb = (Human68k::fcb_t*)&buf[i];
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||
pFcb->mode = ntohs(pFcb->mode);
|
||
pFcb->time = ntohs(pFcb->time);
|
||
pFcb->date = ntohs(pFcb->date);
|
||
pFcb->size = ntohl(pFcb->size);
|
||
|
||
fsresult = fs->Open(nUnit, nKey, pNamests, pFcb);
|
||
|
||
pFcb->fileptr = htonl(pFcb->fileptr);
|
||
pFcb->mode = htons(pFcb->mode);
|
||
pFcb->time = htons(pFcb->time);
|
||
pFcb->date = htons(pFcb->date);
|
||
pFcb->size = htonl(pFcb->size);
|
||
|
||
i = 0;
|
||
memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t));
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
fsoutlen = i;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $4B - ファイルクローズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Close(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD nKey;
|
||
Human68k::fcb_t *pFcb;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nKey = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pFcb = (Human68k::fcb_t*)&buf[i];
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||
pFcb->mode = ntohs(pFcb->mode);
|
||
pFcb->time = ntohs(pFcb->time);
|
||
pFcb->date = ntohs(pFcb->date);
|
||
pFcb->size = ntohl(pFcb->size);
|
||
|
||
fsresult = fs->Close(nUnit, nKey, pFcb);
|
||
|
||
pFcb->fileptr = htonl(pFcb->fileptr);
|
||
pFcb->mode = htons(pFcb->mode);
|
||
pFcb->time = htons(pFcb->time);
|
||
pFcb->date = htons(pFcb->date);
|
||
pFcb->size = htonl(pFcb->size);
|
||
|
||
i = 0;
|
||
memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t));
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
fsoutlen = i;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $4C - ファイル読み込み
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Read(BYTE *buf)
|
||
{
|
||
DWORD nKey;
|
||
Human68k::fcb_t *pFcb;
|
||
DWORD nSize;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nKey = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pFcb = (Human68k::fcb_t*)&buf[i];
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nSize = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||
pFcb->mode = ntohs(pFcb->mode);
|
||
pFcb->time = ntohs(pFcb->time);
|
||
pFcb->date = ntohs(pFcb->date);
|
||
pFcb->size = ntohl(pFcb->size);
|
||
|
||
fsresult = fs->Read(nKey, pFcb, fsopt, nSize);
|
||
|
||
pFcb->fileptr = htonl(pFcb->fileptr);
|
||
pFcb->mode = htons(pFcb->mode);
|
||
pFcb->time = htons(pFcb->time);
|
||
pFcb->date = htons(pFcb->date);
|
||
pFcb->size = htonl(pFcb->size);
|
||
|
||
i = 0;
|
||
memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t));
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
fsoutlen = i;
|
||
|
||
fsoptlen = fsresult;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $4D - ファイル書き込み
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Write(BYTE *buf)
|
||
{
|
||
DWORD nKey;
|
||
Human68k::fcb_t *pFcb;
|
||
DWORD nSize;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nKey = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pFcb = (Human68k::fcb_t*)&buf[i];
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nSize = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||
pFcb->mode = ntohs(pFcb->mode);
|
||
pFcb->time = ntohs(pFcb->time);
|
||
pFcb->date = ntohs(pFcb->date);
|
||
pFcb->size = ntohl(pFcb->size);
|
||
|
||
fsresult = fs->Write(nKey, pFcb, fsopt, nSize);
|
||
|
||
pFcb->fileptr = htonl(pFcb->fileptr);
|
||
pFcb->mode = htons(pFcb->mode);
|
||
pFcb->time = htons(pFcb->time);
|
||
pFcb->date = htons(pFcb->date);
|
||
pFcb->size = htonl(pFcb->size);
|
||
|
||
i = 0;
|
||
memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t));
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
fsoutlen = i;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $4E - ファイルシーク
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Seek(BYTE *buf)
|
||
{
|
||
DWORD nKey;
|
||
Human68k::fcb_t *pFcb;
|
||
DWORD nMode;
|
||
int nOffset;
|
||
DWORD *dp;
|
||
int *ip;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nKey = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pFcb = (Human68k::fcb_t*)&buf[i];
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nMode = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
ip = (int*)&buf[i];
|
||
nOffset = ntohl(*ip);
|
||
i += sizeof(int);
|
||
|
||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||
pFcb->mode = ntohs(pFcb->mode);
|
||
pFcb->time = ntohs(pFcb->time);
|
||
pFcb->date = ntohs(pFcb->date);
|
||
pFcb->size = ntohl(pFcb->size);
|
||
|
||
fsresult = fs->Seek(nKey, pFcb, nMode, nOffset);
|
||
|
||
pFcb->fileptr = htonl(pFcb->fileptr);
|
||
pFcb->mode = htons(pFcb->mode);
|
||
pFcb->time = htons(pFcb->time);
|
||
pFcb->date = htons(pFcb->date);
|
||
pFcb->size = htonl(pFcb->size);
|
||
|
||
i = 0;
|
||
memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t));
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
fsoutlen = i;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $4F - ファイル時刻取得/設定
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_TimeStamp(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD nKey;
|
||
Human68k::fcb_t *pFcb;
|
||
DWORD nHumanTime;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nKey = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pFcb = (Human68k::fcb_t*)&buf[i];
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nHumanTime = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pFcb->fileptr = ntohl(pFcb->fileptr);
|
||
pFcb->mode = ntohs(pFcb->mode);
|
||
pFcb->time = ntohs(pFcb->time);
|
||
pFcb->date = ntohs(pFcb->date);
|
||
pFcb->size = ntohl(pFcb->size);
|
||
|
||
fsresult = fs->TimeStamp(nUnit, nKey, pFcb, nHumanTime);
|
||
|
||
pFcb->fileptr = htonl(pFcb->fileptr);
|
||
pFcb->mode = htons(pFcb->mode);
|
||
pFcb->time = htons(pFcb->time);
|
||
pFcb->date = htons(pFcb->date);
|
||
pFcb->size = htonl(pFcb->size);
|
||
|
||
i = 0;
|
||
memcpy(&fsout[i], pFcb, sizeof(Human68k::fcb_t));
|
||
i += sizeof(Human68k::fcb_t);
|
||
|
||
fsoutlen = i;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $50 - 容量取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_GetCapacity(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
Human68k::capacity_t cap;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
fsresult = fs->GetCapacity(nUnit, &cap);
|
||
|
||
cap.freearea = htons(cap.freearea);
|
||
cap.clusters = htons(cap.clusters);
|
||
cap.sectors = htons(cap.sectors);
|
||
cap.bytes = htons(cap.bytes);
|
||
|
||
memcpy(fsout, &cap, sizeof(Human68k::capacity_t));
|
||
fsoutlen = sizeof(Human68k::capacity_t);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $51 - ドライブ状態検査/制御
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_CtrlDrive(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
Human68k::ctrldrive_t *pCtrlDrive;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pCtrlDrive = (Human68k::ctrldrive_t*)&buf[i];
|
||
i += sizeof(Human68k::ctrldrive_t);
|
||
|
||
fsresult = fs->CtrlDrive(nUnit, pCtrlDrive);
|
||
|
||
memcpy(fsout, pCtrlDrive, sizeof(Human68k::ctrldrive_t));
|
||
fsoutlen = sizeof(Human68k::ctrldrive_t);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $52 - DPB取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_GetDPB(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
Human68k::dpb_t dpb;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
fsresult = fs->GetDPB(nUnit, &dpb);
|
||
|
||
dpb.sector_size = htons(dpb.sector_size);
|
||
dpb.fat_sector = htons(dpb.fat_sector);
|
||
dpb.file_max = htons(dpb.file_max);
|
||
dpb.data_sector = htons(dpb.data_sector);
|
||
dpb.cluster_max = htons(dpb.cluster_max);
|
||
dpb.root_sector = htons(dpb.root_sector);
|
||
|
||
memcpy(fsout, &dpb, sizeof(Human68k::dpb_t));
|
||
fsoutlen = sizeof(Human68k::dpb_t);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $53 - セクタ読み込み
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_DiskRead(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD nSector;
|
||
DWORD nSize;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nSector = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nSize = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
fsresult = fs->DiskRead(nUnit, fsout, nSector, nSize);
|
||
fsoutlen = 0x200;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $54 - セクタ書き込み
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_DiskWrite(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
fsresult = fs->DiskWrite(nUnit);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $55 - IOCTRL
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Ioctrl(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD nFunction;
|
||
Human68k::ioctrl_t *pIoctrl;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
dp = (DWORD*)&buf[i];
|
||
nFunction = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
pIoctrl = (Human68k::ioctrl_t*)&buf[i];
|
||
i += sizeof(Human68k::ioctrl_t);
|
||
|
||
switch (nFunction) {
|
||
case 2:
|
||
case -2:
|
||
pIoctrl->param = htonl(pIoctrl->param);
|
||
break;
|
||
}
|
||
|
||
fsresult = fs->Ioctrl(nUnit, nFunction, pIoctrl);
|
||
|
||
switch (nFunction) {
|
||
case 0:
|
||
pIoctrl->media = htons(pIoctrl->media);
|
||
break;
|
||
case 1:
|
||
case -3:
|
||
pIoctrl->param = htonl(pIoctrl->param);
|
||
break;
|
||
}
|
||
|
||
i = 0;
|
||
memcpy(&fsout[i], pIoctrl, sizeof(Human68k::ioctrl_t));
|
||
i += sizeof(Human68k::ioctrl_t);
|
||
fsoutlen = i;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $56 - フラッシュ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Flush(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
fsresult = fs->Flush(nUnit);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $57 - メディア交換チェック
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_CheckMedia(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
fsresult = fs->CheckMedia(nUnit);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// $58 - 排他制御
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::FS_Lock(BYTE *buf)
|
||
{
|
||
DWORD nUnit;
|
||
DWORD *dp;
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fs);
|
||
ASSERT(buf);
|
||
|
||
i = 0;
|
||
dp = (DWORD*)buf;
|
||
nUnit = ntohl(*dp);
|
||
i += sizeof(DWORD);
|
||
|
||
fsresult = fs->Lock(nUnit);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ファイルシステム読み込み(結果コード)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIBR::ReadFsResult(BYTE *buf)
|
||
{
|
||
DWORD *dp;
|
||
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
dp = (DWORD*)buf;
|
||
*dp = htonl(fsresult);
|
||
return sizeof(DWORD);
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ファイルシステム読み込み(返却データ)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIBR::ReadFsOut(BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
memcpy(buf, fsout, fsoutlen);
|
||
return fsoutlen;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ファイルシステム読み込み(返却オプションデータ)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
int FASTCALL SCSIBR::ReadFsOpt(BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
memcpy(buf, fsopt, fsoptlen);
|
||
return fsoptlen;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ファイルシステム書き込み
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::WriteFs(int func, BYTE *buf)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buf);
|
||
|
||
fsresult = FS_FATAL_INVALIDCOMMAND;
|
||
fsoutlen = 0;
|
||
fsoptlen = 0;
|
||
|
||
// コマンド分岐
|
||
func &= 0x1f;
|
||
switch (func) {
|
||
case 0x00: return FS_InitDevice(buf); // $40 - デバイス起動
|
||
case 0x01: return FS_CheckDir(buf); // $41 - ディレクトリチェック
|
||
case 0x02: return FS_MakeDir(buf); // $42 - ディレクトリ作成
|
||
case 0x03: return FS_RemoveDir(buf); // $43 - ディレクトリ削除
|
||
case 0x04: return FS_Rename(buf); // $44 - ファイル名変更
|
||
case 0x05: return FS_Delete(buf); // $45 - ファイル削除
|
||
case 0x06: return FS_Attribute(buf); // $46 - ファイル属性取得/設定
|
||
case 0x07: return FS_Files(buf); // $47 - ファイル検索
|
||
case 0x08: return FS_NFiles(buf); // $48 - ファイル次検索
|
||
case 0x09: return FS_Create(buf); // $49 - ファイル作成
|
||
case 0x0A: return FS_Open(buf); // $4A - ファイルオープン
|
||
case 0x0B: return FS_Close(buf); // $4B - ファイルクローズ
|
||
case 0x0C: return FS_Read(buf); // $4C - ファイル読み込み
|
||
case 0x0D: return FS_Write(buf); // $4D - ファイル書き込み
|
||
case 0x0E: return FS_Seek(buf); // $4E - ファイルシーク
|
||
case 0x0F: return FS_TimeStamp(buf); // $4F - ファイル更新時刻の取得/設定
|
||
case 0x10: return FS_GetCapacity(buf); // $50 - 容量取得
|
||
case 0x11: return FS_CtrlDrive(buf); // $51 - ドライブ制御/状態検査
|
||
case 0x12: return FS_GetDPB(buf); // $52 - DPB取得
|
||
case 0x13: return FS_DiskRead(buf); // $53 - セクタ読み込み
|
||
case 0x14: return FS_DiskWrite(buf); // $54 - セクタ書き込み
|
||
case 0x15: return FS_Ioctrl(buf); // $55 - IOCTRL
|
||
case 0x16: return FS_Flush(buf); // $56 - フラッシュ
|
||
case 0x17: return FS_CheckMedia(buf); // $57 - メディア交換チェック
|
||
case 0x18: return FS_Lock(buf); // $58 - 排他制御
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ファイルシステム書き込み(入力オプションデータ)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIBR::WriteFsOpt(BYTE *buf, int num)
|
||
{
|
||
ASSERT(this);
|
||
|
||
memcpy(fsopt, buf, num);
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// SASI デバイス
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
#ifdef RASCSI
|
||
SASIDEV::SASIDEV()
|
||
#else
|
||
SASIDEV::SASIDEV(Device *dev)
|
||
#endif // RASCSI
|
||
{
|
||
int i;
|
||
|
||
#ifndef RASCSI
|
||
// ホストデバイスを記憶
|
||
host = dev;
|
||
#endif // RASCSI
|
||
|
||
// ワーク初期化
|
||
ctrl.phase = BUS::busfree;
|
||
ctrl.id = -1;
|
||
ctrl.bus = NULL;
|
||
memset(ctrl.cmd, 0x00, sizeof(ctrl.cmd));
|
||
ctrl.status = 0x00;
|
||
ctrl.message = 0x00;
|
||
#ifdef RASCSI
|
||
ctrl.execstart = 0;
|
||
#endif // RASCSI
|
||
ctrl.bufsize = 0x800;
|
||
ctrl.buffer = (BYTE *)malloc(ctrl.bufsize);
|
||
memset(ctrl.buffer, 0x00, ctrl.bufsize);
|
||
ctrl.blocks = 0;
|
||
ctrl.next = 0;
|
||
ctrl.offset = 0;
|
||
ctrl.length = 0;
|
||
|
||
// 論理ユニット初期化
|
||
for (i = 0; i < UnitMax; i++) {
|
||
ctrl.unit[i] = NULL;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// デストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
SASIDEV::~SASIDEV()
|
||
{
|
||
// バッファを開放
|
||
if (ctrl.buffer) {
|
||
free(ctrl.buffer);
|
||
ctrl.buffer = NULL;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// デバイスリセット
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::Reset()
|
||
{
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
|
||
// ワーク初期化
|
||
memset(ctrl.cmd, 0x00, sizeof(ctrl.cmd));
|
||
ctrl.phase = BUS::busfree;
|
||
ctrl.status = 0x00;
|
||
ctrl.message = 0x00;
|
||
#ifdef RASCSI
|
||
ctrl.execstart = 0;
|
||
#endif // RASCSI
|
||
memset(ctrl.buffer, 0x00, ctrl.bufsize);
|
||
ctrl.blocks = 0;
|
||
ctrl.next = 0;
|
||
ctrl.offset = 0;
|
||
ctrl.length = 0;
|
||
|
||
// ユニット初期化
|
||
for (i = 0; i < UnitMax; i++) {
|
||
if (ctrl.unit[i]) {
|
||
ctrl.unit[i]->Reset();
|
||
}
|
||
}
|
||
}
|
||
|
||
#ifndef RASCSI
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// セーブ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SASIDEV::Save(Fileio *fio, int /*ver*/)
|
||
{
|
||
DWORD sz;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fio);
|
||
|
||
// サイズをセーブ
|
||
sz = 2120;
|
||
if (!fio->Write(&sz, sizeof(sz))) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 実体をセーブ
|
||
PROP_EXPORT(fio, ctrl.phase);
|
||
PROP_EXPORT(fio, ctrl.id);
|
||
PROP_EXPORT(fio, ctrl.cmd);
|
||
PROP_EXPORT(fio, ctrl.status);
|
||
PROP_EXPORT(fio, ctrl.message);
|
||
if (!fio->Write(ctrl.buffer, 0x800)) {
|
||
return FALSE;
|
||
}
|
||
PROP_EXPORT(fio, ctrl.blocks);
|
||
PROP_EXPORT(fio, ctrl.next);
|
||
PROP_EXPORT(fio, ctrl.offset);
|
||
PROP_EXPORT(fio, ctrl.length);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ロード
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SASIDEV::Load(Fileio *fio, int ver)
|
||
{
|
||
DWORD sz;
|
||
|
||
ASSERT(this);
|
||
ASSERT(fio);
|
||
|
||
// version3.11より前はセーブしていない
|
||
if (ver <= 0x0311) {
|
||
return TRUE;
|
||
}
|
||
|
||
// サイズをロード、照合
|
||
if (!fio->Read(&sz, sizeof(sz))) {
|
||
return FALSE;
|
||
}
|
||
if (sz != 2120) {
|
||
return FALSE;
|
||
}
|
||
|
||
// 実体をロード
|
||
PROP_IMPORT(fio, ctrl.phase);
|
||
PROP_IMPORT(fio, ctrl.id);
|
||
PROP_IMPORT(fio, ctrl.cmd);
|
||
PROP_IMPORT(fio, ctrl.status);
|
||
PROP_IMPORT(fio, ctrl.message);
|
||
if (!fio->Read(ctrl.buffer, 0x800)) {
|
||
return FALSE;
|
||
}
|
||
PROP_IMPORT(fio, ctrl.blocks);
|
||
PROP_IMPORT(fio, ctrl.next);
|
||
PROP_IMPORT(fio, ctrl.offset);
|
||
PROP_IMPORT(fio, ctrl.length);
|
||
|
||
return TRUE;
|
||
}
|
||
#endif // RASCSI
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コントローラ接続
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::Connect(int id, BUS *bus)
|
||
{
|
||
ASSERT(this);
|
||
|
||
ctrl.id = id;
|
||
ctrl.bus = bus;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 論理ユニット取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
Disk* FASTCALL SASIDEV::GetUnit(int no)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(no < UnitMax);
|
||
|
||
return ctrl.unit[no];
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 論理ユニット設定
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::SetUnit(int no, Disk *dev)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(no < UnitMax);
|
||
|
||
ctrl.unit[no] = dev;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 有効な論理ユニットを持っているか返す
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SASIDEV::HasUnit()
|
||
{
|
||
int i;
|
||
|
||
ASSERT(this);
|
||
|
||
for (i = 0; i < UnitMax; i++) {
|
||
if (ctrl.unit[i]) {
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 内部データ取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::GetCTRL(ctrl_t *buffer)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(buffer);
|
||
|
||
// 内部ワークをコピー
|
||
*buffer = ctrl;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ビジー状態のユニットを取得
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
Disk* FASTCALL SASIDEV::GetBusyUnit()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
return ctrl.unit[lun];
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 実行
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BUS::phase_t FASTCALL SASIDEV::Process()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// 未接続なら何もしない
|
||
if (ctrl.id < 0 || ctrl.bus == NULL) {
|
||
return ctrl.phase;
|
||
}
|
||
|
||
// バス情報の取り込み
|
||
ctrl.bus->Aquire();
|
||
|
||
// リセット
|
||
if (ctrl.bus->GetRST()) {
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "RESET信号受信");
|
||
#endif // DISK_LOG
|
||
|
||
// コントローラをリセット
|
||
Reset();
|
||
|
||
// バスもリセット
|
||
ctrl.bus->Reset();
|
||
return ctrl.phase;
|
||
}
|
||
|
||
// フェーズ処理
|
||
switch (ctrl.phase) {
|
||
// バスフリー
|
||
case BUS::busfree:
|
||
BusFree();
|
||
break;
|
||
|
||
// セレクション
|
||
case BUS::selection:
|
||
Selection();
|
||
break;
|
||
|
||
// データアウト(MCI=000)
|
||
case BUS::dataout:
|
||
DataOut();
|
||
break;
|
||
|
||
// データイン(MCI=001)
|
||
case BUS::datain:
|
||
DataIn();
|
||
break;
|
||
|
||
// コマンド(MCI=010)
|
||
case BUS::command:
|
||
Command();
|
||
break;
|
||
|
||
// ステータス(MCI=011)
|
||
case BUS::status:
|
||
Status();
|
||
break;
|
||
|
||
// メッセージイン(MCI=111)
|
||
case BUS::msgin:
|
||
MsgIn();
|
||
break;
|
||
|
||
// その他
|
||
default:
|
||
ASSERT(FALSE);
|
||
break;
|
||
}
|
||
|
||
return ctrl.phase;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// バスフリーフェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::BusFree()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// フェーズチェンジ
|
||
if (ctrl.phase != BUS::busfree) {
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "バスフリーフェーズ");
|
||
#endif // DISK_LOG
|
||
|
||
// フェーズ設定
|
||
ctrl.phase = BUS::busfree;
|
||
|
||
// 信号線
|
||
ctrl.bus->SetREQ(FALSE);
|
||
ctrl.bus->SetMSG(FALSE);
|
||
ctrl.bus->SetCD(FALSE);
|
||
ctrl.bus->SetIO(FALSE);
|
||
ctrl.bus->SetBSY(FALSE);
|
||
|
||
// ステータスとメッセージを初期化
|
||
ctrl.status = 0x00;
|
||
ctrl.message = 0x00;
|
||
return;
|
||
}
|
||
|
||
// セレクションフェーズに移行
|
||
if (ctrl.bus->GetSEL() && !ctrl.bus->GetBSY()) {
|
||
Selection();
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// セレクションフェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::Selection()
|
||
{
|
||
DWORD id;
|
||
|
||
ASSERT(this);
|
||
|
||
// フェーズチェンジ
|
||
if (ctrl.phase != BUS::selection) {
|
||
// IDが一致していなければ無効
|
||
id = 1 << ctrl.id;
|
||
if ((ctrl.bus->GetDAT() & id) == 0) {
|
||
return;
|
||
}
|
||
|
||
// 有効なユニットが無ければ終了
|
||
if (!HasUnit()) {
|
||
return;
|
||
}
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal,
|
||
"セレクションフェーズ ID=%d (デバイスあり)", ctrl.id);
|
||
#endif // DISK_LOG
|
||
|
||
// フェーズチェンジ
|
||
ctrl.phase = BUS::selection;
|
||
|
||
// BSYを上げて応答
|
||
ctrl.bus->SetBSY(TRUE);
|
||
return;
|
||
}
|
||
|
||
// セレクション完了でコマンドフェーズ移行
|
||
if (!ctrl.bus->GetSEL() && ctrl.bus->GetBSY()) {
|
||
Command();
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コマンドフェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::Command()
|
||
{
|
||
#ifdef RASCSI
|
||
int count;
|
||
int i;
|
||
#endif // RASCSI
|
||
|
||
ASSERT(this);
|
||
|
||
// フェーズチェンジ
|
||
if (ctrl.phase != BUS::command) {
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "コマンドフェーズ");
|
||
#endif // DISK_LOG
|
||
|
||
// フェーズ設定
|
||
ctrl.phase = BUS::command;
|
||
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetMSG(FALSE);
|
||
ctrl.bus->SetCD(TRUE);
|
||
ctrl.bus->SetIO(FALSE);
|
||
|
||
// データ転送は6バイトx1ブロック
|
||
ctrl.offset = 0;
|
||
ctrl.length = 6;
|
||
ctrl.blocks = 1;
|
||
|
||
#ifdef RASCSI
|
||
// コマンド受信ハンドシェイク(最初のコマンドで自動で10バイト受信する)
|
||
count = ctrl.bus->CommandHandShake(ctrl.buffer);
|
||
|
||
// 1バイトも受信できなければステータスフェーズへ移行
|
||
if (count == 0) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 10バイトCDBのチェック
|
||
if (ctrl.buffer[0] >= 0x20 && ctrl.buffer[0] <= 0x7D) {
|
||
ctrl.length = 10;
|
||
}
|
||
|
||
// 全て受信できなければステータスフェーズへ移行
|
||
if (count != (int)ctrl.length) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// コマンドデータ転送
|
||
for (i = 0; i < (int)ctrl.length; i++) {
|
||
ctrl.cmd[i] = (DWORD)ctrl.buffer[i];
|
||
}
|
||
|
||
// レングスとブロックをクリア
|
||
ctrl.length = 0;
|
||
ctrl.blocks = 0;
|
||
|
||
// 実行フェーズ
|
||
Execute();
|
||
#else
|
||
// コマンドを要求
|
||
ctrl.bus->SetREQ(TRUE);
|
||
return;
|
||
#endif // RASCSI
|
||
}
|
||
#ifndef RASCSI
|
||
// リクエスト中
|
||
if (ctrl.bus->GetREQ()) {
|
||
// イニシエータが送信した
|
||
if (ctrl.bus->GetACK()) {
|
||
Receive();
|
||
}
|
||
} else {
|
||
// イニシエータに次を要求
|
||
if (!ctrl.bus->GetACK()) {
|
||
ReceiveNext();
|
||
}
|
||
}
|
||
#endif // RASCSI
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 実行フェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::Execute()
|
||
{
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "実行フェーズ コマンド$%02X", ctrl.cmd[0]);
|
||
#endif // DISK_LOG
|
||
|
||
// フェーズ設定
|
||
ctrl.phase = BUS::execute;
|
||
|
||
// データ転送のための初期化
|
||
ctrl.offset = 0;
|
||
ctrl.blocks = 1;
|
||
#ifdef RASCSI
|
||
ctrl.execstart = SysTimer::GetTimerLow();
|
||
#endif // RASCSI
|
||
|
||
// コマンド別処理
|
||
switch (ctrl.cmd[0]) {
|
||
// TEST UNIT READY
|
||
case 0x00:
|
||
CmdTestUnitReady();
|
||
return;
|
||
|
||
// REZERO UNIT
|
||
case 0x01:
|
||
CmdRezero();
|
||
return;
|
||
|
||
// REQUEST SENSE
|
||
case 0x03:
|
||
CmdRequestSense();
|
||
return;
|
||
|
||
// FORMAT UNIT
|
||
case 0x04:
|
||
CmdFormat();
|
||
return;
|
||
|
||
// FORMAT UNIT
|
||
case 0x06:
|
||
CmdFormat();
|
||
return;
|
||
|
||
// REASSIGN BLOCKS
|
||
case 0x07:
|
||
CmdReassign();
|
||
return;
|
||
|
||
// READ(6)
|
||
case 0x08:
|
||
CmdRead6();
|
||
return;
|
||
|
||
// WRITE(6)
|
||
case 0x0a:
|
||
CmdWrite6();
|
||
return;
|
||
|
||
// SEEK(6)
|
||
case 0x0b:
|
||
CmdSeek6();
|
||
return;
|
||
|
||
// ASSIGN(SASIのみ)
|
||
case 0x0e:
|
||
CmdAssign();
|
||
return;
|
||
|
||
// SPECIFY(SASIのみ)
|
||
case 0xc2:
|
||
CmdSpecify();
|
||
return;
|
||
}
|
||
|
||
// それ以外は対応していない
|
||
Log(Log::Warning, "未対応コマンド $%02X", ctrl.cmd[0]);
|
||
CmdInvalid();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ステータスフェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::Status()
|
||
{
|
||
#ifdef RASCSI
|
||
DWORD min_exec_time;
|
||
DWORD time;
|
||
#endif // RASCSI
|
||
|
||
ASSERT(this);
|
||
|
||
// フェーズチェンジ
|
||
if (ctrl.phase != BUS::status) {
|
||
|
||
#ifdef RASCSI
|
||
// 最小実行時間
|
||
if (ctrl.execstart > 0) {
|
||
min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi;
|
||
time = SysTimer::GetTimerLow() - ctrl.execstart;
|
||
if (time < min_exec_time) {
|
||
SysTimer::SleepUsec(min_exec_time - time);
|
||
}
|
||
ctrl.execstart = 0;
|
||
} else {
|
||
SysTimer::SleepUsec(5);
|
||
}
|
||
#endif // RASCSI
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "ステータスフェーズ");
|
||
#endif // DISK_LOG
|
||
|
||
// フェーズ設定
|
||
ctrl.phase = BUS::status;
|
||
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetMSG(FALSE);
|
||
ctrl.bus->SetCD(TRUE);
|
||
ctrl.bus->SetIO(TRUE);
|
||
|
||
// データ転送は1バイトx1ブロック
|
||
ctrl.offset = 0;
|
||
ctrl.length = 1;
|
||
ctrl.blocks = 1;
|
||
ctrl.buffer[0] = (BYTE)ctrl.status;
|
||
|
||
#ifndef RASCSI
|
||
// ステータスを要求
|
||
ctrl.bus->SetDAT(ctrl.buffer[0]);
|
||
ctrl.bus->SetREQ(TRUE);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "ステータスフェーズ $%02X", ctrl.status);
|
||
#endif // DISK_LOG
|
||
#endif // RASCSI
|
||
return;
|
||
}
|
||
|
||
#ifdef RASCSI
|
||
// 送信
|
||
Send();
|
||
#else
|
||
// リクエスト中
|
||
if (ctrl.bus->GetREQ()) {
|
||
// イニシエータが受信した
|
||
if (ctrl.bus->GetACK()) {
|
||
SendNext();
|
||
}
|
||
} else {
|
||
// イニシエータが次を要求
|
||
if (!ctrl.bus->GetACK()) {
|
||
Send();
|
||
}
|
||
}
|
||
#endif // RASCSI
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// メッセージインフェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::MsgIn()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// フェーズチェンジ
|
||
if (ctrl.phase != BUS::msgin) {
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "メッセージインフェーズ");
|
||
#endif // DISK_LOG
|
||
|
||
// フェーズ設定
|
||
ctrl.phase = BUS::msgin;
|
||
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetMSG(TRUE);
|
||
ctrl.bus->SetCD(TRUE);
|
||
ctrl.bus->SetIO(TRUE);
|
||
|
||
// length, blocksは設定済み
|
||
ASSERT(ctrl.length > 0);
|
||
ASSERT(ctrl.blocks > 0);
|
||
ctrl.offset = 0;
|
||
|
||
#ifndef RASCSI
|
||
// メッセージを要求
|
||
ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]);
|
||
ctrl.bus->SetREQ(TRUE);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "メッセージインフェーズ $%02X", ctrl.buffer[ctrl.offset]);
|
||
#endif // DISK_LOG
|
||
#endif // RASCSI
|
||
return;
|
||
}
|
||
|
||
#ifdef RASCSI
|
||
// 送信
|
||
Send();
|
||
#else
|
||
// リクエスト中
|
||
if (ctrl.bus->GetREQ()) {
|
||
// イニシエータが受信した
|
||
if (ctrl.bus->GetACK()) {
|
||
SendNext();
|
||
}
|
||
} else {
|
||
// イニシエータが次を要求
|
||
if (!ctrl.bus->GetACK()) {
|
||
Send();
|
||
}
|
||
}
|
||
#endif // RASCSI
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データインフェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::DataIn()
|
||
{
|
||
#ifdef RASCSI
|
||
DWORD min_exec_time;
|
||
DWORD time;
|
||
#endif // RASCSI
|
||
|
||
ASSERT(this);
|
||
ASSERT(ctrl.length >= 0);
|
||
|
||
// フェーズチェンジ
|
||
if (ctrl.phase != BUS::datain) {
|
||
|
||
#ifdef RASCSI
|
||
// 最小実行時間
|
||
if (ctrl.execstart > 0) {
|
||
min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi;
|
||
time = SysTimer::GetTimerLow() - ctrl.execstart;
|
||
if (time < min_exec_time) {
|
||
SysTimer::SleepUsec(min_exec_time - time);
|
||
}
|
||
ctrl.execstart = 0;
|
||
}
|
||
#endif // RASCSI
|
||
|
||
// レングス0なら、ステータスフェーズへ
|
||
if (ctrl.length == 0) {
|
||
Status();
|
||
return;
|
||
}
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "データインフェーズ");
|
||
#endif // DISK_LOG
|
||
|
||
// フェーズ設定
|
||
ctrl.phase = BUS::datain;
|
||
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetMSG(FALSE);
|
||
ctrl.bus->SetCD(FALSE);
|
||
ctrl.bus->SetIO(TRUE);
|
||
|
||
// length, blocksは設定済み
|
||
ASSERT(ctrl.length > 0);
|
||
ASSERT(ctrl.blocks > 0);
|
||
ctrl.offset = 0;
|
||
|
||
#ifndef RASCSI
|
||
// データを設定
|
||
ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]);
|
||
|
||
// データを要求
|
||
ctrl.bus->SetREQ(TRUE);
|
||
#endif // RASCSI
|
||
return;
|
||
}
|
||
|
||
#ifdef RASCSI
|
||
// 送信
|
||
Send();
|
||
#else
|
||
// リクエスト中
|
||
if (ctrl.bus->GetREQ()) {
|
||
// イニシエータが受信した
|
||
if (ctrl.bus->GetACK()) {
|
||
SendNext();
|
||
}
|
||
} else {
|
||
// イニシエータが次を要求
|
||
if (!ctrl.bus->GetACK()) {
|
||
Send();
|
||
}
|
||
}
|
||
#endif // RASCSI
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データアウトフェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::DataOut()
|
||
{
|
||
#ifdef RASCSI
|
||
DWORD min_exec_time;
|
||
DWORD time;
|
||
#endif // RASCSI
|
||
|
||
ASSERT(this);
|
||
ASSERT(ctrl.length >= 0);
|
||
|
||
// フェーズチェンジ
|
||
if (ctrl.phase != BUS::dataout) {
|
||
|
||
#ifdef RASCSI
|
||
// 最小実行時間
|
||
if (ctrl.execstart > 0) {
|
||
min_exec_time = IsSASI() ? min_exec_time_sasi : min_exec_time_scsi;
|
||
time = SysTimer::GetTimerLow() - ctrl.execstart;
|
||
if (time < min_exec_time) {
|
||
SysTimer::SleepUsec(min_exec_time - time);
|
||
}
|
||
ctrl.execstart = 0;
|
||
}
|
||
#endif // RASCSI
|
||
|
||
// レングス0なら、ステータスフェーズへ
|
||
if (ctrl.length == 0) {
|
||
Status();
|
||
return;
|
||
}
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "データアウトフェーズ");
|
||
#endif // DISK_LOG
|
||
|
||
// フェーズ設定
|
||
ctrl.phase = BUS::dataout;
|
||
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetMSG(FALSE);
|
||
ctrl.bus->SetCD(FALSE);
|
||
ctrl.bus->SetIO(FALSE);
|
||
|
||
// length, blocksは設定済み
|
||
ASSERT(ctrl.length > 0);
|
||
ASSERT(ctrl.blocks > 0);
|
||
ctrl.offset = 0;
|
||
|
||
#ifndef RASCSI
|
||
// データを要求
|
||
ctrl.bus->SetREQ(TRUE);
|
||
#endif // RASCSI
|
||
return;
|
||
}
|
||
|
||
#ifdef RASCSI
|
||
// 受信
|
||
Receive();
|
||
#else
|
||
// リクエスト中
|
||
if (ctrl.bus->GetREQ()) {
|
||
// イニシエータが送信した
|
||
if (ctrl.bus->GetACK()) {
|
||
Receive();
|
||
}
|
||
} else {
|
||
// イニシエータに次を要求
|
||
if (!ctrl.bus->GetACK()) {
|
||
ReceiveNext();
|
||
}
|
||
}
|
||
#endif // RASCSI
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 共通エラー
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::Error()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
// バス情報の取り込み
|
||
ctrl.bus->Aquire();
|
||
|
||
// リセットチェック
|
||
if (ctrl.bus->GetRST()) {
|
||
// コントローラをリセット
|
||
Reset();
|
||
|
||
// バスもリセット
|
||
ctrl.bus->Reset();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ、メッセージインフェーズはバスフリー
|
||
if (ctrl.phase == BUS::status || ctrl.phase == BUS::msgin) {
|
||
BusFree();
|
||
return;
|
||
}
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Warning, "エラー(ステータスフェーズへ)");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
|
||
// ステータスとメッセージを設定(CHECK CONDITION)
|
||
ctrl.status = (lun << 5) | 0x02;
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// TEST UNIT READY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::CmdTestUnitReady()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "TEST UNIT READYコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->TestUnitReady(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// REZERO UNIT
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::CmdRezero()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "REZERO UNITコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->Rezero(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// REQUEST SENSE
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::CmdRequestSense()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "REQUEST SENSEコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
ctrl.length = ctrl.unit[lun]->RequestSense(ctrl.cmd, ctrl.buffer);
|
||
ASSERT(ctrl.length > 0);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "センスキー $%02X", ctrl.buffer[2]);
|
||
#endif // DISK_LOG
|
||
|
||
// リードフェーズ
|
||
DataIn();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// FORMAT UNIT
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::CmdFormat()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "FORMAT UNITコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->Format(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// REASSIGN BLOCKS
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::CmdReassign()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "REASSIGN BLOCKSコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->Reassign(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// READ(6)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::CmdRead6()
|
||
{
|
||
DWORD lun;
|
||
DWORD record;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// レコード番号とブロック数を取得
|
||
record = ctrl.cmd[1] & 0x1f;
|
||
record <<= 8;
|
||
record |= ctrl.cmd[2];
|
||
record <<= 8;
|
||
record |= ctrl.cmd[3];
|
||
ctrl.blocks = ctrl.cmd[4];
|
||
if (ctrl.blocks == 0) {
|
||
ctrl.blocks = 0x100;
|
||
}
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal,
|
||
"READ(6)コマンド レコード=%06X ブロック=%d", record, ctrl.blocks);
|
||
#endif // DISK_LOG
|
||
|
||
// ドライブでコマンド処理
|
||
ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record);
|
||
if (ctrl.length <= 0) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 次のブロックを設定
|
||
ctrl.next = record + 1;
|
||
|
||
// リードフェーズ
|
||
DataIn();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// WRITE(6)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::CmdWrite6()
|
||
{
|
||
DWORD lun;
|
||
DWORD record;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// レコード番号とブロック数を取得
|
||
record = ctrl.cmd[1] & 0x1f;
|
||
record <<= 8;
|
||
record |= ctrl.cmd[2];
|
||
record <<= 8;
|
||
record |= ctrl.cmd[3];
|
||
ctrl.blocks = ctrl.cmd[4];
|
||
if (ctrl.blocks == 0) {
|
||
ctrl.blocks = 0x100;
|
||
}
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal,
|
||
"WRITE(6)コマンド レコード=%06X ブロック=%d", record, ctrl.blocks);
|
||
#endif // DISK_LOG
|
||
|
||
// ドライブでコマンド処理
|
||
ctrl.length = ctrl.unit[lun]->WriteCheck(record);
|
||
if (ctrl.length <= 0) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 次のブロックを設定
|
||
ctrl.next = record + 1;
|
||
|
||
// ライトフェーズ
|
||
DataOut();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// SEEK(6)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::CmdSeek6()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "SEEK(6)コマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->Seek(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ASSIGN
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::CmdAssign()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "ASSIGNコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->Assign(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 4バイトのデータをリクエスト
|
||
ctrl.length = 4;
|
||
|
||
// ライトフェーズ
|
||
DataOut();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// SPECIFY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::CmdSpecify()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "SPECIFYコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->Assign(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 10バイトのデータをリクエスト
|
||
ctrl.length = 10;
|
||
|
||
// ライトフェーズ
|
||
DataOut();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// サポートしていないコマンド
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::CmdInvalid()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "サポートしていないコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (ctrl.unit[lun]) {
|
||
// ドライブでコマンド処理
|
||
ctrl.unit[lun]->InvalidCmd();
|
||
}
|
||
|
||
// 失敗(エラー)
|
||
Error();
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// データ転送
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ送信
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::Send()
|
||
{
|
||
#ifdef RASCSI
|
||
int len;
|
||
#endif // RASCSI
|
||
BOOL result;
|
||
|
||
ASSERT(this);
|
||
ASSERT(!ctrl.bus->GetREQ());
|
||
ASSERT(ctrl.bus->GetIO());
|
||
|
||
#ifdef RASCSI
|
||
// レングス!=0なら送信
|
||
if (ctrl.length != 0) {
|
||
len = ctrl.bus->SendHandShake(
|
||
&ctrl.buffer[ctrl.offset], ctrl.length);
|
||
|
||
// 全て送信できなければステータスフェーズへ移行
|
||
if (len != (int)ctrl.length) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// オフセットとレングス
|
||
ctrl.offset += ctrl.length;
|
||
ctrl.length = 0;
|
||
return;
|
||
}
|
||
#else
|
||
// オフセットとレングス
|
||
ASSERT(ctrl.length >= 1);
|
||
ctrl.offset++;
|
||
ctrl.length--;
|
||
|
||
// ACKアサート直後にSendNextでデータ設定済みならリクエストを上げる
|
||
if (ctrl.length != 0) {
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(TRUE);
|
||
return;
|
||
}
|
||
#endif // RASCSI
|
||
|
||
// ブロック減算、リザルト初期化
|
||
ctrl.blocks--;
|
||
result = TRUE;
|
||
|
||
// データ引き取り後の処理(リード/データインのみ)
|
||
if (ctrl.phase == BUS::datain) {
|
||
if (ctrl.blocks != 0) {
|
||
// 次のバッファを設定(offset, lengthをセットすること)
|
||
result = XferIn(ctrl.buffer);
|
||
#ifndef RASCSI
|
||
ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]);
|
||
#endif // RASCSI
|
||
}
|
||
}
|
||
|
||
// リザルトFALSEなら、ステータスフェーズへ移行
|
||
if (!result) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ブロック!=0なら送信継続
|
||
if (ctrl.blocks != 0){
|
||
ASSERT(ctrl.length > 0);
|
||
ASSERT(ctrl.offset == 0);
|
||
#ifndef RASCSI
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(TRUE);
|
||
#endif // RASCSI
|
||
return;
|
||
}
|
||
|
||
// 次フェーズに移動
|
||
switch (ctrl.phase) {
|
||
// メッセージインフェーズ
|
||
case BUS::msgin:
|
||
// バスフリーフェーズ
|
||
BusFree();
|
||
break;
|
||
|
||
// データインフェーズ
|
||
case BUS::datain:
|
||
// ステータスフェーズ
|
||
Status();
|
||
break;
|
||
|
||
// ステータスフェーズ
|
||
case BUS::status:
|
||
// メッセージインフェーズ
|
||
ctrl.length = 1;
|
||
ctrl.blocks = 1;
|
||
ctrl.buffer[0] = (BYTE)ctrl.message;
|
||
MsgIn();
|
||
break;
|
||
|
||
// その他(ありえない)
|
||
default:
|
||
ASSERT(FALSE);
|
||
break;
|
||
}
|
||
}
|
||
|
||
#ifndef RASCSI
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ送信継続
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::SendNext()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// REQが上がっている
|
||
ASSERT(ctrl.bus->GetREQ());
|
||
ASSERT(ctrl.bus->GetIO());
|
||
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(FALSE);
|
||
|
||
// バッファにデータがあれば先に設定する
|
||
if (ctrl.length > 1) {
|
||
ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset + 1]);
|
||
}
|
||
}
|
||
#endif // RASCSI
|
||
|
||
#ifndef RASCSI
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ受信
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::Receive()
|
||
{
|
||
DWORD data;
|
||
|
||
ASSERT(this);
|
||
|
||
// REQが上がっている
|
||
ASSERT(ctrl.bus->GetREQ());
|
||
ASSERT(!ctrl.bus->GetIO());
|
||
|
||
// データ取得
|
||
data = (DWORD)ctrl.bus->GetDAT();
|
||
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(FALSE);
|
||
|
||
switch (ctrl.phase) {
|
||
// コマンドフェーズ
|
||
case BUS::command:
|
||
ctrl.cmd[ctrl.offset] = data;
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "コマンドフェーズ $%02X", data);
|
||
#endif // DISK_LOG
|
||
|
||
// 最初のデータ(オフセット0)によりレングスを再設定
|
||
if (ctrl.offset == 0) {
|
||
if (ctrl.cmd[0] >= 0x20 && ctrl.cmd[0] <= 0x7D) {
|
||
// 10バイトCDB
|
||
ctrl.length = 10;
|
||
}
|
||
}
|
||
break;
|
||
|
||
// データアウトフェーズ
|
||
case BUS::dataout:
|
||
ctrl.buffer[ctrl.offset] = (BYTE)data;
|
||
break;
|
||
|
||
// その他(ありえない)
|
||
default:
|
||
ASSERT(FALSE);
|
||
break;
|
||
}
|
||
}
|
||
#endif // RASCSI
|
||
|
||
#ifdef RASCSI
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ受信
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::Receive()
|
||
#else
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ受信継続
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::ReceiveNext()
|
||
#endif // RASCSI
|
||
{
|
||
#ifdef RASCSI
|
||
int len;
|
||
#endif // RASCSI
|
||
BOOL result;
|
||
|
||
ASSERT(this);
|
||
|
||
// REQが下がっていること
|
||
ASSERT(!ctrl.bus->GetREQ());
|
||
ASSERT(!ctrl.bus->GetIO());
|
||
|
||
#ifdef RASCSI
|
||
// レングス!=0なら受信
|
||
if (ctrl.length != 0) {
|
||
// 受信
|
||
len = ctrl.bus->ReceiveHandShake(
|
||
&ctrl.buffer[ctrl.offset], ctrl.length);
|
||
|
||
// 全て受信できなければステータスフェーズへ移行
|
||
if (len != (int)ctrl.length) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// オフセットとレングス
|
||
ctrl.offset += ctrl.length;
|
||
ctrl.length = 0;
|
||
return;
|
||
}
|
||
#else
|
||
// オフセットとレングス
|
||
ASSERT(ctrl.length >= 1);
|
||
ctrl.offset++;
|
||
ctrl.length--;
|
||
|
||
// レングス!=0なら、再びreqをセット
|
||
if (ctrl.length != 0) {
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(TRUE);
|
||
return;
|
||
}
|
||
#endif // RASCSI
|
||
|
||
// ブロック減算、リザルト初期化
|
||
ctrl.blocks--;
|
||
result = TRUE;
|
||
|
||
// データアウトフェーズの処理
|
||
if (ctrl.phase == BUS::dataout) {
|
||
if (ctrl.blocks == 0) {
|
||
// このバッファで終了
|
||
result = XferOut(FALSE);
|
||
} else {
|
||
// 次のバッファに続く(offset, lengthをセットすること)
|
||
result = XferOut(TRUE);
|
||
}
|
||
}
|
||
|
||
// リザルトFALSEなら、ステータスフェーズへ移行
|
||
if (!result) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ブロック!=0なら受信継続
|
||
if (ctrl.blocks != 0){
|
||
ASSERT(ctrl.length > 0);
|
||
ASSERT(ctrl.offset == 0);
|
||
#ifndef RASCSI
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(TRUE);
|
||
#endif // RASCSI
|
||
return;
|
||
}
|
||
|
||
// 次フェーズに移動
|
||
switch (ctrl.phase) {
|
||
#ifndef RASCSI
|
||
// コマンドフェーズ
|
||
case BUS::command:
|
||
// 実行フェーズ
|
||
Execute();
|
||
break;
|
||
#endif // RASCSI
|
||
|
||
// データアウトフェーズ
|
||
case BUS::dataout:
|
||
// フラッシュ
|
||
FlushUnit();
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
break;
|
||
|
||
// その他(ありえない)
|
||
default:
|
||
ASSERT(FALSE);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ転送IN
|
||
// ※offset, lengthを再設定すること
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SASIDEV::XferIn(BYTE *buf)
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
ASSERT(ctrl.phase == BUS::datain);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
return FALSE;
|
||
}
|
||
|
||
// READ系コマンドに限る
|
||
switch (ctrl.cmd[0]) {
|
||
// READ(6)
|
||
case 0x08:
|
||
// READ(10)
|
||
case 0x28:
|
||
// ディスクから読み取りを行う
|
||
ctrl.length = ctrl.unit[lun]->Read(buf, ctrl.next);
|
||
ctrl.next++;
|
||
|
||
// エラーなら、ステータスフェーズへ
|
||
if (ctrl.length <= 0) {
|
||
// データイン中止
|
||
return FALSE;
|
||
}
|
||
|
||
// 正常なら、ワーク設定
|
||
ctrl.offset = 0;
|
||
break;
|
||
|
||
// その他(ありえない)
|
||
default:
|
||
ASSERT(FALSE);
|
||
return FALSE;
|
||
}
|
||
|
||
// バッファ設定に成功した
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ転送OUT
|
||
// ※cont=TRUEの場合、offset, lengthを再設定すること
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SASIDEV::XferOut(BOOL cont)
|
||
{
|
||
DWORD lun;
|
||
SCSIBR *bridge;
|
||
|
||
ASSERT(this);
|
||
ASSERT(ctrl.phase == BUS::dataout);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
return FALSE;
|
||
}
|
||
|
||
// MODE SELECTまたは、WRITE系
|
||
switch (ctrl.cmd[0]) {
|
||
// MODE SELECT
|
||
case 0x15:
|
||
// MODE SELECT(10)
|
||
case 0x55:
|
||
if (!ctrl.unit[lun]->ModeSelect(
|
||
ctrl.cmd, ctrl.buffer, ctrl.offset)) {
|
||
// MODE SELECTに失敗
|
||
return FALSE;
|
||
}
|
||
break;
|
||
|
||
// WRITE(6)
|
||
case 0x0a:
|
||
// WRITE(10)
|
||
case 0x2a:
|
||
// ホストブリッジはSEND MESSAGE10に差し替える
|
||
if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'B', 'R')) {
|
||
bridge = (SCSIBR*)ctrl.unit[lun];
|
||
if (!bridge->SendMessage10(ctrl.cmd, ctrl.buffer)) {
|
||
// 書き込み失敗
|
||
return FALSE;
|
||
}
|
||
|
||
// 正常なら、ワーク設定
|
||
ctrl.offset = 0;
|
||
break;
|
||
}
|
||
|
||
// WRITE AND VERIFY
|
||
case 0x2e:
|
||
// 書き込みを行う
|
||
if (!ctrl.unit[lun]->Write(ctrl.buffer, ctrl.next - 1)) {
|
||
// 書き込み失敗
|
||
return FALSE;
|
||
}
|
||
|
||
// 次のブロックが必要ないならここまで
|
||
ctrl.next++;
|
||
if (!cont) {
|
||
break;
|
||
}
|
||
|
||
// 次のブロックをチェック
|
||
ctrl.length = ctrl.unit[lun]->WriteCheck(ctrl.next - 1);
|
||
if (ctrl.length <= 0) {
|
||
// 書き込みできない
|
||
return FALSE;
|
||
}
|
||
|
||
// 正常なら、ワーク設定
|
||
ctrl.offset = 0;
|
||
break;
|
||
|
||
// SPECIFY(SASIのみ)
|
||
case 0xc2:
|
||
break;
|
||
|
||
default:
|
||
ASSERT(FALSE);
|
||
break;
|
||
}
|
||
|
||
// バッファ保存に成功した
|
||
return TRUE;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 論理ユニットフラッシュ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::FlushUnit()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
ASSERT(ctrl.phase == BUS::dataout);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
return;
|
||
}
|
||
|
||
// WRITE系のみ
|
||
switch (ctrl.cmd[0]) {
|
||
// WRITE(6)
|
||
case 0x0a:
|
||
// WRITE(10)
|
||
case 0x2a:
|
||
// WRITE AND VERIFY
|
||
case 0x2e:
|
||
// フラッシュ
|
||
if (!ctrl.unit[lun]->IsCacheWB()) {
|
||
ctrl.unit[lun]->Flush();
|
||
}
|
||
break;
|
||
default:
|
||
ASSERT(FALSE);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// ログ出力
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SASIDEV::Log(Log::loglevel level, const char *format, ...)
|
||
{
|
||
#if !defined(BAREMETAL)
|
||
char buffer[0x200];
|
||
va_list args;
|
||
va_start(args, format);
|
||
|
||
#ifdef RASCSI
|
||
#ifndef DISK_LOG
|
||
if (level == Log::Warning) {
|
||
return;
|
||
}
|
||
#endif // DISK_LOG
|
||
#endif // RASCSI
|
||
|
||
// フォーマット
|
||
vsprintf(buffer, format, args);
|
||
|
||
// 可変長引数終了
|
||
va_end(args);
|
||
|
||
// ログ出力
|
||
#ifdef RASCSI
|
||
printf("%s\n", buffer);
|
||
#else
|
||
host->GetVM()->GetLog()->Format(level, host, buffer);
|
||
#endif // RASCSI
|
||
#endif // BAREMETAL
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// SCSI デバイス
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コンストラクタ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
#ifdef RASCSI
|
||
SCSIDEV::SCSIDEV() : SASIDEV()
|
||
#else
|
||
SCSIDEV::SCSIDEV(Device *dev) : SASIDEV(dev)
|
||
#endif
|
||
{
|
||
// 同期転送ワーク初期化
|
||
scsi.syncenable = FALSE;
|
||
scsi.syncperiod = 50;
|
||
scsi.syncoffset = 0;
|
||
scsi.atnmsg = FALSE;
|
||
scsi.msc = 0;
|
||
memset(scsi.msb, 0x00, sizeof(scsi.msb));
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// デバイスリセット
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::Reset()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// ワーク初期化
|
||
scsi.atnmsg = FALSE;
|
||
scsi.msc = 0;
|
||
memset(scsi.msb, 0x00, sizeof(scsi.msb));
|
||
|
||
// 基底クラス
|
||
SASIDEV::Reset();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 実行
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BUS::phase_t FASTCALL SCSIDEV::Process()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// 未接続なら何もしない
|
||
if (ctrl.id < 0 || ctrl.bus == NULL) {
|
||
return ctrl.phase;
|
||
}
|
||
|
||
// バス情報の取り込み
|
||
ctrl.bus->Aquire();
|
||
|
||
// リセット
|
||
if (ctrl.bus->GetRST()) {
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "RESET信号受信");
|
||
#endif // DISK_LOG
|
||
|
||
// コントローラをリセット
|
||
Reset();
|
||
|
||
// バスもリセット
|
||
ctrl.bus->Reset();
|
||
return ctrl.phase;
|
||
}
|
||
|
||
// フェーズ処理
|
||
switch (ctrl.phase) {
|
||
// バスフリー
|
||
case BUS::busfree:
|
||
BusFree();
|
||
break;
|
||
|
||
// セレクションフェーズ
|
||
case BUS::selection:
|
||
Selection();
|
||
break;
|
||
|
||
// データアウト(MCI=000)
|
||
case BUS::dataout:
|
||
DataOut();
|
||
break;
|
||
|
||
// データイン(MCI=001)
|
||
case BUS::datain:
|
||
DataIn();
|
||
break;
|
||
|
||
// コマンド(MCI=010)
|
||
case BUS::command:
|
||
Command();
|
||
break;
|
||
|
||
// ステータス(MCI=011)
|
||
case BUS::status:
|
||
Status();
|
||
break;
|
||
|
||
// メッセージアウト(MCI=110)
|
||
case BUS::msgout:
|
||
MsgOut();
|
||
break;
|
||
|
||
// メッセージイン(MCI=111)
|
||
case BUS::msgin:
|
||
MsgIn();
|
||
break;
|
||
|
||
// その他
|
||
default:
|
||
ASSERT(FALSE);
|
||
break;
|
||
}
|
||
|
||
return ctrl.phase;
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// フェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// バスフリーフェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::BusFree()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// フェーズチェンジ
|
||
if (ctrl.phase != BUS::busfree) {
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "バスフリーフェーズ");
|
||
#endif // DISK_LOG
|
||
|
||
// フェーズ設定
|
||
ctrl.phase = BUS::busfree;
|
||
|
||
// 信号線
|
||
ctrl.bus->SetREQ(FALSE);
|
||
ctrl.bus->SetMSG(FALSE);
|
||
ctrl.bus->SetCD(FALSE);
|
||
ctrl.bus->SetIO(FALSE);
|
||
ctrl.bus->SetBSY(FALSE);
|
||
|
||
// ステータスとメッセージを初期化
|
||
ctrl.status = 0x00;
|
||
ctrl.message = 0x00;
|
||
|
||
// ATNメッセージ受信スタータス初期化
|
||
scsi.atnmsg = FALSE;
|
||
return;
|
||
}
|
||
|
||
// セレクションフェーズに移行
|
||
if (ctrl.bus->GetSEL() && !ctrl.bus->GetBSY()) {
|
||
Selection();
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// セレクションフェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::Selection()
|
||
{
|
||
DWORD id;
|
||
|
||
ASSERT(this);
|
||
|
||
// フェーズチェンジ
|
||
if (ctrl.phase != BUS::selection) {
|
||
// IDが一致していなければ無効
|
||
id = 1 << ctrl.id;
|
||
if ((ctrl.bus->GetDAT() & id) == 0) {
|
||
return;
|
||
}
|
||
|
||
// 有効なユニットが無ければ終了
|
||
if (!HasUnit()) {
|
||
return;
|
||
}
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal,
|
||
"セレクションフェーズ ID=%d (デバイスあり)", ctrl.id);
|
||
#endif // DISK_LOG
|
||
|
||
// フェーズ設定
|
||
ctrl.phase = BUS::selection;
|
||
|
||
// BSYを上げて応答
|
||
ctrl.bus->SetBSY(TRUE);
|
||
return;
|
||
}
|
||
|
||
// セレクション完了
|
||
if (!ctrl.bus->GetSEL() && ctrl.bus->GetBSY()) {
|
||
// ATN=1ならメッセージアウトフェーズ、そうでなければコマンドフェーズ
|
||
if (ctrl.bus->GetATN()) {
|
||
MsgOut();
|
||
} else {
|
||
Command();
|
||
}
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 実行フェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::Execute()
|
||
{
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "実行フェーズ コマンド$%02X", ctrl.cmd[0]);
|
||
#endif // DISK_LOG
|
||
|
||
// フェーズ設定
|
||
ctrl.phase = BUS::execute;
|
||
|
||
// データ転送のための初期化
|
||
ctrl.offset = 0;
|
||
ctrl.blocks = 1;
|
||
#ifdef RASCSI
|
||
ctrl.execstart = SysTimer::GetTimerLow();
|
||
#endif // RASCSI
|
||
|
||
// コマンド別処理
|
||
switch (ctrl.cmd[0]) {
|
||
// TEST UNIT READY
|
||
case 0x00:
|
||
CmdTestUnitReady();
|
||
return;
|
||
|
||
// REZERO
|
||
case 0x01:
|
||
CmdRezero();
|
||
return;
|
||
|
||
// REQUEST SENSE
|
||
case 0x03:
|
||
CmdRequestSense();
|
||
return;
|
||
|
||
// FORMAT UNIT
|
||
case 0x04:
|
||
CmdFormat();
|
||
return;
|
||
|
||
// REASSIGN BLOCKS
|
||
case 0x07:
|
||
CmdReassign();
|
||
return;
|
||
|
||
// READ(6)
|
||
case 0x08:
|
||
CmdRead6();
|
||
return;
|
||
|
||
// WRITE(6)
|
||
case 0x0a:
|
||
CmdWrite6();
|
||
return;
|
||
|
||
// SEEK(6)
|
||
case 0x0b:
|
||
CmdSeek6();
|
||
return;
|
||
|
||
// INQUIRY
|
||
case 0x12:
|
||
CmdInquiry();
|
||
return;
|
||
|
||
// MODE SELECT
|
||
case 0x15:
|
||
CmdModeSelect();
|
||
return;
|
||
|
||
// MDOE SENSE
|
||
case 0x1a:
|
||
CmdModeSense();
|
||
return;
|
||
|
||
// START STOP UNIT
|
||
case 0x1b:
|
||
CmdStartStop();
|
||
return;
|
||
|
||
// SEND DIAGNOSTIC
|
||
case 0x1d:
|
||
CmdSendDiag();
|
||
return;
|
||
|
||
// PREVENT/ALLOW MEDIUM REMOVAL
|
||
case 0x1e:
|
||
CmdRemoval();
|
||
return;
|
||
|
||
// READ CAPACITY
|
||
case 0x25:
|
||
CmdReadCapacity();
|
||
return;
|
||
|
||
// READ(10)
|
||
case 0x28:
|
||
CmdRead10();
|
||
return;
|
||
|
||
// WRITE(10)
|
||
case 0x2a:
|
||
CmdWrite10();
|
||
return;
|
||
|
||
// SEEK(10)
|
||
case 0x2b:
|
||
CmdSeek10();
|
||
return;
|
||
|
||
// WRITE and VERIFY
|
||
case 0x2e:
|
||
CmdWrite10();
|
||
return;
|
||
|
||
// VERIFY
|
||
case 0x2f:
|
||
CmdVerify();
|
||
return;
|
||
|
||
// SYNCHRONIZE CACHE
|
||
case 0x35:
|
||
CmdSynchronizeCache();
|
||
return;
|
||
|
||
// READ DEFECT DATA(10)
|
||
case 0x37:
|
||
CmdReadDefectData10();
|
||
return;
|
||
|
||
// READ TOC
|
||
case 0x43:
|
||
CmdReadToc();
|
||
return;
|
||
|
||
// PLAY AUDIO(10)
|
||
case 0x45:
|
||
CmdPlayAudio10();
|
||
return;
|
||
|
||
// PLAY AUDIO MSF
|
||
case 0x47:
|
||
CmdPlayAudioMSF();
|
||
return;
|
||
|
||
// PLAY AUDIO TRACK
|
||
case 0x48:
|
||
CmdPlayAudioTrack();
|
||
return;
|
||
|
||
// MODE SELECT(10)
|
||
case 0x55:
|
||
CmdModeSelect10();
|
||
return;
|
||
|
||
// MDOE SENSE(10)
|
||
case 0x5a:
|
||
CmdModeSense10();
|
||
return;
|
||
|
||
// SPECIFY(SASIのみ/SxSI利用時の警告抑制)
|
||
case 0xc2:
|
||
CmdInvalid();
|
||
return;
|
||
}
|
||
|
||
// それ以外は対応していない
|
||
Log(Log::Normal, "未対応コマンド $%02X", ctrl.cmd[0]);
|
||
CmdInvalid();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// メッセージアウトフェーズ
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::MsgOut()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// フェーズチェンジ
|
||
if (ctrl.phase != BUS::msgout) {
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "メッセージアウトフェーズ");
|
||
#endif // DISK_LOG
|
||
|
||
// セレクション後のメッセージアウトフェーズは
|
||
// IDENTIFYメッセージの処理
|
||
if (ctrl.phase == BUS::selection) {
|
||
scsi.atnmsg = TRUE;
|
||
scsi.msc = 0;
|
||
memset(scsi.msb, 0x00, sizeof(scsi.msb));
|
||
}
|
||
|
||
// フェーズ設定
|
||
ctrl.phase = BUS::msgout;
|
||
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetMSG(TRUE);
|
||
ctrl.bus->SetCD(TRUE);
|
||
ctrl.bus->SetIO(FALSE);
|
||
|
||
// データ転送は1バイトx1ブロック
|
||
ctrl.offset = 0;
|
||
ctrl.length = 1;
|
||
ctrl.blocks = 1;
|
||
|
||
#ifndef RASCSI
|
||
// メッセージを要求
|
||
ctrl.bus->SetREQ(TRUE);
|
||
#endif // RASCSI
|
||
return;
|
||
}
|
||
|
||
#ifdef RASCSI
|
||
// 受信
|
||
Receive();
|
||
#else
|
||
// リクエスト中
|
||
if (ctrl.bus->GetREQ()) {
|
||
// イニシエータが送信した
|
||
if (ctrl.bus->GetACK()) {
|
||
Receive();
|
||
}
|
||
} else {
|
||
// イニシエータに次を要求
|
||
if (!ctrl.bus->GetACK()) {
|
||
ReceiveNext();
|
||
}
|
||
}
|
||
#endif // RASCSI
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// 共通エラー処理
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::Error()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// バス情報の取り込み
|
||
ctrl.bus->Aquire();
|
||
|
||
// リセットチェック
|
||
if (ctrl.bus->GetRST()) {
|
||
// コントローラをリセット
|
||
Reset();
|
||
|
||
// バスもリセット
|
||
ctrl.bus->Reset();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ、メッセージインフェーズはバスフリー
|
||
if (ctrl.phase == BUS::status || ctrl.phase == BUS::msgin) {
|
||
BusFree();
|
||
return;
|
||
}
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "エラー(ステータスフェーズへ)");
|
||
#endif // DISK_LOG
|
||
|
||
// ステータスとメッセージを設定(CHECK CONDITION)
|
||
ctrl.status = 0x02;
|
||
ctrl.message = 0x00;
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// コマンド
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// INQUIRY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdInquiry()
|
||
{
|
||
Disk *disk;
|
||
int lun;
|
||
DWORD major;
|
||
DWORD minor;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "INQUIRYコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 有効なユニットを探す
|
||
disk = NULL;
|
||
for (lun = 0; lun < UnitMax; lun++) {
|
||
if (ctrl.unit[lun]) {
|
||
disk = ctrl.unit[lun];
|
||
break;
|
||
}
|
||
}
|
||
|
||
// ディスク側で処理(本来はコントローラで処理される)
|
||
if (disk) {
|
||
#ifdef RASCSI
|
||
major = (DWORD)(RASCSI >> 8);
|
||
minor = (DWORD)(RASCSI & 0xff);
|
||
#else
|
||
host->GetVM()->GetVersion(major, minor);
|
||
#endif // RASCSI
|
||
ctrl.length =
|
||
ctrl.unit[lun]->Inquiry(ctrl.cmd, ctrl.buffer, major, minor);
|
||
} else {
|
||
ctrl.length = 0;
|
||
}
|
||
|
||
if (ctrl.length <= 0) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 同期転送サポート情報の追加
|
||
if (scsi.syncenable) {
|
||
ctrl.buffer[7] |= (1 << 4);
|
||
}
|
||
|
||
// データインフェーズ
|
||
DataIn();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MODE SELECT
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdModeSelect()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "MODE SELECTコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
ctrl.length = ctrl.unit[lun]->SelectCheck(ctrl.cmd);
|
||
if (ctrl.length <= 0) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// データアウトフェーズ
|
||
DataOut();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MODE SENSE
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdModeSense()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "MODE SENSEコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
ctrl.length = ctrl.unit[lun]->ModeSense(ctrl.cmd, ctrl.buffer);
|
||
ASSERT(ctrl.length >= 0);
|
||
if (ctrl.length == 0) {
|
||
Log(Log::Warning,
|
||
"サポートしていないMODE SENSEページ $%02X", ctrl.cmd[2]);
|
||
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// データインフェーズ
|
||
DataIn();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// START STOP UNIT
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdStartStop()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "START STOP UNITコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->StartStop(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// SEND DIAGNOSTIC
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdSendDiag()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "SEND DIAGNOSTICコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->SendDiag(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// PREVENT/ALLOW MEDIUM REMOVAL
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdRemoval()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "PREVENT/ALLOW MEDIUM REMOVALコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->Removal(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// READ CAPACITY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdReadCapacity()
|
||
{
|
||
DWORD lun;
|
||
int length;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "READ CAPACITYコマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
length = ctrl.unit[lun]->ReadCapacity(ctrl.cmd, ctrl.buffer);
|
||
ASSERT(length >= 0);
|
||
if (length <= 0) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// レングス設定
|
||
ctrl.length = length;
|
||
|
||
// データインフェーズ
|
||
DataIn();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// READ(10)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdRead10()
|
||
{
|
||
DWORD lun;
|
||
DWORD record;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ホストブリッジならメッセージ受信
|
||
if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'B', 'R')) {
|
||
CmdGetMessage10();
|
||
return;
|
||
}
|
||
|
||
// レコード番号とブロック数を取得
|
||
record = ctrl.cmd[2];
|
||
record <<= 8;
|
||
record |= ctrl.cmd[3];
|
||
record <<= 8;
|
||
record |= ctrl.cmd[4];
|
||
record <<= 8;
|
||
record |= ctrl.cmd[5];
|
||
ctrl.blocks = ctrl.cmd[7];
|
||
ctrl.blocks <<= 8;
|
||
ctrl.blocks |= ctrl.cmd[8];
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "READ(10)コマンド レコード=%08X ブロック=%d", record, ctrl.blocks);
|
||
#endif // DISK_LOG
|
||
|
||
// ブロック数0は処理しない
|
||
if (ctrl.blocks == 0) {
|
||
Status();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record);
|
||
if (ctrl.length <= 0) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 次のブロックを設定
|
||
ctrl.next = record + 1;
|
||
|
||
// データインフェーズ
|
||
DataIn();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// WRITE(10)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdWrite10()
|
||
{
|
||
DWORD lun;
|
||
DWORD record;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ホストブリッジならメッセージ受信
|
||
if (ctrl.unit[lun]->GetID() == MAKEID('S', 'C', 'B', 'R')) {
|
||
CmdSendMessage10();
|
||
return;
|
||
}
|
||
|
||
// レコード番号とブロック数を取得
|
||
record = ctrl.cmd[2];
|
||
record <<= 8;
|
||
record |= ctrl.cmd[3];
|
||
record <<= 8;
|
||
record |= ctrl.cmd[4];
|
||
record <<= 8;
|
||
record |= ctrl.cmd[5];
|
||
ctrl.blocks = ctrl.cmd[7];
|
||
ctrl.blocks <<= 8;
|
||
ctrl.blocks |= ctrl.cmd[8];
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal,
|
||
"WRTIE(10)コマンド レコード=%08X ブロック=%d", record, ctrl.blocks);
|
||
#endif // DISK_LOG
|
||
|
||
// ブロック数0は処理しない
|
||
if (ctrl.blocks == 0) {
|
||
Status();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
ctrl.length = ctrl.unit[lun]->WriteCheck(record);
|
||
if (ctrl.length <= 0) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 次のブロックを設定
|
||
ctrl.next = record + 1;
|
||
|
||
// データアウトフェーズ
|
||
DataOut();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// SEEK(10)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdSeek10()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "SEEK(10)コマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->Seek(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// VERIFY
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdVerify()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
DWORD record;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// レコード番号とブロック数を取得
|
||
record = ctrl.cmd[2];
|
||
record <<= 8;
|
||
record |= ctrl.cmd[3];
|
||
record <<= 8;
|
||
record |= ctrl.cmd[4];
|
||
record <<= 8;
|
||
record |= ctrl.cmd[5];
|
||
ctrl.blocks = ctrl.cmd[7];
|
||
ctrl.blocks <<= 8;
|
||
ctrl.blocks |= ctrl.cmd[8];
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal,
|
||
"VERIFYコマンド レコード=%08X ブロック=%d", record, ctrl.blocks);
|
||
#endif // DISK_LOG
|
||
|
||
// ブロック数0は処理しない
|
||
if (ctrl.blocks == 0) {
|
||
Status();
|
||
return;
|
||
}
|
||
|
||
// BytChk=0なら
|
||
if ((ctrl.cmd[1] & 0x02) == 0) {
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->Seek(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
return;
|
||
}
|
||
|
||
// テスト読み込み
|
||
ctrl.length = ctrl.unit[lun]->Read(ctrl.buffer, record);
|
||
if (ctrl.length <= 0) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 次のブロックを設定
|
||
ctrl.next = record + 1;
|
||
|
||
// データアウトフェーズ
|
||
DataOut();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// SYNCHRONIZE CACHE
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdSynchronizeCache()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 成功したことにする(未実装)
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// READ DEFECT DATA(10)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdReadDefectData10()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "READ DEFECT DATA(10)コマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
ctrl.length = ctrl.unit[lun]->ReadDefectData10(ctrl.cmd, ctrl.buffer);
|
||
ASSERT(ctrl.length >= 0);
|
||
|
||
if (ctrl.length <= 4) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// データインフェーズ
|
||
DataIn();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// READ TOC
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdReadToc()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
ctrl.length = ctrl.unit[lun]->ReadToc(ctrl.cmd, ctrl.buffer);
|
||
if (ctrl.length <= 0) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// データインフェーズ
|
||
DataIn();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// PLAY AUDIO(10)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdPlayAudio10()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->PlayAudio(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// PLAY AUDIO MSF
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdPlayAudioMSF()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->PlayAudioMSF(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// PLAY AUDIO TRACK
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdPlayAudioTrack()
|
||
{
|
||
DWORD lun;
|
||
BOOL status;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
status = ctrl.unit[lun]->PlayAudioTrack(ctrl.cmd);
|
||
if (!status) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MODE SELECT10
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdModeSelect10()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "MODE SELECT10コマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
ctrl.length = ctrl.unit[lun]->SelectCheck10(ctrl.cmd);
|
||
if (ctrl.length <= 0) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// データアウトフェーズ
|
||
DataOut();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// MODE SENSE(10)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdModeSense10()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "MODE SENSE(10)コマンド");
|
||
#endif // DISK_LOG
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ドライブでコマンド処理
|
||
ctrl.length = ctrl.unit[lun]->ModeSense10(ctrl.cmd, ctrl.buffer);
|
||
ASSERT(ctrl.length >= 0);
|
||
if (ctrl.length == 0) {
|
||
Log(Log::Warning,
|
||
"サポートしていないMODE SENSE(10)ページ $%02X", ctrl.cmd[2]);
|
||
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// データインフェーズ
|
||
DataIn();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// GET MESSAGE(10)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdGetMessage10()
|
||
{
|
||
DWORD lun;
|
||
SCSIBR *bridge;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ホストブリッジでないならエラー
|
||
if (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'B', 'R')) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// バッファの再確保(ブロック毎の転送ではないため)
|
||
if (ctrl.bufsize < 0x1000000) {
|
||
free(ctrl.buffer);
|
||
ctrl.bufsize = 0x1000000;
|
||
ctrl.buffer = (BYTE *)malloc(ctrl.bufsize);
|
||
}
|
||
|
||
// ドライブで処理する
|
||
bridge = (SCSIBR*)ctrl.unit[lun];
|
||
ctrl.length = bridge->GetMessage10(ctrl.cmd, ctrl.buffer);
|
||
|
||
if (ctrl.length <= 0) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 次のブロックを設定
|
||
ctrl.blocks = 1;
|
||
ctrl.next = 1;
|
||
|
||
// リードフェーズ
|
||
DataIn();
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// SEND MESSAGE(10)
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::CmdSendMessage10()
|
||
{
|
||
DWORD lun;
|
||
|
||
ASSERT(this);
|
||
|
||
// 論理ユニット
|
||
lun = (ctrl.cmd[1] >> 5) & 0x07;
|
||
if (!ctrl.unit[lun]) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ホストブリッジでないならエラー
|
||
if (ctrl.unit[lun]->GetID() != MAKEID('S', 'C', 'B', 'R')) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// バッファの再確保(ブロック毎の転送ではないため)
|
||
if (ctrl.bufsize < 0x1000000) {
|
||
free(ctrl.buffer);
|
||
ctrl.bufsize = 0x1000000;
|
||
ctrl.buffer = (BYTE *)malloc(ctrl.bufsize);
|
||
}
|
||
|
||
// 転送量を設定
|
||
ctrl.length = ctrl.cmd[6];
|
||
ctrl.length <<= 8;
|
||
ctrl.length |= ctrl.cmd[7];
|
||
ctrl.length <<= 8;
|
||
ctrl.length |= ctrl.cmd[8];
|
||
|
||
if (ctrl.length <= 0) {
|
||
// 失敗(エラー)
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// 次のブロックを設定
|
||
ctrl.blocks = 1;
|
||
ctrl.next = 1;
|
||
|
||
// ライトフェーズ
|
||
DataOut();
|
||
}
|
||
|
||
//===========================================================================
|
||
//
|
||
// データ転送
|
||
//
|
||
//===========================================================================
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ送信
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::Send()
|
||
{
|
||
#ifdef RASCSI
|
||
int len;
|
||
#endif // RASCSI
|
||
BOOL result;
|
||
|
||
ASSERT(this);
|
||
ASSERT(!ctrl.bus->GetREQ());
|
||
ASSERT(ctrl.bus->GetIO());
|
||
|
||
#ifdef RASCSI
|
||
// レングス!=0なら送信
|
||
if (ctrl.length != 0) {
|
||
len = ctrl.bus->SendHandShake(
|
||
&ctrl.buffer[ctrl.offset], ctrl.length);
|
||
|
||
// 全て送信できなければステータスフェーズへ移行
|
||
if (len != (int)ctrl.length) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// オフセットとレングス
|
||
ctrl.offset += ctrl.length;
|
||
ctrl.length = 0;
|
||
return;
|
||
}
|
||
#else
|
||
// オフセットとレングス
|
||
ASSERT(ctrl.length >= 1);
|
||
ctrl.offset++;
|
||
ctrl.length--;
|
||
|
||
// ACKアサート直後にSendNextでデータ設定済みならリクエストを上げる
|
||
if (ctrl.length != 0) {
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(TRUE);
|
||
return;
|
||
}
|
||
#endif // RASCSI
|
||
|
||
// ブロック減算、リザルト初期化
|
||
ctrl.blocks--;
|
||
result = TRUE;
|
||
|
||
// データ引き取り後の処理(リード/データインのみ)
|
||
if (ctrl.phase == BUS::datain) {
|
||
if (ctrl.blocks != 0) {
|
||
// 次のバッファを設定(offset, lengthをセットすること)
|
||
result = XferIn(ctrl.buffer);
|
||
#ifndef RASCSI
|
||
ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset]);
|
||
#endif // RASCSI
|
||
}
|
||
}
|
||
|
||
// リザルトFALSEなら、ステータスフェーズへ移行
|
||
if (!result) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ブロック!=0なら送信継続
|
||
if (ctrl.blocks != 0){
|
||
ASSERT(ctrl.length > 0);
|
||
ASSERT(ctrl.offset == 0);
|
||
#ifndef RASCSI
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(TRUE);
|
||
#endif // RASCSI
|
||
return;
|
||
}
|
||
|
||
// 次フェーズに移動
|
||
switch (ctrl.phase) {
|
||
// メッセージインフェーズ
|
||
case BUS::msgin:
|
||
// IDENTIFYメッセージの拡張メッセージに対する応答送信完了
|
||
if (scsi.atnmsg) {
|
||
// フラグオフ
|
||
scsi.atnmsg = FALSE;
|
||
|
||
// コマンドフェーズ
|
||
Command();
|
||
} else {
|
||
// バスフリーフェーズ
|
||
BusFree();
|
||
}
|
||
break;
|
||
|
||
// データインフェーズ
|
||
case BUS::datain:
|
||
// ステータスフェーズ
|
||
Status();
|
||
break;
|
||
|
||
// ステータスフェーズ
|
||
case BUS::status:
|
||
// メッセージインフェーズ
|
||
ctrl.length = 1;
|
||
ctrl.blocks = 1;
|
||
ctrl.buffer[0] = (BYTE)ctrl.message;
|
||
MsgIn();
|
||
break;
|
||
|
||
// その他(ありえない)
|
||
default:
|
||
ASSERT(FALSE);
|
||
break;
|
||
}
|
||
}
|
||
|
||
#ifndef RASCSI
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ送信継続
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::SendNext()
|
||
{
|
||
ASSERT(this);
|
||
|
||
// REQが上がっている
|
||
ASSERT(ctrl.bus->GetREQ());
|
||
ASSERT(ctrl.bus->GetIO());
|
||
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(FALSE);
|
||
|
||
// バッファにデータがあれば先に設定する
|
||
if (ctrl.length > 1) {
|
||
ctrl.bus->SetDAT(ctrl.buffer[ctrl.offset + 1]);
|
||
}
|
||
}
|
||
#endif // RASCSI
|
||
|
||
#ifndef RASCSI
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ受信
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::Receive()
|
||
{
|
||
DWORD data;
|
||
|
||
ASSERT(this);
|
||
|
||
// REQが上がっている
|
||
ASSERT(ctrl.bus->GetREQ());
|
||
ASSERT(!ctrl.bus->GetIO());
|
||
|
||
// データ取得
|
||
data = (DWORD)ctrl.bus->GetDAT();
|
||
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(FALSE);
|
||
|
||
switch (ctrl.phase) {
|
||
// コマンドフェーズ
|
||
case BUS::command:
|
||
ctrl.cmd[ctrl.offset] = data;
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "コマンドフェーズ $%02X", data);
|
||
#endif // DISK_LOG
|
||
|
||
// 最初のデータ(オフセット0)によりレングスを再設定
|
||
if (ctrl.offset == 0) {
|
||
if (ctrl.cmd[0] >= 0x20) {
|
||
// 10バイトCDB
|
||
ctrl.length = 10;
|
||
}
|
||
}
|
||
break;
|
||
|
||
// メッセージアウトフェーズ
|
||
case BUS::msgout:
|
||
ctrl.message = data;
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "メッセージアウトフェーズ $%02X", data);
|
||
#endif // DISK_LOG
|
||
break;
|
||
|
||
// データアウトフェーズ
|
||
case BUS::dataout:
|
||
ctrl.buffer[ctrl.offset] = (BYTE)data;
|
||
break;
|
||
|
||
// その他(ありえない)
|
||
default:
|
||
ASSERT(FALSE);
|
||
break;
|
||
}
|
||
}
|
||
#endif // RASCSI
|
||
|
||
#ifdef RASCSI
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ受信
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::Receive()
|
||
#else
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ受信継続
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
void FASTCALL SCSIDEV::ReceiveNext()
|
||
#endif // RASCSI
|
||
{
|
||
#ifdef RASCSI
|
||
int len;
|
||
#endif // RASCSI
|
||
BOOL result;
|
||
int i;
|
||
BYTE data;
|
||
|
||
ASSERT(this);
|
||
|
||
// REQが下がっていること
|
||
ASSERT(!ctrl.bus->GetREQ());
|
||
ASSERT(!ctrl.bus->GetIO());
|
||
|
||
#ifdef RASCSI
|
||
// レングス!=0なら受信
|
||
if (ctrl.length != 0) {
|
||
// 受信
|
||
len = ctrl.bus->ReceiveHandShake(
|
||
&ctrl.buffer[ctrl.offset], ctrl.length);
|
||
|
||
// 全て受信できなければステータスフェーズへ移行
|
||
if (len != (int)ctrl.length) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// オフセットとレングス
|
||
ctrl.offset += ctrl.length;
|
||
ctrl.length = 0;;
|
||
return;
|
||
}
|
||
#else
|
||
// オフセットとレングス
|
||
ASSERT(ctrl.length >= 1);
|
||
ctrl.offset++;
|
||
ctrl.length--;
|
||
|
||
// レングス!=0なら、再びreqをセット
|
||
if (ctrl.length != 0) {
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(TRUE);
|
||
return;
|
||
}
|
||
#endif // RASCSI
|
||
|
||
// ブロック減算、リザルト初期化
|
||
ctrl.blocks--;
|
||
result = TRUE;
|
||
|
||
// データ受理後の処理(フェーズ別)
|
||
switch (ctrl.phase) {
|
||
|
||
// データアウトフェーズ
|
||
case BUS::dataout:
|
||
if (ctrl.blocks == 0) {
|
||
// このバッファで終了
|
||
result = XferOut(FALSE);
|
||
} else {
|
||
// 次のバッファに続く(offset, lengthをセットすること)
|
||
result = XferOut(TRUE);
|
||
}
|
||
break;
|
||
|
||
// メッセージアウトフェーズ
|
||
case BUS::msgout:
|
||
ctrl.message = ctrl.buffer[0];
|
||
if (!XferMsg(ctrl.message)) {
|
||
// メッセージアウトに失敗したら、即座にバスフリー
|
||
BusFree();
|
||
return;
|
||
}
|
||
|
||
// メッセージインに備え、メッセージデータをクリアしておく
|
||
ctrl.message = 0x00;
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
// リザルトFALSEなら、ステータスフェーズへ移行
|
||
if (!result) {
|
||
Error();
|
||
return;
|
||
}
|
||
|
||
// ブロック!=0なら受信継続
|
||
if (ctrl.blocks != 0){
|
||
ASSERT(ctrl.length > 0);
|
||
ASSERT(ctrl.offset == 0);
|
||
#ifndef RASCSI
|
||
// ターゲットが操作する信号線
|
||
ctrl.bus->SetREQ(TRUE);
|
||
#endif // RASCSI
|
||
return;
|
||
}
|
||
|
||
// 次フェーズに移動
|
||
switch (ctrl.phase) {
|
||
// コマンドフェーズ
|
||
case BUS::command:
|
||
#ifdef RASCSI
|
||
// コマンドデータ転送
|
||
len = 6;
|
||
if (ctrl.buffer[0] >= 0x20 && ctrl.buffer[0] <= 0x7D) {
|
||
// 10バイトCDB
|
||
len = 10;
|
||
}
|
||
for (i = 0; i < len; i++) {
|
||
ctrl.cmd[i] = (DWORD)ctrl.buffer[i];
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal, "コマンド $%02X", ctrl.cmd[i]);
|
||
#endif // DISK_LOG
|
||
}
|
||
#endif // RASCSI
|
||
|
||
// 実行フェーズ
|
||
Execute();
|
||
break;
|
||
|
||
// メッセージアウトフェーズ
|
||
case BUS::msgout:
|
||
// ATNがアサートし続ける限りメッセージアウトフェーズを継続
|
||
if (ctrl.bus->GetATN()) {
|
||
// データ転送は1バイトx1ブロック
|
||
ctrl.offset = 0;
|
||
ctrl.length = 1;
|
||
ctrl.blocks = 1;
|
||
#ifndef RASCSI
|
||
// メッセージを要求
|
||
ctrl.bus->SetREQ(TRUE);
|
||
#endif // RASCSI
|
||
return;
|
||
}
|
||
|
||
// ATNで送信されたメッセージの解析
|
||
if (scsi.atnmsg) {
|
||
i = 0;
|
||
while (i < scsi.msc) {
|
||
// メッセージの種類
|
||
data = scsi.msb[i];
|
||
|
||
// ABORT
|
||
if (data == 0x06) {
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal,
|
||
"メッセージコード ABORT $%02X", data);
|
||
#endif // DISK_LOG
|
||
BusFree();
|
||
return;
|
||
}
|
||
|
||
// BUS DEVICE RESET
|
||
if (data == 0x0C) {
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal,
|
||
"メッセージコード BUS DEVICE RESET $%02X", data);
|
||
#endif // DISK_LOG
|
||
scsi.syncoffset = 0;
|
||
BusFree();
|
||
return;
|
||
}
|
||
|
||
// IDENTIFY
|
||
if (data >= 0x80) {
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal,
|
||
"メッセージコード IDENTIFY $%02X", data);
|
||
#endif // DISK_LOG
|
||
}
|
||
|
||
// 拡張メッセージ
|
||
if (data == 0x01) {
|
||
#if defined(DISK_LOG)
|
||
Log(Log::Normal,
|
||
"メッセージコード EXTENDED MESSAGE $%02X", data);
|
||
#endif // DISK_LOG
|
||
|
||
// 同期転送が可能な時だけチェック
|
||
if (!scsi.syncenable || scsi.msb[i + 2] != 0x01) {
|
||
ctrl.length = 1;
|
||
ctrl.blocks = 1;
|
||
ctrl.buffer[0] = 0x07;
|
||
MsgIn();
|
||
return;
|
||
}
|
||
|
||
// Transfer period factor(50 x 4 = 200nsに制限)
|
||
scsi.syncperiod = scsi.msb[i + 3];
|
||
if (scsi.syncperiod > 50) {
|
||
scsi.syncoffset = 50;
|
||
}
|
||
|
||
// REQ/ACK offset(16に制限)
|
||
scsi.syncoffset = scsi.msb[i + 4];
|
||
if (scsi.syncoffset > 16) {
|
||
scsi.syncoffset = 16;
|
||
}
|
||
|
||
// STDR応答メッセージ生成
|
||
ctrl.length = 5;
|
||
ctrl.blocks = 1;
|
||
ctrl.buffer[0] = 0x01;
|
||
ctrl.buffer[1] = 0x03;
|
||
ctrl.buffer[2] = 0x01;
|
||
ctrl.buffer[3] = (BYTE)scsi.syncperiod;
|
||
ctrl.buffer[4] = (BYTE)scsi.syncoffset;
|
||
MsgIn();
|
||
return;
|
||
}
|
||
|
||
// 次へ
|
||
i++;
|
||
}
|
||
}
|
||
|
||
// ATNメッセージ受信スタータス初期化
|
||
scsi.atnmsg = FALSE;
|
||
|
||
// コマンドフェーズ
|
||
Command();
|
||
break;
|
||
|
||
// データアウトフェーズ
|
||
case BUS::dataout:
|
||
// フラッシュ
|
||
FlushUnit();
|
||
|
||
// ステータスフェーズ
|
||
Status();
|
||
break;
|
||
|
||
// その他(ありえない)
|
||
default:
|
||
ASSERT(FALSE);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//---------------------------------------------------------------------------
|
||
//
|
||
// データ転送MSG
|
||
//
|
||
//---------------------------------------------------------------------------
|
||
BOOL FASTCALL SCSIDEV::XferMsg(DWORD msg)
|
||
{
|
||
ASSERT(this);
|
||
ASSERT(ctrl.phase == BUS::msgout);
|
||
|
||
// メッセージアウトデータの保存
|
||
if (scsi.atnmsg) {
|
||
scsi.msb[scsi.msc] = (BYTE)msg;
|
||
scsi.msc++;
|
||
scsi.msc %= 256;
|
||
}
|
||
|
||
return TRUE;
|
||
}
|