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