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

📄 dvdproxy.cpp

📁 DVD工具dvdsynth的源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:


bool DVDProxy::ConstructUserModeRequest(SCSI_REQUEST_BLOCK* src, ULONG sequence_number, SCSI_REQUEST_BLOCK* dst) {
   DBGPRINT((DBGLEVEL "sending request for %x(%d)\n", src, sequence_number));

   if (dst->SenseInfoBuffer) {
      for (int i=0; i<dst->SenseInfoBufferLength; ++i)
         ((char*)dst->SenseInfoBuffer)[i] = i+0xAB;
   }

   unsigned data_bytes = (src->SrbFlags & SRB_FLAGS_DATA_OUT) ? src->DataTransferLength : 0;
   unsigned total_bytes = data_bytes + sizeof(UserModeRequest);
   if (total_bytes > dst->DataTransferLength) {
//      DBGPRINT((DBGLEVEL "DVDPROXY_ERROR_NEED_MORE_DATA_SPACE: had %d, need %d (cdb=%s)\n", dst->DataTransferLength, total_bytes, CDBString(src->Cdb, src->CdbLength)));
      return false;
   }
   UserModeRequest* req = (UserModeRequest*)dst->DataBuffer;
   req->sequence_number = sequence_number;
   req->target = src->TargetId;
   req->data_transfer_direction = UCHAR((src->SrbFlags >> 6) & 3);
   req->cdb_length = src->CdbLength;
   req->reserved = 0;
   req->data_transfer_length = src->DataTransferLength;
   CopyCDB(req->cdb, src->Cdb);
   UCHAR* data = (UCHAR*)req + sizeof(UserModeRequest);
   if (data_bytes)
      ScsiPortMoveMemory(data, src->DataBuffer, data_bytes);
   dst->DataTransferLength = total_bytes;
   dst->SenseInfoBufferLength = 0;
   return true;
}


void DVDProxy::UnpackUserModeResponse(SCSI_REQUEST_BLOCK* src, SCSI_REQUEST_BLOCK* dst) {
   CDB_RetireSRB* resp = (CDB_RetireSRB*)src->Cdb;

   dst->SrbStatus = resp->srb_status;
   dst->ScsiStatus = resp->scsi_status;

   dst->DataTransferLength = min(dst->DataTransferLength, src->DataTransferLength - 18*resp->sense_included);
   if (dst->DataTransferLength)
      ScsiPortMoveMemory(dst->DataBuffer, src->DataBuffer, dst->DataTransferLength);

   dst->SenseInfoBufferLength = min(dst->SenseInfoBufferLength, 18*resp->sense_included);
   if (dst->SenseInfoBufferLength) {
      SenseData* sense_data = (SenseData*)((char*)src->DataBuffer + src->DataTransferLength - 18);
      ScsiPortMoveMemory(dst->SenseInfoBuffer, sense_data, dst->SenseInfoBufferLength);
   }
}


VOID DVDProxy::ScsiTimer() {
   if (!user_attached)
      return;
   DBGPRINT((DBGLEVEL "listen=%d response=%d\n", user_listen_countdown, user_response_countdown));
   if (srb_listen) {
      if (user_listen_countdown > 0) {
         --user_listen_countdown;
      }
      if (user_listen_countdown == 0) {
         CompleteWithScsiSense(srb_listen, DVDPROXY_ERROR_LISTEN_TIMEOUT);
         srb_listen = NULL;
      }
   } else {
      if (user_response_countdown > 0) {
         --user_response_countdown;
      }
      if (user_response_countdown == 0) {
         user_attached = false;
         ResetBus(0);
      }
   }
   ScsiPortNotification(RequestTimerCall, this, HwScsiTimer, tick_length);
}


