#include "config.h" #include "winbase.h" #include "wine/windef16.h" #include "wine/winaspi.h" #include "heap.h" #include "debugtools.h" #include "selectors.h" #include "miscemu.h" /* DOSMEM_* */ #include "callback.h" #include "winerror.h" DEFAULT_DEBUG_CHANNEL(aspi) static HINSTANCE hWNASPI32 = INVALID_HANDLE_VALUE; static DWORD (__cdecl *pSendASPI32Command) (LPSRB) = NULL; static void DOSASPI_PostProc( SRB_ExecSCSICmd *lpPRB ) { DWORD ptrSRB; LPSRB16 lpSRB16; memcpy(&ptrSRB,(LPBYTE)(lpPRB+1)+lpPRB->SRB_SenseLen,sizeof(DWORD)); TRACE("Copying data back to DOS client at 0x%8lx\n",ptrSRB); lpSRB16 = DOSMEM_MapRealToLinear(ptrSRB); lpSRB16->cmd.SRB_TargStat = lpPRB->SRB_TargStat; lpSRB16->cmd.SRB_HaStat = lpPRB->SRB_HaStat; memcpy((LPBYTE)(lpSRB16+1)+lpSRB16->cmd.SRB_CDBLen,&lpPRB->SenseArea[0],lpSRB16->cmd.SRB_SenseLen); /* Now do posting */ if( lpPRB->SRB_Status == SS_SECURITY_VIOLATION ) { /* SS_SECURITY_VIOLATION isn't defined in DOS ASPI */ TRACE("Returning SS_NO_DEVICE for SS_SECURITY_VIOLATION\n"); lpPRB->SRB_Status = SS_NO_DEVICE; } lpSRB16->cmd.SRB_Status = lpPRB->SRB_Status; TRACE("SRB_Status = 0x%x\n", lpPRB->SRB_Status); HeapFree(GetProcessHeap(),0,lpPRB); if( (lpSRB16->cmd.SRB_Flags & SRB_POSTING) && lpSRB16->cmd.SRB_PostProc ) { CONTEXT86 ctx; /* The stack should look like this on entry to proc * NOTE: the SDK draws the following diagram bass akwards, use this one * to avoid being confused. Remember, the act of pushing something on * an intel stack involves decreasing the stack pointer by the size of * the data, and then copying the data at the new SP. */ /*************************** * ... Other crap that is already on the stack ... * Segment of SRB Pointer <- SP+6 * Offset of SRB Pointer <- SP+4 * Segment of return address <- SP+2 * Offset of return address <- SP+0 */ /* FIXME: I am about 99% sure what is here is correct, * but this code has never been tested (and probably * won't be either until someone finds a DOS program * that actually uses a Post Routine) */ /* Zero everything */ memset(&ctx, 0, sizeof(ctx)); /* CS:IP is routine to call */ ctx.SegCs = SELECTOROF(lpSRB16->cmd.SRB_PostProc); ctx.Eip = OFFSETOF(lpSRB16->cmd.SRB_PostProc); /* DPMI_CallRMProc will push the pointer to the stack * it is given (in this case &ptrSRB) with length * 2*sizeof(WORD), that is, it copies the the contents * of ptrSRB onto the stack, and decs sp by 2*sizeof(WORD). * After doing that, it pushes the return address * onto the stack (so we don't need to worry about that) * So the stack should be okay for the PostProc */ if(DPMI_CallRMProc(&ctx, (LPWORD)&ptrSRB, 2, FALSE)) { TRACE("DPMI_CallRMProc returned nonzero (error) status\n"); } } /* if ((SRB_Flags&SRB_POSTING) && SRB_PostProc) */ } static DWORD ASPI_SendASPIDOSCommand(DWORD ptrSRB) { PSRB_ExecSCSICmd lpPRB; DWORD retval; union tagSRB16 * lpSRB16; lpSRB16 = DOSMEM_MapRealToLinear(ptrSRB); retval = SS_ERR; switch( lpSRB16->common.SRB_Cmd ) { case SC_HA_INQUIRY: TRACE("SC_HA_INQUIRY\n"); /* Format is identical in this case */ retval = (*pSendASPI32Command)((LPSRB)lpSRB16); break; case SC_GET_DEV_TYPE: TRACE("SC_GET_DEV_TYPE\n"); /* Format is identical in this case */ retval = (*pSendASPI32Command)((LPSRB)lpSRB16); break; case SC_EXEC_SCSI_CMD: TRACE("SC_EXEC_SCSI_CMD\n"); TRACE("Copying data from DOS client at 0x%8lx\n",ptrSRB); lpPRB = HeapAlloc(GetProcessHeap(),0,sizeof(SRB)+lpSRB16->cmd.SRB_SenseLen+sizeof(DWORD)); #define srb_dos_to_w32(name) \ lpPRB->SRB_##name = lpSRB16->cmd.SRB_##name srb_dos_to_w32(Cmd); srb_dos_to_w32(Status); srb_dos_to_w32(HaId); srb_dos_to_w32(BufLen); srb_dos_to_w32(SenseLen); srb_dos_to_w32(CDBLen); srb_dos_to_w32(Target); srb_dos_to_w32(Lun); #undef srb_dos_to_w32 /* Allow certain flags to go on to WNASPI32, we also need * to make sure SRB_POSTING is enabled */ lpPRB->SRB_Flags = SRB_POSTING | (lpSRB16->cmd.SRB_Flags&(SRB_DIR_IN|SRB_DIR_OUT|SRB_ENABLE_RESIDUAL_COUNT)); /* Pointer to data buffer */ lpPRB->SRB_BufPointer = DOSMEM_MapRealToLinear(lpSRB16->cmd.SRB_BufPointer); /* Copy CDB in */ memcpy(&lpPRB->CDBByte[0],&lpSRB16->cmd.CDBByte[0],lpSRB16->cmd.SRB_CDBLen); /* Set post proc to our post proc */ lpPRB->SRB_PostProc = &DOSASPI_PostProc; /* Stick the DWORD after all the sense info */ memcpy((LPBYTE)(lpPRB+1)+lpPRB->SRB_SenseLen,&ptrSRB,sizeof(DWORD)); retval = (*pSendASPI32Command)((LPSRB)lpPRB); break; case SC_ABORT_SRB: TRACE("SC_ABORT_SRB\n"); /* Would need some sort of table of active shit */ break; case SC_RESET_DEV: TRACE("SC_RESET_DEV\n"); break; default: TRACE("Unkown command code\n"); break; } TRACE("Returning %lx\n", retval ); return retval; } void WINAPI ASPI_DOS_func(CONTEXT86 *context) { WORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp); DWORD ptrSRB = *(DWORD *)&stack[2]; ASPI_SendASPIDOSCommand(ptrSRB); /* simulate a normal RETF sequence as required by DPMI CallRMProcFar */ context->Eip = *(stack++); context->SegCs = *(stack++); context->Esp += 2*sizeof(WORD); } /* returns the address of a real mode callback to ASPI_DOS_func() */ void ASPI_DOS_HandleInt(CONTEXT86 *context) { FARPROC16 *p = (FARPROC16 *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx); TRACE("DOS ASPI opening\n"); if ((CX_reg(context) == 4) || (CX_reg(context) == 5)) { if( hWNASPI32 == INVALID_HANDLE_VALUE ) { TRACE("Loading WNASPI32\n"); hWNASPI32 = LoadLibraryExA("WNASPI32", 0, 0); } if( hWNASPI32 == INVALID_HANDLE_VALUE ) { ERR("Error loading WNASPI32\n"); goto error_exit; } /* Get SendASPI32Command by Ordinal 2 */ /* Cast to correct argument/return types */ pSendASPI32Command = (DWORD (*)(LPSRB))GetProcAddress(hWNASPI32, (LPBYTE)2); if( !pSendASPI32Command ) { ERR("Error getting ordinal 2 from WNASPI32\n"); goto error_exit; } *p = DPMI_AllocInternalRMCB(ASPI_DOS_func); TRACE("allocated real mode proc %p\n", *p); AX_reg(context) = CX_reg(context); return; } error_exit: /* Return some error... General Failure sounds okay */ AX_reg(context) = ERROR_GEN_FAILURE; SET_CFLAG(context); }