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

📄 worker_thread.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>.
***********************************************************************/


#include "scsi-miniport.h"
#include "../dvdproxy95/dvdproxy95.h"
#include "../include/dvdsynth-device.h"

#include "ddk.h"
#include "internal.h"


// Returns 0 on success, MS-DOS error code on error.
int __stdcall OpenFileRO(unsigned* phandle, const char* pathname) {
   const unsigned flags = RING0_OPENCREATE_FLAG_MM|RING0_OPENCREATE_FLAG_ALLOW_EXISTING|RING0_OPENCREATE_FLAG_NO_INT_24|RING0_OPENCREATE_FLAG_EXTENDED_SIZE|RING0_OPENCREATE_FLAG_DENYNONE|RING0_OPENCREATE_FLAG_READONLY;
   return Ring0_OpenCreate(flags, pathname, phandle);
}
//80013040

// Returns 0 on success, MS-DOS error code on error.
int __stdcall CreateOrOpenFileRW(unsigned* phandle, const char* pathname, int creation_disposition) {
   const unsigned flags = (RING0_OPENCREATE_FLAG_MM|RING0_OPENCREATE_FLAG_NO_INT_24|RING0_OPENCREATE_FLAG_EXTENDED_SIZE|RING0_OPENCREATE_FLAG_DENYWRITE|RING0_OPENCREATE_FLAG_READWRITE) + RING0_OPENCREATE_FLAG_ALLOW_EXISTING*(creation_disposition<=1) + RING0_OPENCREATE_FLAG_ALLOW_CREATE*(creation_disposition>=1);
   return Ring0_OpenCreate(flags, pathname, phandle);
}

// Returns bytes read on success, negative of MS-DOS error code on error
int ReadFile(dvs_file_handle handle, unsigned offset, unsigned offset_high, unsigned count, void* buf) {
   if (offset_high != 0)
      return 0;
   return Ring0_ReadWrite(R0_READFILE, (unsigned)handle, offset, count, buf);
}

// Returns bytes written on success, negative of MS-DOS error code on error
int WriteFile(dvs_file_handle handle, unsigned offset, unsigned offset_high, unsigned count, void* buf) {
   if (offset_high != 0)
      return 0;
   return Ring0_ReadWrite(R0_WRITEFILE, (unsigned)handle, offset, count, buf);
}

// Returns file size on success, 0 on error
unsigned GetFileSize(dvs_file_handle handle, unsigned* size_high) {
   if (size_high)
      *size_high = 0;
   return Ring0_SizeClose(R0_GETFILESIZE, (unsigned)handle);
}

void CloseFile(dvs_file_handle handle) {
   Ring0_SizeClose(R0_CLOSEFILE, (unsigned)handle);
}


__declspec(naked)
void* __stdcall MakeThunkCall(void* func, void* args, unsigned arg_bytes) {
   __asm {
      push  ebp
      mov   ebp,esp

      mov   edx,[ebp+12]   /* args */
      mov   ecx,[ebp+16]   /* arg_bytes */
      shr   ecx,2
      jz    make_call

copy_loop:
      dec   ecx
      push  [edx+ecx*4]
      jnz   copy_loop

make_call:
      call  [ebp+8]        /* func */

      mov   esp,ebp
      pop   ebp
      ret   12
   }
}


/*******************************************************************\
\*******************************************************************/


struct AsyncCallRecord {
   void (__stdcall*f)(void*, int);
   void* p;
   int i;
};


struct AsyncCallQueue {
   unsigned head,tail;
   enum { queue_size = 16 };
   AsyncCallRecord q[queue_size];
   unsigned records_lost;

   void Reset() {
      tail = head;
   }

   void Put(void (__stdcall*f)(void*, int), void* p, int i) {
      unsigned h = head;
      // this is safe because VxDs are cooperatively multitasked
      if (h > tail && q[(h-1u)%queue_size].f == f
         && q[(h-1u)%queue_size].p == p && q[(h-1u)%queue_size].i == i)
      {
         return;
      }
      if (h - tail < queue_size) {
         q[h%queue_size].f = f;
         q[h%queue_size].p = p;
         q[h%queue_size].i = i;
         head = h+1;
      } else {
         ++records_lost;
      }
   }
};

