wine/dlls/winedos/dosaspi.c
2009-03-04 12:07:20 +01:00

234 lines
7.2 KiB
C

/*
* Copyright 2000 David Elliott
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <stdarg.h>
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "wine/windef16.h"
#include "wine/winaspi.h"
#include "wine/debug.h"
#include "dosexe.h"
#include "winerror.h"
WINE_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%8x\n",ptrSRB);
lpSRB16 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(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));
ctx.EFlags |= V86_FLAG;
/* 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 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 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(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%8x\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 = PTR_REAL_TO_LIN(SELECTOROF(lpSRB16->cmd.SRB_BufPointer),
OFFSETOF(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("Unknown command code\n");
break;
}
TRACE("Returning %x\n", retval );
return retval;
}
static 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);
}
/**********************************************************************
* ASPIHandler (WINEDOS.@)
*
* returns the address of a real mode callback to ASPI_DOS_func()
*/
void WINAPI DOSVM_ASPIHandler( CONTEXT86 *context )
{
FARPROC16 *p = 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, (LPCSTR)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);
SET_AX( context, CX_reg(context) );
return;
}
error_exit:
/* Return some error... General Failure sounds okay */
SET_AX( context, ERROR_GEN_FAILURE );
SET_CFLAG(context);
}