Moved memory/environ.c, memory/virtual.c and misc/cpu.c to
[wine] / dlls / kernel / device.c
1 /*
2  * Win32 device functions
3  *
4  * Copyright 1998 Marcus Meissner
5  * Copyright 1998 Ulrich Weigand
6  * Copyright 1998 Patrik Stridvall
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdlib.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <sys/types.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include <time.h>
34
35 #include "ntstatus.h"
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winreg.h"
39 #include "winerror.h"
40 #include "winnls.h"
41 #include "file.h"
42 #include "winioctl.h"
43 #include "winnt.h"
44 #include "msdos.h"
45 #include "miscemu.h"
46 #include "wine/server.h"
47 #include "wine/debug.h"
48 #include "callback.h"
49
50 WINE_DEFAULT_DEBUG_CHANNEL(file);
51
52
53 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode,
54                               LPVOID lpvInBuffer, DWORD cbInBuffer,
55                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
56                               LPDWORD lpcbBytesReturned,
57                               LPOVERLAPPED lpOverlapped);
58 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
59                               LPVOID lpvInBuffer, DWORD cbInBuffer,
60                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
61                               LPDWORD lpcbBytesReturned,
62                               LPOVERLAPPED lpOverlapped);
63 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
64                               LPVOID lpvInBuffer, DWORD cbInBuffer,
65                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
66                               LPDWORD lpcbBytesReturned,
67                               LPOVERLAPPED lpOverlapped);
68
69 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode,
70                               LPVOID lpvInBuffer, DWORD cbInBuffer,
71                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
72                               LPDWORD lpcbBytesReturned,
73                               LPOVERLAPPED lpOverlapped);
74
75 static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
76                               LPVOID lpvInBuffer, DWORD cbInBuffer,
77                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
78                               LPDWORD lpcbBytesReturned,
79                               LPOVERLAPPED lpOverlapped);
80
81 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
82                               LPVOID lpvInBuffer, DWORD cbInBuffer,
83                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
84                               LPDWORD lpcbBytesReturned,
85                               LPOVERLAPPED lpOverlapped);
86
87 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
88                               LPVOID lpvInBuffer, DWORD cbInBuffer,
89                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
90                               LPDWORD lpcbBytesReturned,
91                               LPOVERLAPPED lpOverlapped);
92
93 static BOOL DeviceIo_HASP (DWORD dwIoControlCode,
94                               LPVOID lpvInBuffer, DWORD cbInBuffer,
95                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
96                               LPDWORD lpcbBytesReturned,
97                               LPOVERLAPPED lpOverlapped);
98 /*
99  * VxD names are taken from the Win95 DDK
100  */
101
102 struct VxDInfo
103 {
104     LPCSTR  name;
105     WORD    id;
106     BOOL  (*deviceio)(DWORD, LPVOID, DWORD,
107                         LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
108 };
109
110 static const struct VxDInfo VxDList[] =
111 {
112     /* Standard VxD IDs */
113     { "VMM",      0x0001, NULL },
114     { "DEBUG",    0x0002, NULL },
115     { "VPICD",    0x0003, NULL },
116     { "VDMAD",    0x0004, NULL },
117     { "VTD",      0x0005, NULL },
118     { "V86MMGR",  0x0006, NULL },
119     { "PAGESWAP", 0x0007, NULL },
120     { "PARITY",   0x0008, NULL },
121     { "REBOOT",   0x0009, NULL },
122     { "VDD",      0x000A, NULL },
123     { "VSD",      0x000B, NULL },
124     { "VMD",      0x000C, NULL },
125     { "VKD",      0x000D, NULL },
126     { "VCD",      0x000E, DeviceIo_VCD },
127     { "VPD",      0x000F, NULL },
128     { "BLOCKDEV", 0x0010, NULL },
129     { "VMCPD",    0x0011, NULL },
130     { "EBIOS",    0x0012, NULL },
131     { "BIOSXLAT", 0x0013, NULL },
132     { "VNETBIOS", 0x0014, NULL },
133     { "DOSMGR",   0x0015, NULL },
134     { "WINLOAD",  0x0016, NULL },
135     { "SHELL",    0x0017, NULL },
136     { "VMPOLL",   0x0018, NULL },
137     { "VPROD",    0x0019, NULL },
138     { "DOSNET",   0x001A, NULL },
139     { "VFD",      0x001B, NULL },
140     { "VDD2",     0x001C, NULL },
141     { "WINDEBUG", 0x001D, NULL },
142     { "TSRLOAD",  0x001E, NULL },
143     { "BIOSHOOK", 0x001F, NULL },
144     { "INT13",    0x0020, NULL },
145     { "PAGEFILE", 0x0021, NULL },
146     { "SCSI",     0x0022, NULL },
147     { "MCA_POS",  0x0023, NULL },
148     { "SCSIFD",   0x0024, NULL },
149     { "VPEND",    0x0025, NULL },
150     { "VPOWERD",  0x0026, NULL },
151     { "VXDLDR",   0x0027, NULL },
152     { "NDIS",     0x0028, NULL },
153     { "BIOS_EXT", 0x0029, NULL },
154     { "VWIN32",   0x002A, DeviceIo_VWin32 },
155     { "VCOMM",    0x002B, NULL },
156     { "SPOOLER",  0x002C, NULL },
157     { "WIN32S",   0x002D, NULL },
158     { "DEBUGCMD", 0x002E, NULL },
159
160     { "VNB",      0x0031, NULL },
161     { "SERVER",   0x0032, NULL },
162     { "CONFIGMG", 0x0033, NULL },
163     { "DWCFGMG",  0x0034, NULL },
164     { "SCSIPORT", 0x0035, NULL },
165     { "VFBACKUP", 0x0036, NULL },
166     { "ENABLE",   0x0037, NULL },
167     { "VCOND",    0x0038, NULL },
168
169     { "EFAX",     0x003A, NULL },
170     { "DSVXD",    0x003B, NULL },
171     { "ISAPNP",   0x003C, NULL },
172     { "BIOS",     0x003D, NULL },
173     { "WINSOCK",  0x003E, NULL },
174     { "WSOCK",    0x003E, NULL },
175     { "WSIPX",    0x003F, NULL },
176     { "IFSMgr",   0x0040, DeviceIo_IFSMgr },
177     { "VCDFSD",   0x0041, NULL },
178     { "MRCI2",    0x0042, NULL },
179     { "PCI",      0x0043, NULL },
180     { "PELOADER", 0x0044, NULL },
181     { "EISA",     0x0045, NULL },
182     { "DRAGCLI",  0x0046, NULL },
183     { "DRAGSRV",  0x0047, NULL },
184     { "PERF",     0x0048, NULL },
185     { "AWREDIR",  0x0049, NULL },
186
187     /* Far East support */
188     { "ETEN",     0x0060, NULL },
189     { "CHBIOS",   0x0061, NULL },
190     { "VMSGD",    0x0062, NULL },
191     { "VPPID",    0x0063, NULL },
192     { "VIME",     0x0064, NULL },
193     { "VHBIOSD",  0x0065, NULL },
194
195     /* Multimedia OEM IDs */
196     { "VTDAPI",   0x0442, DeviceIo_VTDAPI },
197     { "MMDEVLDR", 0x044A, DeviceIo_MMDEVLDR },
198
199     /* Network Device IDs */
200     { "VNetSup",  0x0480, NULL },
201     { "VRedir",   0x0481, NULL },
202     { "VBrowse",  0x0482, NULL },
203     { "VSHARE",   0x0483, NULL },
204     { "IFSMgr",   0x0484, NULL },
205     { "MEMPROBE", 0x0485, NULL },
206     { "VFAT",     0x0486, NULL },
207     { "NWLINK",   0x0487, NULL },
208     { "VNWLINK",  0x0487, NULL },
209     { "NWSUP",    0x0487, NULL },
210     { "VTDI",     0x0488, NULL },
211     { "VIP",      0x0489, NULL },
212     { "VTCP",     0x048A, NULL },
213     { "VCache",   0x048B, NULL },
214     { "VUDP",     0x048C, NULL },
215     { "VAsync",   0x048D, NULL },
216     { "NWREDIR",  0x048E, NULL },
217     { "STAT80",   0x048F, NULL },
218     { "SCSIPORT", 0x0490, NULL },
219     { "FILESEC",  0x0491, NULL },
220     { "NWSERVER", 0x0492, NULL },
221     { "SECPROV",  0x0493, NULL },
222     { "NSCL",     0x0494, NULL },
223     { "WSTCP",    0x0495, NULL },
224     { "NDIS2SUP", 0x0496, NULL },
225     { "MSODISUP", 0x0497, NULL },
226     { "Splitter", 0x0498, NULL },
227     { "PPP",      0x0499, NULL },
228     { "VDHCP",    0x049A, NULL },
229     { "VNBT",     0x049B, NULL },
230     { "LOGGER",   0x049D, NULL },
231     { "EFILTER",  0x049E, NULL },
232     { "FFILTER",  0x049F, NULL },
233     { "TFILTER",  0x04A0, NULL },
234     { "AFILTER",  0x04A1, NULL },
235     { "IRLAMP",   0x04A2, NULL },
236
237     { "PCCARD",   0x097C, DeviceIo_PCCARD },
238     { "HASP95",   0x3721, DeviceIo_HASP },
239
240     /* WINE additions, ids unknown */
241     { "MONODEBG.VXD", 0x4242, DeviceIo_MONODEBG },
242
243     { NULL,       0,      NULL }
244 };
245
246 HANDLE DEVICE_Open( LPCWSTR filenameW, DWORD access, LPSECURITY_ATTRIBUTES sa )
247 {
248     const struct VxDInfo *info;
249     char filename[MAX_PATH];
250
251     if (!WideCharToMultiByte(CP_ACP, 0, filenameW, -1, filename, MAX_PATH, NULL, NULL))
252     {
253         SetLastError( ERROR_FILE_NOT_FOUND );
254         return 0;
255     }
256
257     for (info = VxDList; info->name; info++)
258         if (!strncasecmp( info->name, filename, strlen(info->name) ))
259             return FILE_CreateDevice( info->id | 0x10000, access, sa );
260
261     FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
262            filename);
263     SetLastError( ERROR_FILE_NOT_FOUND );
264     return 0;
265 }
266
267 static DWORD DEVICE_GetClientID( HANDLE handle )
268 {
269     DWORD       ret = 0;
270     SERVER_START_REQ( get_device_id )
271     {
272         req->handle = handle;
273         if (!wine_server_call( req )) ret = reply->id;
274     }
275     SERVER_END_REQ;
276     return ret;
277 }
278
279 static const struct VxDInfo *DEVICE_GetInfo( DWORD clientID )
280 {
281     const struct VxDInfo *info = NULL;
282
283     if (clientID & 0x10000)
284     {
285         for (info = VxDList; info->name; info++)
286             if (info->id == LOWORD(clientID)) break;
287     }
288     return info;
289 }
290
291 /****************************************************************************
292  *              DeviceIoControl (KERNEL32.@)
293  * This is one of those big ugly nasty procedure which can do
294  * a million and one things when it comes to devices. It can also be
295  * used for VxD communication.
296  *
297  * A return value of FALSE indicates that something has gone wrong which
298  * GetLastError can decipher.
299  */
300 BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
301                               LPVOID lpvInBuffer, DWORD cbInBuffer,
302                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
303                               LPDWORD lpcbBytesReturned,
304                               LPOVERLAPPED lpOverlapped)
305 {
306         DWORD clientID;
307
308         TRACE( "(%p,%ld,%p,%ld,%p,%ld,%p,%p)\n",
309                hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
310                lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped  );
311
312         if (!(clientID = DEVICE_GetClientID( hDevice )))
313         {
314                 SetLastError( ERROR_INVALID_PARAMETER );
315                 return FALSE;
316         }
317
318         /* Check if this is a user defined control code for a VxD */
319         if( HIWORD( dwIoControlCode ) == 0 )
320         {
321                 const struct VxDInfo *info;
322                 if (!(info = DEVICE_GetInfo( clientID )))
323                 {
324                         FIXME( "No device found for id %lx\n", clientID);
325                 }
326                 else if ( info->deviceio )
327                 {
328                         return info->deviceio( dwIoControlCode,
329                                         lpvInBuffer, cbInBuffer,
330                                         lpvOutBuffer, cbOutBuffer,
331                                         lpcbBytesReturned, lpOverlapped );
332                 }
333                 else
334                 {
335                         FIXME( "Unimplemented control %ld for VxD device %s\n",
336                                dwIoControlCode, info->name ? info->name : "???" );
337                         /* FIXME: this is for invalid calls on W98SE,
338                          * but maybe we should use ERROR_CALL_NOT_IMPLEMENTED
339                          * instead ? */
340                         SetLastError( ERROR_INVALID_FUNCTION );
341                 }
342         }
343         else
344         {       
345             NTSTATUS            status;
346
347             if (lpOverlapped)
348             {
349                 status = NtDeviceIoControlFile(hDevice, lpOverlapped->hEvent, 
350                                                NULL, NULL, 
351                                                (PIO_STATUS_BLOCK)lpOverlapped,
352                                                dwIoControlCode, 
353                                                lpvInBuffer, cbInBuffer,
354                                                lpvOutBuffer, cbOutBuffer);
355                 if (status) SetLastError(RtlNtStatusToDosError(status));
356                 if (lpcbBytesReturned) *lpcbBytesReturned = lpOverlapped->InternalHigh;
357                 return !status;
358             }
359             else
360             {
361                 IO_STATUS_BLOCK     iosb;
362
363                 status = NtDeviceIoControlFile(hDevice, NULL, NULL, NULL, &iosb,
364                                                dwIoControlCode, 
365                                                lpvInBuffer, cbInBuffer,
366                                                lpvOutBuffer, cbOutBuffer);
367                 if (status) SetLastError(RtlNtStatusToDosError(status));
368                 if (lpcbBytesReturned) *lpcbBytesReturned = iosb.Information;
369                 return !status;
370             }
371         }
372         return FALSE;
373 }
374
375 /***********************************************************************
376  *           DeviceIo_VTDAPI
377  */
378 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
379                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
380                               LPDWORD lpcbBytesReturned,
381                               LPOVERLAPPED lpOverlapped)
382 {
383     BOOL retv = TRUE;
384
385     switch (dwIoControlCode)
386     {
387     case 5:
388         if (lpvOutBuffer && (cbOutBuffer>=4))
389             *(DWORD*)lpvOutBuffer = GetTickCount();
390
391         if (lpcbBytesReturned)
392             *lpcbBytesReturned = 4;
393
394         break;
395
396     default:
397         FIXME( "Control %ld not implemented\n", dwIoControlCode);
398         retv = FALSE;
399         break;
400     }
401
402     return retv;
403 }
404
405 /***********************************************************************
406  *           DeviceIo_IFSMgr
407  * NOTES
408  *   These ioctls are used by 'MSNET32.DLL'.
409  *
410  *   I have been unable to uncover any documentation about the ioctls so
411  *   the implementation of the cases IFS_IOCTL_21 and IFS_IOCTL_2F are
412  *   based on reasonable guesses on information found in the Windows 95 DDK.
413  *
414  */
415
416 /*
417  * IFSMgr DeviceIO service
418  */
419
420 #define IFS_IOCTL_21                100
421 #define IFS_IOCTL_2F                101
422 #define IFS_IOCTL_GET_RES           102
423 #define IFS_IOCTL_GET_NETPRO_NAME_A 103
424
425 struct win32apireq {
426         unsigned long   ar_proid;
427         unsigned long   ar_eax;
428         unsigned long   ar_ebx;
429         unsigned long   ar_ecx;
430         unsigned long   ar_edx;
431         unsigned long   ar_esi;
432         unsigned long   ar_edi;
433         unsigned long   ar_ebp;
434         unsigned short  ar_error;
435         unsigned short  ar_pad;
436 };
437
438 static void win32apieq_2_CONTEXT(struct win32apireq *pIn,CONTEXT86 *pCxt)
439 {
440         memset(pCxt,0,sizeof(*pCxt));
441
442         pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
443         pCxt->Eax = pIn->ar_eax;
444         pCxt->Ebx = pIn->ar_ebx;
445         pCxt->Ecx = pIn->ar_ecx;
446         pCxt->Edx = pIn->ar_edx;
447         pCxt->Esi = pIn->ar_esi;
448         pCxt->Edi = pIn->ar_edi;
449
450         /* FIXME: Only partial CONTEXT86_CONTROL */
451         pCxt->Ebp = pIn->ar_ebp;
452
453         /* FIXME: pIn->ar_proid ignored */
454         /* FIXME: pIn->ar_error ignored */
455         /* FIXME: pIn->ar_pad ignored */
456 }
457
458 static void CONTEXT_2_win32apieq(CONTEXT86 *pCxt,struct win32apireq *pOut)
459 {
460         memset(pOut,0,sizeof(struct win32apireq));
461
462         pOut->ar_eax = pCxt->Eax;
463         pOut->ar_ebx = pCxt->Ebx;
464         pOut->ar_ecx = pCxt->Ecx;
465         pOut->ar_edx = pCxt->Edx;
466         pOut->ar_esi = pCxt->Esi;
467         pOut->ar_edi = pCxt->Edi;
468
469         /* FIXME: Only partial CONTEXT86_CONTROL */
470         pOut->ar_ebp = pCxt->Ebp;
471
472         /* FIXME: pOut->ar_proid ignored */
473         /* FIXME: pOut->ar_error ignored */
474         /* FIXME: pOut->ar_pad ignored */
475 }
476
477 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
478                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
479                               LPDWORD lpcbBytesReturned,
480                               LPOVERLAPPED lpOverlapped)
481 {
482     BOOL retv = TRUE;
483         TRACE("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
484                         dwIoControlCode,
485                         lpvInBuffer,cbInBuffer,
486                         lpvOutBuffer,cbOutBuffer,
487                         lpcbBytesReturned,
488                         lpOverlapped);
489
490     switch (dwIoControlCode)
491     {
492         case IFS_IOCTL_21:
493         case IFS_IOCTL_2F:{
494                 CONTEXT86 cxt;
495                 struct win32apireq *pIn=(struct win32apireq *) lpvInBuffer;
496                 struct win32apireq *pOut=(struct win32apireq *) lpvOutBuffer;
497
498                 TRACE(
499                         "Control '%s': "
500                         "proid=0x%08lx, eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
501                         "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx, ebp=0x%08lx, "
502                         "error=0x%04x, pad=0x%04x\n",
503                         (dwIoControlCode==IFS_IOCTL_21)?"IFS_IOCTL_21":"IFS_IOCTL_2F",
504                         pIn->ar_proid, pIn->ar_eax, pIn->ar_ebx, pIn->ar_ecx,
505                         pIn->ar_edx, pIn->ar_esi, pIn->ar_edi, pIn->ar_ebp,
506                         pIn->ar_error, pIn->ar_pad
507                 );
508
509                 win32apieq_2_CONTEXT(pIn,&cxt);
510
511                 if(dwIoControlCode==IFS_IOCTL_21)
512                 {
513                     if(Dosvm.CallBuiltinHandler || DPMI_LoadDosSystem())
514                         Dosvm.CallBuiltinHandler( &cxt, 0x21 );
515                } 
516                 else 
517                 {
518                     if(Dosvm.CallBuiltinHandler || DPMI_LoadDosSystem())
519                         Dosvm.CallBuiltinHandler( &cxt, 0x2f );
520                 }
521
522                 CONTEXT_2_win32apieq(&cxt,pOut);
523
524         retv = TRUE;
525         } break;
526         case IFS_IOCTL_GET_RES:{
527         FIXME( "Control 'IFS_IOCTL_GET_RES' not implemented\n");
528         retv = FALSE;
529         } break;
530         case IFS_IOCTL_GET_NETPRO_NAME_A:{
531         FIXME( "Control 'IFS_IOCTL_GET_NETPRO_NAME_A' not implemented\n");
532         retv = FALSE;
533         } break;
534     default:
535         FIXME( "Control %ld not implemented\n", dwIoControlCode);
536         retv = FALSE;
537     }
538
539     return retv;
540 }
541
542 /***********************************************************************
543  *           DeviceIo_VCD
544  */
545 static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
546                               LPVOID lpvInBuffer, DWORD cbInBuffer,
547                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
548                               LPDWORD lpcbBytesReturned,
549                               LPOVERLAPPED lpOverlapped)
550 {
551     BOOL retv = TRUE;
552
553     switch (dwIoControlCode)
554     {
555     case IOCTL_SERIAL_LSRMST_INSERT:
556     {
557         FIXME( "IOCTL_SERIAL_LSRMST_INSERT NIY !\n");
558         retv = FALSE;
559     }
560     break;
561
562     default:
563         FIXME( "Unknown Control %ld\n", dwIoControlCode);
564         retv = FALSE;
565         break;
566     }
567
568     return retv;
569 }
570
571
572 /***********************************************************************
573  *           DeviceIo_VWin32
574  */
575
576 static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
577 {
578     memset( pCxt, 0, sizeof(*pCxt) );
579     /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN
580              will interpret 32-bit register contents as linear pointers */
581
582     pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
583     pCxt->Eax = pIn->reg_EAX;
584     pCxt->Ebx = pIn->reg_EBX;
585     pCxt->Ecx = pIn->reg_ECX;
586     pCxt->Edx = pIn->reg_EDX;
587     pCxt->Esi = pIn->reg_ESI;
588     pCxt->Edi = pIn->reg_EDI;
589
590     /* FIXME: Only partial CONTEXT86_CONTROL */
591     pCxt->EFlags = pIn->reg_Flags;
592 }
593
594 static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut )
595 {
596     memset( pOut, 0, sizeof(DIOC_REGISTERS) );
597
598     pOut->reg_EAX = pCxt->Eax;
599     pOut->reg_EBX = pCxt->Ebx;
600     pOut->reg_ECX = pCxt->Ecx;
601     pOut->reg_EDX = pCxt->Edx;
602     pOut->reg_ESI = pCxt->Esi;
603     pOut->reg_EDI = pCxt->Edi;
604
605     /* FIXME: Only partial CONTEXT86_CONTROL */
606     pOut->reg_Flags = pCxt->EFlags;
607 }
608
609 #define DIOC_AH(regs) (((unsigned char*)&((regs)->reg_EAX))[1])
610 #define DIOC_AL(regs) (((unsigned char*)&((regs)->reg_EAX))[0])
611 #define DIOC_BH(regs) (((unsigned char*)&((regs)->reg_EBX))[1])
612 #define DIOC_BL(regs) (((unsigned char*)&((regs)->reg_EBX))[0])
613 #define DIOC_DH(regs) (((unsigned char*)&((regs)->reg_EDX))[1])
614 #define DIOC_DL(regs) (((unsigned char*)&((regs)->reg_EDX))[0])
615
616 #define DIOC_AX(regs) (((unsigned short*)&((regs)->reg_EAX))[0])
617 #define DIOC_BX(regs) (((unsigned short*)&((regs)->reg_EBX))[0])
618 #define DIOC_CX(regs) (((unsigned short*)&((regs)->reg_ECX))[0])
619 #define DIOC_DX(regs) (((unsigned short*)&((regs)->reg_EDX))[0])
620
621 #define DIOC_SET_CARRY(regs) (((regs)->reg_Flags)|=0x00000001)
622
623 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
624                               LPVOID lpvInBuffer, DWORD cbInBuffer,
625                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
626                               LPDWORD lpcbBytesReturned,
627                               LPOVERLAPPED lpOverlapped)
628 {
629     BOOL retv = TRUE;
630
631     switch (dwIoControlCode)
632     {
633     case VWIN32_DIOC_DOS_IOCTL:
634     case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
635     case VWIN32_DIOC_DOS_INT13:
636     case VWIN32_DIOC_DOS_INT25:
637     case VWIN32_DIOC_DOS_INT26:
638     case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
639     case VWIN32_DIOC_DOS_DRIVEINFO:
640     {
641         CONTEXT86 cxt;
642         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
643         DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;
644         BYTE intnum = 0;
645
646         TRACE( "Control '%s': "
647                "eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
648                "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx \n",
649                (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" :
650                (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" :
651                (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" :
652                (dwIoControlCode == VWIN32_DIOC_DOS_DRIVEINFO)? "VWIN32_DIOC_DOS_DRIVEINFO" :  "???",
653                pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX,
654                pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI );
655
656         DIOCRegs_2_CONTEXT( pIn, &cxt );
657
658         switch (dwIoControlCode)
659         {
660         case VWIN32_DIOC_DOS_IOCTL: /* Call int 21h */
661         case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
662         case VWIN32_DIOC_DOS_DRIVEINFO:        /* Call int 21h 730x */
663             intnum = 0x21;
664             break;
665         case VWIN32_DIOC_DOS_INT13:
666             intnum = 0x13;
667             break;
668         case VWIN32_DIOC_DOS_INT25: 
669             intnum = 0x25;
670             break;
671         case VWIN32_DIOC_DOS_INT26:
672             intnum = 0x26;
673             break;
674         case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
675             intnum = 0x31;
676             break;
677         }
678
679         if(Dosvm.CallBuiltinHandler || DPMI_LoadDosSystem())
680             Dosvm.CallBuiltinHandler( &cxt, intnum );
681
682         CONTEXT_2_DIOCRegs( &cxt, pOut );
683     }
684     break;
685
686     case VWIN32_DIOC_SIMCTRLC:
687         FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n");
688         retv = FALSE;
689         break;
690
691     default:
692         FIXME( "Unknown Control %ld\n", dwIoControlCode);
693         retv = FALSE;
694         break;
695     }
696
697     return retv;
698 }
699
700 /* this is the main multimedia device loader */
701 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
702                               LPVOID lpvInBuffer, DWORD cbInBuffer,
703                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
704                               LPDWORD lpcbBytesReturned,
705                               LPOVERLAPPED lpOverlapped)
706 {
707         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
708             dwIoControlCode,
709             lpvInBuffer,cbInBuffer,
710             lpvOutBuffer,cbOutBuffer,
711             lpcbBytesReturned,
712             lpOverlapped
713         );
714         switch (dwIoControlCode) {
715         case 5:
716                 /* Hmm. */
717                 *(DWORD*)lpvOutBuffer=0;
718                 *lpcbBytesReturned=4;
719                 return TRUE;
720         }
721         return FALSE;
722 }
723 /* this is used by some Origin games */
724 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
725                               LPVOID lpvInBuffer, DWORD cbInBuffer,
726                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
727                               LPDWORD lpcbBytesReturned,
728                               LPOVERLAPPED lpOverlapped)
729 {
730         switch (dwIoControlCode) {
731         case 1: /* version */
732                 *(LPDWORD)lpvOutBuffer = 0x20004; /* WC SecretOps */
733                 break;
734         case 9: /* debug output */
735                 ERR("MONODEBG: %s\n",debugstr_a(lpvInBuffer));
736                 break;
737         default:
738                 FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
739                         dwIoControlCode,
740                         lpvInBuffer,cbInBuffer,
741                         lpvOutBuffer,cbOutBuffer,
742                         lpcbBytesReturned,
743                         lpOverlapped
744                 );
745                 break;
746         }
747         return TRUE;
748 }
749 /* pccard */
750 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
751                               LPVOID lpvInBuffer, DWORD cbInBuffer,
752                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
753                               LPDWORD lpcbBytesReturned,
754                               LPOVERLAPPED lpOverlapped)
755 {
756         switch (dwIoControlCode) {
757         case 0x0000: /* PCCARD_Get_Version */
758         case 0x0001: /* PCCARD_Card_Services */
759         default:
760                 FIXME( "(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
761                         dwIoControlCode,
762                         lpvInBuffer,cbInBuffer,
763                         lpvOutBuffer,cbOutBuffer,
764                         lpcbBytesReturned,
765                         lpOverlapped
766                 );
767                 break;
768         }
769         return FALSE;
770 }
771
772 static BOOL DeviceIo_HASP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
773                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
774                               LPDWORD lpcbBytesReturned,
775                               LPOVERLAPPED lpOverlapped)
776 {
777     BOOL retv = TRUE;
778         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
779                         dwIoControlCode,
780                         lpvInBuffer,cbInBuffer,
781                         lpvOutBuffer,cbOutBuffer,
782                         lpcbBytesReturned,
783                         lpOverlapped);
784
785     return retv;
786 }