dosaspi.c 7.19 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * 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
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 18
 */

19 20
#include "config.h"

21
#include <stdarg.h>
22
#include <string.h>
23
#include "windef.h"
24
#include "winbase.h"
25 26
#include "wine/windef16.h"
#include "wine/winaspi.h"
27
#include "wine/debug.h"
28
#include "dosexe.h"
29 30
#include "winerror.h"

31
WINE_DEFAULT_DEBUG_CHANNEL(aspi);
32 33 34 35 36 37 38 39 40 41 42

static HINSTANCE hWNASPI32 = INVALID_HANDLE_VALUE;
static DWORD (__cdecl *pSendASPI32Command) (LPSRB) = NULL;

static void
DOSASPI_PostProc( SRB_ExecSCSICmd *lpPRB )
{
	DWORD ptrSRB;
	LPSRB16 lpSRB16;


43
	memcpy(&ptrSRB,lpPRB->SenseArea + lpPRB->SRB_SenseLen,sizeof(DWORD));
44
	TRACE("Copying data back to DOS client at 0x%8x\n",ptrSRB);
45
	lpSRB16 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(ptrSRB));
46 47
	lpSRB16->cmd.SRB_TargStat = lpPRB->SRB_TargStat;
	lpSRB16->cmd.SRB_HaStat = lpPRB->SRB_HaStat;
48
	memcpy(lpSRB16->cmd.CDBByte + lpSRB16->cmd.SRB_CDBLen,lpPRB->SenseArea,lpSRB16->cmd.SRB_SenseLen);
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

	/* 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
78
 */
79 80 81 82 83 84 85
		/* 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));
86 87
                ctx.EFlags |= V86_FLAG;

88
		/* CS:IP is routine to call */
89 90
		ctx.SegCs = SELECTOROF(lpSRB16->cmd.SRB_PostProc);
		ctx.Eip   = OFFSETOF(lpSRB16->cmd.SRB_PostProc);
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
		/* 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) */
}

106
static
107 108 109 110 111 112
DWORD ASPI_SendASPIDOSCommand(DWORD ptrSRB)
{
	PSRB_ExecSCSICmd lpPRB;
	DWORD retval;
	union tagSRB16 * lpSRB16;

113
	lpSRB16 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(ptrSRB));
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129

	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");
130
		TRACE("Copying data from DOS client at 0x%8x\n",ptrSRB);
131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
		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 */
150 151
		lpPRB->SRB_BufPointer = PTR_REAL_TO_LIN(SELECTOROF(lpSRB16->cmd.SRB_BufPointer),
                                                        OFFSETOF(lpSRB16->cmd.SRB_BufPointer));
152 153 154 155 156 157 158
		/* 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 */
159
		memcpy(lpPRB->SenseArea + lpPRB->SRB_SenseLen,&ptrSRB,sizeof(DWORD));
160 161 162 163 164 165 166 167 168 169
		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:
170
		TRACE("Unknown command code\n");
171 172 173
		break;
	}

174
	TRACE("Returning %x\n", retval );
175 176 177
	return retval;
}

178
static void WINAPI ASPI_DOS_func(CONTEXT86 *context)
179
{
180
	WORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
181 182 183 184 185
	DWORD ptrSRB = *(DWORD *)&stack[2];

	ASPI_SendASPIDOSCommand(ptrSRB);

	/* simulate a normal RETF sequence as required by DPMI CallRMProcFar */
186 187 188
	context->Eip = *(stack++);
	context->SegCs  = *(stack++);
	context->Esp += 2*sizeof(WORD);
189 190 191
}


192
/**********************************************************************
193
 *	    ASPIHandler  (WINEDOS.@)
194 195 196 197
 *
 * returns the address of a real mode callback to ASPI_DOS_func()
 */
void WINAPI DOSVM_ASPIHandler( CONTEXT86 *context )
198
{
199
	FARPROC16 *p = (FARPROC16 *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
200 201 202 203 204 205
	TRACE("DOS ASPI opening\n");
	if ((CX_reg(context) == 4) || (CX_reg(context) == 5))
	{
		if( hWNASPI32 == INVALID_HANDLE_VALUE )
		{
			TRACE("Loading WNASPI32\n");
206
			hWNASPI32 = LoadLibraryExA("WNASPI32", 0, 0);
207 208 209 210 211 212 213 214 215 216
		}

		if( hWNASPI32 == INVALID_HANDLE_VALUE )
		{
			ERR("Error loading WNASPI32\n");
			goto error_exit;
		}

		/* Get SendASPI32Command by Ordinal 2 */
		/* Cast to correct argument/return types */
Mike McCormack's avatar
Mike McCormack committed
217
		pSendASPI32Command = (DWORD (*)(LPSRB))GetProcAddress(hWNASPI32, (LPCSTR)2);
218 219 220 221 222 223 224 225
		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);
226
		SET_AX( context, CX_reg(context) );
227 228 229 230 231

		return;
	}
error_exit:
	/* Return some error... General Failure sounds okay */
232
	SET_AX( context, ERROR_GEN_FAILURE );
233 234
	SET_CFLAG(context);
}