/*********************************************************************** 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 #define STRICT #include #include "miniport.h" #include "aspi.h" #include "../dvdproxy95/dvdproxy95.h" #include "../include/dvdsynth-plugin.h" #include "SharedPool.h" /*******************************************************************\ \*******************************************************************/ #include extern DvsBasePluginCallbacks* g_callbacks; /*******************************************************************\ \*******************************************************************/ // ASPI is only used to send DVDPROXY_CMD_THUNK_CALL requests to the // kernel driver. I wish I could avoid this, but there doesn't seem to // be any way to contact a SCSI miniport driver from ring 3 except by // sending SCSI commands. namespace ASPI { const SenseData default_sense = { 0x70, 0, 0, {0,0,0,0}, 10, {0,0,0,0}, 0, 0, 0, {0,0,0} }; DWORD (*SendASPI32Command)(LPSRB) = 0; int dvdsynth_ha_id = -1; enum { dvdsynth_targ_id = 0 }; scsi_result_t SendSCSICommand(int ha, int targ, int lun, const unsigned char* cdb, int cdblen, unsigned char* buffer, unsigned long* pbuflen, int inout, SenseData* sense) { // Creating a new event for each call seems wasteful, but I'd // rather that this function be thread-safe. HANDLE hCompleted = CreateEvent(NULL, TRUE, FALSE, NULL); SRB_ExecSCSICmd srb; memset(&srb, 0, sizeof(srb)); srb.SRB_Cmd = SC_EXEC_SCSI_CMD; srb.SRB_HaId = ha; srb.SRB_Flags = SRB_EVENT_NOTIFY + SRB_ENABLE_RESIDUAL_COUNT + (inout==1 ? SRB_DIR_IN : inout==2 ? SRB_DIR_OUT : SRB_DIR_SCSI); srb.SRB_Target = targ; srb.SRB_Lun = lun; srb.SRB_BufLen = *pbuflen; srb.SRB_BufPointer = buffer; srb.SRB_SenseLen = 16; srb.SRB_CDBLen = cdblen; memcpy(srb.CDBByte, cdb, cdblen); srb.SRB_PostProc = hCompleted; if (SS_PENDING == SendASPI32Command(&srb)) { WaitForSingleObject(hCompleted, INFINITE); } CloseHandle(hCompleted); *pbuflen -= srb.SRB_BufLen; *sense = default_sense; memcpy(sense, srb.SenseArea, srb.SRB_SenseLen); return MAKE_SCSIRESULT(srb.SRB_Status, srb.SRB_TargStat, sense->sense_key, sense->asc, sense->ascq); } int GetHATargetMax(int ha) { SRB_HAInquiry srb; memset(&srb, 0, sizeof(srb)); srb.SRB_Cmd = SC_HA_INQUIRY; srb.SRB_HaId = ha; SendASPI32Command(&srb); if (srb.SRB_Status != SS_COMP) { return 0; } else { return max(8, srb.HA_Unique[3]); } } int Init() { // Initialize ASPI HMODULE hASPI = LoadLibrary("wnaspi32.dll"); if (!hASPI) return -1; DWORD (*GetASPI32SupportInfo)(); GetASPI32SupportInfo = (DWORD (*)()) GetProcAddress(hASPI, "GetASPI32SupportInfo"); SendASPI32Command = (DWORD (*)(LPSRB)) GetProcAddress(hASPI, "SendASPI32Command"); if (GetASPI32SupportInfo == 0 || SendASPI32Command == 0) return -2; DWORD rtn = GetASPI32SupportInfo(); if ((rtn & 0xFF00) != (SS_COMP * 256) || (rtn & 0xFF) == 0) return -3; int num_host_adapters = rtn & 0xFF; // Scan for the DVDSynth miniport by comparing INQUIRY data static const unsigned char cdb_inquiry[6] = { 0x12, 0, 0, 0, 36, 0 }; for (int i=0; i= SS_INVALID_CMD && aspi_srb_status <= SS_NO_DEVICE) { return aspi_srb_status - SS_INVALID_CMD + SRB_STATUS_INVALID_REQUEST; } else if (aspi_srb_status == SS_INVALID_SRB) { // SS_INVALID_SRB is returned for several different errors. // I'm assuming no one checks these codes too closely... return SRB_STATUS_INVALID_TARGET_ID; } else { return SRB_STATUS_BAD_FUNCTION; // ??? } } */ } /*******************************************************************\ \*******************************************************************/ namespace Miniport { void Hello() { static const CDB_Dvdproxy cdb = { DVDPROXY_SCSIOP, DVDPROXY_VERSION, DVDPROXY_CMD_HELLO }; SenseData sense; scsi_result_t result = ASPI::SendMiniportCommand((const unsigned char*)&cdb, "", 0, 1, &sense); } void* DriverCall(void* module, const char* entry_name, const char* types, ...) { bool numerical_export = (unsigned(entry_name) < 65536); const char* printable_entry_name = entry_name; char printable_entry_name_buf[16]; if (numerical_export) { g_callbacks->Sprint(printable_entry_name_buf, 16, "#%1", "d", entry_name); printable_entry_name = printable_entry_name_buf; } enum { max_args=16 }; int num_args = strspn(types, "ips&<>E"); if (types[num_args] != 0) { char buf[256]; g_callbacks->Sprint(buf, 256, "\"%1\" had an argument of an unrecognized type (\"%2\").", "sc", entry_name, types[num_args]); MessageBox(NULL, buf, "DVDSynth", MB_OK); } if (num_args > max_args) { char buf[256]; g_callbacks->Sprint(buf, 256, "DriverCall invoked with %1 arguments (max %2)", "dd", num_args, max_args); MessageBox(NULL, buf, "DVDSynth", MB_OK); return 0; } // get args void* args[max_args]; void* original_args[max_args]; { va_list val; va_start(val, types); for (int i=0; i' && types[i+1] != 'i' && types[i+1] != '&')) { char buf[256]; g_callbacks->Sprint(buf, 256, "DriverCall type '<' or '>' does not point to integer argument (in call of \"%1\" with args \"%2\")", 0, printable_entry_name, types); MessageBox(NULL, buf, "DVDSynth", MB_OK); return 0; } } va_end(val); } // determine shared memory space needed bool need_pool = !numerical_export; unsigned object_sizes[max_args]; for (int i=0; i= 65536) { switch (types[i]) { case '&': object_size = 4; break; case '<': object_size = (types[i-1] == '&') ? *(unsigned*)args[i-1] : (unsigned)args[i-1]; break; case '>': object_size = (types[i+1] == '&') ? *(unsigned*)args[i+1] : (unsigned)args[i+1]; break; case 's': object_size = lstrlen((const char*)args[i]) + 1; break; } } object_sizes[i] = object_size; if (object_size > 0) { need_pool = true; } } // NB: the SharedPool_* functions sometimes call DriverCall recursively. // But none of these calls requires the use of buffer_pool, so infinite // recursion is avoided by creating/using buffer_pool only when it's needed. static void* buffer_pool; if (need_pool) { if (buffer_pool == 0) { buffer_pool = SharedPool_Create(true); } if (!numerical_export) { int len = lstrlen(entry_name)+1; char* buf = (char*)SharedPool_Alloc(buffer_pool, len); memcpy(buf, entry_name, len); entry_name = buf; } for (int i=0; iSprint(buf, 256, "Call to driver-exported function \"%1\" failed: the function was not found.", 0, entry_name); MessageBox(NULL, buf, "DVDSynth", MB_OK); return 0; } else { char buf[256]; g_callbacks->Sprint(buf, 256, "Call to driver-exported function \"%1\" failed with error code %2.\n\nPlease report this as a DVDSynth bug.", "sX", entry_name, result); MessageBox(NULL, buf, "DVDSynth", MB_OK); return 0; } } int Init() { int aspi_init_result = ASPI::Init(); if (aspi_init_result != 0) return aspi_init_result; Hello(); DriverCall(miniport_handle, (char*)mpdfunc_Init, "p", g_callbacks->GetTaskbarHWND()); return 0; } }