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