void DVDProxy::HandleSkeletonDevice(SCSI_REQUEST_BLOCK* Srb) {
   InquiryData* data = &inquiry_data[Srb->TargetId-1];
   if (data->inquiry_length == 0) {
      CompleteWithSrbStatus(Srb, SRB_STATUS_INVALID_TARGET_ID);
   } else if (Srb->Cdb[0] == SCSIOP_INQUIRY) {
      if (Srb->Cdb[1] == 0 && Srb->Cdb[2] == 0) {
         CompleteWithData(Srb, data->inquiry, data->inquiry_length, ScsiByteToInt(Srb->Cdb[4]));
      } else {
         CompleteWithScsiSense(Srb, 0x52400);   // INVALID FIELD IN CDB
      }
   } else if (Srb->Cdb[0] == SCSIOP_MODE_SENSE10 && data->modepage_2a_length != 0) {
      if (Srb->Cdb[1] == 0 && Srb->Cdb[2] == 0x2A) {
         // Mode page 0x2A (CD/DVD Capabilities and Mechanical Status)
         CompleteWithData(Srb, data->modepage_2a, data->modepage_2a_length, Srb->Cdb[7]*256+Srb->Cdb[8]);
      } else {
         CompleteWithScsiSense(Srb, 0x52400);   // INVALID FIELD IN CDB
      }
   } else {
      CompleteWithScsiSense(Srb, 0x52000);   // INVALID COMMAND OPERATION CODE
   }
}


void DVDProxy::HandleDummyDevice(SCSI_REQUEST_BLOCK* Srb) {
   // I have to simulate this device because the idiot ScsiPort wrapper
   // won't pass SCSI commands to my driver unless I convince it there's
   // a device on the bus.
   if (Srb->Cdb[0] == SCSIOP_INQUIRY && Srb->Cdb[1] == 0 && Srb->Cdb[2] == 0) {

      CompleteWithData(Srb, dvdproxy_device_inquiry_data, 36, ScsiByteToInt(Srb->Cdb[4]));

   } else if (Srb->Cdb[0] == DVDPROXY_SCSIOP && Srb->Cdb[1] == DVDPROXY_VERSION) {

      switch (Srb->Cdb[2]) {
      case DVDPROXY_CMD_GET_SRB:
//         DBGPRINT((DBGLEVEL "DVDPROXY_CMD_GET_SRB\n"));
         if (srb_listen != NULL) {
            DBGPRINT((DBGLEVEL "Someone is already listening (this should never happen)\n"));
            CompleteWithScsiSense(srb_listen, DVDPROXY_ERROR_OLD_LISTENER);
            srb_listen = NULL;
         }
         {
            CDB_GetSRB* cdb = (CDB_GetSRB*)Srb->Cdb;
            tick_length = 1000 * cdb->tick_length_in_ms;
            user_listen_countdown = cdb->listen_timeout;
            user_response_countdown = cdb->response_timeout;
            if (!user_attached) {
               user_attached = true;
               ScsiPortNotification(RequestTimerCall, this, HwScsiTimer, tick_length);
            }
            ULONG seqnum;
            SCSI_REQUEST_BLOCK* dispatch_srb = queue.GetDispatchSRB(&seqnum);
            if (dispatch_srb) {
               DBGPRINT((DBGLEVEL "Dispatching %x\n", dispatch_srb));
               if (ConstructUserModeRequest(dispatch_srb, seqnum, Srb)) {
                  CompleteWithScsiSuccess(Srb);
               } else {
                  DBGPRINT((DBGLEVEL "Dispatch failed: need more space\n", dispatch_srb));
                  queue.UngetDispatchSRB();
                  CompleteWithScsiSense(Srb, DVDPROXY_ERROR_NEED_MORE_DATA_SPACE);
               }
            } else {
               DBGPRINT((DBGLEVEL "Putting request on hold\n"));
               srb_listen = Srb;
            }
         }
         break;
      case DVDPROXY_CMD_KEEP_ALIVE:
         DBGPRINT((DBGLEVEL "DVDPROXY_CMD_KEEP_ALIVE\n"));
         user_response_countdown = ((CDB_KeepAlive*)Srb->Cdb)->ticks;
         if (!user_attached) {
            user_attached = true;
            ScsiPortNotification(RequestTimerCall, this, HwScsiTimer, tick_length);
         }
         break;
      case DVDPROXY_CMD_RETIRE_SRB:
//         DBGPRINT((DBGLEVEL "DVDPROXY_CMD_RETIRE_SRB\n"));
         {
            ULONG seqnum = ((CDB_RetireSRB*)Srb->Cdb)->sequence_number;
            SCSI_REQUEST_BLOCK* retire_srb = queue.RemoveRetireeByIndex(seqnum);
            if (retire_srb) {
               DBGPRINT((DBGLEVEL "Retiring %x\n", retire_srb));
               UnpackUserModeResponse(Srb, retire_srb);
               Complete(retire_srb);
            } else {
               DBGPRINT((DBGLEVEL "Attemped to retire an unqueued SRB (%d)\n", seqnum));
            }
            CompleteWithScsiSuccess(Srb);
         }
         break;
      case DVDPROXY_CMD_BUS_CHANGE:
         DBGPRINT((DBGLEVEL "DVDPROXY_CMD_BUS_CHANGE\n"));
         CompleteWithScsiSuccess(Srb);
         ScsiPortNotification(BusChangeDetected, this, 0);
         break;
      case DVDPROXY_CMD_SET_INQUIRY_DATA:
         DBGPRINT((DBGLEVEL "DVDPROXY_CMD_SET_INQUIRY_DATA\n"));
         ScsiPortMoveMemory(inquiry_data, Srb->DataBuffer, min(Srb->DataTransferLength, 31*sizeof(InquiryData)));
         CompleteWithScsiSuccess(Srb);
         break;
      case DVDPROXY_CMD_DETACH:
         DBGPRINT((DBGLEVEL "DVDPROXY_CMD_DETACH\n"));
         if (srb_listen) {
            CompleteWithScsiSense(srb_listen, DVDPROXY_ERROR_DETACH);
         }
         user_attached = false;
         CompleteWithScsiSuccess(Srb);
         break;
      case DVDPROXY_CMD_GENERATE_ERROR:
         DBGPRINT((DBGLEVEL "DVDPROXY_CMD_GENERATE_ERROR\n"));
         CompleteWithSrbStatus(Srb, ((CDB_GenerateError*)Srb->Cdb)->error_code);
         break;
      default:
         DBGPRINT((DBGLEVEL "invalid operation code (%d)\n", Srb->Cdb[2]));
         CompleteWithScsiSense(Srb, DVDPROXY_ERROR_INVALID_COMMAND);
         break;
      }

   } else {
      CompleteWithScsiSense(Srb, 0x52000);  // INVALID COMMAND OPERATION CODE
   }
}


