📄 logscsi.cpp
字号:
int len = min(available_length, actual_length);
for (int i=0; i<len; ++i) {
wsprintf(buf + i*3, "%02X ", bytes[i]);
}
if (actual_length <= available_length) {
buf[len*3-1] = 0;
} else {
wsprintf(buf + len*3 - 1, "... (%d bytes)", actual_length);
}
return buf;
}
const char* GetItemText(LogScsiUser* that, int row, int col) {
if (row == LogScsiUser::max_scis - 1) {
switch (col) {
case 1: return "[Log buffer full]";
case 2: return "[Clear it to continue logging]";
default: return 0;
}
}
static char buf[128];
SavedCommandInfo sci = that->scis[row];
switch (col) {
case 0: // command
if (sci.cdb[0] <= 0x5D) {
return scsi_command_names_00_5D[sci.cdb[0]];
} else if (sci.cdb[0] >= 0xA0 && sci.cdb[0] <= 0xBF) {
return scsi_command_names_A0_BF[sci.cdb[0]-0xA0];
} else {
return undefined;
}
case 1: // CDB
return HexByteString(sci.cdb, 12, sci.cdb_size+1);
case 2: // Result
{
if (sci.result == SCSIRESULT_SUCCESS) {
return "success";
}
unsigned char srb_stat = SCSIRESULT_SRBSTAT(sci.result);
unsigned char targ_stat = SCSIRESULT_TARGSTAT(sci.result);
unsigned char sense_key = SCSIRESULT_SENSEKEY(sci.result);
unsigned char asc = SCSIRESULT_ASC(sci.result);
unsigned char ascq = SCSIRESULT_ASCQ(sci.result);
if (srb_stat != SRB_STATUS_SUCCESS && srb_stat != SRB_STATUS_ERROR) {
if (srb_stat <= 0x24 && srb_status_names[srb_stat] != 0) {
strcpy(buf, srb_status_names[srb_stat]);
} else {
wsprintf(buf, "%02X", srb_stat);
}
wsprintf(buf+strlen(buf), " (%02X %X %02X %02X)", targ_stat, sense_key, asc, ascq);
return buf;
}
buf[0] = 0;
if (srb_stat != SRB_STATUS_ERROR || targ_stat != SCSISTAT_CHECK_CONDITION) {
if (targ_stat <= 0x28 && target_status_names[targ_stat>>1] != 0) {
wsprintf(buf, "%s/%s/", srb_status_names[srb_stat], target_status_names[targ_stat>>1]);
} else {
wsprintf(buf, "%s/%02X/", srb_status_names[srb_stat], targ_stat);
}
}
// note: depends on format of scsi_result_t
for (int i=0; i<sizeof(result_code_names)/sizeof(result_code_names[0]); ++i) {
if (result_code_names[i].result == SCSIRESULT_SENSE(sci.result)) {
strcat(buf, result_code_names[i].text);
return buf;
}
}
wsprintf(buf+strlen(buf), "%s (%02X %02X)", sense_key_names[sense_key], asc, ascq);
return buf;
}
case 3: // Data out
if ((sci.inout & 2) && sci.buffer_size != 0) {
return HexByteString(sci.buffer, 12, sci.buffer_size);
} else {
return "";
}
case 4: // Data in
if ((sci.inout & 1) && sci.buffer_size != 0) {
return HexByteString(sci.buffer, 12, sci.buffer_size);
} else {
return "";
}
default:
return "???";
}
}
void SaveLog(HWND hwndOwner, LogScsiUser* u) {
static char filename[MAX_PATH];
OPENFILENAME ofn;
ofn.lStructSize = 76;
ofn.hwndOwner = hwndOwner;
ofn.hInstance = g_hinstance;
ofn.lpstrFilter = "Comma-delimited text file (*.csv)\0*.csv\0";
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 2;
ofn.lpstrFile = filename;
ofn.nMaxFile = MAX_PATH;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = "Save SCSI log";
ofn.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY;
ofn.lpstrDefExt = "csv";
ofn.lpfnHook = NULL;
ofn.lpTemplateName = NULL;
if (GetSaveFileName(&ofn)) {
FILE* out = fopen(filename, "wb");
if (out) {
for (int row = 0; row < u->num_scis; ++row) {
for (int col = 0; col < 5; ++col) {
if (col != 0)
putc(',', out);
const char* text = GetItemText(u, row, col);
if (text) {
const char* comma = strchr(text, ',');
if (comma)
putc('"', out);
fputs(text, out);
if (comma)
putc('"', out);
}
}
putc('\n', out);
}
fclose(out);
} else {
MessageBox(hwndOwner, "Could not open the file for writing.", "SCSI logger", MB_OK);
}
}
}
class LogCommandsListView : public ListView {
LogScsiUser* that;
public:
LogCommandsListView(NestableWindow* parent, LogScsiUser* _that) : ListView(parent), that(_that) {}
const char* GetItemText(int row, int col) { return ::GetItemText(that, row, col); }
};
class LogCommandsFrameWindow : public FrameWindow {
HMENU hmenu;
LogScsiUser* that;
public:
bool hidden;
LogCommandsFrameWindow(const char* name, LogScsiUser* _that)
: FrameWindow(name, hmenu = LoadMenu(g_hinstance, MAKEINTRESOURCE(IDR_LOGCOMMANDS))),
that(_that)
{
hidden = false;
}
bool OnClose() {
Hide();
hidden = true;
return true;
}
bool OnMenuCommand(int id, bool is_accelerator) {
static MENUITEMINFO mii = { 48, MIIM_TYPE, MFT_STRING };
switch (id) {
case ID_STARTSTOP:
that->k->log = !that->k->log;
mii.dwTypeData = (char*)(that->k->log ? "&Stop!" : "&Start!");
SetMenuItemInfo(hmenu, id, FALSE, &mii);
DrawMenuBar(hwnd);
return true;
case ID_CLEAR:
that->num_scis = 0;
that->listview->SetNumItems(0);
return true;
case ID_FILE_SAVEAS:
SaveLog(hwnd, that);
return true;
case ID_OPTIONS_IGNORETESTUNITREADY:
that->k->ignore_testunitready = !that->k->ignore_testunitready;
CheckMenuItem(hmenu, id, that->k->ignore_testunitready ? MF_CHECKED : MF_UNCHECKED);
return true;
default:
return false;
}
}
};
unsigned __stdcall ThreadProc(void* param) {
LogScsiUser* u = (LogScsiUser*)param;
LogScsiKernel* k = u->k;
for (;;) {
WaitForSingleObject(u->event, INFINITE);
if (u->quit)
break;
unsigned h = k->head, t = k->tail;
if (t < h) {
do {
if (u->num_scis < u->max_scis) {
u->scis[u->num_scis++] = k->scis[t % k->queue_size];
u->listview->AddItem(true);
}
++t;
} while (t < h);
k->tail = t;
}
}
return 0;
}
void LogScsiUser_ShowHide(void* self, int) {
LogScsiUser* u = (LogScsiUser*) self;
u->frame->hidden = !u->frame->hidden;
if (u->frame->hidden)
u->frame->Hide();
else
u->frame->Show();
}
void LogScsiUser_AddDeviceMenuItems(DvsDeviceUser* self, DvsMenu* menu) {
LogScsiUser* u = (LogScsiUser*) self;
menu->vtable->AddItem(menu, "Show SCSI log", !u->frame->hidden, LogScsiUser_ShowHide, u, 0);
}
void LogScsiUser_Delete(DvsDeviceUser* self) {
LogScsiUser* u = (LogScsiUser*) self;
g_callbacks->Driver_Unload(u->driver_handle);
u->quit = true;
SetEvent(u->event);
WaitForSingleObject(u->hthread, INFINITE);
CloseHandle(u->hthread);
g_callbacks->CloseKernelEventHandle(u->k->event);
CloseHandle(u->event);
delete u->frame;
delete u->listview;
delete u;
}
DvsDeviceUser_vtable logscsiuser_vtable = {
LogScsiUser_AddDeviceMenuItems,
0, // queryunplug
LogScsiUser_Delete
};
DvsDeviceUser* HookDevice(DvsDeviceKernel** pkernel, DvsDockingBay* bay) {
LogScsiUser* u = new LogScsiUser;
u->vtable = &logscsiuser_vtable;
u->name = "SCSI log";
u->frame = new LogCommandsFrameWindow(u->name, u);
u->listview = new LogCommandsListView(u->frame, u);
u->listview->InsertColumn(0, 100, "Command", 0);
u->listview->InsertColumn(1, 200, "CDB", 0);
u->listview->InsertColumn(2, 120, "Result", 0);
u->listview->InsertColumn(3, 100, "Data out", 0);
u->listview->InsertColumn(4, 100, "Data in", 0);
u->frame->SetChild(u->listview);
u->event = CreateEvent(NULL, FALSE, FALSE, NULL);
u->quit = false;
u->num_scis = 0;
u->driver_handle = g_callbacks->Driver_Load("LogScsi.kll");
u->k = (LogScsiKernel*)bay->vtable->SharedPool_Alloc(bay, sizeof(LogScsiKernel));
u->k->ScsiCommand = (dvs_scsi_func*)g_callbacks->Driver_Call(u->driver_handle, "GetDispatchFunc", "");
u->k->child = *pkernel;
u->k->event = g_callbacks->OpenKernelEventHandle(u->event);
u->k->log = true;
u->k->ignore_testunitready = true;
u->k->head = 0;
u->k->tail = 0;
unsigned thread_id;
u->hthread = (HANDLE)_beginthreadex(NULL, 0, ThreadProc, u, 0, &thread_id);
*pkernel = u->k;
return u;
}
DvsFilterGlobal plugin_info = {
0,
"SCSI protocol spy",
DVDSYNTH_FILTER_ALL_DEVICE_CLASSES,
HookDevice,
0
};
extern "C"
DvsFilterGlobal* DvdsynthFilterPluginEntry(DvsDockingBayGlobal* callbacks) {
g_callbacks = callbacks;
return &plugin_info;
}
extern "C"
BOOL WINAPI DllMain(HINSTANCE hinst, DWORD dwReason, LPVOID) {
g_hinstance = hinst;
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -