| #include "config.h" | |
| #include <string.h> | |
| #include "winbase.h" | |
| #include "wine/windef16.h" | |
| #include "wine/winaspi.h" | |
| #include "heap.h" | |
| #include "debugtools.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,lpPRB->SenseArea + 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(lpSRB16->cmd.CDBByte + lpSRB16->cmd.SRB_CDBLen,lpPRB->SenseArea,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(lpPRB->SenseArea + 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); | |
| } |