/*********************************************************************** 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 . ***********************************************************************/ #define WIN32_LEAN_AND_MEAN #include #include "miniport.h" #include "../include/dvdsynth-plugin.h" #include "../include/dvdsynth-scsi.h" #include "../dvdproxy2k/dvdproxy2k.h" #include "scsipt.h" #include 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); } }