AsyncCallQueue async_call_queue;

ULONG notification_hwnd;

#define WM_APP_APC  0xA5FC


__declspec(naked)
void AsyncPostMessage() {
   __asm {
      pushad
      mov   esi,offset callback
      VXD_CALL(1,14)  // Schedule_VM_Event
      popad
      retn
   callback:
      mov   eax,[notification_hwnd]
      test  eax,eax
      jz    exit
      push  0
      push  0
      push  offset async_call_queue
      push  0
      push  WM_APP_APC
      push  eax
      VXD_CALL(23,6)  // _SHELL_PostMessage
      add   esp,24
   exit:
      retn
   }
}


void __stdcall AsyncUserModeCall(void (__stdcall*f)(void*, int), void* p, int i) {
   async_call_queue.Put(f,p,i);
   AsyncPostMessage();
}


void __cdecl SetAsyncNotificationWindow(ULONG hwnd) {
   notification_hwnd = hwnd;
   async_call_queue.Reset();
}


__declspec(naked)
void AsyncSetEvent(unsigned event) {
   __asm {
      pushad
      VXD_CALL(1,3)     // Get_Sys_VM_Handle (in ebx)
      mov   esi,offset callback
      mov   edx,[esp+36]
      VXD_CALL(1,17)    // Call_VM_Event
      popad
      retn
   callback:
      mov   eax,edx
      VXD_JUMP(42,14)   // _VWIN32_SetWin32Event
   }
}


__declspec(naked)
void __stdcall CloseEvent(unsigned event) {
   __asm {
      pushad
      mov   eax,[esp+36]
      VXD_CALL(42,20)   // _VWIN32_CloseVxDHandle
      popad
      retn  4
   }
}


/*******************************************************************\
\*******************************************************************/


void __cdecl MemCpy(void* dst, const void* src, unsigned long count) {
   ScsiPortMoveMemory(dst, src, count);
}


/*******************************************************************\
\*******************************************************************/


void CallDriverInitFunc(dvs_driver_handle hmodule) {
   static DvsDockingBayKernelGlobal callbacks = {
      MemSet,
      MemCpy,
      DebugPrintf,
      0, //AsyncUserModeCall,
      ReadFile,
      WriteFile,
      AsyncSetEvent,
   };
   void* function = _PELDR_GetProcAddress(hmodule, "DvdsynthDriverInit");
   if (function) {
      ((void(__cdecl*)(DvsDockingBayKernelGlobal*))function)(&callbacks);
   }
}


//__declspec(naked)
scsi_result_t ScsiDispatch(DvsDeviceKernel* device, const unsigned char* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) {
   return device->ScsiCommand(device, cdb, cdblen, buffer, pbuflen, inout, sense);
}


void __cdecl Init(ULONG notification_hwnd) {
//   SetAsyncNotificationWindow(notification_hwnd);
//   IPSA::IPSAInit();
}


/*******************************************************************\
\*******************************************************************/


DVDProxy* g_dvdproxy;

void __cdecl SetHandler(int scsi_id, DvsDeviceKernel* handler) {
//   DebugPrintf("SetHandler(%d,%X)\n", scsi_id, handler);
//   if (handler==(DvsDeviceKernel*)-1) {
//      extern DvsDeviceKernel dummy_device;
//      handler = &dummy_device;
//   }
   if (scsi_id > 0 && scsi_id < 32) {
      g_dvdproxy->handlers[scsi_id] = handler;
   }
}


/*******************************************************************\
\*******************************************************************/


// This must match the mpdfunc_* enum in miniport.h!
void* mpdfunc_pointers[] = {
   Init,
   _PELDR_LoadModule,
   _PELDR_FreeModule,
   CallDriverInitFunc,
   SetHandler,
   ScsiDispatch,
   _PageReserve,
   _PageCommit,
   _PageFree,
   CONFIGMG_Locate_DevNode,
   CONFIGMG_Get_Child,
   CONFIGMG_Get_Sibling,
   CONFIGMG_Query_Remove_SubTree,
   CONFIGMG_Remove_SubTree,
   CONFIGMG_Reenumerate_DevNode,
   OpenFileRO,
   CreateOrOpenFileRW,
   ReadFile,
   WriteFile,
   GetFileSize,
   CloseFile,
   CloseEvent,
};


