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