📄 miniport.cpp
字号:
/***********************************************************************
Copyright 2002 Ben Rudiak-Gould.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
or visit <http://www.gnu.org/copyleft/gpl.html>.
***********************************************************************/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "miniport.h"
#include "../include/dvdsynth-plugin.h"
#include "../include/dvdsynth-scsi.h"
#include "../dvdproxy2k/dvdproxy2k.h"
#include "scsipt.h"
#include <stddef.h>
namespace SPTI {
const SenseData default_sense = { 0x70, 0, 0, {0,0,0,0}, 10, {0,0,0,0}, 0, 0, 0, {0,0,0} };
HANDLE scsi_port;
int scsi_port_number;
scsi_result_t __cdecl SendMiniportSCSICommand(const unsigned char* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) {
SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
memset(&swb, 0, sizeof(swb));
swb.spt.Length = sizeof(SCSI_PASS_THROUGH);
//swb.spt.TargetId = 0;
swb.spt.CdbLength = cdblen;
swb.spt.DataIn = inout==1 ? SCSI_IOCTL_DATA_IN : inout==2 ? SCSI_IOCTL_DATA_IN : SCSI_IOCTL_DATA_UNSPECIFIED;
swb.spt.DataTransferLength = *pbuflen;
swb.spt.TimeOutValue = 60;
swb.spt.DataBuffer = swb.spt.DataTransferLength ? buffer : NULL;
swb.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
swb.spt.SenseInfoLength = 18;
memcpy(swb.ucSenseBuf, sense, swb.spt.SenseInfoLength);
memcpy(swb.spt.Cdb, cdb, cdblen);
ULONG length = sizeof(swb);
ULONG returned;
if (DeviceIoControl(scsi_port, IOCTL_SCSI_PASS_THROUGH_DIRECT, &swb, length, &swb, length, &returned, NULL)) {
*pbuflen = swb.spt.DataTransferLength;
memcpy(sense, swb.ucSenseBuf, swb.spt.SenseInfoLength);
if (swb.spt.ScsiStatus) {
return MAKE_SCSIRESULT(SRB_STATUS_ERROR, swb.spt.ScsiStatus, sense->sense_key, sense->asc, sense->ascq);
} else {
return SCSIRESULT_SUCCESS;
}
} else {
UCHAR srb_status; // Why can't the damned ioctl return this???
// It's impossible to recover the original value because many
// different codes are collapsed into the same Win32 error. Is
// this even worth it?
switch (GetLastError()) {
case 37:
srb_status = SRB_STATUS_INVALID_TARGET_ID;
break;
case 79:
srb_status = SRB_STATUS_TIMEOUT;
break;
case 1167:
srb_status = SRB_STATUS_SELECTION_TIMEOUT;
break;
default:
srb_status = SRB_STATUS_BUS_RESET; // no clue here...
break;
}
return MAKE_SCSIRESULT(srb_status, 0, 0, 0, 0);
}
}
int Init(const unsigned char* desired_inquiry_data) {
if (scsi_port) {
CloseHandle(scsi_port);
scsi_port = 0;
}
for (scsi_port_number = 0; ; ++scsi_port_number) {
char buf[32];
wsprintf(buf, "\\\\.\\Scsi%d:", scsi_port_number);
scsi_port = CreateFile(buf, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (scsi_port == INVALID_HANDLE_VALUE) {
return -1; // no more SCSI ports (I assume) and we didn't find ours
} else {
static const unsigned char cdb_inquiry[6] = { 0x12, 0, 0, 0, 36, 0 };
unsigned char inquiry_buf[36];
memset(inquiry_buf, 0, sizeof(inquiry_buf));
unsigned long buflen = 36;
SenseData sense;
if (SCSIRESULT_SUCCESS == SendMiniportSCSICommand(cdb_inquiry, 6, inquiry_buf, &buflen, 1, &sense)) {
if (memcmp(inquiry_buf, desired_inquiry_data, 36) == 0) {
return 0;
}
}
CloseHandle(scsi_port);
}
}
}
}
/*******************************************************************\
\*******************************************************************/
namespace Miniport {
bool Init() {
return SPTI::Init(dvdproxy_device_inquiry_data) >= 0;
}
inline scsi_result_t SendCommand(const void* cdb, const void* buf, unsigned long buflen, int inout) {
SenseData sense;
return SPTI::SendMiniportSCSICommand((const BYTE*)cdb, 12, (BYTE*)buf, &buflen, inout, &sense);
}
void RetireRequest(unsigned char* req_buffer, scsi_result_t result) {
UserModeRequest* req = (UserModeRequest*)req_buffer;
const bool send_sense = ((result & 0xFFF00000) == MAKE_SCSIRESULT_ERROR(0));
unsigned long buflen = req->data_transfer_length + 18 * send_sense;
static CDB_RetireSRB retire_cdb = { DVDPROXY_SCSIOP, DVDPROXY_VERSION, DVDPROXY_CMD_RETIRE_SRB };
retire_cdb.sense_included = send_sense;
retire_cdb.sequence_number = req->sequence_number;
retire_cdb.srb_status = SCSIRESULT_SRBSTAT(result) + (send_sense * SRB_STATUS_AUTOSENSE_VALID);
retire_cdb.scsi_status = SCSIRESULT_TARGSTAT(result);
SendCommand(&retire_cdb, req_buffer + sizeof(UserModeRequest), buflen, 2);
}
scsi_result_t GetSRB(unsigned char* buffer, unsigned long buflen, int tick_length, int listen_timeout, int response_timeout) {
static CDB_GetSRB get_cdb = { DVDPROXY_SCSIOP, DVDPROXY_VERSION, DVDPROXY_CMD_GET_SRB };
get_cdb.tick_length_in_ms = tick_length;
get_cdb.listen_timeout = listen_timeout;
get_cdb.response_timeout = response_timeout;
return SendCommand(&get_cdb, buffer, buflen, 1);
}
void KeepAlive(int ticks) {
static CDB_KeepAlive keepalive_cdb = { DVDPROXY_SCSIOP, DVDPROXY_VERSION, DVDPROXY_CMD_KEEP_ALIVE };
keepalive_cdb.ticks = ticks;
SendCommand(&keepalive_cdb, "", 0, 2);
}
void GenericDvdproxyCommand(int cmd) {
static CDB_Dvdproxy cdb = { DVDPROXY_SCSIOP, DVDPROXY_VERSION };
cdb.cmd = cmd;
SendCommand(&cdb, "", 0, 2);
}
void Detach() {
GenericDvdproxyCommand(DVDPROXY_CMD_DETACH);
}
void BusChange() {
GenericDvdproxyCommand(DVDPROXY_CMD_BUS_CHANGE);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -