Added support for nested server waits (to allow waiting in signal
[wine/multimedia.git] / msdos / dosaspi.c
blob29771cbda5ea581066995dcfd197c871133dd5eb
1 #include "config.h"
3 #include <string.h>
4 #include "winbase.h"
5 #include "wine/windef16.h"
6 #include "wine/winaspi.h"
7 #include "heap.h"
8 #include "debugtools.h"
9 #include "miscemu.h" /* DOSMEM_* */
10 #include "callback.h"
11 #include "winerror.h"
13 DEFAULT_DEBUG_CHANNEL(aspi);
15 static HINSTANCE hWNASPI32 = INVALID_HANDLE_VALUE;
16 static DWORD (__cdecl *pSendASPI32Command) (LPSRB) = NULL;
18 static void
19 DOSASPI_PostProc( SRB_ExecSCSICmd *lpPRB )
21 DWORD ptrSRB;
22 LPSRB16 lpSRB16;
25 memcpy(&ptrSRB,lpPRB->SenseArea + 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(lpSRB16->cmd.CDBByte + lpSRB16->cmd.SRB_CDBLen,lpPRB->SenseArea,lpSRB16->cmd.SRB_SenseLen);
32 /* Now do posting */
33 if( lpPRB->SRB_Status == SS_SECURITY_VIOLATION )
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;
40 lpSRB16->cmd.SRB_Status = lpPRB->SRB_Status;
41 TRACE("SRB_Status = 0x%x\n", lpPRB->SRB_Status);
43 HeapFree(GetProcessHeap(),0,lpPRB);
45 if( (lpSRB16->cmd.SRB_Flags & SRB_POSTING) && lpSRB16->cmd.SRB_PostProc )
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.
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) */
66 /* Zero everything */
67 memset(&ctx, 0, sizeof(ctx));
68 /* CS:IP is routine to call */
69 ctx.SegCs = SELECTOROF(lpSRB16->cmd.SRB_PostProc);
70 ctx.Eip = 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
79 if(DPMI_CallRMProc(&ctx, (LPWORD)&ptrSRB, 2, FALSE))
81 TRACE("DPMI_CallRMProc returned nonzero (error) status\n");
83 } /* if ((SRB_Flags&SRB_POSTING) && SRB_PostProc) */
86 static
87 DWORD ASPI_SendASPIDOSCommand(DWORD ptrSRB)
89 PSRB_ExecSCSICmd lpPRB;
90 DWORD retval;
91 union tagSRB16 * lpSRB16;
93 lpSRB16 = DOSMEM_MapRealToLinear(ptrSRB);
95 retval = SS_ERR;
96 switch( lpSRB16->common.SRB_Cmd )
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
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
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));
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);
134 /* Set post proc to our post proc */
135 lpPRB->SRB_PostProc = &DOSASPI_PostProc;
137 /* Stick the DWORD after all the sense info */
138 memcpy(lpPRB->SenseArea + 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;
153 TRACE("Returning %lx\n", retval );
154 return retval;
157 void WINAPI ASPI_DOS_func(CONTEXT86 *context)
159 WORD *stack = CTX_SEG_OFF_TO_LIN(context, context->SegSs, context->Esp);
160 DWORD ptrSRB = *(DWORD *)&stack[2];
162 ASPI_SendASPIDOSCommand(ptrSRB);
164 /* simulate a normal RETF sequence as required by DPMI CallRMProcFar */
165 context->Eip = *(stack++);
166 context->SegCs = *(stack++);
167 context->Esp += 2*sizeof(WORD);
171 /* returns the address of a real mode callback to ASPI_DOS_func() */
172 void ASPI_DOS_HandleInt(CONTEXT86 *context)
174 FARPROC16 *p = (FARPROC16 *)CTX_SEG_OFF_TO_LIN(context, context->SegDs, context->Edx);
175 TRACE("DOS ASPI opening\n");
176 if ((CX_reg(context) == 4) || (CX_reg(context) == 5))
178 if( hWNASPI32 == INVALID_HANDLE_VALUE )
180 TRACE("Loading WNASPI32\n");
181 hWNASPI32 = LoadLibraryExA("WNASPI32", 0, 0);
184 if( hWNASPI32 == INVALID_HANDLE_VALUE )
186 ERR("Error loading WNASPI32\n");
187 goto error_exit;
190 /* Get SendASPI32Command by Ordinal 2 */
191 /* Cast to correct argument/return types */
192 pSendASPI32Command = (DWORD (*)(LPSRB))GetProcAddress(hWNASPI32, (LPBYTE)2);
193 if( !pSendASPI32Command )
195 ERR("Error getting ordinal 2 from WNASPI32\n");
196 goto error_exit;
199 *p = DPMI_AllocInternalRMCB(ASPI_DOS_func);
200 TRACE("allocated real mode proc %p\n", *p);
201 AX_reg(context) = CX_reg(context);
203 return;
205 error_exit:
206 /* Return some error... General Failure sounds okay */
207 AX_reg(context) = ERROR_GEN_FAILURE;
208 SET_CFLAG(context);