Commit | Line | Data |
---|---|---|
0799c1a7 AJ |
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 | |
360a3f91 | 16 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
0799c1a7 AJ |
17 | */ |
18 | ||
c3bcd6ce DE |
19 | #include "config.h" |
20 | ||
e37c6e18 | 21 | #include <stdarg.h> |
f4d5fefb | 22 | #include <string.h> |
e37c6e18 | 23 | #include "windef.h" |
c3bcd6ce | 24 | #include "winbase.h" |
83f52d11 AJ |
25 | #include "wine/windef16.h" |
26 | #include "wine/winaspi.h" | |
0799c1a7 | 27 | #include "wine/debug.h" |
02e17775 | 28 | #include "dosexe.h" |
c3bcd6ce DE |
29 | #include "winerror.h" |
30 | ||
0799c1a7 | 31 | WINE_DEFAULT_DEBUG_CHANNEL(aspi); |
c3bcd6ce DE |
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 | ||
ab170a9c | 43 | memcpy(&ptrSRB,lpPRB->SenseArea + lpPRB->SRB_SenseLen,sizeof(DWORD)); |
db4eaf5e | 44 | TRACE("Copying data back to DOS client at 0x%8x\n",ptrSRB); |
0d875e77 | 45 | lpSRB16 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(ptrSRB)); |
c3bcd6ce DE |
46 | lpSRB16->cmd.SRB_TargStat = lpPRB->SRB_TargStat; |
47 | lpSRB16->cmd.SRB_HaStat = lpPRB->SRB_HaStat; | |
ab170a9c | 48 | memcpy(lpSRB16->cmd.CDBByte + lpSRB16->cmd.SRB_CDBLen,lpPRB->SenseArea,lpSRB16->cmd.SRB_SenseLen); |
c3bcd6ce DE |
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 | |
9a624916 | 78 | */ |
c3bcd6ce DE |
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)); | |
be3b2569 JH |
86 | ctx.EFlags |= V86_FLAG; |
87 | ||
c3bcd6ce | 88 | /* CS:IP is routine to call */ |
d8fab2e6 AJ |
89 | ctx.SegCs = SELECTOROF(lpSRB16->cmd.SRB_PostProc); |
90 | ctx.Eip = OFFSETOF(lpSRB16->cmd.SRB_PostProc); | |
c3bcd6ce DE |
91 | /* DPMI_CallRMProc will push the pointer to the stack |
92 | * it is given (in this case &ptrSRB) with length | |
c4b1195c | 93 | * 2*sizeof(WORD), that is, it copies the contents |
c3bcd6ce DE |
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 | ||
9a624916 | 106 | static |
c3bcd6ce DE |
107 | DWORD ASPI_SendASPIDOSCommand(DWORD ptrSRB) |
108 | { | |
109 | PSRB_ExecSCSICmd lpPRB; | |
110 | DWORD retval; | |
111 | union tagSRB16 * lpSRB16; | |
112 | ||
0d875e77 | 113 | lpSRB16 = PTR_REAL_TO_LIN(SELECTOROF(ptrSRB),OFFSETOF(ptrSRB)); |
c3bcd6ce DE |
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"); | |
db4eaf5e | 130 | TRACE("Copying data from DOS client at 0x%8x\n",ptrSRB); |
c3bcd6ce DE |
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 */ | |
0d875e77 AJ |
150 | lpPRB->SRB_BufPointer = PTR_REAL_TO_LIN(SELECTOROF(lpSRB16->cmd.SRB_BufPointer), |
151 | OFFSETOF(lpSRB16->cmd.SRB_BufPointer)); | |
c3bcd6ce DE |
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 */ | |
7e917a0f | 156 | lpPRB->SRB_PostProc = DOSASPI_PostProc; |
c3bcd6ce DE |
157 | |
158 | /* Stick the DWORD after all the sense info */ | |
ab170a9c | 159 | memcpy(lpPRB->SenseArea + lpPRB->SRB_SenseLen,&ptrSRB,sizeof(DWORD)); |
c3bcd6ce DE |
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: | |
6d442aeb | 170 | TRACE("Unknown command code\n"); |
c3bcd6ce DE |
171 | break; |
172 | } | |
173 | ||
db4eaf5e | 174 | TRACE("Returning %x\n", retval ); |
c3bcd6ce DE |
175 | return retval; |
176 | } | |
177 | ||
bf98c9d1 | 178 | static void WINAPI ASPI_DOS_func(CONTEXT86 *context) |
c3bcd6ce | 179 | { |
d8fab2e6 | 180 | WORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp); |
c3bcd6ce DE |
181 | DWORD ptrSRB = *(DWORD *)&stack[2]; |
182 | ||
183 | ASPI_SendASPIDOSCommand(ptrSRB); | |
184 | ||
185 | /* simulate a normal RETF sequence as required by DPMI CallRMProcFar */ | |
d8fab2e6 AJ |
186 | context->Eip = *(stack++); |
187 | context->SegCs = *(stack++); | |
188 | context->Esp += 2*sizeof(WORD); | |
c3bcd6ce DE |
189 | } |
190 | ||
191 | ||
8cd55d0e | 192 | /********************************************************************** |
19d66cc1 | 193 | * ASPIHandler (WINEDOS.@) |
8cd55d0e AJ |
194 | * |
195 | * returns the address of a real mode callback to ASPI_DOS_func() | |
196 | */ | |
197 | void WINAPI DOSVM_ASPIHandler( CONTEXT86 *context ) | |
c3bcd6ce | 198 | { |
d8fab2e6 | 199 | FARPROC16 *p = (FARPROC16 *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx); |
c3bcd6ce DE |
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"); | |
12222f0d | 206 | hWNASPI32 = LoadLibraryExA("WNASPI32", 0, 0); |
c3bcd6ce DE |
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 */ | |
93ab695a | 217 | pSendASPI32Command = (DWORD (*)(LPSRB))GetProcAddress(hWNASPI32, (LPCSTR)2); |
c3bcd6ce DE |
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); | |
3fa613cf | 226 | SET_AX( context, CX_reg(context) ); |
c3bcd6ce DE |
227 | |
228 | return; | |
229 | } | |
230 | error_exit: | |
231 | /* Return some error... General Failure sounds okay */ | |
3fa613cf | 232 | SET_AX( context, ERROR_GEN_FAILURE ); |
c3bcd6ce DE |
233 | SET_CFLAG(context); |
234 | } |