Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2000 David Elliott |
| 3 | * |
| 4 | * This library is free software; you can redistribute it and/or |
| 5 | * modify it under the terms of the GNU Lesser General Public |
| 6 | * License as published by the Free Software Foundation; either |
| 7 | * version 2.1 of the License, or (at your option) any later version. |
| 8 | * |
| 9 | * This library is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | * Lesser General Public License for more details. |
| 13 | * |
| 14 | * You should have received a copy of the GNU Lesser General Public |
| 15 | * License along with this library; if not, write to the Free Software |
Jonathan Ernst | 360a3f9 | 2006-05-18 14:49:52 +0200 | [diff] [blame] | 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 17 | */ |
| 18 | |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 19 | #include "config.h" |
| 20 | |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 21 | #include <stdarg.h> |
James Juran | f4d5fef | 2001-01-26 20:43:40 +0000 | [diff] [blame] | 22 | #include <string.h> |
Alexandre Julliard | e37c6e1 | 2003-09-05 23:08:26 +0000 | [diff] [blame] | 23 | #include "windef.h" |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 24 | #include "winbase.h" |
Alexandre Julliard | 83f52d1 | 2000-09-26 22:20:14 +0000 | [diff] [blame] | 25 | #include "wine/windef16.h" |
| 26 | #include "wine/winaspi.h" |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 27 | #include "wine/debug.h" |
Jukka Heinonen | 02e1777 | 2002-11-18 22:53:38 +0000 | [diff] [blame] | 28 | #include "dosexe.h" |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 29 | #include "winerror.h" |
| 30 | |
Alexandre Julliard | 0799c1a | 2002-03-09 23:29:33 +0000 | [diff] [blame] | 31 | WINE_DEFAULT_DEBUG_CHANNEL(aspi); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 32 | |
| 33 | static HINSTANCE hWNASPI32 = INVALID_HANDLE_VALUE; |
| 34 | static DWORD (__cdecl *pSendASPI32Command) (LPSRB) = NULL; |
| 35 | |
| 36 | static void |
| 37 | DOSASPI_PostProc( SRB_ExecSCSICmd *lpPRB ) |
| 38 | { |
| 39 | DWORD ptrSRB; |
| 40 | LPSRB16 lpSRB16; |
| 41 | |
| 42 | |
Alexandre Julliard | ab170a9 | 2000-09-27 00:25:24 +0000 | [diff] [blame] | 43 | memcpy(&ptrSRB,lpPRB->SenseArea + lpPRB->SRB_SenseLen,sizeof(DWORD)); |
Michael Stefaniuc | db4eaf5 | 2006-10-03 14:04:49 +0200 | [diff] [blame] | 44 | TRACE("Copying data back to DOS client at 0x%8x\n",ptrSRB); |
Alexandre Julliard | 0d875e7 | 2002-08-30 00:03:25 +0000 | [diff] [blame] | 45 | lpSRB16 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(ptrSRB)); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 46 | lpSRB16->cmd.SRB_TargStat = lpPRB->SRB_TargStat; |
| 47 | lpSRB16->cmd.SRB_HaStat = lpPRB->SRB_HaStat; |
Alexandre Julliard | ab170a9 | 2000-09-27 00:25:24 +0000 | [diff] [blame] | 48 | memcpy(lpSRB16->cmd.CDBByte + lpSRB16->cmd.SRB_CDBLen,lpPRB->SenseArea,lpSRB16->cmd.SRB_SenseLen); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 49 | |
| 50 | /* Now do posting */ |
| 51 | if( lpPRB->SRB_Status == SS_SECURITY_VIOLATION ) |
| 52 | { |
| 53 | /* SS_SECURITY_VIOLATION isn't defined in DOS ASPI */ |
| 54 | TRACE("Returning SS_NO_DEVICE for SS_SECURITY_VIOLATION\n"); |
| 55 | lpPRB->SRB_Status = SS_NO_DEVICE; |
| 56 | } |
| 57 | |
| 58 | lpSRB16->cmd.SRB_Status = lpPRB->SRB_Status; |
| 59 | TRACE("SRB_Status = 0x%x\n", lpPRB->SRB_Status); |
| 60 | |
| 61 | HeapFree(GetProcessHeap(),0,lpPRB); |
| 62 | |
| 63 | if( (lpSRB16->cmd.SRB_Flags & SRB_POSTING) && lpSRB16->cmd.SRB_PostProc ) |
| 64 | { |
| 65 | CONTEXT86 ctx; |
| 66 | /* The stack should look like this on entry to proc |
| 67 | * NOTE: the SDK draws the following diagram bass akwards, use this one |
| 68 | * to avoid being confused. Remember, the act of pushing something on |
| 69 | * an intel stack involves decreasing the stack pointer by the size of |
| 70 | * the data, and then copying the data at the new SP. |
| 71 | */ |
| 72 | /*************************** |
| 73 | * ... Other crap that is already on the stack ... |
| 74 | * Segment of SRB Pointer <- SP+6 |
| 75 | * Offset of SRB Pointer <- SP+4 |
| 76 | * Segment of return address <- SP+2 |
| 77 | * Offset of return address <- SP+0 |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 78 | */ |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 79 | /* FIXME: I am about 99% sure what is here is correct, |
| 80 | * but this code has never been tested (and probably |
| 81 | * won't be either until someone finds a DOS program |
| 82 | * that actually uses a Post Routine) */ |
| 83 | |
| 84 | /* Zero everything */ |
| 85 | memset(&ctx, 0, sizeof(ctx)); |
Jukka Heinonen | be3b256 | 2003-08-25 01:01:01 +0000 | [diff] [blame] | 86 | ctx.EFlags |= V86_FLAG; |
| 87 | |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 88 | /* CS:IP is routine to call */ |
Alexandre Julliard | d8fab2e | 2000-09-25 23:53:07 +0000 | [diff] [blame] | 89 | ctx.SegCs = SELECTOROF(lpSRB16->cmd.SRB_PostProc); |
| 90 | ctx.Eip = OFFSETOF(lpSRB16->cmd.SRB_PostProc); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 91 | /* DPMI_CallRMProc will push the pointer to the stack |
| 92 | * it is given (in this case &ptrSRB) with length |
Francois Gouget | c4b1195 | 2007-10-23 15:30:30 +0200 | [diff] [blame] | 93 | * 2*sizeof(WORD), that is, it copies the contents |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 94 | * of ptrSRB onto the stack, and decs sp by 2*sizeof(WORD). |
| 95 | * After doing that, it pushes the return address |
| 96 | * onto the stack (so we don't need to worry about that) |
| 97 | * So the stack should be okay for the PostProc |
| 98 | */ |
| 99 | if(DPMI_CallRMProc(&ctx, (LPWORD)&ptrSRB, 2, FALSE)) |
| 100 | { |
| 101 | TRACE("DPMI_CallRMProc returned nonzero (error) status\n"); |
| 102 | } |
| 103 | } /* if ((SRB_Flags&SRB_POSTING) && SRB_PostProc) */ |
| 104 | } |
| 105 | |
Vincent Béron | 9a62491 | 2002-05-31 23:06:46 +0000 | [diff] [blame] | 106 | static |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 107 | DWORD ASPI_SendASPIDOSCommand(DWORD ptrSRB) |
| 108 | { |
| 109 | PSRB_ExecSCSICmd lpPRB; |
| 110 | DWORD retval; |
| 111 | union tagSRB16 * lpSRB16; |
| 112 | |
Alexandre Julliard | 0d875e7 | 2002-08-30 00:03:25 +0000 | [diff] [blame] | 113 | lpSRB16 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(ptrSRB)); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 114 | |
| 115 | retval = SS_ERR; |
| 116 | switch( lpSRB16->common.SRB_Cmd ) |
| 117 | { |
| 118 | case SC_HA_INQUIRY: |
| 119 | TRACE("SC_HA_INQUIRY\n"); |
| 120 | /* Format is identical in this case */ |
| 121 | retval = (*pSendASPI32Command)((LPSRB)lpSRB16); |
| 122 | break; |
| 123 | case SC_GET_DEV_TYPE: |
| 124 | TRACE("SC_GET_DEV_TYPE\n"); |
| 125 | /* Format is identical in this case */ |
| 126 | retval = (*pSendASPI32Command)((LPSRB)lpSRB16); |
| 127 | break; |
| 128 | case SC_EXEC_SCSI_CMD: |
| 129 | TRACE("SC_EXEC_SCSI_CMD\n"); |
Michael Stefaniuc | db4eaf5 | 2006-10-03 14:04:49 +0200 | [diff] [blame] | 130 | TRACE("Copying data from DOS client at 0x%8x\n",ptrSRB); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 131 | lpPRB = HeapAlloc(GetProcessHeap(),0,sizeof(SRB)+lpSRB16->cmd.SRB_SenseLen+sizeof(DWORD)); |
| 132 | #define srb_dos_to_w32(name) \ |
| 133 | lpPRB->SRB_##name = lpSRB16->cmd.SRB_##name |
| 134 | |
| 135 | srb_dos_to_w32(Cmd); |
| 136 | srb_dos_to_w32(Status); |
| 137 | srb_dos_to_w32(HaId); |
| 138 | srb_dos_to_w32(BufLen); |
| 139 | srb_dos_to_w32(SenseLen); |
| 140 | srb_dos_to_w32(CDBLen); |
| 141 | srb_dos_to_w32(Target); |
| 142 | srb_dos_to_w32(Lun); |
| 143 | #undef srb_dos_to_w32 |
| 144 | |
| 145 | /* Allow certain flags to go on to WNASPI32, we also need |
| 146 | * to make sure SRB_POSTING is enabled */ |
| 147 | lpPRB->SRB_Flags = SRB_POSTING | (lpSRB16->cmd.SRB_Flags&(SRB_DIR_IN|SRB_DIR_OUT|SRB_ENABLE_RESIDUAL_COUNT)); |
| 148 | |
| 149 | /* Pointer to data buffer */ |
Alexandre Julliard | 0d875e7 | 2002-08-30 00:03:25 +0000 | [diff] [blame] | 150 | lpPRB->SRB_BufPointer = PTR_REAL_TO_LIN(SELECTOROF(lpSRB16->cmd.SRB_BufPointer), |
| 151 | OFFSETOF(lpSRB16->cmd.SRB_BufPointer)); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 152 | /* Copy CDB in */ |
| 153 | memcpy(&lpPRB->CDBByte[0],&lpSRB16->cmd.CDBByte[0],lpSRB16->cmd.SRB_CDBLen); |
| 154 | |
| 155 | /* Set post proc to our post proc */ |
Andrew Talbot | 7e917a0 | 2008-07-06 13:00:58 +0100 | [diff] [blame] | 156 | lpPRB->SRB_PostProc = DOSASPI_PostProc; |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 157 | |
| 158 | /* Stick the DWORD after all the sense info */ |
Alexandre Julliard | ab170a9 | 2000-09-27 00:25:24 +0000 | [diff] [blame] | 159 | memcpy(lpPRB->SenseArea + lpPRB->SRB_SenseLen,&ptrSRB,sizeof(DWORD)); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 160 | retval = (*pSendASPI32Command)((LPSRB)lpPRB); |
| 161 | break; |
| 162 | case SC_ABORT_SRB: |
| 163 | TRACE("SC_ABORT_SRB\n"); |
| 164 | /* Would need some sort of table of active shit */ |
| 165 | break; |
| 166 | case SC_RESET_DEV: |
| 167 | TRACE("SC_RESET_DEV\n"); |
| 168 | break; |
| 169 | default: |
Francois Gouget | 6d442ae | 2005-11-23 20:14:43 +0100 | [diff] [blame] | 170 | TRACE("Unknown command code\n"); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 171 | break; |
| 172 | } |
| 173 | |
Michael Stefaniuc | db4eaf5 | 2006-10-03 14:04:49 +0200 | [diff] [blame] | 174 | TRACE("Returning %x\n", retval ); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 175 | return retval; |
| 176 | } |
| 177 | |
Andrew Talbot | bf98c9d | 2007-02-02 14:38:45 +0000 | [diff] [blame] | 178 | static void WINAPI ASPI_DOS_func(CONTEXT86 *context) |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 179 | { |
Alexandre Julliard | d8fab2e | 2000-09-25 23:53:07 +0000 | [diff] [blame] | 180 | WORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 181 | DWORD ptrSRB = *(DWORD *)&stack[2]; |
| 182 | |
| 183 | ASPI_SendASPIDOSCommand(ptrSRB); |
| 184 | |
| 185 | /* simulate a normal RETF sequence as required by DPMI CallRMProcFar */ |
Alexandre Julliard | d8fab2e | 2000-09-25 23:53:07 +0000 | [diff] [blame] | 186 | context->Eip = *(stack++); |
| 187 | context->SegCs = *(stack++); |
| 188 | context->Esp += 2*sizeof(WORD); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 189 | } |
| 190 | |
| 191 | |
Alexandre Julliard | 8cd55d0 | 2001-12-04 19:54:44 +0000 | [diff] [blame] | 192 | /********************************************************************** |
Alexandre Julliard | 58cd87a | 2010-01-04 13:44:22 +0100 | [diff] [blame] | 193 | * ASPIHandler |
Alexandre Julliard | 8cd55d0 | 2001-12-04 19:54:44 +0000 | [diff] [blame] | 194 | * |
| 195 | * returns the address of a real mode callback to ASPI_DOS_func() |
| 196 | */ |
Alexandre Julliard | 58cd87a | 2010-01-04 13:44:22 +0100 | [diff] [blame] | 197 | void DOSVM_ASPIHandler( CONTEXT86 *context ) |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 198 | { |
Michael Stefaniuc | c6be3fe | 2009-03-04 10:41:06 +0100 | [diff] [blame] | 199 | FARPROC16 *p = CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 200 | TRACE("DOS ASPI opening\n"); |
| 201 | if ((CX_reg(context) == 4) || (CX_reg(context) == 5)) |
| 202 | { |
| 203 | if( hWNASPI32 == INVALID_HANDLE_VALUE ) |
| 204 | { |
| 205 | TRACE("Loading WNASPI32\n"); |
Eric Pouech | 12222f0 | 2000-04-29 14:29:41 +0000 | [diff] [blame] | 206 | hWNASPI32 = LoadLibraryExA("WNASPI32", 0, 0); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 207 | } |
| 208 | |
| 209 | if( hWNASPI32 == INVALID_HANDLE_VALUE ) |
| 210 | { |
| 211 | ERR("Error loading WNASPI32\n"); |
| 212 | goto error_exit; |
| 213 | } |
| 214 | |
| 215 | /* Get SendASPI32Command by Ordinal 2 */ |
| 216 | /* Cast to correct argument/return types */ |
Mike McCormack | 93ab695 | 2005-08-26 08:53:31 +0000 | [diff] [blame] | 217 | pSendASPI32Command = (DWORD (*)(LPSRB))GetProcAddress(hWNASPI32, (LPCSTR)2); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 218 | if( !pSendASPI32Command ) |
| 219 | { |
| 220 | ERR("Error getting ordinal 2 from WNASPI32\n"); |
| 221 | goto error_exit; |
| 222 | } |
| 223 | |
| 224 | *p = DPMI_AllocInternalRMCB(ASPI_DOS_func); |
| 225 | TRACE("allocated real mode proc %p\n", *p); |
Alexandre Julliard | 3fa613c | 2002-08-31 18:47:00 +0000 | [diff] [blame] | 226 | SET_AX( context, CX_reg(context) ); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 227 | |
| 228 | return; |
| 229 | } |
| 230 | error_exit: |
| 231 | /* Return some error... General Failure sounds okay */ |
Alexandre Julliard | 3fa613c | 2002-08-31 18:47:00 +0000 | [diff] [blame] | 232 | SET_AX( context, ERROR_GEN_FAILURE ); |
David Elliott | c3bcd6c | 2000-03-08 19:41:49 +0000 | [diff] [blame] | 233 | SET_CFLAG(context); |
| 234 | } |