Fixed some issues found by winapi_check.
[wine] / dlls / winedos / dosaspi.c
1 #include "config.h"
2
3 #include <string.h>
4 #include "winbase.h"
5 #include "wine/windef16.h"
6 #include "wine/winaspi.h"
7 #include "debugtools.h"
8 #include "miscemu.h" /* DOSMEM_* */
9 #include "winerror.h"
10
11 DEFAULT_DEBUG_CHANNEL(aspi);
12
13 static HINSTANCE hWNASPI32 = INVALID_HANDLE_VALUE;
14 static DWORD (__cdecl *pSendASPI32Command) (LPSRB) = NULL;
15
16 static void
17 DOSASPI_PostProc( SRB_ExecSCSICmd *lpPRB )
18 {
19         DWORD ptrSRB;
20         LPSRB16 lpSRB16;
21
22
23         memcpy(&ptrSRB,lpPRB->SenseArea + lpPRB->SRB_SenseLen,sizeof(DWORD));
24         TRACE("Copying data back to DOS client at 0x%8lx\n",ptrSRB);
25         lpSRB16 = DOSMEM_MapRealToLinear(ptrSRB);
26         lpSRB16->cmd.SRB_TargStat = lpPRB->SRB_TargStat;
27         lpSRB16->cmd.SRB_HaStat = lpPRB->SRB_HaStat;
28         memcpy(lpSRB16->cmd.CDBByte + lpSRB16->cmd.SRB_CDBLen,lpPRB->SenseArea,lpSRB16->cmd.SRB_SenseLen);
29
30         /* Now do posting */
31         if( lpPRB->SRB_Status == SS_SECURITY_VIOLATION )
32         {
33                 /* SS_SECURITY_VIOLATION isn't defined in DOS ASPI */
34                 TRACE("Returning SS_NO_DEVICE for SS_SECURITY_VIOLATION\n");
35                 lpPRB->SRB_Status = SS_NO_DEVICE;
36         }
37
38         lpSRB16->cmd.SRB_Status = lpPRB->SRB_Status;
39         TRACE("SRB_Status = 0x%x\n", lpPRB->SRB_Status);
40
41         HeapFree(GetProcessHeap(),0,lpPRB);
42
43         if( (lpSRB16->cmd.SRB_Flags & SRB_POSTING) && lpSRB16->cmd.SRB_PostProc )
44         {
45                 CONTEXT86 ctx;
46 /* The stack should look like this on entry to proc
47  * NOTE: the SDK draws the following diagram bass akwards, use this one
48  * to avoid being confused.  Remember, the act of pushing something on
49  * an intel stack involves decreasing the stack pointer by the size of
50  * the data, and then copying the data at the new SP.
51  */
52 /***************************
53  * ... Other crap that is already on the stack ...
54  * Segment of SRB Pointer               <- SP+6
55  * Offset of SRB Pointer                <- SP+4
56  * Segment of return address            <- SP+2
57  * Offset of return address             <- SP+0
58  */ 
59                 /* FIXME: I am about 99% sure what is here is correct,
60                  * but this code has never been tested (and probably
61                  * won't be either until someone finds a DOS program
62                  * that actually uses a Post Routine) */
63
64                 /* Zero everything */
65                 memset(&ctx, 0, sizeof(ctx));
66                 /* CS:IP is routine to call */
67                 ctx.SegCs = SELECTOROF(lpSRB16->cmd.SRB_PostProc);
68                 ctx.Eip   = OFFSETOF(lpSRB16->cmd.SRB_PostProc);
69                 /* DPMI_CallRMProc will push the pointer to the stack
70                  * it is given (in this case &ptrSRB) with length
71                  * 2*sizeof(WORD), that is, it copies the the contents
72                  * of ptrSRB onto the stack, and decs sp by 2*sizeof(WORD).
73                  * After doing that, it pushes the return address
74                  * onto the stack (so we don't need to worry about that)
75                  * So the stack should be okay for the PostProc
76                  */
77                 if(DPMI_CallRMProc(&ctx, (LPWORD)&ptrSRB, 2, FALSE))
78                 {
79                         TRACE("DPMI_CallRMProc returned nonzero (error) status\n");
80                 }
81         } /* if ((SRB_Flags&SRB_POSTING) && SRB_PostProc) */
82 }
83
84 static 
85 DWORD ASPI_SendASPIDOSCommand(DWORD ptrSRB)
86 {
87         PSRB_ExecSCSICmd lpPRB;
88         DWORD retval;
89         union tagSRB16 * lpSRB16;
90
91         lpSRB16 = DOSMEM_MapRealToLinear(ptrSRB);
92
93         retval = SS_ERR;
94         switch( lpSRB16->common.SRB_Cmd )
95         {
96         case SC_HA_INQUIRY:
97                 TRACE("SC_HA_INQUIRY\n");
98                 /* Format is identical in this case */
99                 retval = (*pSendASPI32Command)((LPSRB)lpSRB16);
100                 break;
101         case SC_GET_DEV_TYPE:
102                 TRACE("SC_GET_DEV_TYPE\n");
103                 /* Format is identical in this case */
104                 retval = (*pSendASPI32Command)((LPSRB)lpSRB16);
105                 break;
106         case SC_EXEC_SCSI_CMD:
107                 TRACE("SC_EXEC_SCSI_CMD\n");
108                 TRACE("Copying data from DOS client at 0x%8lx\n",ptrSRB);
109                 lpPRB = HeapAlloc(GetProcessHeap(),0,sizeof(SRB)+lpSRB16->cmd.SRB_SenseLen+sizeof(DWORD));
110 #define srb_dos_to_w32(name) \
111                 lpPRB->SRB_##name = lpSRB16->cmd.SRB_##name
112
113                 srb_dos_to_w32(Cmd);
114                 srb_dos_to_w32(Status);
115                 srb_dos_to_w32(HaId);
116                 srb_dos_to_w32(BufLen);
117                 srb_dos_to_w32(SenseLen);
118                 srb_dos_to_w32(CDBLen);
119                 srb_dos_to_w32(Target);
120                 srb_dos_to_w32(Lun);
121 #undef srb_dos_to_w32
122
123                 /* Allow certain flags to go on to WNASPI32, we also need
124                  * to make sure SRB_POSTING is enabled */
125                 lpPRB->SRB_Flags = SRB_POSTING | (lpSRB16->cmd.SRB_Flags&(SRB_DIR_IN|SRB_DIR_OUT|SRB_ENABLE_RESIDUAL_COUNT));
126
127                 /* Pointer to data buffer */
128                 lpPRB->SRB_BufPointer = DOSMEM_MapRealToLinear(lpSRB16->cmd.SRB_BufPointer);
129                 /* Copy CDB in */
130                 memcpy(&lpPRB->CDBByte[0],&lpSRB16->cmd.CDBByte[0],lpSRB16->cmd.SRB_CDBLen);
131
132                 /* Set post proc to our post proc */
133                 lpPRB->SRB_PostProc = &DOSASPI_PostProc;
134
135                 /* Stick the DWORD after all the sense info */
136                 memcpy(lpPRB->SenseArea + lpPRB->SRB_SenseLen,&ptrSRB,sizeof(DWORD));
137                 retval = (*pSendASPI32Command)((LPSRB)lpPRB);
138                 break;
139         case SC_ABORT_SRB:
140                 TRACE("SC_ABORT_SRB\n");
141                 /* Would need some sort of table of active shit */
142                 break;
143         case SC_RESET_DEV:
144                 TRACE("SC_RESET_DEV\n");
145                 break;
146         default:
147                 TRACE("Unkown command code\n");
148                 break;
149         }
150
151         TRACE("Returning %lx\n", retval );
152         return retval;
153 }
154
155 void WINAPI ASPI_DOS_func(CONTEXT86 *context)
156 {
157         WORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
158         DWORD ptrSRB = *(DWORD *)&stack[2];
159
160         ASPI_SendASPIDOSCommand(ptrSRB);
161
162         /* simulate a normal RETF sequence as required by DPMI CallRMProcFar */
163         context->Eip = *(stack++);
164         context->SegCs  = *(stack++);
165         context->Esp += 2*sizeof(WORD);
166 }
167
168
169 /**********************************************************************
170  *          ASPIHandler  (WINEDOS.@)
171  *
172  * returns the address of a real mode callback to ASPI_DOS_func()
173  */
174 void WINAPI DOSVM_ASPIHandler( CONTEXT86 *context )
175 {
176         FARPROC16 *p = (FARPROC16 *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
177         TRACE("DOS ASPI opening\n");
178         if ((CX_reg(context) == 4) || (CX_reg(context) == 5))
179         {
180                 if( hWNASPI32 == INVALID_HANDLE_VALUE )
181                 {
182                         TRACE("Loading WNASPI32\n");
183                         hWNASPI32 = LoadLibraryExA("WNASPI32", 0, 0);
184                 }
185
186                 if( hWNASPI32 == INVALID_HANDLE_VALUE )
187                 {
188                         ERR("Error loading WNASPI32\n");
189                         goto error_exit;
190                 }
191
192                 /* Get SendASPI32Command by Ordinal 2 */
193                 /* Cast to correct argument/return types */
194                 pSendASPI32Command = (DWORD (*)(LPSRB))GetProcAddress(hWNASPI32, (LPBYTE)2);
195                 if( !pSendASPI32Command )
196                 {
197                         ERR("Error getting ordinal 2 from WNASPI32\n");
198                         goto error_exit;
199                 }
200
201                 *p = DPMI_AllocInternalRMCB(ASPI_DOS_func);
202                 TRACE("allocated real mode proc %p\n", *p);
203                 AX_reg(context) = CX_reg(context);
204
205                 return;
206         }
207 error_exit:
208         /* Return some error... General Failure sounds okay */
209         AX_reg(context) = ERROR_GEN_FAILURE;
210         SET_CFLAG(context);
211 }