static const void* miniport_handle = (void*)~0;


/*******************************************************************\
\*******************************************************************/


scsi_result_t __cdecl HandleDummyDevice(DvsDeviceKernel*, const unsigned char* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) {
   if (cdb[0] == DVDPROXY_SCSIOP) {
      if (cdb[1] != DVDPROXY_VERSION) {
         return MAKE_SCSIRESULT_ERROR(DVDPROXY_ERROR_WRONG_VERSION);
      } else if (cdb[2] != DVDPROXY_CMD_THUNK_CALL) {
         return MAKE_SCSIRESULT_ERROR(DVDPROXY_ERROR_INVALID_COMMAND);
      } else {
         CDB_Thunk_Call* call_cdb = (CDB_Thunk_Call*)cdb;
         void* function = 0;
         unsigned index = (unsigned)call_cdb->export_name;
         if (call_cdb->hmodule == hmodule_miniport) {
            DebugPrintf("looking up miniport function #%d\n", index);
            if (index < sizeof(mpdfunc_pointers)/sizeof(mpdfunc_pointers[0])) {
               function = mpdfunc_pointers[index];
            }
         } else {
            if (index<65536) {
               DebugPrintf("looking up export #%d in module %X\n", call_cdb->export_name, call_cdb->hmodule);
            } else {
               DebugPrintf("looking up export %X in module %X\n", call_cdb->export_name, call_cdb->hmodule);
               DebugPrintf("  (%s)\n", call_cdb->export_name);
            }
            function = _PELDR_GetProcAddress(call_cdb->hmodule, call_cdb->export_name);
         }
         if (function == 0) {
            return MAKE_SCSIRESULT_ERROR(DVDPROXY_ERROR_EXPORT_NOT_FOUND);
         } else {
            *(void**)sense->command_specific = MakeThunkCall(function, buffer, *pbuflen);
            return MAKE_SCSIRESULT_ERROR(DVDPROXY_ERROR_THUNK_CALL_SUCCEEDED);
         }
      }

   } else {
      return MAKE_SCSIRESULT_ERROR(0x52000);  // INVALID COMMAND OPERATION CODE
   }
}


DvsDeviceKernel dummy_device = { HandleDummyDevice };


/*******************************************************************\
\*******************************************************************/


scsi_result_t HandleSRB(SCSI_REQUEST_BLOCK* Srb, DvsDeviceKernel* handler, SenseData* sense) {
   if (handler == 0) {
      return MAKE_SCSIRESULT(SRB_STATUS_INVALID_TARGET_ID, 0, 0, 0, 0);
   }

   const unsigned char* cdb = Srb->Cdb;
   int cdblen = Srb->CdbLength;

   // check CDB length
   static const BYTE expected_cdb_lengths[] = { 6, 10, 10, 0, 0, 12, 0, 0 };
   BYTE expected_cdb_length = expected_cdb_lengths[cdb[0]>>5];
   if (expected_cdb_length ? (expected_cdb_length != cdblen) : (cdblen < 6 || cdblen > 16)) {
      return MAKE_SCSIRESULT_ERROR(0x51A00);    // PARAMETER LIST LENGTH ERROR
   }

   // convert READ(6) and READ(12) commands into READ(10)
   unsigned char cdbbuf[10];
   if (cdb[0] == SCSIOP_READ6) {
      cdbbuf[0] = SCSIOP_READ;
      cdbbuf[1] = cdb[1] & 0xE0;
      cdbbuf[2] = 0;
      cdbbuf[3] = cdb[1] & 0x1F;
      cdbbuf[4] = cdb[2];
      cdbbuf[5] = cdb[3];    // logical block address
      cdbbuf[6] = 0;
      cdbbuf[7] = !cdb[4];
      cdbbuf[8] = cdb[4];    // transfer length
      cdbbuf[9] = cdb[5];    // control
      cdb = cdbbuf;
      cdblen = 10;
   } else if (cdb[0] == SCSIOP_READ12) {
      if (cdb[6] == 0 && cdb[7] == 0) {
         cdbbuf[0] = SCSIOP_READ;
         cdbbuf[1] = cdb[1];
         cdbbuf[2] = cdb[2];
         cdbbuf[3] = cdb[3];
         cdbbuf[4] = cdb[4];
         cdbbuf[5] = cdb[5];    // logical block address
         cdbbuf[6] = 0;
         cdbbuf[7] = cdb[8];
         cdbbuf[8] = cdb[9];    // transfer length
         cdbbuf[9] = cdb[11];   // control
         cdb = cdbbuf;
         cdblen = 10;
      } else {
         // The caller wants to transfer 65536 or
         // more *blocks* in one call -- unlikely!
         return SCSIRESULT_INVALID_CDB;
      }
   }

   // dispatch
   DBGPRINT((DBGLEVEL "Dispatching (handler %X)\n", handler));
   return handler->ScsiCommand(handler, cdb, cdblen, (unsigned char*)Srb->DataBuffer, &Srb->DataTransferLength, (Srb->SrbFlags & 0xC0) >> 6, sense);
}


