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