void DVDProxy::QueueSRB(SCSI_REQUEST_BLOCK* Srb) {
   DBGPRINT((DBGLEVEL "Queueing %x\n", Srb));

   if (!queue.AddIncomingSRB(Srb)) {
      DBGPRINT((DBGLEVEL "Queue full!\n"));
      CompleteWithSrbStatus(Srb, SRB_STATUS_BUSY);
      return;
   }

   if (srb_listen) {
      ULONG seqnum;
      SCSI_REQUEST_BLOCK* dispatch_srb = queue.GetDispatchSRB(&seqnum);
      // assert(dispatch_srb == Srb);
      if (dispatch_srb) {
         DBGPRINT((DBGLEVEL "Dispatching %x immediately\n", dispatch_srb));
         if (ConstructUserModeRequest(dispatch_srb, seqnum, srb_listen)) {
            CompleteWithScsiSuccess(srb_listen);
         } else {
            DBGPRINT((DBGLEVEL "Dispatch failed: need more space\n", dispatch_srb));
            queue.UngetDispatchSRB();
            CompleteWithScsiSense(srb_listen, DVDPROXY_ERROR_NEED_MORE_DATA_SPACE);
         }
         srb_listen = NULL;
      } else {
         DBGPRINT((DBGLEVEL "No SRB to dispatch! (bug)\n", Srb));
      }
   } else {
      DBGPRINT((DBGLEVEL "No current listener\n", Srb));
   }
}


