Documentation updates (mainly thru vs. through).
[wine] / win32 / 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  */
9
10 #include "config.h"
11
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <string.h>
16 #include <stdarg.h>
17 #include <time.h>
18 #include "wine/port.h"
19 #include "windef.h"
20 #include "winbase.h"
21 #include "winreg.h"
22 #include "winerror.h"
23 #include "file.h"
24 #include "winioctl.h"
25 #include "winnt.h"
26 #include "msdos.h"
27 #include "miscemu.h"
28 #include "stackframe.h"
29 #include "wine/server.h"
30 #include "debugtools.h"
31
32 DEFAULT_DEBUG_CHANNEL(win32);
33
34
35 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, 
36                               LPVOID lpvInBuffer, DWORD cbInBuffer,
37                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
38                               LPDWORD lpcbBytesReturned,
39                               LPOVERLAPPED lpOverlapped);
40 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode, 
41                               LPVOID lpvInBuffer, DWORD cbInBuffer,
42                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
43                               LPDWORD lpcbBytesReturned,
44                               LPOVERLAPPED lpOverlapped);
45 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode, 
46                               LPVOID lpvInBuffer, DWORD cbInBuffer,
47                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
48                               LPDWORD lpcbBytesReturned,
49                               LPOVERLAPPED lpOverlapped);
50
51 static DWORD VxDCall_VMM( DWORD service, CONTEXT86 *context );
52
53 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, 
54                               LPVOID lpvInBuffer, DWORD cbInBuffer,
55                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
56                               LPDWORD lpcbBytesReturned,
57                               LPOVERLAPPED lpOverlapped);
58
59 static BOOL DeviceIo_VCD(DWORD dwIoControlCode, 
60                               LPVOID lpvInBuffer, DWORD cbInBuffer,
61                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
62                               LPDWORD lpcbBytesReturned,
63                               LPOVERLAPPED lpOverlapped);
64
65 static DWORD VxDCall_VWin32( DWORD service, CONTEXT86 *context );
66
67 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode, 
68                               LPVOID lpvInBuffer, DWORD cbInBuffer,
69                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
70                               LPDWORD lpcbBytesReturned,
71                               LPOVERLAPPED lpOverlapped);
72
73 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode, 
74                               LPVOID lpvInBuffer, DWORD cbInBuffer,
75                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
76                               LPDWORD lpcbBytesReturned,
77                               LPOVERLAPPED lpOverlapped);
78
79 static BOOL DeviceIo_HASP (DWORD dwIoControlCode, 
80                               LPVOID lpvInBuffer, DWORD cbInBuffer,
81                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
82                               LPDWORD lpcbBytesReturned,
83                               LPOVERLAPPED lpOverlapped);
84 /*
85  * VxD names are taken from the Win95 DDK
86  */
87
88 struct VxDInfo
89 {
90     LPCSTR  name;
91     WORD    id;
92     DWORD (*vxdcall)(DWORD, CONTEXT86 *);
93     BOOL  (*deviceio)(DWORD, LPVOID, DWORD, 
94                         LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
95 };
96
97 static const struct VxDInfo VxDList[] = 
98 {
99     /* Standard VxD IDs */
100     { "VMM",      0x0001, VxDCall_VMM, NULL },
101     { "DEBUG",    0x0002, NULL, NULL },
102     { "VPICD",    0x0003, NULL, NULL },
103     { "VDMAD",    0x0004, NULL, NULL },
104     { "VTD",      0x0005, NULL, NULL },
105     { "V86MMGR",  0x0006, NULL, NULL },
106     { "PAGESWAP", 0x0007, NULL, NULL },
107     { "PARITY",   0x0008, NULL, NULL },
108     { "REBOOT",   0x0009, NULL, NULL },
109     { "VDD",      0x000A, NULL, NULL },
110     { "VSD",      0x000B, NULL, NULL },
111     { "VMD",      0x000C, NULL, NULL },
112     { "VKD",      0x000D, NULL, NULL },
113     { "VCD",      0x000E, NULL, DeviceIo_VCD },
114     { "VPD",      0x000F, NULL, NULL },
115     { "BLOCKDEV", 0x0010, NULL, NULL },
116     { "VMCPD",    0x0011, NULL, NULL },
117     { "EBIOS",    0x0012, NULL, NULL },
118     { "BIOSXLAT", 0x0013, NULL, NULL },
119     { "VNETBIOS", 0x0014, NULL, NULL },
120     { "DOSMGR",   0x0015, NULL, NULL },
121     { "WINLOAD",  0x0016, NULL, NULL },
122     { "SHELL",    0x0017, NULL, NULL },
123     { "VMPOLL",   0x0018, NULL, NULL },
124     { "VPROD",    0x0019, NULL, NULL },
125     { "DOSNET",   0x001A, NULL, NULL },
126     { "VFD",      0x001B, NULL, NULL },
127     { "VDD2",     0x001C, NULL, NULL },
128     { "WINDEBUG", 0x001D, NULL, NULL },
129     { "TSRLOAD",  0x001E, NULL, NULL },
130     { "BIOSHOOK", 0x001F, NULL, NULL },
131     { "INT13",    0x0020, NULL, NULL },
132     { "PAGEFILE", 0x0021, NULL, NULL },
133     { "SCSI",     0x0022, NULL, NULL },
134     { "MCA_POS",  0x0023, NULL, NULL },
135     { "SCSIFD",   0x0024, NULL, NULL },
136     { "VPEND",    0x0025, NULL, NULL },
137     { "VPOWERD",  0x0026, NULL, NULL },
138     { "VXDLDR",   0x0027, NULL, NULL },
139     { "NDIS",     0x0028, NULL, NULL },
140     { "BIOS_EXT", 0x0029, NULL, NULL },
141     { "VWIN32",   0x002A, VxDCall_VWin32, DeviceIo_VWin32 },
142     { "VCOMM",    0x002B, NULL, NULL },
143     { "SPOOLER",  0x002C, NULL, NULL },
144     { "WIN32S",   0x002D, NULL, NULL },
145     { "DEBUGCMD", 0x002E, NULL, NULL },
146
147     { "VNB",      0x0031, NULL, NULL },
148     { "SERVER",   0x0032, NULL, NULL },
149     { "CONFIGMG", 0x0033, NULL, NULL },
150     { "DWCFGMG",  0x0034, NULL, NULL },
151     { "SCSIPORT", 0x0035, NULL, NULL },
152     { "VFBACKUP", 0x0036, NULL, NULL },
153     { "ENABLE",   0x0037, NULL, NULL },
154     { "VCOND",    0x0038, NULL, NULL },
155
156     { "EFAX",     0x003A, NULL, NULL },
157     { "DSVXD",    0x003B, NULL, NULL },
158     { "ISAPNP",   0x003C, NULL, NULL },
159     { "BIOS",     0x003D, NULL, NULL },
160     { "WINSOCK",  0x003E, NULL, NULL },
161     { "WSOCK",    0x003E, NULL, NULL },
162     { "WSIPX",    0x003F, NULL, NULL },
163     { "IFSMgr",   0x0040, NULL, DeviceIo_IFSMgr },
164     { "VCDFSD",   0x0041, NULL, NULL },
165     { "MRCI2",    0x0042, NULL, NULL },
166     { "PCI",      0x0043, NULL, NULL },
167     { "PELOADER", 0x0044, NULL, NULL },
168     { "EISA",     0x0045, NULL, NULL },
169     { "DRAGCLI",  0x0046, NULL, NULL },
170     { "DRAGSRV",  0x0047, NULL, NULL },
171     { "PERF",     0x0048, NULL, NULL },
172     { "AWREDIR",  0x0049, NULL, NULL },
173
174     /* Far East support */
175     { "ETEN",     0x0060, NULL, NULL },
176     { "CHBIOS",   0x0061, NULL, NULL },
177     { "VMSGD",    0x0062, NULL, NULL },
178     { "VPPID",    0x0063, NULL, NULL },
179     { "VIME",     0x0064, NULL, NULL },
180     { "VHBIOSD",  0x0065, NULL, NULL },
181
182     /* Multimedia OEM IDs */
183     { "VTDAPI",   0x0442, NULL, DeviceIo_VTDAPI },
184     { "MMDEVLDR", 0x044A, NULL, DeviceIo_MMDEVLDR },
185
186     /* Network Device IDs */
187     { "VNetSup",  0x0480, NULL, NULL },
188     { "VRedir",   0x0481, NULL, NULL },
189     { "VBrowse",  0x0482, NULL, NULL },
190     { "VSHARE",   0x0483, NULL, NULL },
191     { "IFSMgr",   0x0484, NULL, NULL },
192     { "MEMPROBE", 0x0485, NULL, NULL },
193     { "VFAT",     0x0486, NULL, NULL },
194     { "NWLINK",   0x0487, NULL, NULL },
195     { "VNWLINK",  0x0487, NULL, NULL },
196     { "NWSUP",    0x0487, NULL, NULL },
197     { "VTDI",     0x0488, NULL, NULL },
198     { "VIP",      0x0489, NULL, NULL },
199     { "VTCP",     0x048A, NULL, NULL },
200     { "VCache",   0x048B, NULL, NULL },
201     { "VUDP",     0x048C, NULL, NULL },
202     { "VAsync",   0x048D, NULL, NULL },
203     { "NWREDIR",  0x048E, NULL, NULL },
204     { "STAT80",   0x048F, NULL, NULL },
205     { "SCSIPORT", 0x0490, NULL, NULL },
206     { "FILESEC",  0x0491, NULL, NULL },
207     { "NWSERVER", 0x0492, NULL, NULL },
208     { "SECPROV",  0x0493, NULL, NULL },
209     { "NSCL",     0x0494, NULL, NULL },
210     { "WSTCP",    0x0495, NULL, NULL },
211     { "NDIS2SUP", 0x0496, NULL, NULL },
212     { "MSODISUP", 0x0497, NULL, NULL },
213     { "Splitter", 0x0498, NULL, NULL },
214     { "PPP",      0x0499, NULL, NULL },
215     { "VDHCP",    0x049A, NULL, NULL },
216     { "VNBT",     0x049B, NULL, NULL },
217     { "LOGGER",   0x049D, NULL, NULL },
218     { "EFILTER",  0x049E, NULL, NULL },
219     { "FFILTER",  0x049F, NULL, NULL },
220     { "TFILTER",  0x04A0, NULL, NULL },
221     { "AFILTER",  0x04A1, NULL, NULL },
222     { "IRLAMP",   0x04A2, NULL, NULL },
223
224     { "PCCARD",   0x097C, NULL, DeviceIo_PCCARD },
225     { "HASP95",   0x3721, NULL, DeviceIo_HASP },
226
227     /* WINE additions, ids unknown */
228     { "MONODEBG.VXD", 0x4242, NULL, DeviceIo_MONODEBG },
229
230     { NULL,       0,      NULL, NULL }
231 };
232
233 /*
234  * VMM VxDCall service names are (mostly) taken from Stan Mitchell's
235  * "Inside the Windows 95 File System"
236  */
237
238 #define N_VMM_SERVICE 41
239
240 LPCSTR VMM_Service_Name[N_VMM_SERVICE] =
241
242     "PageReserve",            /* 0x0000 */
243     "PageCommit",             /* 0x0001 */
244     "PageDecommit",           /* 0x0002 */
245     "PagerRegister",          /* 0x0003 */
246     "PagerQuery",             /* 0x0004 */
247     "HeapAllocate",           /* 0x0005 */
248     "ContextCreate",          /* 0x0006 */
249     "ContextDestroy",         /* 0x0007 */
250     "PageAttach",             /* 0x0008 */
251     "PageFlush",              /* 0x0009 */
252     "PageFree",               /* 0x000A */
253     "ContextSwitch",          /* 0x000B */
254     "HeapReAllocate",         /* 0x000C */
255     "PageModifyPermissions",  /* 0x000D */
256     "PageQuery",              /* 0x000E */
257     "GetCurrentContext",      /* 0x000F */
258     "HeapFree",               /* 0x0010 */
259     "RegOpenKey",             /* 0x0011 */
260     "RegCreateKey",           /* 0x0012 */
261     "RegCloseKey",            /* 0x0013 */
262     "RegDeleteKey",           /* 0x0014 */
263     "RegSetValue",            /* 0x0015 */
264     "RegDeleteValue",         /* 0x0016 */
265     "RegQueryValue",          /* 0x0017 */
266     "RegEnumKey",             /* 0x0018 */
267     "RegEnumValue",           /* 0x0019 */
268     "RegQueryValueEx",        /* 0x001A */
269     "RegSetValueEx",          /* 0x001B */
270     "RegFlushKey",            /* 0x001C */
271     "RegQueryInfoKey",        /* 0x001D */
272     "GetDemandPageInfo",      /* 0x001E */
273     "BlockOnID",              /* 0x001F */
274     "SignalID",               /* 0x0020 */
275     "RegLoadKey",             /* 0x0021 */
276     "RegUnLoadKey",           /* 0x0022 */
277     "RegSaveKey",             /* 0x0023 */
278     "RegRemapPreDefKey",      /* 0x0024 */
279     "PageChangePager",        /* 0x0025 */
280     "RegQueryMultipleValues", /* 0x0026 */
281     "RegReplaceKey",          /* 0x0027 */
282     "<KERNEL32.101>"          /* 0x0028 -- What does this do??? */
283 };
284
285 /* PageReserve arena values */
286 #define PR_PRIVATE  0x80000400  /* anywhere in private arena */
287 #define PR_SHARED   0x80060000  /* anywhere in shared arena */
288 #define PR_SYSTEM   0x80080000  /* anywhere in system arena */
289
290 /* PageReserve flags */
291 #define PR_FIXED    0x00000008  /* don't move during PageReAllocate */
292 #define PR_4MEG     0x00000001  /* allocate on 4mb boundary */
293 #define PR_STATIC   0x00000010  /* see PageReserve documentation */
294
295 /* PageCommit default pager handle values */
296 #define PD_ZEROINIT 0x00000001  /* swappable zero-initialized pages */
297 #define PD_NOINIT   0x00000002  /* swappable uninitialized pages */
298 #define PD_FIXEDZERO    0x00000003  /* fixed zero-initialized pages */
299 #define PD_FIXED    0x00000004  /* fixed uninitialized pages */
300
301 /* PageCommit flags */
302 #define PC_FIXED    0x00000008  /* pages are permanently locked */
303 #define PC_LOCKED   0x00000080  /* pages are made present and locked */
304 #define PC_LOCKEDIFDP   0x00000100  /* pages are locked if swap via DOS */
305 #define PC_WRITEABLE    0x00020000  /* make the pages writeable */
306 #define PC_USER     0x00040000  /* make the pages ring 3 accessible */
307 #define PC_INCR     0x40000000  /* increment "pagerdata" each page */
308 #define PC_PRESENT  0x80000000  /* make pages initially present */
309 #define PC_STATIC   0x20000000  /* allow commit in PR_STATIC object */
310 #define PC_DIRTY    0x08000000  /* make pages initially dirty */
311 #define PC_CACHEDIS 0x00100000  /* Allocate uncached pages - new for WDM */
312 #define PC_CACHEWT  0x00080000  /* Allocate write through cache pages - new for WDM */
313 #define PC_PAGEFLUSH 0x00008000 /* Touch device mapped pages on alloc - new for WDM */
314
315 /* PageCommitContig additional flags */
316 #define PCC_ZEROINIT    0x00000001  /* zero-initialize new pages */
317 #define PCC_NOLIN   0x10000000  /* don't map to any linear address */
318
319
320
321 HANDLE DEVICE_Open( LPCSTR filename, DWORD access,
322                       LPSECURITY_ATTRIBUTES sa )
323 {
324     const struct VxDInfo *info;
325
326     for (info = VxDList; info->name; info++)
327         if (!strncasecmp( info->name, filename, strlen(info->name) ))
328             return FILE_CreateDevice( info->id | 0x10000, access, sa );
329
330     FIXME( "Unknown VxD %s. Try --winver nt40 or win31 !\n", filename);
331     SetLastError( ERROR_FILE_NOT_FOUND );
332     return 0;
333 }
334
335 static const struct VxDInfo *DEVICE_GetInfo( HANDLE handle )
336 {
337     const struct VxDInfo *info = NULL;
338     SERVER_START_REQ( get_file_info )
339     {
340         req->handle = handle;
341         if (!SERVER_CALL() &&
342             (req->type == FILE_TYPE_UNKNOWN) &&
343             (req->attr & 0x10000))
344         {
345             for (info = VxDList; info->name; info++)
346                 if (info->id == LOWORD(req->attr)) break;
347         }
348     }
349     SERVER_END_REQ;
350     return info;
351 }
352
353 /****************************************************************************
354  *              DeviceIoControl (KERNEL32.@)
355  * This is one of those big ugly nasty procedure which can do
356  * a million and one things when it comes to devices. It can also be
357  * used for VxD communication.
358  *
359  * A return value of FALSE indicates that something has gone wrong which
360  * GetLastError can decipher.
361  */
362 BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, 
363                               LPVOID lpvInBuffer, DWORD cbInBuffer,
364                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
365                               LPDWORD lpcbBytesReturned,
366                               LPOVERLAPPED lpOverlapped)
367 {
368         const struct VxDInfo *info;
369
370         TRACE( "(%d,%ld,%p,%ld,%p,%ld,%p,%p)\n",
371                hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
372                lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped  );
373
374         if (!(info = DEVICE_GetInfo( hDevice )))
375         {
376                 SetLastError( ERROR_INVALID_PARAMETER );
377                 return FALSE;
378         }
379
380         /* Check if this is a user defined control code for a VxD */
381         if( HIWORD( dwIoControlCode ) == 0 )
382         {
383                 if ( info->deviceio )
384                 {
385                         return info->deviceio( dwIoControlCode, 
386                                         lpvInBuffer, cbInBuffer, 
387                                         lpvOutBuffer, cbOutBuffer, 
388                                         lpcbBytesReturned, lpOverlapped );
389                 }
390                 else
391                 {
392                         FIXME( "Unimplemented control %ld for VxD device %s\n", 
393                                dwIoControlCode, info->name ? info->name : "???" );
394                         /* FIXME: this is for invalid calls on W98SE,
395                          * but maybe we should use ERROR_CALL_NOT_IMPLEMENTED
396                          * instead ? */
397                         SetLastError( ERROR_INVALID_FUNCTION );
398                 }
399         }
400         else
401         {
402                 switch( dwIoControlCode )
403                 {
404                 case FSCTL_DELETE_REPARSE_POINT:
405                 case FSCTL_DISMOUNT_VOLUME:
406                 case FSCTL_GET_COMPRESSION:
407                 case FSCTL_GET_REPARSE_POINT:
408                 case FSCTL_LOCK_VOLUME:
409                 case FSCTL_QUERY_ALLOCATED_RANGES:
410                 case FSCTL_SET_COMPRESSION:
411                 case FSCTL_SET_REPARSE_POINT:
412                 case FSCTL_SET_SPARSE:
413                 case FSCTL_SET_ZERO_DATA:
414                 case FSCTL_UNLOCK_VOLUME:
415                 case IOCTL_DISK_CHECK_VERIFY:
416                 case IOCTL_DISK_EJECT_MEDIA:
417                 case IOCTL_DISK_FORMAT_TRACKS:
418                 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
419                 case IOCTL_DISK_GET_DRIVE_LAYOUT:
420                 case IOCTL_DISK_GET_MEDIA_TYPES:
421                 case IOCTL_DISK_GET_PARTITION_INFO:
422                 case IOCTL_DISK_LOAD_MEDIA:
423                 case IOCTL_DISK_MEDIA_REMOVAL:
424                 case IOCTL_DISK_PERFORMANCE:
425                 case IOCTL_DISK_REASSIGN_BLOCKS:
426                 case IOCTL_DISK_SET_DRIVE_LAYOUT:
427                 case IOCTL_DISK_SET_PARTITION_INFO:
428                 case IOCTL_DISK_VERIFY:
429                 case IOCTL_SERIAL_LSRMST_INSERT:
430                 case IOCTL_STORAGE_CHECK_VERIFY:
431                 case IOCTL_STORAGE_EJECT_MEDIA:
432                 case IOCTL_STORAGE_GET_MEDIA_TYPES:
433                 case IOCTL_STORAGE_LOAD_MEDIA:
434                 case IOCTL_STORAGE_MEDIA_REMOVAL:
435                         FIXME( "unimplemented dwIoControlCode=%08lx\n", dwIoControlCode);
436                         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
437                         return FALSE;
438                         break;
439                 default:
440                         FIXME( "ignored dwIoControlCode=%08lx\n",dwIoControlCode);
441                         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
442                         return FALSE;
443                         break;
444                 }
445         }
446         return FALSE;
447 }
448  
449 /***********************************************************************
450  *           DeviceIo_VTDAPI
451  */
452 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
453                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
454                               LPDWORD lpcbBytesReturned,
455                               LPOVERLAPPED lpOverlapped)
456 {
457     BOOL retv = TRUE;
458
459     switch (dwIoControlCode)
460     {
461     case 5:
462         if (lpvOutBuffer && (cbOutBuffer>=4))
463             *(DWORD*)lpvOutBuffer = GetTickCount();
464
465         if (lpcbBytesReturned)
466             *lpcbBytesReturned = 4;
467
468         break;
469
470     default:
471         FIXME( "Control %ld not implemented\n", dwIoControlCode);
472         retv = FALSE;
473         break;
474     }
475
476     return retv;
477 }
478
479 /***********************************************************************
480  *              VxDCall0 (KERNEL32.1)
481  *              VxDCall1 (KERNEL32.2)
482  *              VxDCall2 (KERNEL32.3)
483  *              VxDCall3 (KERNEL32.4)
484  *              VxDCall4 (KERNEL32.5)
485  *              VxDCall5 (KERNEL32.6)
486  *              VxDCall6 (KERNEL32.7)
487  *              VxDCall7 (KERNEL32.8)
488  *              VxDCall8 (KERNEL32.9)
489  */
490 void VxDCall( DWORD service, CONTEXT86 *context )
491 {
492     DWORD ret = 0xffffffff; /* FIXME */
493     int i;
494
495     TRACE( "(%08lx, ...)\n", service);
496
497     for (i = 0; VxDList[i].name; i++)
498         if (VxDList[i].id == HIWORD(service))
499             break;
500
501     if (!VxDList[i].name)
502         FIXME( "Unknown VxD (%08lx)\n", service);
503     else if (!VxDList[i].vxdcall)
504         FIXME( "Unimplemented VxD (%08lx)\n", service);
505     else
506         ret = VxDList[i].vxdcall( service, context );
507
508     context->Eax = ret;
509 }
510
511
512 /***********************************************************************
513  *           VxDCall_VMM
514  */
515 static DWORD VxDCall_VMM( DWORD service, CONTEXT86 *context )
516 {
517     switch ( LOWORD(service) )
518     {
519     case 0x0011:  /* RegOpenKey */
520     {
521         HKEY    hkey       = (HKEY)  stack32_pop( context );
522         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
523         LPHKEY  retkey     = (LPHKEY)stack32_pop( context );
524         return RegOpenKeyA( hkey, lpszSubKey, retkey );
525     }
526
527     case 0x0012:  /* RegCreateKey */
528     {
529         HKEY    hkey       = (HKEY)  stack32_pop( context );
530         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
531         LPHKEY  retkey     = (LPHKEY)stack32_pop( context );
532         return RegCreateKeyA( hkey, lpszSubKey, retkey );
533     }
534
535     case 0x0013:  /* RegCloseKey */
536     {
537         HKEY    hkey       = (HKEY)stack32_pop( context );
538         return RegCloseKey( hkey );
539     }
540
541     case 0x0014:  /* RegDeleteKey */
542     {
543         HKEY    hkey       = (HKEY)  stack32_pop( context );
544         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
545         return RegDeleteKeyA( hkey, lpszSubKey );
546     }
547
548     case 0x0015:  /* RegSetValue */
549     {
550         HKEY    hkey       = (HKEY)  stack32_pop( context );
551         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
552         DWORD   dwType     = (DWORD) stack32_pop( context );
553         LPCSTR  lpszData   = (LPCSTR)stack32_pop( context );
554         DWORD   cbData     = (DWORD) stack32_pop( context );
555         return RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData );
556     }
557
558     case 0x0016:  /* RegDeleteValue */
559     {
560         HKEY    hkey       = (HKEY) stack32_pop( context );
561         LPSTR   lpszValue  = (LPSTR)stack32_pop( context );
562         return RegDeleteValueA( hkey, lpszValue );
563     }
564
565     case 0x0017:  /* RegQueryValue */
566     {
567         HKEY    hkey       = (HKEY)   stack32_pop( context );
568         LPSTR   lpszSubKey = (LPSTR)  stack32_pop( context );
569         LPSTR   lpszData   = (LPSTR)  stack32_pop( context );
570         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
571         return RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData );
572     }
573
574     case 0x0018:  /* RegEnumKey */
575     {
576         HKEY    hkey       = (HKEY) stack32_pop( context );
577         DWORD   iSubkey    = (DWORD)stack32_pop( context );
578         LPSTR   lpszName   = (LPSTR)stack32_pop( context );
579         DWORD   lpcchName  = (DWORD)stack32_pop( context );
580         return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName );
581     }
582
583     case 0x0019:  /* RegEnumValue */
584     {
585         HKEY    hkey       = (HKEY)   stack32_pop( context );
586         DWORD   iValue     = (DWORD)  stack32_pop( context );
587         LPSTR   lpszValue  = (LPSTR)  stack32_pop( context );
588         LPDWORD lpcchValue = (LPDWORD)stack32_pop( context );
589         LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
590         LPDWORD lpdwType   = (LPDWORD)stack32_pop( context );
591         LPBYTE  lpbData    = (LPBYTE) stack32_pop( context );
592         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
593         return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, 
594                               lpReserved, lpdwType, lpbData, lpcbData );
595     }
596
597     case 0x001A:  /* RegQueryValueEx */
598     {
599         HKEY    hkey       = (HKEY)   stack32_pop( context );
600         LPSTR   lpszValue  = (LPSTR)  stack32_pop( context );
601         LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
602         LPDWORD lpdwType   = (LPDWORD)stack32_pop( context );
603         LPBYTE  lpbData    = (LPBYTE) stack32_pop( context );
604         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
605         return RegQueryValueExA( hkey, lpszValue, lpReserved, 
606                                  lpdwType, lpbData, lpcbData );
607     }
608
609     case 0x001B:  /* RegSetValueEx */
610     {
611         HKEY    hkey       = (HKEY)  stack32_pop( context );
612         LPSTR   lpszValue  = (LPSTR) stack32_pop( context );
613         DWORD   dwReserved = (DWORD) stack32_pop( context );
614         DWORD   dwType     = (DWORD) stack32_pop( context );
615         LPBYTE  lpbData    = (LPBYTE)stack32_pop( context );
616         DWORD   cbData     = (DWORD) stack32_pop( context );
617         return RegSetValueExA( hkey, lpszValue, dwReserved, 
618                                dwType, lpbData, cbData );
619     }
620
621     case 0x001C:  /* RegFlushKey */
622     {
623         HKEY    hkey       = (HKEY)stack32_pop( context );
624         return RegFlushKey( hkey );
625     }
626
627     case 0x001D:  /* RegQueryInfoKey */
628     {
629         /* NOTE: This VxDCall takes only a subset of the parameters that the
630                  corresponding Win32 API call does. The implementation in Win95
631                  ADVAPI32 sets all output parameters not mentioned here to zero. */
632
633         HKEY    hkey              = (HKEY)   stack32_pop( context );
634         LPDWORD lpcSubKeys        = (LPDWORD)stack32_pop( context );
635         LPDWORD lpcchMaxSubKey    = (LPDWORD)stack32_pop( context );
636         LPDWORD lpcValues         = (LPDWORD)stack32_pop( context );
637         LPDWORD lpcchMaxValueName = (LPDWORD)stack32_pop( context );
638         LPDWORD lpcchMaxValueData = (LPDWORD)stack32_pop( context );
639         return RegQueryInfoKeyA( hkey, NULL, NULL, NULL, lpcSubKeys, lpcchMaxSubKey,
640                                  NULL, lpcValues, lpcchMaxValueName, lpcchMaxValueData,
641                                  NULL, NULL );
642     }
643
644     case 0x0021:  /* RegLoadKey */
645     {
646         HKEY    hkey       = (HKEY)  stack32_pop( context );
647         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
648         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
649         return RegLoadKeyA( hkey, lpszSubKey, lpszFile );
650     }
651
652     case 0x0022:  /* RegUnLoadKey */
653     {
654         HKEY    hkey       = (HKEY)  stack32_pop( context );
655         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
656         return RegUnLoadKeyA( hkey, lpszSubKey );
657     }
658
659     case 0x0023:  /* RegSaveKey */
660     {
661         HKEY    hkey       = (HKEY)  stack32_pop( context );
662         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
663         LPSECURITY_ATTRIBUTES sa = (LPSECURITY_ATTRIBUTES)stack32_pop( context );
664         return RegSaveKeyA( hkey, lpszFile, sa );
665     }
666
667 #if 0 /* Functions are not yet implemented in misc/registry.c */
668     case 0x0024:  /* RegRemapPreDefKey */
669     case 0x0026:  /* RegQueryMultipleValues */
670 #endif
671
672     case 0x0027:  /* RegReplaceKey */
673     {
674         HKEY    hkey       = (HKEY)  stack32_pop( context );
675         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
676         LPCSTR  lpszNewFile= (LPCSTR)stack32_pop( context );
677         LPCSTR  lpszOldFile= (LPCSTR)stack32_pop( context );
678         return RegReplaceKeyA( hkey, lpszSubKey, lpszNewFile, lpszOldFile );
679     }
680     case 0x0000: /* PageReserve */
681       {
682         LPVOID address;
683         LPVOID ret;
684         DWORD psize = getpagesize();
685         ULONG page   = (ULONG) stack32_pop( context );
686         ULONG npages = (ULONG) stack32_pop( context );
687         ULONG flags  = (ULONG) stack32_pop( context );
688
689         TRACE("PageReserve: page: %08lx, npages: %08lx, flags: %08lx partial stub!\n",
690               page, npages, flags );
691
692         if ( page == PR_SYSTEM ) {
693           ERR("Can't reserve ring 1 memory\n");
694           return -1;
695         }
696         /* FIXME: This has to be handled separately for the separate
697            address-spaces we now have */
698         if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0;
699         /* FIXME: Handle flags in some way */
700         address = (LPVOID )(page * psize); 
701         ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 );
702         TRACE("PageReserve: returning: %08lx\n", (DWORD )ret );
703         if ( ret == NULL )
704           return -1;
705         else
706           return (DWORD )ret;
707       }
708
709     case 0x0001: /* PageCommit */
710       {
711         LPVOID address;
712         LPVOID ret;
713         DWORD virt_perm;
714         DWORD psize = getpagesize();
715         ULONG page   = (ULONG) stack32_pop( context );
716         ULONG npages = (ULONG) stack32_pop( context );
717         ULONG hpd  = (ULONG) stack32_pop( context );
718         ULONG pagerdata   = (ULONG) stack32_pop( context );
719         ULONG flags  = (ULONG) stack32_pop( context );
720
721         TRACE("PageCommit: page: %08lx, npages: %08lx, hpd: %08lx pagerdata: "
722               "%08lx, flags: %08lx partial stub\n",
723               page, npages, hpd, pagerdata, flags );
724         
725         if ( flags & PC_USER )
726           if ( flags & PC_WRITEABLE )
727             virt_perm = PAGE_EXECUTE_READWRITE;
728           else
729             virt_perm = PAGE_EXECUTE_READ;
730         else
731           virt_perm = PAGE_NOACCESS;
732
733         address = (LPVOID )(page * psize); 
734         ret = VirtualAlloc ( address, ( npages * psize ), MEM_COMMIT, virt_perm );
735         TRACE("PageCommit: Returning: %08lx\n", (DWORD )ret );
736         return (DWORD )ret;
737
738       }
739     case 0x0002: /* PageDecommit */
740       {
741         LPVOID address;
742         BOOL ret;
743         DWORD psize = getpagesize();
744         ULONG page = (ULONG) stack32_pop( context );
745         ULONG npages = (ULONG) stack32_pop( context );
746         ULONG flags = (ULONG) stack32_pop( context );
747
748         TRACE("PageDecommit: page: %08lx, npages: %08lx, flags: %08lx partial stub\n",
749               page, npages, flags );
750         address = (LPVOID )( page * psize );
751         ret = VirtualFree ( address, ( npages * psize ), MEM_DECOMMIT ); 
752         TRACE("PageDecommit: Returning: %s\n", ret ? "TRUE" : "FALSE" );
753         return ret;
754       }
755     case 0x000d: /* PageModifyPermissions */
756       { 
757         DWORD pg_old_perm;
758         DWORD pg_new_perm;
759         DWORD virt_old_perm;
760         DWORD virt_new_perm;
761         MEMORY_BASIC_INFORMATION mbi;
762         LPVOID address;
763         DWORD psize = getpagesize();
764         ULONG page = stack32_pop ( context );
765         ULONG npages = stack32_pop ( context );
766         ULONG permand = stack32_pop ( context );
767         ULONG permor = stack32_pop ( context );
768
769         TRACE("PageModifyPermissions %08lx %08lx %08lx %08lx partial stub\n",
770               page, npages, permand, permor );
771         address = (LPVOID )( page * psize );
772
773         VirtualQuery ( address, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ));
774         virt_old_perm = mbi.Protect;
775
776         switch ( virt_old_perm & mbi.Protect ) {
777         case PAGE_READONLY:
778         case PAGE_EXECUTE:
779         case PAGE_EXECUTE_READ:
780           pg_old_perm = PC_USER;
781           break;
782         case PAGE_READWRITE:
783         case PAGE_WRITECOPY:
784         case PAGE_EXECUTE_READWRITE:
785         case PAGE_EXECUTE_WRITECOPY:
786           pg_old_perm = PC_USER | PC_WRITEABLE;
787           break; 
788         case PAGE_NOACCESS:
789         default:
790           pg_old_perm = 0;
791           break;
792         }       
793         pg_new_perm = pg_old_perm;
794         pg_new_perm &= permand & ~PC_STATIC;
795         pg_new_perm |= permor  & ~PC_STATIC;
796
797         virt_new_perm = ( virt_old_perm )  & ~0xff;
798         if ( pg_new_perm & PC_USER )
799         {
800           if ( pg_new_perm & PC_WRITEABLE )
801             virt_new_perm |= PAGE_EXECUTE_READWRITE;
802           else
803             virt_new_perm |= PAGE_EXECUTE_READ;
804         }
805   
806         if ( ! VirtualProtect ( address, ( npages * psize ), virt_new_perm, &virt_old_perm ) ) {
807           ERR("Can't change page permissions for %08lx\n", (DWORD )address );
808           return 0xffffffff;
809         }
810         TRACE("Returning: %08lx\n", pg_old_perm );
811         return pg_old_perm;
812       }
813     case 0x000a: /* PageFree */
814       {
815         BOOL ret;
816         LPVOID hmem = (LPVOID) stack32_pop( context );
817         DWORD flags = (DWORD ) stack32_pop( context );
818         
819         TRACE("PageFree: hmem: %08lx, flags: %08lx partial stub\n",
820               (DWORD )hmem, flags );
821
822         ret = VirtualFree ( hmem, 0, MEM_RELEASE );
823         context->Eax = ret;
824         TRACE("Returning: %d\n", ret );
825
826         return 0;
827       }
828     case 0x001e: /* GetDemandPageInfo */
829       {
830          DWORD dinfo = (DWORD)stack32_pop( context );
831          DWORD flags = (DWORD)stack32_pop( context );   
832
833          /* GetDemandPageInfo is supposed to fill out the struct at
834           * "dinfo" with various low-level memory management information.
835           * Apps are certainly not supposed to call this, although it's
836           * demoed and documented by Pietrek on pages 441-443 of "Windows
837           * 95 System Programming Secrets" if any program needs a real
838           * implementation of this.
839           */
840
841          FIXME("GetDemandPageInfo(%08lx %08lx): stub!\n", dinfo, flags);
842
843          return 0;
844       }
845     default:
846         if (LOWORD(service) < N_VMM_SERVICE)
847             FIXME( "Unimplemented service %s (%08lx)\n",
848                           VMM_Service_Name[LOWORD(service)], service);
849         else
850             FIXME( "Unknown service %08lx\n", service);
851         break;
852     }
853
854     return 0xffffffff;  /* FIXME */
855 }
856
857 /***********************************************************************
858  *           DeviceIo_IFSMgr
859  * NOTES
860  *   These ioctls are used by 'MSNET32.DLL'.
861  *
862  *   I have been unable to uncover any documentation about the ioctls so 
863  *   the implementation of the cases IFS_IOCTL_21 and IFS_IOCTL_2F are
864  *   based on reasonable guesses on information found in the Windows 95 DDK.
865  *   
866  */
867
868 /*
869  * IFSMgr DeviceIO service
870  */
871
872 #define IFS_IOCTL_21                100
873 #define IFS_IOCTL_2F                101
874 #define IFS_IOCTL_GET_RES           102
875 #define IFS_IOCTL_GET_NETPRO_NAME_A 103
876
877 struct win32apireq {
878         unsigned long   ar_proid;
879         unsigned long   ar_eax;         
880         unsigned long   ar_ebx; 
881         unsigned long   ar_ecx; 
882         unsigned long   ar_edx; 
883         unsigned long   ar_esi; 
884         unsigned long   ar_edi;
885         unsigned long   ar_ebp;         
886         unsigned short  ar_error;
887         unsigned short  ar_pad;
888 };
889
890 static void win32apieq_2_CONTEXT(struct win32apireq *pIn,CONTEXT86 *pCxt)
891 {
892         memset(pCxt,0,sizeof(*pCxt));
893
894         pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
895         pCxt->Eax = pIn->ar_eax;
896         pCxt->Ebx = pIn->ar_ebx;
897         pCxt->Ecx = pIn->ar_ecx;
898         pCxt->Edx = pIn->ar_edx;
899         pCxt->Esi = pIn->ar_esi;
900         pCxt->Edi = pIn->ar_edi;
901
902         /* FIXME: Only partial CONTEXT86_CONTROL */
903         pCxt->Ebp = pIn->ar_ebp;
904
905         /* FIXME: pIn->ar_proid ignored */
906         /* FIXME: pIn->ar_error ignored */
907         /* FIXME: pIn->ar_pad ignored */
908 }
909
910 static void CONTEXT_2_win32apieq(CONTEXT86 *pCxt,struct win32apireq *pOut)
911 {
912         memset(pOut,0,sizeof(struct win32apireq));
913
914         pOut->ar_eax = pCxt->Eax;
915         pOut->ar_ebx = pCxt->Ebx;
916         pOut->ar_ecx = pCxt->Ecx;
917         pOut->ar_edx = pCxt->Edx;
918         pOut->ar_esi = pCxt->Esi;
919         pOut->ar_edi = pCxt->Edi;
920
921         /* FIXME: Only partial CONTEXT86_CONTROL */
922         pOut->ar_ebp = pCxt->Ebp;
923
924         /* FIXME: pOut->ar_proid ignored */
925         /* FIXME: pOut->ar_error ignored */
926         /* FIXME: pOut->ar_pad ignored */
927 }
928
929 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
930                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
931                               LPDWORD lpcbBytesReturned,
932                               LPOVERLAPPED lpOverlapped)
933 {
934     BOOL retv = TRUE;
935         TRACE("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
936                         dwIoControlCode,
937                         lpvInBuffer,cbInBuffer,
938                         lpvOutBuffer,cbOutBuffer,
939                         lpcbBytesReturned,
940                         lpOverlapped);
941
942     switch (dwIoControlCode)
943     {
944         case IFS_IOCTL_21:
945         case IFS_IOCTL_2F:{
946                 CONTEXT86 cxt;
947                 struct win32apireq *pIn=(struct win32apireq *) lpvInBuffer;
948                 struct win32apireq *pOut=(struct win32apireq *) lpvOutBuffer;
949
950                 TRACE(
951                         "Control '%s': "
952                         "proid=0x%08lx, eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
953                         "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx, ebp=0x%08lx, "
954                         "error=0x%04x, pad=0x%04x\n",
955                         (dwIoControlCode==IFS_IOCTL_21)?"IFS_IOCTL_21":"IFS_IOCTL_2F",
956                         pIn->ar_proid, pIn->ar_eax, pIn->ar_ebx, pIn->ar_ecx,
957                         pIn->ar_edx, pIn->ar_esi, pIn->ar_edi, pIn->ar_ebp,
958                         pIn->ar_error, pIn->ar_pad
959                 );                              
960                 
961                 win32apieq_2_CONTEXT(pIn,&cxt);
962
963                 if(dwIoControlCode==IFS_IOCTL_21)
964                 {
965                         DOS3Call(&cxt); /* Call int 21h */
966                 } else {
967                         INT_Int2fHandler(&cxt); /* Call int 2Fh */
968                 }
969                 
970                 CONTEXT_2_win32apieq(&cxt,pOut);
971                         
972         retv = TRUE;
973         } break;
974         case IFS_IOCTL_GET_RES:{
975         FIXME( "Control 'IFS_IOCTL_GET_RES' not implemented\n");
976         retv = FALSE;
977         } break;
978         case IFS_IOCTL_GET_NETPRO_NAME_A:{
979         FIXME( "Control 'IFS_IOCTL_GET_NETPRO_NAME_A' not implemented\n");
980         retv = FALSE;
981         } break;         
982     default:
983         FIXME( "Control %ld not implemented\n", dwIoControlCode);
984         retv = FALSE;
985     }
986
987     return retv;
988 }
989
990 /********************************************************************************
991  *      VxDCall_VWin32
992  *
993  *  Service numbers taken from page 448 of Pietrek's "Windows 95 System
994  *  Programming Secrets".  Parameters from experimentation on real Win98.
995  *
996  */
997
998 static DWORD VxDCall_VWin32( DWORD service, CONTEXT86 *context )
999 {
1000   switch ( LOWORD(service) )
1001     {
1002     case 0x0000: /* GetVersion */
1003     {
1004         DWORD vers = GetVersion();
1005         return (LOBYTE(vers) << 8) | HIBYTE(vers);
1006     }
1007     break;
1008
1009     case 0x0020: /* Get VMCPD Version */
1010     {
1011         DWORD parm = (DWORD) stack32_pop(context);
1012
1013         FIXME("Get VMCPD Version(%08lx): partial stub!\n", parm);
1014
1015         /* FIXME: This is what Win98 returns, it may
1016          *        not be correct in all situations.
1017          *        It makes Bleem! happy though.
1018          */
1019
1020         return 0x0405;
1021     }
1022
1023     case 0x0029: /* Int31/DPMI dispatch */
1024     {
1025         DWORD callnum = (DWORD) stack32_pop(context);
1026         DWORD parm    = (DWORD) stack32_pop(context);
1027  
1028         TRACE("Int31/DPMI dispatch(%08lx)\n", callnum);
1029
1030         AX_reg(context) = callnum;
1031         CX_reg(context) = parm;  
1032         INT_Int31Handler(context);
1033
1034         return LOWORD(context->Eax);
1035     }
1036     break;
1037
1038     case 0x002a: /* Int41 dispatch - parm = int41 service number */
1039     {
1040         DWORD callnum = (DWORD) stack32_pop(context);
1041
1042         return callnum; /* FIXME: should really call INT_Int41Handler() */
1043     }
1044     break;
1045
1046     default:
1047       FIXME("Unknown VWin32 service %08lx\n", service);
1048       break;
1049     }
1050
1051   return 0xffffffff;
1052 }
1053                          
1054
1055 /***********************************************************************
1056  *           DeviceIo_VCD
1057  */
1058 static BOOL DeviceIo_VCD(DWORD dwIoControlCode, 
1059                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1060                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1061                               LPDWORD lpcbBytesReturned,
1062                               LPOVERLAPPED lpOverlapped)
1063 {
1064     BOOL retv = TRUE;
1065
1066     switch (dwIoControlCode)
1067     {
1068     case IOCTL_SERIAL_LSRMST_INSERT:
1069     {
1070         FIXME( "IOCTL_SERIAL_LSRMST_INSERT NIY !\n");
1071         retv = FALSE;
1072     }
1073     break;
1074
1075     default:
1076         FIXME( "Unknown Control %ld\n", dwIoControlCode);
1077         retv = FALSE;
1078         break;
1079     }
1080
1081     return retv;
1082 }
1083
1084  
1085 /***********************************************************************
1086  *           DeviceIo_VWin32
1087  */
1088
1089 static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
1090 {
1091     memset( pCxt, 0, sizeof(*pCxt) );
1092     /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN
1093              will interpret 32-bit register contents as linear pointers */
1094
1095     pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
1096     pCxt->Eax = pIn->reg_EAX;
1097     pCxt->Ebx = pIn->reg_EBX;
1098     pCxt->Ecx = pIn->reg_ECX;
1099     pCxt->Edx = pIn->reg_EDX;
1100     pCxt->Esi = pIn->reg_ESI;
1101     pCxt->Edi = pIn->reg_EDI;
1102
1103     /* FIXME: Only partial CONTEXT86_CONTROL */
1104     pCxt->EFlags = pIn->reg_Flags;
1105 }
1106
1107 static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut )
1108 {
1109     memset( pOut, 0, sizeof(DIOC_REGISTERS) );
1110
1111     pOut->reg_EAX = pCxt->Eax;
1112     pOut->reg_EBX = pCxt->Ebx;
1113     pOut->reg_ECX = pCxt->Ecx;
1114     pOut->reg_EDX = pCxt->Edx;
1115     pOut->reg_ESI = pCxt->Esi;
1116     pOut->reg_EDI = pCxt->Edi;
1117
1118     /* FIXME: Only partial CONTEXT86_CONTROL */
1119     pOut->reg_Flags = pCxt->EFlags;
1120 }
1121
1122
1123 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode, 
1124                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1125                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1126                               LPDWORD lpcbBytesReturned,
1127                               LPOVERLAPPED lpOverlapped)
1128 {
1129     BOOL retv = TRUE;
1130
1131     switch (dwIoControlCode)
1132     {
1133     case VWIN32_DIOC_DOS_IOCTL:
1134     case VWIN32_DIOC_DOS_INT13:
1135     case VWIN32_DIOC_DOS_INT25:
1136     case VWIN32_DIOC_DOS_INT26:
1137         case VWIN32_DIOC_DOS_DRIVEINFO:
1138     {
1139         CONTEXT86 cxt;
1140         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
1141         DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;
1142
1143         TRACE( "Control '%s': "
1144                "eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
1145                "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx ",
1146                (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" :
1147                (dwIoControlCode == VWIN32_DIOC_DOS_INT13)? "VWIN32_DIOC_DOS_INT13" :
1148                (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" :
1149                (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" : 
1150                (dwIoControlCode == VWIN32_DIOC_DOS_DRIVEINFO)? "VWIN32_DIOC_DOS_DRIVEINFO" :  "???",
1151                pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX,
1152                pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI );
1153
1154         DIOCRegs_2_CONTEXT( pIn, &cxt );
1155
1156         switch (dwIoControlCode)
1157         {
1158         case VWIN32_DIOC_DOS_IOCTL: DOS3Call( &cxt ); break; /* Call int 21h */
1159         case VWIN32_DIOC_DOS_INT13: INT_Int13Handler( &cxt ); break;
1160         case VWIN32_DIOC_DOS_INT25: INT_Int25Handler( &cxt ); break;
1161         case VWIN32_DIOC_DOS_INT26: INT_Int26Handler( &cxt ); break;
1162                 case VWIN32_DIOC_DOS_DRIVEINFO: DOS3Call( &cxt ); break; /* Call int 21h 730x */
1163         }
1164
1165         CONTEXT_2_DIOCRegs( &cxt, pOut );
1166     }
1167     break;
1168
1169     case VWIN32_DIOC_SIMCTRLC:
1170         FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n");
1171         retv = FALSE;
1172         break;
1173
1174     default:
1175         FIXME( "Unknown Control %ld\n", dwIoControlCode);
1176         retv = FALSE;
1177         break;
1178     }
1179
1180     return retv;
1181 }
1182
1183 /* this is the main multimedia device loader */
1184 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode, 
1185                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1186                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1187                               LPDWORD lpcbBytesReturned,
1188                               LPOVERLAPPED lpOverlapped)
1189 {
1190         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1191             dwIoControlCode,
1192             lpvInBuffer,cbInBuffer,
1193             lpvOutBuffer,cbOutBuffer,
1194             lpcbBytesReturned,
1195             lpOverlapped
1196         );
1197         switch (dwIoControlCode) {
1198         case 5:
1199                 /* Hmm. */
1200                 *(DWORD*)lpvOutBuffer=0;
1201                 *lpcbBytesReturned=4;
1202                 return TRUE;
1203         }
1204         return FALSE;
1205 }
1206 /* this is used by some Origin games */
1207 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode, 
1208                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1209                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1210                               LPDWORD lpcbBytesReturned,
1211                               LPOVERLAPPED lpOverlapped)
1212 {
1213         switch (dwIoControlCode) {
1214         case 1: /* version */
1215                 *(LPDWORD)lpvOutBuffer = 0x20004; /* WC SecretOps */
1216                 break;
1217         case 9: /* debug output */
1218                 ERR("MONODEBG: %s\n",debugstr_a(lpvInBuffer));
1219                 break;
1220         default:
1221                 FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1222                         dwIoControlCode,
1223                         lpvInBuffer,cbInBuffer,
1224                         lpvOutBuffer,cbOutBuffer,
1225                         lpcbBytesReturned,
1226                         lpOverlapped
1227                 );
1228                 break;
1229         }
1230         return TRUE;
1231 }
1232 /* pccard */
1233 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode, 
1234                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1235                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1236                               LPDWORD lpcbBytesReturned,
1237                               LPOVERLAPPED lpOverlapped)
1238 {
1239         switch (dwIoControlCode) {
1240         case 0x0000: /* PCCARD_Get_Version */
1241         case 0x0001: /* PCCARD_Card_Services */
1242         default:
1243                 FIXME( "(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1244                         dwIoControlCode,
1245                         lpvInBuffer,cbInBuffer,
1246                         lpvOutBuffer,cbOutBuffer,
1247                         lpcbBytesReturned,
1248                         lpOverlapped
1249                 );
1250                 break;
1251         }
1252         return FALSE;
1253 }
1254
1255 /***********************************************************************
1256  *              OpenVxDHandle (KERNEL32.@)
1257  */
1258 DWORD   WINAPI  OpenVxDHandle(DWORD pmt)
1259 {
1260         FIXME( "(0x%08lx) stub!\n", pmt);
1261         return 0;
1262 }
1263
1264 static BOOL DeviceIo_HASP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
1265                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1266                               LPDWORD lpcbBytesReturned,
1267                               LPOVERLAPPED lpOverlapped)
1268 {
1269     BOOL retv = TRUE;
1270         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1271                         dwIoControlCode,
1272                         lpvInBuffer,cbInBuffer,
1273                         lpvOutBuffer,cbOutBuffer,
1274                         lpcbBytesReturned,
1275                         lpOverlapped);
1276
1277     return retv;
1278 }
1279