/*******************************************************************\
\*******************************************************************/


void SetScsiSense(SCSI_REQUEST_BLOCK* completed_srb, SenseData* sense, scsi_result_t result) {
   completed_srb->SrbStatus = SCSIRESULT_SRBSTAT(result);
   completed_srb->ScsiStatus = SCSIRESULT_TARGSTAT(result);
   // Windows doesn't seem to like it if you set
   // SRB_STATUS_AUTOSENSE_VALID on success.
   if (result != SCSIRESULT_SUCCESS
     && (SCSIRESULT_SRBSTAT(result) == SRB_STATUS_SUCCESS
         || SCSIRESULT_SRBSTAT(result) == SRB_STATUS_ERROR))
   {
      unsigned sense_len = min(18U, completed_srb->SenseInfoBufferLength);
      if (sense_len > 0) {
         sense->sense_key = (sense->sense_key & 0xF0) | SCSIRESULT_SENSEKEY(result);
         sense->asc = SCSIRESULT_ASC(result);
         sense->ascq = SCSIRESULT_ASCQ(result);
         ScsiPortMoveMemory(completed_srb->SenseInfoBuffer, sense, sense_len);
         completed_srb->SenseInfoBufferLength = sense_len;
         completed_srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
      }
   }
}


/*******************************************************************\
\*******************************************************************/


static const SenseData default_sense = { 0x70, 0, 0, {0,0,0,0}, 10, {0,0,0,0}, 0, 0, 0, {0,0,0} };

#ifdef WORKER_THREAD

void __cdecl WorkerThreadProc(void* _self) {
   DBGPRINT((DBGLEVEL "WorkerThreadProc start"));
   DVDProxy* self = (DVDProxy*)_self;
   g_dvdproxy = self;
   for (;;) {
      Wait_Semaphore(self->semaphore_handle, BLOCK_SVC_INTS|BLOCK_THREAD_IDLE);
      for (int n = 0; n < DVDProxy::max_outstanding_srbs; ++n) {
         if (self->srbs[n] != 0 && !self->srb_complete[n]) {
            SCSI_REQUEST_BLOCK* srb = self->srbs[n];
            DBGPRINT((DBGLEVEL "Worker thread: got SRB %X\n", srb));
            SenseData sense = default_sense;
            scsi_result_t result = HandleSRB(srb, self->handlers[srb->TargetId], &sense);
            DBGPRINT((DBGLEVEL "Worker thread: finished %X with result %X\n", srb, result));
            SetScsiSense(srb, &sense, result);
            self->srb_complete[n] = true;
            //WakeMiniportThread();
         }
      }
   }
}

#else

void __cdecl WorkProc(DVDProxy* self, SCSI_REQUEST_BLOCK* srb) {
   g_dvdproxy = self;
   SenseData sense = default_sense;
   scsi_result_t result = HandleSRB(srb, self->handlers[srb->TargetId], &sense);
   SetScsiSense(srb, &sense, result);
}

#endif

⌨️ 快捷键说明

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