BOOLEAN DVDProxy::StartIo(SCSI_REQUEST_BLOCK* Srb) {

#ifdef DBGLEVEL
   queue.DebugPrintQueue();
#endif

   unsigned char path = Srb->PathId, targ = Srb->TargetId, lun = Srb->Lun;

   switch (Srb->Function) {

   case SRB_FUNCTION_EXECUTE_SCSI:

      DBGPRINT((DBGLEVEL "SCSI command: Srb=%x Addr=%d:%d:%d Data=%d Cdb=%s\n",
         Srb, path, targ, lun, Srb->DataTransferLength, CDBString(Srb->Cdb, Srb->CdbLength)));

      ZeroMemory(Srb->SenseInfoBuffer, Srb->SenseInfoBufferLength);

      if (path != 0) {
         DBGPRINT((DBGLEVEL "pathid != 0\n"));
         CompleteWithSrbStatus(Srb, SRB_STATUS_INVALID_PATH_ID);
      } else if (lun != 0) {
         DBGPRINT((DBGLEVEL "lun != 0\n"));
         CompleteWithSrbStatus(Srb, SRB_STATUS_INVALID_LUN);
      } else if (targ == 0) {
         HandleDummyDevice(Srb);
      } else if (user_attached) {
         QueueSRB(Srb);
      } else {
         HandleSkeletonDevice(Srb);
      }
      break;

   case SRB_FUNCTION_IO_CONTROL:

   case SRB_FUNCTION_ABORT_COMMAND:
   case SRB_FUNCTION_TERMINATE_IO:
      DBGPRINT((DBGLEVEL "SRB_FUNCTION_ABORT_COMMAND or SRB_FUNCTION_TERMINATE_IO\n"));
      queue.RemoveSRB(Srb->NextSrb);
      CompleteWithSrbStatus(Srb->NextSrb, SRB_STATUS_ABORTED);
      CompleteWithSrbStatus(Srb, SRB_STATUS_SUCCESS);
      break;

   case SRB_FUNCTION_RESET_BUS:
      DBGPRINT((DBGLEVEL "SRB_FUNCTION_RESET_BUS\n"));
      ResetBus(path);
      CompleteWithSrbStatus(Srb, SRB_STATUS_SUCCESS);
      break;
/*
#ifdef DBGLEVEL
   case SRB_FUNCTION_IO_CONTROL:
      {
         struct SRB_IO_CONTROL {
            ULONG hdrlen;
            UCHAR sig[8];
            ULONG timeout;
            ULONG ctlcode;
            ULONG rtncode;
            ULONG len;
         };
         SRB_IO_CONTROL* ioctl = (SRB_IO_CONTROL*)Srb->DataBuffer;
         ioctl->timeout = 0;
         DBGPRINT((DBGLEVEL "SRB_FUNCTION_IO_CONTROL: %s %x len=%d\n", ioctl->sig, ioctl->ctlcode, ioctl->len));
         CompleteWithSrbStatus(Srb, SRB_STATUS_INVALID_REQUEST);
         break;
      }
#endif
*/
   default:
      DBGPRINT((DBGLEVEL "Srb->Function=%d\n", Srb->Function));
      CompleteWithSrbStatus(Srb, SRB_STATUS_INVALID_REQUEST);
      break;
   }

//   ScsiPortNotification(NextLuRequest, this, path, targ, lun);
   ScsiPortNotification(NextRequest, this, NULL);

   return TRUE;
}


extern "C" ULONG DriverEntry(IN PVOID DriverObject, IN PVOID Argument2) {
   DBGPRINT((DBGLEVEL "DVDProxy DriverEntry\n"));

   HW_INITIALIZATION_DATA hwInitializationData;
   ZeroMemory(&hwInitializationData, sizeof(hwInitializationData));

   hwInitializationData.HwInitializationDataSize = 80;/*sizeof(hwInitializationData)*/

   hwInitializationData.AdapterInterfaceType = Isa;

   hwInitializationData.HwInitialize = HwInitialize;
   hwInitializationData.HwStartIo = HwStartIo;
   hwInitializationData.HwFindAdapter = HwFindAdapter;
   hwInitializationData.HwResetBus = HwResetBus;

   hwInitializationData.DeviceExtensionSize = sizeof(DVDProxy);

//   hwInitializationData.NumberOfAccessRanges = 1;

   hwInitializationData.MapBuffers = TRUE;
   hwInitializationData.AutoRequestSense = TRUE;
//   hwInitializationData.MultipleRequestPerLu = TRUE;
//   hwInitializationData.TaggedQueuing = TRUE;

   hwInitializationData.HwAdapterControl = HwAdapterControl;

   return ScsiPortInitialize(DriverObject, Argument2, &hwInitializationData, 0);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -