Updated documentation to reflect renamed header.
[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 <errno.h>
11 #include <assert.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #ifdef HAVE_SYS_MMAN_H
17 #include <sys/mman.h>
18 #endif
19 #include <fcntl.h>
20 #include <string.h>
21 #include <stdarg.h>
22 #include <time.h>
23 #include "winbase.h"
24 #include "winreg.h"
25 #include "winerror.h"
26 #include "file.h"
27 #include "process.h"
28 #include "mmsystem.h"
29 #include "heap.h"
30 #include "winioctl.h"
31 #include "winnt.h"
32 #include "msdos.h"
33 #include "miscemu.h"
34 #include "server.h"
35 #include "debugtools.h"
36
37 DEFAULT_DEBUG_CHANNEL(win32)
38
39
40 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, 
41                               LPVOID lpvInBuffer, DWORD cbInBuffer,
42                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
43                               LPDWORD lpcbBytesReturned,
44                               LPOVERLAPPED lpOverlapped);
45 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode, 
46                               LPVOID lpvInBuffer, DWORD cbInBuffer,
47                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
48                               LPDWORD lpcbBytesReturned,
49                               LPOVERLAPPED lpOverlapped);
50 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode, 
51                               LPVOID lpvInBuffer, DWORD cbInBuffer,
52                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
53                               LPDWORD lpcbBytesReturned,
54                               LPOVERLAPPED lpOverlapped);
55
56 static DWORD VxDCall_VMM( DWORD service, va_list args );
57
58 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, 
59                               LPVOID lpvInBuffer, DWORD cbInBuffer,
60                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
61                               LPDWORD lpcbBytesReturned,
62                               LPOVERLAPPED lpOverlapped);
63
64 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode, 
65                               LPVOID lpvInBuffer, DWORD cbInBuffer,
66                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
67                               LPDWORD lpcbBytesReturned,
68                               LPOVERLAPPED lpOverlapped);
69
70 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode, 
71                               LPVOID lpvInBuffer, DWORD cbInBuffer,
72                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
73                               LPDWORD lpcbBytesReturned,
74                               LPOVERLAPPED lpOverlapped);
75 /*
76  * VxD names are taken from the Win95 DDK
77  */
78
79 struct VxDInfo
80 {
81     LPCSTR  name;
82     WORD    id;
83     DWORD (*vxdcall)(DWORD, va_list);
84     BOOL  (*deviceio)(DWORD, LPVOID, DWORD, 
85                         LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
86 };
87
88 static const struct VxDInfo VxDList[] = 
89 {
90     /* Standard VxD IDs */
91     { "VMM",      0x0001, VxDCall_VMM, NULL },
92     { "DEBUG",    0x0002, NULL, NULL },
93     { "VPICD",    0x0003, NULL, NULL },
94     { "VDMAD",    0x0004, NULL, NULL },
95     { "VTD",      0x0005, NULL, NULL },
96     { "V86MMGR",  0x0006, NULL, NULL },
97     { "PAGESWAP", 0x0007, NULL, NULL },
98     { "PARITY",   0x0008, NULL, NULL },
99     { "REBOOT",   0x0009, NULL, NULL },
100     { "VDD",      0x000A, NULL, NULL },
101     { "VSD",      0x000B, NULL, NULL },
102     { "VMD",      0x000C, NULL, NULL },
103     { "VKD",      0x000D, NULL, NULL },
104     { "VCD",      0x000E, NULL, NULL },
105     { "VPD",      0x000F, NULL, NULL },
106     { "BLOCKDEV", 0x0010, NULL, NULL },
107     { "VMCPD",    0x0011, NULL, NULL },
108     { "EBIOS",    0x0012, NULL, NULL },
109     { "BIOSXLAT", 0x0013, NULL, NULL },
110     { "VNETBIOS", 0x0014, NULL, NULL },
111     { "DOSMGR",   0x0015, NULL, NULL },
112     { "WINLOAD",  0x0016, NULL, NULL },
113     { "SHELL",    0x0017, NULL, NULL },
114     { "VMPOLL",   0x0018, NULL, NULL },
115     { "VPROD",    0x0019, NULL, NULL },
116     { "DOSNET",   0x001A, NULL, NULL },
117     { "VFD",      0x001B, NULL, NULL },
118     { "VDD2",     0x001C, NULL, NULL },
119     { "WINDEBUG", 0x001D, NULL, NULL },
120     { "TSRLOAD",  0x001E, NULL, NULL },
121     { "BIOSHOOK", 0x001F, NULL, NULL },
122     { "INT13",    0x0020, NULL, NULL },
123     { "PAGEFILE", 0x0021, NULL, NULL },
124     { "SCSI",     0x0022, NULL, NULL },
125     { "MCA_POS",  0x0023, NULL, NULL },
126     { "SCSIFD",   0x0024, NULL, NULL },
127     { "VPEND",    0x0025, NULL, NULL },
128     { "VPOWERD",  0x0026, NULL, NULL },
129     { "VXDLDR",   0x0027, NULL, NULL },
130     { "NDIS",     0x0028, NULL, NULL },
131     { "BIOS_EXT", 0x0029, NULL, NULL },
132     { "VWIN32",   0x002A, NULL, DeviceIo_VWin32 },
133     { "VCOMM",    0x002B, NULL, NULL },
134     { "SPOOLER",  0x002C, NULL, NULL },
135     { "WIN32S",   0x002D, NULL, NULL },
136     { "DEBUGCMD", 0x002E, NULL, NULL },
137
138     { "VNB",      0x0031, NULL, NULL },
139     { "SERVER",   0x0032, NULL, NULL },
140     { "CONFIGMG", 0x0033, NULL, NULL },
141     { "DWCFGMG",  0x0034, NULL, NULL },
142     { "SCSIPORT", 0x0035, NULL, NULL },
143     { "VFBACKUP", 0x0036, NULL, NULL },
144     { "ENABLE",   0x0037, NULL, NULL },
145     { "VCOND",    0x0038, NULL, NULL },
146
147     { "EFAX",     0x003A, NULL, NULL },
148     { "DSVXD",    0x003B, NULL, NULL },
149     { "ISAPNP",   0x003C, NULL, NULL },
150     { "BIOS",     0x003D, NULL, NULL },
151     { "WINSOCK",  0x003E, NULL, NULL },
152     { "WSOCK",    0x003E, NULL, NULL },
153     { "WSIPX",    0x003F, NULL, NULL },
154     { "IFSMgr",   0x0040, NULL, DeviceIo_IFSMgr },
155     { "VCDFSD",   0x0041, NULL, NULL },
156     { "MRCI2",    0x0042, NULL, NULL },
157     { "PCI",      0x0043, NULL, NULL },
158     { "PELOADER", 0x0044, NULL, NULL },
159     { "EISA",     0x0045, NULL, NULL },
160     { "DRAGCLI",  0x0046, NULL, NULL },
161     { "DRAGSRV",  0x0047, NULL, NULL },
162     { "PERF",     0x0048, NULL, NULL },
163     { "AWREDIR",  0x0049, NULL, NULL },
164
165     /* Far East support */
166     { "ETEN",     0x0060, NULL, NULL },
167     { "CHBIOS",   0x0061, NULL, NULL },
168     { "VMSGD",    0x0062, NULL, NULL },
169     { "VPPID",    0x0063, NULL, NULL },
170     { "VIME",     0x0064, NULL, NULL },
171     { "VHBIOSD",  0x0065, NULL, NULL },
172
173     /* Multimedia OEM IDs */
174     { "VTDAPI",   0x0442, NULL, DeviceIo_VTDAPI },
175     { "MMDEVLDR", 0x044A, NULL, DeviceIo_MMDEVLDR },
176
177     /* Network Device IDs */
178     { "VNetSup",  0x0480, NULL, NULL },
179     { "VRedir",   0x0481, NULL, NULL },
180     { "VBrowse",  0x0482, NULL, NULL },
181     { "VSHARE",   0x0483, NULL, NULL },
182     { "IFSMgr",   0x0484, NULL, NULL },
183     { "MEMPROBE", 0x0485, NULL, NULL },
184     { "VFAT",     0x0486, NULL, NULL },
185     { "NWLINK",   0x0487, NULL, NULL },
186     { "VNWLINK",  0x0487, NULL, NULL },
187     { "NWSUP",    0x0487, NULL, NULL },
188     { "VTDI",     0x0488, NULL, NULL },
189     { "VIP",      0x0489, NULL, NULL },
190     { "VTCP",     0x048A, NULL, NULL },
191     { "VCache",   0x048B, NULL, NULL },
192     { "VUDP",     0x048C, NULL, NULL },
193     { "VAsync",   0x048D, NULL, NULL },
194     { "NWREDIR",  0x048E, NULL, NULL },
195     { "STAT80",   0x048F, NULL, NULL },
196     { "SCSIPORT", 0x0490, NULL, NULL },
197     { "FILESEC",  0x0491, NULL, NULL },
198     { "NWSERVER", 0x0492, NULL, NULL },
199     { "SECPROV",  0x0493, NULL, NULL },
200     { "NSCL",     0x0494, NULL, NULL },
201     { "WSTCP",    0x0495, NULL, NULL },
202     { "NDIS2SUP", 0x0496, NULL, NULL },
203     { "MSODISUP", 0x0497, NULL, NULL },
204     { "Splitter", 0x0498, NULL, NULL },
205     { "PPP",      0x0499, NULL, NULL },
206     { "VDHCP",    0x049A, NULL, NULL },
207     { "VNBT",     0x049B, NULL, NULL },
208     { "LOGGER",   0x049D, NULL, NULL },
209     { "EFILTER",  0x049E, NULL, NULL },
210     { "FFILTER",  0x049F, NULL, NULL },
211     { "TFILTER",  0x04A0, NULL, NULL },
212     { "AFILTER",  0x04A1, NULL, NULL },
213     { "IRLAMP",   0x04A2, NULL, NULL },
214
215     { "PCCARD",   0x097C, NULL, DeviceIo_PCCARD },
216
217     /* WINE additions, ids unknown */
218     { "MONODEBG.VXD", 0x4242, NULL, DeviceIo_MONODEBG },
219
220     { NULL,       0,      NULL, NULL }
221 };
222
223 /*
224  * VMM VxDCall service names are (mostly) taken from Stan Mitchell's
225  * "Inside the Windows 95 File System"
226  */
227
228 #define N_VMM_SERVICE 41
229
230 LPCSTR VMM_Service_Name[N_VMM_SERVICE] =
231
232     "PageReserve",            /* 0x0000 */
233     "PageCommit",             /* 0x0001 */
234     "PageDecommit",           /* 0x0002 */
235     "PagerRegister",          /* 0x0003 */
236     "PagerQuery",             /* 0x0004 */
237     "HeapAllocate",           /* 0x0005 */
238     "ContextCreate",          /* 0x0006 */
239     "ContextDestroy",         /* 0x0007 */
240     "PageAttach",             /* 0x0008 */
241     "PageFlush",              /* 0x0009 */
242     "PageFree",               /* 0x000A */
243     "ContextSwitch",          /* 0x000B */
244     "HeapReAllocate",         /* 0x000C */
245     "PageModifyPerm",         /* 0x000D */
246     "PageQuery",              /* 0x000E */
247     "GetCurrentContext",      /* 0x000F */
248     "HeapFree",               /* 0x0010 */
249     "RegOpenKey",             /* 0x0011 */
250     "RegCreateKey",           /* 0x0012 */
251     "RegCloseKey",            /* 0x0013 */
252     "RegDeleteKey",           /* 0x0014 */
253     "RegSetValue",            /* 0x0015 */
254     "RegDeleteValue",         /* 0x0016 */
255     "RegQueryValue",          /* 0x0017 */
256     "RegEnumKey",             /* 0x0018 */
257     "RegEnumValue",           /* 0x0019 */
258     "RegQueryValueEx",        /* 0x001A */
259     "RegSetValueEx",          /* 0x001B */
260     "RegFlushKey",            /* 0x001C */
261     "RegQueryInfoKey",        /* 0x001D */
262     "GetDemandPageInfo",      /* 0x001E */
263     "BlockOnID",              /* 0x001F */
264     "SignalID",               /* 0x0020 */
265     "RegLoadKey",             /* 0x0021 */
266     "RegUnLoadKey",           /* 0x0022 */
267     "RegSaveKey",             /* 0x0023 */
268     "RegRemapPreDefKey",      /* 0x0024 */
269     "PageChangePager",        /* 0x0025 */
270     "RegQueryMultipleValues", /* 0x0026 */
271     "RegReplaceKey",          /* 0x0027 */
272     "<KERNEL32.101>"          /* 0x0028 -- What does this do??? */
273 };
274
275 HANDLE DEVICE_Open( LPCSTR filename, DWORD access,
276                       LPSECURITY_ATTRIBUTES sa )
277 {
278     const struct VxDInfo *info;
279
280     for (info = VxDList; info->name; info++)
281         if (!lstrcmpiA( info->name, filename ))
282             return FILE_CreateDevice( info->id | 0x10000, access, sa );
283
284     FIXME( "Unknown VxD %s\n", filename);
285     return FILE_CreateDevice( 0x10000, access, sa );
286 }
287
288 static const struct VxDInfo *DEVICE_GetInfo( HANDLE handle )
289 {
290     struct get_file_info_request *req = get_req_buffer();
291
292     req->handle = handle;
293     if (!server_call( REQ_GET_FILE_INFO ) &&
294         (req->type == FILE_TYPE_UNKNOWN) &&
295         (req->attr & 0x10000))
296     {
297         const struct VxDInfo *info;
298         for (info = VxDList; info->name; info++)
299             if (info->id == LOWORD(req->attr)) return info;
300     }
301     return NULL;
302 }
303
304 /****************************************************************************
305  *              DeviceIoControl (KERNEL32.188)
306  * This is one of those big ugly nasty procedure which can do
307  * a million and one things when it comes to devices. It can also be
308  * used for VxD communication.
309  *
310  * A return value of FALSE indicates that something has gone wrong which
311  * GetLastError can decypher.
312  */
313 BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, 
314                               LPVOID lpvInBuffer, DWORD cbInBuffer,
315                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
316                               LPDWORD lpcbBytesReturned,
317                               LPOVERLAPPED lpOverlapped)
318 {
319         const struct VxDInfo *info;
320
321         TRACE( "(%d,%ld,%p,%ld,%p,%ld,%p,%p)\n",
322                hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
323                lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped  );
324
325         if (!(info = DEVICE_GetInfo( hDevice )))
326         {
327                 SetLastError( ERROR_INVALID_PARAMETER );
328                 return FALSE;
329         }
330
331         /* Check if this is a user defined control code for a VxD */
332         if( HIWORD( dwIoControlCode ) == 0 )
333         {
334                 if ( info->deviceio )
335                 {
336                         return info->deviceio( dwIoControlCode, 
337                                         lpvInBuffer, cbInBuffer, 
338                                         lpvOutBuffer, cbOutBuffer, 
339                                         lpcbBytesReturned, lpOverlapped );
340                 }
341                 else
342                 {
343                         /* FIXME: Set appropriate error */
344                         FIXME( "Unimplemented control %ld for VxD device %s\n", 
345                                dwIoControlCode, info->name ? info->name : "???" );
346                 }
347         }
348         else
349         {
350                 switch( dwIoControlCode )
351                 {
352                 case FSCTL_DELETE_REPARSE_POINT:
353                 case FSCTL_DISMOUNT_VOLUME:
354                 case FSCTL_GET_COMPRESSION:
355                 case FSCTL_GET_REPARSE_POINT:
356                 case FSCTL_LOCK_VOLUME:
357                 case FSCTL_QUERY_ALLOCATED_RANGES:
358                 case FSCTL_SET_COMPRESSION:
359                 case FSCTL_SET_REPARSE_POINT:
360                 case FSCTL_SET_SPARSE:
361                 case FSCTL_SET_ZERO_DATA:
362                 case FSCTL_UNLOCK_VOLUME:
363                 case IOCTL_DISK_CHECK_VERIFY:
364                 case IOCTL_DISK_EJECT_MEDIA:
365                 case IOCTL_DISK_FORMAT_TRACKS:
366                 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
367                 case IOCTL_DISK_GET_DRIVE_LAYOUT:
368                 case IOCTL_DISK_GET_MEDIA_TYPES:
369                 case IOCTL_DISK_GET_PARTITION_INFO:
370                 case IOCTL_DISK_LOAD_MEDIA:
371                 case IOCTL_DISK_MEDIA_REMOVAL:
372                 case IOCTL_DISK_PERFORMANCE:
373                 case IOCTL_DISK_REASSIGN_BLOCKS:
374                 case IOCTL_DISK_SET_DRIVE_LAYOUT:
375                 case IOCTL_DISK_SET_PARTITION_INFO:
376                 case IOCTL_DISK_VERIFY:
377                 case IOCTL_SERIAL_LSRMST_INSERT:
378                 case IOCTL_STORAGE_CHECK_VERIFY:
379                 case IOCTL_STORAGE_EJECT_MEDIA:
380                 case IOCTL_STORAGE_GET_MEDIA_TYPES:
381                 case IOCTL_STORAGE_LOAD_MEDIA:
382                 case IOCTL_STORAGE_MEDIA_REMOVAL:
383                         FIXME( "unimplemented dwIoControlCode=%08lx\n", dwIoControlCode);
384                         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
385                         return FALSE;
386                         break;
387                 default:
388                         FIXME( "ignored dwIoControlCode=%08lx\n",dwIoControlCode);
389                         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
390                         return FALSE;
391                         break;
392                 }
393         }
394         return FALSE;
395 }
396  
397 /***********************************************************************
398  *           DeviceIo_VTDAPI
399  */
400 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
401                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
402                               LPDWORD lpcbBytesReturned,
403                               LPOVERLAPPED lpOverlapped)
404 {
405     BOOL retv = TRUE;
406
407     switch (dwIoControlCode)
408     {
409     case 5:
410         if (lpvOutBuffer && (cbOutBuffer>=4))
411             *(DWORD*)lpvOutBuffer = timeGetTime();
412
413         if (lpcbBytesReturned)
414             *lpcbBytesReturned = 4;
415
416         break;
417
418     default:
419         FIXME( "Control %ld not implemented\n", dwIoControlCode);
420         retv = FALSE;
421         break;
422     }
423
424     return retv;
425 }
426
427
428
429
430
431 /***********************************************************************
432  *           VxDCall                   (KERNEL32.[1-9])
433  */
434 static DWORD VxDCall( DWORD service, ... )
435 {
436     DWORD ret = 0xffffffff; /* FIXME */
437     int i;
438
439     TRACE( "(%08lx, ...)\n", service);
440
441     for (i = 0; VxDList[i].name; i++)
442         if (VxDList[i].id == HIWORD(service))
443             break;
444
445     if (!VxDList[i].name)
446         FIXME( "Unknown VxD (%08lx)\n", service);
447     else if (!VxDList[i].vxdcall)
448         FIXME( "Unimplemented VxD (%08lx)\n", service);
449     else
450     {
451         va_list args;
452         va_start( args, service );
453         ret = VxDList[i].vxdcall( service, args );
454         va_end( args );
455     }
456     return ret;
457 }
458
459 DWORD WINAPI VxDCall0( DWORD service )
460 {
461     return VxDCall( service );
462 }
463
464 DWORD WINAPI VxDCall1( DWORD service, DWORD arg1 )
465 {
466     return VxDCall( service, arg1 );
467 }
468
469 DWORD WINAPI VxDCall2( DWORD service, DWORD arg1, DWORD arg2 )
470 {
471     return VxDCall( service, arg1, arg2 );
472 }
473
474 DWORD WINAPI VxDCall3( DWORD service, DWORD arg1, DWORD arg2, DWORD arg3 )
475 {
476     return VxDCall( service, arg1, arg2, arg3 );
477 }
478
479 DWORD WINAPI VxDCall4( DWORD service, DWORD arg1, DWORD arg2, DWORD arg3, DWORD arg4 )
480 {
481     return VxDCall( service, arg1, arg2, arg3, arg4 );
482 }
483
484 DWORD WINAPI VxDCall5( DWORD service, DWORD arg1, DWORD arg2, DWORD arg3,
485                        DWORD arg4, DWORD arg5 )
486 {
487     return VxDCall( service, arg1, arg2, arg3, arg4, arg5 );
488 }
489
490 DWORD WINAPI VxDCall6( DWORD service, DWORD arg1, DWORD arg2, DWORD arg3,
491                        DWORD arg4, DWORD arg5, DWORD arg6 )
492 {
493     return VxDCall( service, arg1, arg2, arg3, arg4, arg5, arg6 );
494 }
495
496 DWORD WINAPI VxDCall7( DWORD service, DWORD arg1, DWORD arg2, DWORD arg3,
497                        DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7 )
498 {
499     return VxDCall( service, arg1, arg2, arg3, arg4, arg5, arg6, arg7 );
500 }
501
502 DWORD WINAPI VxDCall8( DWORD service, DWORD arg1, DWORD arg2, DWORD arg3,
503                        DWORD arg4, DWORD arg5, DWORD arg6, DWORD arg7, DWORD arg8 )
504 {
505     return VxDCall( service, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 );
506 }
507
508 /***********************************************************************
509  *           VxDCall_VMM
510  */
511 static DWORD VxDCall_VMM( DWORD service, va_list args )
512 {
513     switch ( LOWORD(service) )
514     {
515     case 0x0011:  /* RegOpenKey */
516     {
517         HKEY    hkey       = va_arg( args, HKEY );
518         LPCSTR  lpszSubKey = va_arg( args, LPCSTR );
519         LPHKEY  retkey     = va_arg( args, LPHKEY );
520         return RegOpenKeyA( hkey, lpszSubKey, retkey );
521     }
522
523     case 0x0012:  /* RegCreateKey */
524     {
525         HKEY    hkey       = va_arg( args, HKEY );
526         LPCSTR  lpszSubKey = va_arg( args, LPCSTR );
527         LPHKEY  retkey     = va_arg( args, LPHKEY );
528         return RegCreateKeyA( hkey, lpszSubKey, retkey );
529     }
530
531     case 0x0013:  /* RegCloseKey */
532     {
533         HKEY    hkey       = va_arg( args, HKEY );
534         return RegCloseKey( hkey );
535     }
536
537     case 0x0014:  /* RegDeleteKey */
538     {
539         HKEY    hkey       = va_arg( args, HKEY );
540         LPCSTR  lpszSubKey = va_arg( args, LPCSTR );
541         return RegDeleteKeyA( hkey, lpszSubKey );
542     }
543
544     case 0x0015:  /* RegSetValue */
545     {
546         HKEY    hkey       = va_arg( args, HKEY );
547         LPCSTR  lpszSubKey = va_arg( args, LPCSTR );
548         DWORD   dwType     = va_arg( args, DWORD );
549         LPCSTR  lpszData   = va_arg( args, LPCSTR );
550         DWORD   cbData     = va_arg( args, DWORD );
551         return RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData );
552     }
553
554     case 0x0016:  /* RegDeleteValue */
555     {
556         HKEY    hkey       = va_arg( args, HKEY );
557         LPSTR   lpszValue  = va_arg( args, LPSTR );
558         return RegDeleteValueA( hkey, lpszValue );
559     }
560
561     case 0x0017:  /* RegQueryValue */
562     {
563         HKEY    hkey       = va_arg( args, HKEY );
564         LPSTR   lpszSubKey = va_arg( args, LPSTR );
565         LPSTR   lpszData   = va_arg( args, LPSTR );
566         LPDWORD lpcbData   = va_arg( args, LPDWORD );
567         return RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData );
568     }
569
570     case 0x0018:  /* RegEnumKey */
571     {
572         HKEY    hkey       = va_arg( args, HKEY );
573         DWORD   iSubkey    = va_arg( args, DWORD );
574         LPSTR   lpszName   = va_arg( args, LPSTR );
575         DWORD   lpcchName  = va_arg( args, DWORD );
576         return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName );
577     }
578
579     case 0x0019:  /* RegEnumValue */
580     {
581         HKEY    hkey       = va_arg( args, HKEY );
582         DWORD   iValue     = va_arg( args, DWORD );
583         LPSTR   lpszValue  = va_arg( args, LPSTR );
584         LPDWORD lpcchValue = va_arg( args, LPDWORD );
585         LPDWORD lpReserved = va_arg( args, LPDWORD );
586         LPDWORD lpdwType   = va_arg( args, LPDWORD );
587         LPBYTE  lpbData    = va_arg( args, LPBYTE );
588         LPDWORD lpcbData   = va_arg( args, LPDWORD );
589         return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue, 
590                               lpReserved, lpdwType, lpbData, lpcbData );
591     }
592
593     case 0x001A:  /* RegQueryValueEx */
594     {
595         HKEY    hkey       = va_arg( args, HKEY );
596         LPSTR   lpszValue  = va_arg( args, LPSTR );
597         LPDWORD lpReserved = va_arg( args, LPDWORD );
598         LPDWORD lpdwType   = va_arg( args, LPDWORD );
599         LPBYTE  lpbData    = va_arg( args, LPBYTE );
600         LPDWORD lpcbData   = va_arg( args, LPDWORD );
601         return RegQueryValueExA( hkey, lpszValue, lpReserved, 
602                                  lpdwType, lpbData, lpcbData );
603     }
604
605     case 0x001B:  /* RegSetValueEx */
606     {
607         HKEY    hkey       = va_arg( args, HKEY );
608         LPSTR   lpszValue  = va_arg( args, LPSTR );
609         DWORD   dwReserved = va_arg( args, DWORD );
610         DWORD   dwType     = va_arg( args, DWORD );
611         LPBYTE  lpbData    = va_arg( args, LPBYTE );
612         DWORD   cbData     = va_arg( args, DWORD );
613         return RegSetValueExA( hkey, lpszValue, dwReserved, 
614                                dwType, lpbData, cbData );
615     }
616
617     case 0x001C:  /* RegFlushKey */
618     {
619         HKEY    hkey       = va_arg( args, HKEY );
620         return RegFlushKey( hkey );
621     }
622
623     case 0x001D:  /* RegQueryInfoKey */
624     {
625         /* NOTE: This VxDCall takes only a subset of the parameters that the
626                  corresponding Win32 API call does. The implementation in Win95
627                  ADVAPI32 sets all output parameters not mentioned here to zero. */
628
629         HKEY    hkey              = va_arg( args, HKEY );
630         LPDWORD lpcSubKeys        = va_arg( args, LPDWORD );
631         LPDWORD lpcchMaxSubKey    = va_arg( args, LPDWORD );
632         LPDWORD lpcValues         = va_arg( args, LPDWORD );
633         LPDWORD lpcchMaxValueName = va_arg( args, LPDWORD );
634         LPDWORD lpcchMaxValueData = va_arg( args, LPDWORD );
635         return RegQueryInfoKeyA( hkey, NULL, NULL, NULL, lpcSubKeys, lpcchMaxSubKey,
636                                  NULL, lpcValues, lpcchMaxValueName, lpcchMaxValueData,
637                                  NULL, NULL );
638     }
639
640     case 0x0021:  /* RegLoadKey */
641     {
642         HKEY    hkey       = va_arg( args, HKEY );
643         LPCSTR  lpszSubKey = va_arg( args, LPCSTR );
644         LPCSTR  lpszFile   = va_arg( args, LPCSTR );
645         return RegLoadKeyA( hkey, lpszSubKey, lpszFile );
646     }
647
648     case 0x0022:  /* RegUnLoadKey */
649     {
650         HKEY    hkey       = va_arg( args, HKEY );
651         LPCSTR  lpszSubKey = va_arg( args, LPCSTR );
652         return RegUnLoadKeyA( hkey, lpszSubKey );
653     }
654
655     case 0x0023:  /* RegSaveKey */
656     {
657         HKEY    hkey       = va_arg( args, HKEY );
658         LPCSTR  lpszFile   = va_arg( args, LPCSTR );
659         LPSECURITY_ATTRIBUTES sa = va_arg( args, LPSECURITY_ATTRIBUTES );
660         return RegSaveKeyA( hkey, lpszFile, sa );
661     }
662
663 #if 0 /* Functions are not yet implemented in misc/registry.c */
664     case 0x0024:  /* RegRemapPreDefKey */
665     case 0x0026:  /* RegQueryMultipleValues */
666 #endif
667
668     case 0x0027:  /* RegReplaceKey */
669     {
670         HKEY    hkey       = va_arg( args, HKEY );
671         LPCSTR  lpszSubKey = va_arg( args, LPCSTR );
672         LPCSTR  lpszNewFile= va_arg( args, LPCSTR );
673         LPCSTR  lpszOldFile= va_arg( args, LPCSTR );
674         return RegReplaceKeyA( hkey, lpszSubKey, lpszNewFile, lpszOldFile );
675     }
676
677     default:
678         if (LOWORD(service) < N_VMM_SERVICE)
679             FIXME( "Unimplemented service %s (%08lx)\n",
680                           VMM_Service_Name[LOWORD(service)], service);
681         else
682             FIXME( "Unknown service %08lx\n", service);
683         break;
684     }
685
686     return 0xffffffff;  /* FIXME */
687 }
688
689 /***********************************************************************
690  *           DeviceIo_IFSMgr
691  * NOTES
692  *   The ioctls is used by 'MSNET32.DLL'.
693  *
694  *   I have been unable to uncover any documentation about the ioctls so 
695  *   the implementation of the cases IFS_IOCTL_21 and IFS_IOCTL_2F are
696  *   based on a resonable guesses on information found in the Windows 95 DDK.
697  *   
698  */
699
700 /*
701  * IFSMgr DeviceIO service
702  */
703
704 #define IFS_IOCTL_21                100
705 #define IFS_IOCTL_2F                101
706 #define IFS_IOCTL_GET_RES           102
707 #define IFS_IOCTL_GET_NETPRO_NAME_A 103
708
709 struct win32apireq {
710         unsigned long   ar_proid;
711         unsigned long   ar_eax;         
712         unsigned long   ar_ebx; 
713         unsigned long   ar_ecx; 
714         unsigned long   ar_edx; 
715         unsigned long   ar_esi; 
716         unsigned long   ar_edi;
717         unsigned long   ar_ebp;         
718         unsigned short  ar_error;
719         unsigned short  ar_pad;
720 };
721
722 static void win32apieq_2_CONTEXT(struct win32apireq *pIn,CONTEXT86 *pCxt)
723 {
724         memset(pCxt,0,sizeof(*pCxt));
725
726         pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
727         pCxt->Eax = pIn->ar_eax;
728         pCxt->Ebx = pIn->ar_ebx;
729         pCxt->Ecx = pIn->ar_ecx;
730         pCxt->Edx = pIn->ar_edx;
731         pCxt->Esi = pIn->ar_esi;
732         pCxt->Edi = pIn->ar_edi;
733
734         /* FIXME: Only partial CONTEXT86_CONTROL */
735         pCxt->Ebp = pIn->ar_ebp;
736
737         /* FIXME: pIn->ar_proid ignored */
738         /* FIXME: pIn->ar_error ignored */
739         /* FIXME: pIn->ar_pad ignored */
740 }
741
742 static void CONTEXT_2_win32apieq(CONTEXT86 *pCxt,struct win32apireq *pOut)
743 {
744         memset(pOut,0,sizeof(struct win32apireq));
745
746         pOut->ar_eax = pCxt->Eax;
747         pOut->ar_ebx = pCxt->Ebx;
748         pOut->ar_ecx = pCxt->Ecx;
749         pOut->ar_edx = pCxt->Edx;
750         pOut->ar_esi = pCxt->Esi;
751         pOut->ar_edi = pCxt->Edi;
752
753         /* FIXME: Only partial CONTEXT86_CONTROL */
754         pOut->ar_ebp = pCxt->Ebp;
755
756         /* FIXME: pOut->ar_proid ignored */
757         /* FIXME: pOut->ar_error ignored */
758         /* FIXME: pOut->ar_pad ignored */
759 }
760
761 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
762                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
763                               LPDWORD lpcbBytesReturned,
764                               LPOVERLAPPED lpOverlapped)
765 {
766     BOOL retv = TRUE;
767         TRACE("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
768                         dwIoControlCode,
769                         lpvInBuffer,cbInBuffer,
770                         lpvOutBuffer,cbOutBuffer,
771                         lpcbBytesReturned,
772                         lpOverlapped);
773
774     switch (dwIoControlCode)
775     {
776         case IFS_IOCTL_21:
777         case IFS_IOCTL_2F:{
778                 CONTEXT86 cxt;
779                 struct win32apireq *pIn=(struct win32apireq *) lpvInBuffer;
780                 struct win32apireq *pOut=(struct win32apireq *) lpvOutBuffer;
781
782                 TRACE(
783                         "Control '%s': "
784                         "proid=0x%08lx, eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
785                         "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx, ebp=0x%08lx, "
786                         "error=0x%04x, pad=0x%04x\n",
787                         (dwIoControlCode==IFS_IOCTL_21)?"IFS_IOCTL_21":"IFS_IOCTL_2F",
788                         pIn->ar_proid, pIn->ar_eax, pIn->ar_ebx, pIn->ar_ecx,
789                         pIn->ar_edx, pIn->ar_esi, pIn->ar_edi, pIn->ar_ebp,
790                         pIn->ar_error, pIn->ar_pad
791                 );                              
792                 
793                 win32apieq_2_CONTEXT(pIn,&cxt);
794
795                 if(dwIoControlCode==IFS_IOCTL_21)
796                 {
797                         DOS3Call(&cxt); /* Call int 21h */
798                 } else {
799                         INT_Int2fHandler(&cxt); /* Call int 2Fh */
800                 }
801                 
802                 CONTEXT_2_win32apieq(&cxt,pOut);
803                         
804         retv = TRUE;
805         } break;
806         case IFS_IOCTL_GET_RES:{
807         FIXME( "Control 'IFS_IOCTL_GET_RES' not implemented\n");
808         retv = FALSE;
809         } break;
810         case IFS_IOCTL_GET_NETPRO_NAME_A:{
811         FIXME( "Control 'IFS_IOCTL_GET_NETPRO_NAME_A' not implemented\n");
812         retv = FALSE;
813         } break;         
814     default:
815         FIXME( "Control %ld not implemented\n", dwIoControlCode);
816         retv = FALSE;
817     }
818
819     return retv;
820 }
821
822  
823 /***********************************************************************
824  *           DeviceIo_VWin32
825  */
826
827 static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
828 {
829     memset( pCxt, 0, sizeof(*pCxt) );
830     /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN
831              will interpret 32-bit register contents as linear pointers */
832
833     pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
834     pCxt->Eax = pIn->reg_EAX;
835     pCxt->Ebx = pIn->reg_EBX;
836     pCxt->Ecx = pIn->reg_ECX;
837     pCxt->Edx = pIn->reg_EDX;
838     pCxt->Esi = pIn->reg_ESI;
839     pCxt->Edi = pIn->reg_EDI;
840
841     /* FIXME: Only partial CONTEXT86_CONTROL */
842     pCxt->EFlags = pIn->reg_Flags;
843 }
844
845 static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut )
846 {
847     memset( pOut, 0, sizeof(DIOC_REGISTERS) );
848
849     pOut->reg_EAX = pCxt->Eax;
850     pOut->reg_EBX = pCxt->Ebx;
851     pOut->reg_ECX = pCxt->Ecx;
852     pOut->reg_EDX = pCxt->Edx;
853     pOut->reg_ESI = pCxt->Esi;
854     pOut->reg_EDI = pCxt->Edi;
855
856     /* FIXME: Only partial CONTEXT86_CONTROL */
857     pOut->reg_Flags = pCxt->EFlags;
858 }
859
860
861 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode, 
862                               LPVOID lpvInBuffer, DWORD cbInBuffer,
863                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
864                               LPDWORD lpcbBytesReturned,
865                               LPOVERLAPPED lpOverlapped)
866 {
867     BOOL retv = TRUE;
868
869     switch (dwIoControlCode)
870     {
871     case VWIN32_DIOC_DOS_IOCTL:
872     case VWIN32_DIOC_DOS_INT13:
873     case VWIN32_DIOC_DOS_INT25:
874     case VWIN32_DIOC_DOS_INT26:
875     {
876         CONTEXT86 cxt;
877         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
878         DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;
879
880         TRACE( "Control '%s': "
881                "eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
882                "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx ",
883                (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" :
884                (dwIoControlCode == VWIN32_DIOC_DOS_INT13)? "VWIN32_DIOC_DOS_INT13" :
885                (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" :
886                (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" : "???",
887                pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX,
888                pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI );
889
890         DIOCRegs_2_CONTEXT( pIn, &cxt );
891
892         switch (dwIoControlCode)
893         {
894         case VWIN32_DIOC_DOS_IOCTL: DOS3Call( &cxt ); break; /* Call int 21h */
895         case VWIN32_DIOC_DOS_INT13: INT_Int13Handler( &cxt ); break;
896         case VWIN32_DIOC_DOS_INT25: INT_Int25Handler( &cxt ); break;
897         case VWIN32_DIOC_DOS_INT26: INT_Int26Handler( &cxt ); break;
898         }
899
900         CONTEXT_2_DIOCRegs( &cxt, pOut );
901     }
902     break;
903
904     case VWIN32_DIOC_SIMCTRLC:
905         FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n");
906         retv = FALSE;
907         break;
908
909     default:
910         FIXME( "Unknown Control %ld\n", dwIoControlCode);
911         retv = FALSE;
912         break;
913     }
914
915     return retv;
916 }
917
918 /* this is the main multimedia device loader */
919 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode, 
920                               LPVOID lpvInBuffer, DWORD cbInBuffer,
921                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
922                               LPDWORD lpcbBytesReturned,
923                               LPOVERLAPPED lpOverlapped)
924 {
925         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
926             dwIoControlCode,
927             lpvInBuffer,cbInBuffer,
928             lpvOutBuffer,cbOutBuffer,
929             lpcbBytesReturned,
930             lpOverlapped
931         );
932         switch (dwIoControlCode) {
933         case 5:
934                 /* Hmm. */
935                 *(DWORD*)lpvOutBuffer=0;
936                 *lpcbBytesReturned=4;
937                 return TRUE;
938         }
939         return FALSE;
940 }
941 /* this is used by some Origin games */
942 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode, 
943                               LPVOID lpvInBuffer, DWORD cbInBuffer,
944                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
945                               LPDWORD lpcbBytesReturned,
946                               LPOVERLAPPED lpOverlapped)
947 {
948         switch (dwIoControlCode) {
949         case 1: /* version */
950                 *(LPDWORD)lpvOutBuffer = 0x20004; /* WC SecretOps */
951                 break;
952         case 9: /* debug output */
953                 fprintf(stderr,"MONODEBG: %s\n",debugstr_a(lpvInBuffer));
954                 break;
955         default:
956                 FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
957                         dwIoControlCode,
958                         lpvInBuffer,cbInBuffer,
959                         lpvOutBuffer,cbOutBuffer,
960                         lpcbBytesReturned,
961                         lpOverlapped
962                 );
963                 break;
964         }
965         return TRUE;
966 }
967 /* pccard */
968 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode, 
969                               LPVOID lpvInBuffer, DWORD cbInBuffer,
970                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
971                               LPDWORD lpcbBytesReturned,
972                               LPOVERLAPPED lpOverlapped)
973 {
974         switch (dwIoControlCode) {
975         case 0x0000: /* PCCARD_Get_Version */
976         case 0x0001: /* PCCARD_Card_Services */
977         default:
978                 FIXME( "(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
979                         dwIoControlCode,
980                         lpvInBuffer,cbInBuffer,
981                         lpvOutBuffer,cbOutBuffer,
982                         lpcbBytesReturned,
983                         lpOverlapped
984                 );
985                 break;
986         }
987         return FALSE;
988 }
989
990 DWORD   WINAPI  OpenVxDHandle(DWORD pmt)
991 {
992         FIXME( "(0x%08lx) stub!\n", pmt);
993         return 0;
994 }