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