⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 miniport.cpp

📁 DVD工具dvdsynth的源码
💻 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 + -