Added regedit unit test, a couple minor changes to regedit.
[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 /* int 13 stuff */
47 #ifdef HAVE_SYS_IOCTL_H
48 # include <sys/ioctl.h>
49 #endif
50 #include <fcntl.h>
51 #ifdef linux
52 # include <linux/fd.h>
53 #endif
54 #include "drive.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(file);
57
58
59 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode,
60                               LPVOID lpvInBuffer, DWORD cbInBuffer,
61                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
62                               LPDWORD lpcbBytesReturned,
63                               LPOVERLAPPED lpOverlapped);
64 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
65                               LPVOID lpvInBuffer, DWORD cbInBuffer,
66                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
67                               LPDWORD lpcbBytesReturned,
68                               LPOVERLAPPED lpOverlapped);
69 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
70                               LPVOID lpvInBuffer, DWORD cbInBuffer,
71                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
72                               LPDWORD lpcbBytesReturned,
73                               LPOVERLAPPED lpOverlapped);
74
75 static DWORD VxDCall_VMM( DWORD service, CONTEXT86 *context );
76
77 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode,
78                               LPVOID lpvInBuffer, DWORD cbInBuffer,
79                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
80                               LPDWORD lpcbBytesReturned,
81                               LPOVERLAPPED lpOverlapped);
82
83 static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
84                               LPVOID lpvInBuffer, DWORD cbInBuffer,
85                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
86                               LPDWORD lpcbBytesReturned,
87                               LPOVERLAPPED lpOverlapped);
88
89 static DWORD VxDCall_VWin32( DWORD service, CONTEXT86 *context );
90
91 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
92                               LPVOID lpvInBuffer, DWORD cbInBuffer,
93                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
94                               LPDWORD lpcbBytesReturned,
95                               LPOVERLAPPED lpOverlapped);
96
97 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
98                               LPVOID lpvInBuffer, DWORD cbInBuffer,
99                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
100                               LPDWORD lpcbBytesReturned,
101                               LPOVERLAPPED lpOverlapped);
102
103 static BOOL DeviceIo_HASP (DWORD dwIoControlCode,
104                               LPVOID lpvInBuffer, DWORD cbInBuffer,
105                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
106                               LPDWORD lpcbBytesReturned,
107                               LPOVERLAPPED lpOverlapped);
108 /*
109  * VxD names are taken from the Win95 DDK
110  */
111
112 struct VxDInfo
113 {
114     LPCSTR  name;
115     WORD    id;
116     DWORD (*vxdcall)(DWORD, CONTEXT86 *);
117     BOOL  (*deviceio)(DWORD, LPVOID, DWORD,
118                         LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
119 };
120
121 static const struct VxDInfo VxDList[] =
122 {
123     /* Standard VxD IDs */
124     { "VMM",      0x0001, VxDCall_VMM, NULL },
125     { "DEBUG",    0x0002, NULL, NULL },
126     { "VPICD",    0x0003, NULL, NULL },
127     { "VDMAD",    0x0004, NULL, NULL },
128     { "VTD",      0x0005, NULL, NULL },
129     { "V86MMGR",  0x0006, NULL, NULL },
130     { "PAGESWAP", 0x0007, NULL, NULL },
131     { "PARITY",   0x0008, NULL, NULL },
132     { "REBOOT",   0x0009, NULL, NULL },
133     { "VDD",      0x000A, NULL, NULL },
134     { "VSD",      0x000B, NULL, NULL },
135     { "VMD",      0x000C, NULL, NULL },
136     { "VKD",      0x000D, NULL, NULL },
137     { "VCD",      0x000E, NULL, DeviceIo_VCD },
138     { "VPD",      0x000F, NULL, NULL },
139     { "BLOCKDEV", 0x0010, NULL, NULL },
140     { "VMCPD",    0x0011, NULL, NULL },
141     { "EBIOS",    0x0012, NULL, NULL },
142     { "BIOSXLAT", 0x0013, NULL, NULL },
143     { "VNETBIOS", 0x0014, NULL, NULL },
144     { "DOSMGR",   0x0015, NULL, NULL },
145     { "WINLOAD",  0x0016, NULL, NULL },
146     { "SHELL",    0x0017, NULL, NULL },
147     { "VMPOLL",   0x0018, NULL, NULL },
148     { "VPROD",    0x0019, NULL, NULL },
149     { "DOSNET",   0x001A, NULL, NULL },
150     { "VFD",      0x001B, NULL, NULL },
151     { "VDD2",     0x001C, NULL, NULL },
152     { "WINDEBUG", 0x001D, NULL, NULL },
153     { "TSRLOAD",  0x001E, NULL, NULL },
154     { "BIOSHOOK", 0x001F, NULL, NULL },
155     { "INT13",    0x0020, NULL, NULL },
156     { "PAGEFILE", 0x0021, NULL, NULL },
157     { "SCSI",     0x0022, NULL, NULL },
158     { "MCA_POS",  0x0023, NULL, NULL },
159     { "SCSIFD",   0x0024, NULL, NULL },
160     { "VPEND",    0x0025, NULL, NULL },
161     { "VPOWERD",  0x0026, NULL, NULL },
162     { "VXDLDR",   0x0027, NULL, NULL },
163     { "NDIS",     0x0028, NULL, NULL },
164     { "BIOS_EXT", 0x0029, NULL, NULL },
165     { "VWIN32",   0x002A, VxDCall_VWin32, DeviceIo_VWin32 },
166     { "VCOMM",    0x002B, NULL, NULL },
167     { "SPOOLER",  0x002C, NULL, NULL },
168     { "WIN32S",   0x002D, NULL, NULL },
169     { "DEBUGCMD", 0x002E, NULL, NULL },
170
171     { "VNB",      0x0031, NULL, NULL },
172     { "SERVER",   0x0032, NULL, NULL },
173     { "CONFIGMG", 0x0033, NULL, NULL },
174     { "DWCFGMG",  0x0034, NULL, NULL },
175     { "SCSIPORT", 0x0035, NULL, NULL },
176     { "VFBACKUP", 0x0036, NULL, NULL },
177     { "ENABLE",   0x0037, NULL, NULL },
178     { "VCOND",    0x0038, NULL, NULL },
179
180     { "EFAX",     0x003A, NULL, NULL },
181     { "DSVXD",    0x003B, NULL, NULL },
182     { "ISAPNP",   0x003C, NULL, NULL },
183     { "BIOS",     0x003D, NULL, NULL },
184     { "WINSOCK",  0x003E, NULL, NULL },
185     { "WSOCK",    0x003E, NULL, NULL },
186     { "WSIPX",    0x003F, NULL, NULL },
187     { "IFSMgr",   0x0040, NULL, DeviceIo_IFSMgr },
188     { "VCDFSD",   0x0041, NULL, NULL },
189     { "MRCI2",    0x0042, NULL, NULL },
190     { "PCI",      0x0043, NULL, NULL },
191     { "PELOADER", 0x0044, NULL, NULL },
192     { "EISA",     0x0045, NULL, NULL },
193     { "DRAGCLI",  0x0046, NULL, NULL },
194     { "DRAGSRV",  0x0047, NULL, NULL },
195     { "PERF",     0x0048, NULL, NULL },
196     { "AWREDIR",  0x0049, NULL, NULL },
197
198     /* Far East support */
199     { "ETEN",     0x0060, NULL, NULL },
200     { "CHBIOS",   0x0061, NULL, NULL },
201     { "VMSGD",    0x0062, NULL, NULL },
202     { "VPPID",    0x0063, NULL, NULL },
203     { "VIME",     0x0064, NULL, NULL },
204     { "VHBIOSD",  0x0065, NULL, NULL },
205
206     /* Multimedia OEM IDs */
207     { "VTDAPI",   0x0442, NULL, DeviceIo_VTDAPI },
208     { "MMDEVLDR", 0x044A, NULL, DeviceIo_MMDEVLDR },
209
210     /* Network Device IDs */
211     { "VNetSup",  0x0480, NULL, NULL },
212     { "VRedir",   0x0481, NULL, NULL },
213     { "VBrowse",  0x0482, NULL, NULL },
214     { "VSHARE",   0x0483, NULL, NULL },
215     { "IFSMgr",   0x0484, NULL, NULL },
216     { "MEMPROBE", 0x0485, NULL, NULL },
217     { "VFAT",     0x0486, NULL, NULL },
218     { "NWLINK",   0x0487, NULL, NULL },
219     { "VNWLINK",  0x0487, NULL, NULL },
220     { "NWSUP",    0x0487, NULL, NULL },
221     { "VTDI",     0x0488, NULL, NULL },
222     { "VIP",      0x0489, NULL, NULL },
223     { "VTCP",     0x048A, NULL, NULL },
224     { "VCache",   0x048B, NULL, NULL },
225     { "VUDP",     0x048C, NULL, NULL },
226     { "VAsync",   0x048D, NULL, NULL },
227     { "NWREDIR",  0x048E, NULL, NULL },
228     { "STAT80",   0x048F, NULL, NULL },
229     { "SCSIPORT", 0x0490, NULL, NULL },
230     { "FILESEC",  0x0491, NULL, NULL },
231     { "NWSERVER", 0x0492, NULL, NULL },
232     { "SECPROV",  0x0493, NULL, NULL },
233     { "NSCL",     0x0494, NULL, NULL },
234     { "WSTCP",    0x0495, NULL, NULL },
235     { "NDIS2SUP", 0x0496, NULL, NULL },
236     { "MSODISUP", 0x0497, NULL, NULL },
237     { "Splitter", 0x0498, NULL, NULL },
238     { "PPP",      0x0499, NULL, NULL },
239     { "VDHCP",    0x049A, NULL, NULL },
240     { "VNBT",     0x049B, NULL, NULL },
241     { "LOGGER",   0x049D, NULL, NULL },
242     { "EFILTER",  0x049E, NULL, NULL },
243     { "FFILTER",  0x049F, NULL, NULL },
244     { "TFILTER",  0x04A0, NULL, NULL },
245     { "AFILTER",  0x04A1, NULL, NULL },
246     { "IRLAMP",   0x04A2, NULL, NULL },
247
248     { "PCCARD",   0x097C, NULL, DeviceIo_PCCARD },
249     { "HASP95",   0x3721, NULL, DeviceIo_HASP },
250
251     /* WINE additions, ids unknown */
252     { "MONODEBG.VXD", 0x4242, NULL, DeviceIo_MONODEBG },
253
254     { NULL,       0,      NULL, NULL }
255 };
256
257 /*
258  * VMM VxDCall service names are (mostly) taken from Stan Mitchell's
259  * "Inside the Windows 95 File System"
260  */
261
262 #define N_VMM_SERVICE 41
263
264 LPCSTR VMM_Service_Name[N_VMM_SERVICE] =
265 {
266     "PageReserve",            /* 0x0000 */
267     "PageCommit",             /* 0x0001 */
268     "PageDecommit",           /* 0x0002 */
269     "PagerRegister",          /* 0x0003 */
270     "PagerQuery",             /* 0x0004 */
271     "HeapAllocate",           /* 0x0005 */
272     "ContextCreate",          /* 0x0006 */
273     "ContextDestroy",         /* 0x0007 */
274     "PageAttach",             /* 0x0008 */
275     "PageFlush",              /* 0x0009 */
276     "PageFree",               /* 0x000A */
277     "ContextSwitch",          /* 0x000B */
278     "HeapReAllocate",         /* 0x000C */
279     "PageModifyPermissions",  /* 0x000D */
280     "PageQuery",              /* 0x000E */
281     "GetCurrentContext",      /* 0x000F */
282     "HeapFree",               /* 0x0010 */
283     "RegOpenKey",             /* 0x0011 */
284     "RegCreateKey",           /* 0x0012 */
285     "RegCloseKey",            /* 0x0013 */
286     "RegDeleteKey",           /* 0x0014 */
287     "RegSetValue",            /* 0x0015 */
288     "RegDeleteValue",         /* 0x0016 */
289     "RegQueryValue",          /* 0x0017 */
290     "RegEnumKey",             /* 0x0018 */
291     "RegEnumValue",           /* 0x0019 */
292     "RegQueryValueEx",        /* 0x001A */
293     "RegSetValueEx",          /* 0x001B */
294     "RegFlushKey",            /* 0x001C */
295     "RegQueryInfoKey",        /* 0x001D */
296     "GetDemandPageInfo",      /* 0x001E */
297     "BlockOnID",              /* 0x001F */
298     "SignalID",               /* 0x0020 */
299     "RegLoadKey",             /* 0x0021 */
300     "RegUnLoadKey",           /* 0x0022 */
301     "RegSaveKey",             /* 0x0023 */
302     "RegRemapPreDefKey",      /* 0x0024 */
303     "PageChangePager",        /* 0x0025 */
304     "RegQueryMultipleValues", /* 0x0026 */
305     "RegReplaceKey",          /* 0x0027 */
306     "<KERNEL32.101>"          /* 0x0028 -- What does this do??? */
307 };
308
309 /* PageReserve arena values */
310 #define PR_PRIVATE  0x80000400  /* anywhere in private arena */
311 #define PR_SHARED   0x80060000  /* anywhere in shared arena */
312 #define PR_SYSTEM   0x80080000  /* anywhere in system arena */
313
314 /* PageReserve flags */
315 #define PR_FIXED    0x00000008  /* don't move during PageReAllocate */
316 #define PR_4MEG     0x00000001  /* allocate on 4mb boundary */
317 #define PR_STATIC   0x00000010  /* see PageReserve documentation */
318
319 /* PageCommit default pager handle values */
320 #define PD_ZEROINIT 0x00000001  /* swappable zero-initialized pages */
321 #define PD_NOINIT   0x00000002  /* swappable uninitialized pages */
322 #define PD_FIXEDZERO    0x00000003  /* fixed zero-initialized pages */
323 #define PD_FIXED    0x00000004  /* fixed uninitialized pages */
324
325 /* PageCommit flags */
326 #define PC_FIXED    0x00000008  /* pages are permanently locked */
327 #define PC_LOCKED   0x00000080  /* pages are made present and locked */
328 #define PC_LOCKEDIFDP   0x00000100  /* pages are locked if swap via DOS */
329 #define PC_WRITEABLE    0x00020000  /* make the pages writeable */
330 #define PC_USER     0x00040000  /* make the pages ring 3 accessible */
331 #define PC_INCR     0x40000000  /* increment "pagerdata" each page */
332 #define PC_PRESENT  0x80000000  /* make pages initially present */
333 #define PC_STATIC   0x20000000  /* allow commit in PR_STATIC object */
334 #define PC_DIRTY    0x08000000  /* make pages initially dirty */
335 #define PC_CACHEDIS 0x00100000  /* Allocate uncached pages - new for WDM */
336 #define PC_CACHEWT  0x00080000  /* Allocate write through cache pages - new for WDM */
337 #define PC_PAGEFLUSH 0x00008000 /* Touch device mapped pages on alloc - new for WDM */
338
339 /* PageCommitContig additional flags */
340 #define PCC_ZEROINIT    0x00000001  /* zero-initialize new pages */
341 #define PCC_NOLIN   0x10000000  /* don't map to any linear address */
342
343
344
345 HANDLE DEVICE_Open( LPCSTR filename, DWORD access, LPSECURITY_ATTRIBUTES sa )
346 {
347     const struct VxDInfo *info;
348
349     for (info = VxDList; info->name; info++)
350         if (!strncasecmp( info->name, filename, strlen(info->name) ))
351             return FILE_CreateDevice( info->id | 0x10000, access, sa );
352
353     FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
354            filename);
355     SetLastError( ERROR_FILE_NOT_FOUND );
356     return 0;
357 }
358
359 static DWORD DEVICE_GetClientID( HANDLE handle )
360 {
361     DWORD       ret = 0;
362     SERVER_START_REQ( get_file_info )
363     {
364         req->handle = handle;
365         if (!wine_server_call( req ) && (reply->type == FILE_TYPE_UNKNOWN))
366             ret = reply->attr;
367     }
368     SERVER_END_REQ;
369     return ret;
370 }
371
372 static const struct VxDInfo *DEVICE_GetInfo( DWORD clientID )
373 {
374     const struct VxDInfo *info = NULL;
375
376     if (clientID & 0x10000)
377     {
378         for (info = VxDList; info->name; info++)
379             if (info->id == LOWORD(clientID)) break;
380     }
381     return info;
382 }
383
384 /****************************************************************************
385  *              DeviceIoControl (KERNEL32.@)
386  * This is one of those big ugly nasty procedure which can do
387  * a million and one things when it comes to devices. It can also be
388  * used for VxD communication.
389  *
390  * A return value of FALSE indicates that something has gone wrong which
391  * GetLastError can decipher.
392  */
393 BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
394                               LPVOID lpvInBuffer, DWORD cbInBuffer,
395                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
396                               LPDWORD lpcbBytesReturned,
397                               LPOVERLAPPED lpOverlapped)
398 {
399         DWORD clientID;
400
401         TRACE( "(%d,%ld,%p,%ld,%p,%ld,%p,%p)\n",
402                hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
403                lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped  );
404
405         if (!(clientID = DEVICE_GetClientID( hDevice )))
406         {
407                 SetLastError( ERROR_INVALID_PARAMETER );
408                 return FALSE;
409         }
410
411         /* Check if this is a user defined control code for a VxD */
412         if( HIWORD( dwIoControlCode ) == 0 )
413         {
414                 const struct VxDInfo *info;
415                 if (!(info = DEVICE_GetInfo( clientID )))
416                 {
417                         FIXME( "No device found for id %lx\n", clientID);
418                 }
419                 else if ( info->deviceio )
420                 {
421                         return info->deviceio( dwIoControlCode,
422                                         lpvInBuffer, cbInBuffer,
423                                         lpvOutBuffer, cbOutBuffer,
424                                         lpcbBytesReturned, lpOverlapped );
425                 }
426                 else
427                 {
428                         FIXME( "Unimplemented control %ld for VxD device %s\n",
429                                dwIoControlCode, info->name ? info->name : "???" );
430                         /* FIXME: this is for invalid calls on W98SE,
431                          * but maybe we should use ERROR_CALL_NOT_IMPLEMENTED
432                          * instead ? */
433                         SetLastError( ERROR_INVALID_FUNCTION );
434                 }
435         }
436         else
437         {
438                 char str[3];
439
440                 strcpy(str,  "A:");
441                 str[0] += LOBYTE(clientID);
442                 if (GetDriveTypeA(str) == DRIVE_CDROM)
443                     return CDROM_DeviceIoControl(clientID, hDevice, dwIoControlCode, lpvInBuffer, cbInBuffer,
444                                                  lpvOutBuffer, cbOutBuffer, lpcbBytesReturned,
445                                                  lpOverlapped);
446                 else switch( dwIoControlCode )
447                 {
448                 case FSCTL_DELETE_REPARSE_POINT:
449                 case FSCTL_DISMOUNT_VOLUME:
450                 case FSCTL_GET_COMPRESSION:
451                 case FSCTL_GET_REPARSE_POINT:
452                 case FSCTL_LOCK_VOLUME:
453                 case FSCTL_QUERY_ALLOCATED_RANGES:
454                 case FSCTL_SET_COMPRESSION:
455                 case FSCTL_SET_REPARSE_POINT:
456                 case FSCTL_SET_SPARSE:
457                 case FSCTL_SET_ZERO_DATA:
458                 case FSCTL_UNLOCK_VOLUME:
459                 case IOCTL_DISK_CHECK_VERIFY:
460                 case IOCTL_DISK_EJECT_MEDIA:
461                 case IOCTL_DISK_FORMAT_TRACKS:
462                 case IOCTL_DISK_GET_DRIVE_GEOMETRY:
463                 case IOCTL_DISK_GET_DRIVE_LAYOUT:
464                 case IOCTL_DISK_GET_MEDIA_TYPES:
465                 case IOCTL_DISK_GET_PARTITION_INFO:
466                 case IOCTL_DISK_LOAD_MEDIA:
467                 case IOCTL_DISK_MEDIA_REMOVAL:
468                 case IOCTL_DISK_PERFORMANCE:
469                 case IOCTL_DISK_REASSIGN_BLOCKS:
470                 case IOCTL_DISK_SET_DRIVE_LAYOUT:
471                 case IOCTL_DISK_SET_PARTITION_INFO:
472                 case IOCTL_DISK_VERIFY:
473                 case IOCTL_SERIAL_LSRMST_INSERT:
474                 case IOCTL_STORAGE_CHECK_VERIFY:
475                 case IOCTL_STORAGE_EJECT_MEDIA:
476                 case IOCTL_STORAGE_GET_MEDIA_TYPES:
477                 case IOCTL_STORAGE_LOAD_MEDIA:
478                 case IOCTL_STORAGE_MEDIA_REMOVAL:
479                         FIXME( "unimplemented dwIoControlCode=%08lx\n", dwIoControlCode);
480                         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
481                         return FALSE;
482                         break;
483                 default:
484                         FIXME( "ignored dwIoControlCode=%08lx\n",dwIoControlCode);
485                         SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
486                         return FALSE;
487                         break;
488                 }
489         }
490         return FALSE;
491 }
492
493 /***********************************************************************
494  *           DeviceIo_VTDAPI
495  */
496 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
497                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
498                               LPDWORD lpcbBytesReturned,
499                               LPOVERLAPPED lpOverlapped)
500 {
501     BOOL retv = TRUE;
502
503     switch (dwIoControlCode)
504     {
505     case 5:
506         if (lpvOutBuffer && (cbOutBuffer>=4))
507             *(DWORD*)lpvOutBuffer = GetTickCount();
508
509         if (lpcbBytesReturned)
510             *lpcbBytesReturned = 4;
511
512         break;
513
514     default:
515         FIXME( "Control %ld not implemented\n", dwIoControlCode);
516         retv = FALSE;
517         break;
518     }
519
520     return retv;
521 }
522
523 /***********************************************************************
524  *              VxDCall0 (KERNEL32.1)
525  *              VxDCall1 (KERNEL32.2)
526  *              VxDCall2 (KERNEL32.3)
527  *              VxDCall3 (KERNEL32.4)
528  *              VxDCall4 (KERNEL32.5)
529  *              VxDCall5 (KERNEL32.6)
530  *              VxDCall6 (KERNEL32.7)
531  *              VxDCall7 (KERNEL32.8)
532  *              VxDCall8 (KERNEL32.9)
533  */
534 void VxDCall( DWORD service, CONTEXT86 *context )
535 {
536     DWORD ret = 0xffffffff; /* FIXME */
537     int i;
538
539     TRACE( "(%08lx, ...)\n", service);
540
541     for (i = 0; VxDList[i].name; i++)
542         if (VxDList[i].id == HIWORD(service))
543             break;
544
545     if (!VxDList[i].name)
546         FIXME( "Unknown VxD (%08lx)\n", service);
547     else if (!VxDList[i].vxdcall)
548         FIXME( "Unimplemented VxD (%08lx)\n", service);
549     else
550         ret = VxDList[i].vxdcall( service, context );
551
552     context->Eax = ret;
553 }
554
555
556 /***********************************************************************
557  *           VxDCall_VMM
558  */
559 static DWORD VxDCall_VMM( DWORD service, CONTEXT86 *context )
560 {
561     switch ( LOWORD(service) )
562     {
563     case 0x0011:  /* RegOpenKey */
564     {
565         HKEY    hkey       = (HKEY)  stack32_pop( context );
566         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
567         LPHKEY  retkey     = (LPHKEY)stack32_pop( context );
568         return RegOpenKeyA( hkey, lpszSubKey, retkey );
569     }
570
571     case 0x0012:  /* RegCreateKey */
572     {
573         HKEY    hkey       = (HKEY)  stack32_pop( context );
574         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
575         LPHKEY  retkey     = (LPHKEY)stack32_pop( context );
576         return RegCreateKeyA( hkey, lpszSubKey, retkey );
577     }
578
579     case 0x0013:  /* RegCloseKey */
580     {
581         HKEY    hkey       = (HKEY)stack32_pop( context );
582         return RegCloseKey( hkey );
583     }
584
585     case 0x0014:  /* RegDeleteKey */
586     {
587         HKEY    hkey       = (HKEY)  stack32_pop( context );
588         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
589         return RegDeleteKeyA( hkey, lpszSubKey );
590     }
591
592     case 0x0015:  /* RegSetValue */
593     {
594         HKEY    hkey       = (HKEY)  stack32_pop( context );
595         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
596         DWORD   dwType     = (DWORD) stack32_pop( context );
597         LPCSTR  lpszData   = (LPCSTR)stack32_pop( context );
598         DWORD   cbData     = (DWORD) stack32_pop( context );
599         return RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData );
600     }
601
602     case 0x0016:  /* RegDeleteValue */
603     {
604         HKEY    hkey       = (HKEY) stack32_pop( context );
605         LPSTR   lpszValue  = (LPSTR)stack32_pop( context );
606         return RegDeleteValueA( hkey, lpszValue );
607     }
608
609     case 0x0017:  /* RegQueryValue */
610     {
611         HKEY    hkey       = (HKEY)   stack32_pop( context );
612         LPSTR   lpszSubKey = (LPSTR)  stack32_pop( context );
613         LPSTR   lpszData   = (LPSTR)  stack32_pop( context );
614         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
615         return RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData );
616     }
617
618     case 0x0018:  /* RegEnumKey */
619     {
620         HKEY    hkey       = (HKEY) stack32_pop( context );
621         DWORD   iSubkey    = (DWORD)stack32_pop( context );
622         LPSTR   lpszName   = (LPSTR)stack32_pop( context );
623         DWORD   lpcchName  = (DWORD)stack32_pop( context );
624         return RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName );
625     }
626
627     case 0x0019:  /* RegEnumValue */
628     {
629         HKEY    hkey       = (HKEY)   stack32_pop( context );
630         DWORD   iValue     = (DWORD)  stack32_pop( context );
631         LPSTR   lpszValue  = (LPSTR)  stack32_pop( context );
632         LPDWORD lpcchValue = (LPDWORD)stack32_pop( context );
633         LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
634         LPDWORD lpdwType   = (LPDWORD)stack32_pop( context );
635         LPBYTE  lpbData    = (LPBYTE) stack32_pop( context );
636         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
637         return RegEnumValueA( hkey, iValue, lpszValue, lpcchValue,
638                               lpReserved, lpdwType, lpbData, lpcbData );
639     }
640
641     case 0x001A:  /* RegQueryValueEx */
642     {
643         HKEY    hkey       = (HKEY)   stack32_pop( context );
644         LPSTR   lpszValue  = (LPSTR)  stack32_pop( context );
645         LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
646         LPDWORD lpdwType   = (LPDWORD)stack32_pop( context );
647         LPBYTE  lpbData    = (LPBYTE) stack32_pop( context );
648         LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
649         return RegQueryValueExA( hkey, lpszValue, lpReserved,
650                                  lpdwType, lpbData, lpcbData );
651     }
652
653     case 0x001B:  /* RegSetValueEx */
654     {
655         HKEY    hkey       = (HKEY)  stack32_pop( context );
656         LPSTR   lpszValue  = (LPSTR) stack32_pop( context );
657         DWORD   dwReserved = (DWORD) stack32_pop( context );
658         DWORD   dwType     = (DWORD) stack32_pop( context );
659         LPBYTE  lpbData    = (LPBYTE)stack32_pop( context );
660         DWORD   cbData     = (DWORD) stack32_pop( context );
661         return RegSetValueExA( hkey, lpszValue, dwReserved,
662                                dwType, lpbData, cbData );
663     }
664
665     case 0x001C:  /* RegFlushKey */
666     {
667         HKEY    hkey       = (HKEY)stack32_pop( context );
668         return RegFlushKey( hkey );
669     }
670
671     case 0x001D:  /* RegQueryInfoKey */
672     {
673         /* NOTE: This VxDCall takes only a subset of the parameters that the
674                  corresponding Win32 API call does. The implementation in Win95
675                  ADVAPI32 sets all output parameters not mentioned here to zero. */
676
677         HKEY    hkey              = (HKEY)   stack32_pop( context );
678         LPDWORD lpcSubKeys        = (LPDWORD)stack32_pop( context );
679         LPDWORD lpcchMaxSubKey    = (LPDWORD)stack32_pop( context );
680         LPDWORD lpcValues         = (LPDWORD)stack32_pop( context );
681         LPDWORD lpcchMaxValueName = (LPDWORD)stack32_pop( context );
682         LPDWORD lpcchMaxValueData = (LPDWORD)stack32_pop( context );
683         return RegQueryInfoKeyA( hkey, NULL, NULL, NULL, lpcSubKeys, lpcchMaxSubKey,
684                                  NULL, lpcValues, lpcchMaxValueName, lpcchMaxValueData,
685                                  NULL, NULL );
686     }
687
688     case 0x0021:  /* RegLoadKey */
689     {
690         HKEY    hkey       = (HKEY)  stack32_pop( context );
691         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
692         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
693         return RegLoadKeyA( hkey, lpszSubKey, lpszFile );
694     }
695
696     case 0x0022:  /* RegUnLoadKey */
697     {
698         HKEY    hkey       = (HKEY)  stack32_pop( context );
699         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
700         return RegUnLoadKeyA( hkey, lpszSubKey );
701     }
702
703     case 0x0023:  /* RegSaveKey */
704     {
705         HKEY    hkey       = (HKEY)  stack32_pop( context );
706         LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
707         LPSECURITY_ATTRIBUTES sa = (LPSECURITY_ATTRIBUTES)stack32_pop( context );
708         return RegSaveKeyA( hkey, lpszFile, sa );
709     }
710
711 #if 0 /* Functions are not yet implemented in misc/registry.c */
712     case 0x0024:  /* RegRemapPreDefKey */
713     case 0x0026:  /* RegQueryMultipleValues */
714 #endif
715
716     case 0x0027:  /* RegReplaceKey */
717     {
718         HKEY    hkey       = (HKEY)  stack32_pop( context );
719         LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
720         LPCSTR  lpszNewFile= (LPCSTR)stack32_pop( context );
721         LPCSTR  lpszOldFile= (LPCSTR)stack32_pop( context );
722         return RegReplaceKeyA( hkey, lpszSubKey, lpszNewFile, lpszOldFile );
723     }
724     case 0x0000: /* PageReserve */
725       {
726         LPVOID address;
727         LPVOID ret;
728         DWORD psize = getpagesize();
729         ULONG page   = (ULONG) stack32_pop( context );
730         ULONG npages = (ULONG) stack32_pop( context );
731         ULONG flags  = (ULONG) stack32_pop( context );
732
733         TRACE("PageReserve: page: %08lx, npages: %08lx, flags: %08lx partial stub!\n",
734               page, npages, flags );
735
736         if ( page == PR_SYSTEM ) {
737           ERR("Can't reserve ring 1 memory\n");
738           return -1;
739         }
740         /* FIXME: This has to be handled separately for the separate
741            address-spaces we now have */
742         if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0;
743         /* FIXME: Handle flags in some way */
744         address = (LPVOID )(page * psize);
745         ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 );
746         TRACE("PageReserve: returning: %08lx\n", (DWORD )ret );
747         if ( ret == NULL )
748           return -1;
749         else
750           return (DWORD )ret;
751       }
752
753     case 0x0001: /* PageCommit */
754       {
755         LPVOID address;
756         LPVOID ret;
757         DWORD virt_perm;
758         DWORD psize = getpagesize();
759         ULONG page   = (ULONG) stack32_pop( context );
760         ULONG npages = (ULONG) stack32_pop( context );
761         ULONG hpd  = (ULONG) stack32_pop( context );
762         ULONG pagerdata   = (ULONG) stack32_pop( context );
763         ULONG flags  = (ULONG) stack32_pop( context );
764
765         TRACE("PageCommit: page: %08lx, npages: %08lx, hpd: %08lx pagerdata: "
766               "%08lx, flags: %08lx partial stub\n",
767               page, npages, hpd, pagerdata, flags );
768
769         if ( flags & PC_USER )
770           if ( flags & PC_WRITEABLE )
771             virt_perm = PAGE_EXECUTE_READWRITE;
772           else
773             virt_perm = PAGE_EXECUTE_READ;
774         else
775           virt_perm = PAGE_NOACCESS;
776
777         address = (LPVOID )(page * psize);
778         ret = VirtualAlloc ( address, ( npages * psize ), MEM_COMMIT, virt_perm );
779         TRACE("PageCommit: Returning: %08lx\n", (DWORD )ret );
780         return (DWORD )ret;
781
782       }
783     case 0x0002: /* PageDecommit */
784       {
785         LPVOID address;
786         BOOL ret;
787         DWORD psize = getpagesize();
788         ULONG page = (ULONG) stack32_pop( context );
789         ULONG npages = (ULONG) stack32_pop( context );
790         ULONG flags = (ULONG) stack32_pop( context );
791
792         TRACE("PageDecommit: page: %08lx, npages: %08lx, flags: %08lx partial stub\n",
793               page, npages, flags );
794         address = (LPVOID )( page * psize );
795         ret = VirtualFree ( address, ( npages * psize ), MEM_DECOMMIT );
796         TRACE("PageDecommit: Returning: %s\n", ret ? "TRUE" : "FALSE" );
797         return ret;
798       }
799     case 0x000d: /* PageModifyPermissions */
800       {
801         DWORD pg_old_perm;
802         DWORD pg_new_perm;
803         DWORD virt_old_perm;
804         DWORD virt_new_perm;
805         MEMORY_BASIC_INFORMATION mbi;
806         LPVOID address;
807         DWORD psize = getpagesize();
808         ULONG page = stack32_pop ( context );
809         ULONG npages = stack32_pop ( context );
810         ULONG permand = stack32_pop ( context );
811         ULONG permor = stack32_pop ( context );
812
813         TRACE("PageModifyPermissions %08lx %08lx %08lx %08lx partial stub\n",
814               page, npages, permand, permor );
815         address = (LPVOID )( page * psize );
816
817         VirtualQuery ( address, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ));
818         virt_old_perm = mbi.Protect;
819
820         switch ( virt_old_perm & mbi.Protect ) {
821         case PAGE_READONLY:
822         case PAGE_EXECUTE:
823         case PAGE_EXECUTE_READ:
824           pg_old_perm = PC_USER;
825           break;
826         case PAGE_READWRITE:
827         case PAGE_WRITECOPY:
828         case PAGE_EXECUTE_READWRITE:
829         case PAGE_EXECUTE_WRITECOPY:
830           pg_old_perm = PC_USER | PC_WRITEABLE;
831           break;
832         case PAGE_NOACCESS:
833         default:
834           pg_old_perm = 0;
835           break;
836         }
837         pg_new_perm = pg_old_perm;
838         pg_new_perm &= permand & ~PC_STATIC;
839         pg_new_perm |= permor  & ~PC_STATIC;
840
841         virt_new_perm = ( virt_old_perm )  & ~0xff;
842         if ( pg_new_perm & PC_USER )
843         {
844           if ( pg_new_perm & PC_WRITEABLE )
845             virt_new_perm |= PAGE_EXECUTE_READWRITE;
846           else
847             virt_new_perm |= PAGE_EXECUTE_READ;
848         }
849
850         if ( ! VirtualProtect ( address, ( npages * psize ), virt_new_perm, &virt_old_perm ) ) {
851           ERR("Can't change page permissions for %08lx\n", (DWORD )address );
852           return 0xffffffff;
853         }
854         TRACE("Returning: %08lx\n", pg_old_perm );
855         return pg_old_perm;
856       }
857     case 0x000a: /* PageFree */
858       {
859         BOOL ret;
860         LPVOID hmem = (LPVOID) stack32_pop( context );
861         DWORD flags = (DWORD ) stack32_pop( context );
862
863         TRACE("PageFree: hmem: %08lx, flags: %08lx partial stub\n",
864               (DWORD )hmem, flags );
865
866         ret = VirtualFree ( hmem, 0, MEM_RELEASE );
867         context->Eax = ret;
868         TRACE("Returning: %d\n", ret );
869
870         return 0;
871       }
872     case 0x001e: /* GetDemandPageInfo */
873       {
874          DWORD dinfo = (DWORD)stack32_pop( context );
875          DWORD flags = (DWORD)stack32_pop( context );
876
877          /* GetDemandPageInfo is supposed to fill out the struct at
878           * "dinfo" with various low-level memory management information.
879           * Apps are certainly not supposed to call this, although it's
880           * demoed and documented by Pietrek on pages 441-443 of "Windows
881           * 95 System Programming Secrets" if any program needs a real
882           * implementation of this.
883           */
884
885          FIXME("GetDemandPageInfo(%08lx %08lx): stub!\n", dinfo, flags);
886
887          return 0;
888       }
889     default:
890         if (LOWORD(service) < N_VMM_SERVICE)
891             FIXME( "Unimplemented service %s (%08lx)\n",
892                           VMM_Service_Name[LOWORD(service)], service);
893         else
894             FIXME( "Unknown service %08lx\n", service);
895         break;
896     }
897
898     return 0xffffffff;  /* FIXME */
899 }
900
901 /***********************************************************************
902  *           DeviceIo_IFSMgr
903  * NOTES
904  *   These ioctls are used by 'MSNET32.DLL'.
905  *
906  *   I have been unable to uncover any documentation about the ioctls so
907  *   the implementation of the cases IFS_IOCTL_21 and IFS_IOCTL_2F are
908  *   based on reasonable guesses on information found in the Windows 95 DDK.
909  *
910  */
911
912 /*
913  * IFSMgr DeviceIO service
914  */
915
916 #define IFS_IOCTL_21                100
917 #define IFS_IOCTL_2F                101
918 #define IFS_IOCTL_GET_RES           102
919 #define IFS_IOCTL_GET_NETPRO_NAME_A 103
920
921 struct win32apireq {
922         unsigned long   ar_proid;
923         unsigned long   ar_eax;
924         unsigned long   ar_ebx;
925         unsigned long   ar_ecx;
926         unsigned long   ar_edx;
927         unsigned long   ar_esi;
928         unsigned long   ar_edi;
929         unsigned long   ar_ebp;
930         unsigned short  ar_error;
931         unsigned short  ar_pad;
932 };
933
934 static void win32apieq_2_CONTEXT(struct win32apireq *pIn,CONTEXT86 *pCxt)
935 {
936         memset(pCxt,0,sizeof(*pCxt));
937
938         pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
939         pCxt->Eax = pIn->ar_eax;
940         pCxt->Ebx = pIn->ar_ebx;
941         pCxt->Ecx = pIn->ar_ecx;
942         pCxt->Edx = pIn->ar_edx;
943         pCxt->Esi = pIn->ar_esi;
944         pCxt->Edi = pIn->ar_edi;
945
946         /* FIXME: Only partial CONTEXT86_CONTROL */
947         pCxt->Ebp = pIn->ar_ebp;
948
949         /* FIXME: pIn->ar_proid ignored */
950         /* FIXME: pIn->ar_error ignored */
951         /* FIXME: pIn->ar_pad ignored */
952 }
953
954 static void CONTEXT_2_win32apieq(CONTEXT86 *pCxt,struct win32apireq *pOut)
955 {
956         memset(pOut,0,sizeof(struct win32apireq));
957
958         pOut->ar_eax = pCxt->Eax;
959         pOut->ar_ebx = pCxt->Ebx;
960         pOut->ar_ecx = pCxt->Ecx;
961         pOut->ar_edx = pCxt->Edx;
962         pOut->ar_esi = pCxt->Esi;
963         pOut->ar_edi = pCxt->Edi;
964
965         /* FIXME: Only partial CONTEXT86_CONTROL */
966         pOut->ar_ebp = pCxt->Ebp;
967
968         /* FIXME: pOut->ar_proid ignored */
969         /* FIXME: pOut->ar_error ignored */
970         /* FIXME: pOut->ar_pad ignored */
971 }
972
973 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
974                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
975                               LPDWORD lpcbBytesReturned,
976                               LPOVERLAPPED lpOverlapped)
977 {
978     BOOL retv = TRUE;
979         TRACE("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
980                         dwIoControlCode,
981                         lpvInBuffer,cbInBuffer,
982                         lpvOutBuffer,cbOutBuffer,
983                         lpcbBytesReturned,
984                         lpOverlapped);
985
986     switch (dwIoControlCode)
987     {
988         case IFS_IOCTL_21:
989         case IFS_IOCTL_2F:{
990                 CONTEXT86 cxt;
991                 struct win32apireq *pIn=(struct win32apireq *) lpvInBuffer;
992                 struct win32apireq *pOut=(struct win32apireq *) lpvOutBuffer;
993
994                 TRACE(
995                         "Control '%s': "
996                         "proid=0x%08lx, eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
997                         "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx, ebp=0x%08lx, "
998                         "error=0x%04x, pad=0x%04x\n",
999                         (dwIoControlCode==IFS_IOCTL_21)?"IFS_IOCTL_21":"IFS_IOCTL_2F",
1000                         pIn->ar_proid, pIn->ar_eax, pIn->ar_ebx, pIn->ar_ecx,
1001                         pIn->ar_edx, pIn->ar_esi, pIn->ar_edi, pIn->ar_ebp,
1002                         pIn->ar_error, pIn->ar_pad
1003                 );
1004
1005                 win32apieq_2_CONTEXT(pIn,&cxt);
1006
1007                 if(dwIoControlCode==IFS_IOCTL_21)
1008                 {
1009                         DOS3Call(&cxt); /* Call int 21h */
1010                 } else {
1011                         INT_Int2fHandler(&cxt); /* Call int 2Fh */
1012                 }
1013
1014                 CONTEXT_2_win32apieq(&cxt,pOut);
1015
1016         retv = TRUE;
1017         } break;
1018         case IFS_IOCTL_GET_RES:{
1019         FIXME( "Control 'IFS_IOCTL_GET_RES' not implemented\n");
1020         retv = FALSE;
1021         } break;
1022         case IFS_IOCTL_GET_NETPRO_NAME_A:{
1023         FIXME( "Control 'IFS_IOCTL_GET_NETPRO_NAME_A' not implemented\n");
1024         retv = FALSE;
1025         } break;
1026     default:
1027         FIXME( "Control %ld not implemented\n", dwIoControlCode);
1028         retv = FALSE;
1029     }
1030
1031     return retv;
1032 }
1033
1034 /********************************************************************************
1035  *      VxDCall_VWin32
1036  *
1037  *  Service numbers taken from page 448 of Pietrek's "Windows 95 System
1038  *  Programming Secrets".  Parameters from experimentation on real Win98.
1039  *
1040  */
1041
1042 static DWORD VxDCall_VWin32( DWORD service, CONTEXT86 *context )
1043 {
1044   switch ( LOWORD(service) )
1045     {
1046     case 0x0000: /* GetVersion */
1047     {
1048         DWORD vers = GetVersion();
1049         return (LOBYTE(vers) << 8) | HIBYTE(vers);
1050     }
1051     break;
1052
1053     case 0x0020: /* Get VMCPD Version */
1054     {
1055         DWORD parm = (DWORD) stack32_pop(context);
1056
1057         FIXME("Get VMCPD Version(%08lx): partial stub!\n", parm);
1058
1059         /* FIXME: This is what Win98 returns, it may
1060          *        not be correct in all situations.
1061          *        It makes Bleem! happy though.
1062          */
1063
1064         return 0x0405;
1065     }
1066
1067     case 0x0029: /* Int31/DPMI dispatch */
1068     {
1069         DWORD callnum = (DWORD) stack32_pop(context);
1070         DWORD parm    = (DWORD) stack32_pop(context);
1071
1072         TRACE("Int31/DPMI dispatch(%08lx)\n", callnum);
1073
1074         AX_reg(context) = callnum;
1075         CX_reg(context) = parm;
1076         INT_Int31Handler(context);
1077
1078         return LOWORD(context->Eax);
1079     }
1080     break;
1081
1082     case 0x002a: /* Int41 dispatch - parm = int41 service number */
1083     {
1084         DWORD callnum = (DWORD) stack32_pop(context);
1085
1086         return callnum; /* FIXME: should really call INT_Int41Handler() */
1087     }
1088     break;
1089
1090     default:
1091       FIXME("Unknown VWin32 service %08lx\n", service);
1092       break;
1093     }
1094
1095   return 0xffffffff;
1096 }
1097
1098
1099 /***********************************************************************
1100  *           DeviceIo_VCD
1101  */
1102 static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
1103                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1104                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1105                               LPDWORD lpcbBytesReturned,
1106                               LPOVERLAPPED lpOverlapped)
1107 {
1108     BOOL retv = TRUE;
1109
1110     switch (dwIoControlCode)
1111     {
1112     case IOCTL_SERIAL_LSRMST_INSERT:
1113     {
1114         FIXME( "IOCTL_SERIAL_LSRMST_INSERT NIY !\n");
1115         retv = FALSE;
1116     }
1117     break;
1118
1119     default:
1120         FIXME( "Unknown Control %ld\n", dwIoControlCode);
1121         retv = FALSE;
1122         break;
1123     }
1124
1125     return retv;
1126 }
1127
1128
1129 /***********************************************************************
1130  *           DeviceIo_VWin32
1131  */
1132
1133 static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
1134 {
1135     memset( pCxt, 0, sizeof(*pCxt) );
1136     /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN
1137              will interpret 32-bit register contents as linear pointers */
1138
1139     pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
1140     pCxt->Eax = pIn->reg_EAX;
1141     pCxt->Ebx = pIn->reg_EBX;
1142     pCxt->Ecx = pIn->reg_ECX;
1143     pCxt->Edx = pIn->reg_EDX;
1144     pCxt->Esi = pIn->reg_ESI;
1145     pCxt->Edi = pIn->reg_EDI;
1146
1147     /* FIXME: Only partial CONTEXT86_CONTROL */
1148     pCxt->EFlags = pIn->reg_Flags;
1149 }
1150
1151 static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut )
1152 {
1153     memset( pOut, 0, sizeof(DIOC_REGISTERS) );
1154
1155     pOut->reg_EAX = pCxt->Eax;
1156     pOut->reg_EBX = pCxt->Ebx;
1157     pOut->reg_ECX = pCxt->Ecx;
1158     pOut->reg_EDX = pCxt->Edx;
1159     pOut->reg_ESI = pCxt->Esi;
1160     pOut->reg_EDI = pCxt->Edi;
1161
1162     /* FIXME: Only partial CONTEXT86_CONTROL */
1163     pOut->reg_Flags = pCxt->EFlags;
1164 }
1165
1166 #define DIOC_AH(regs) (((unsigned char*)&((regs)->reg_EAX))[1])
1167 #define DIOC_AL(regs) (((unsigned char*)&((regs)->reg_EAX))[0])
1168 #define DIOC_BH(regs) (((unsigned char*)&((regs)->reg_EBX))[1])
1169 #define DIOC_BL(regs) (((unsigned char*)&((regs)->reg_EBX))[0])
1170 #define DIOC_DH(regs) (((unsigned char*)&((regs)->reg_EDX))[1])
1171 #define DIOC_DL(regs) (((unsigned char*)&((regs)->reg_EDX))[0])
1172
1173 #define DIOC_AX(regs) (((unsigned short*)&((regs)->reg_EAX))[0])
1174 #define DIOC_BX(regs) (((unsigned short*)&((regs)->reg_EBX))[0])
1175 #define DIOC_CX(regs) (((unsigned short*)&((regs)->reg_ECX))[0])
1176 #define DIOC_DX(regs) (((unsigned short*)&((regs)->reg_EDX))[0])
1177
1178 #define DIOC_SET_CARRY(regs) (((regs)->reg_Flags)|=0x00000001)
1179
1180 static const DWORD VWIN32_DriveTypeInfo[7]={
1181     0x0000, /* none */
1182     0x2709, /* 360 K */
1183     0x4f0f, /* 1.2 M */
1184     0x4f09, /* 720 K */
1185     0x4f12, /* 1.44 M */
1186     0x4f24, /* 2.88 M */
1187     0x4f24  /* 2.88 M */
1188 };
1189
1190 /**********************************************************************
1191  *          VWIN32_ReadFloppyParams
1192  *
1193  * Handler for int 13h (disk I/O).
1194  */
1195 static VOID VWIN32_ReadFloppyParams(DIOC_REGISTERS *regs)
1196 {
1197 #ifdef linux
1198     static BYTE floppy_params[2][13] =
1199     {
1200         { 0xaf, 0x02, 0x25, 0x02, 0x12, 0x1b, 0xff, 0x6c, 0xf6, 0x0f, 0x08 },
1201         { 0xaf, 0x02, 0x25, 0x02, 0x12, 0x1b, 0xff, 0x6c, 0xf6, 0x0f, 0x08 }
1202     };
1203
1204     unsigned int i, nr_of_drives = 0;
1205     BYTE drive_nr = DIOC_DL(regs);
1206     int floppy_fd,r;
1207     struct floppy_drive_params floppy_parm;
1208     char root[] = "A:\\";
1209
1210     TRACE("in  [ EDX=%08lx ]\n", regs->reg_EDX );
1211
1212     DIOC_AH(regs) = 0x00; /* success */
1213
1214     for (i = 0; i < MAX_DOS_DRIVES; i++, root[0]++)
1215         if (GetDriveTypeA(root) == DRIVE_REMOVABLE) nr_of_drives++;
1216     DIOC_DL(regs) = nr_of_drives;
1217
1218     if (drive_nr > 1) { /* invalid drive ? */
1219         DIOC_BX(regs) = 0;
1220         DIOC_CX(regs) = 0;
1221         DIOC_DH(regs) = 0;
1222         DIOC_SET_CARRY(regs);
1223         return;
1224     }
1225
1226     if ( (floppy_fd = DRIVE_OpenDevice( drive_nr, O_NONBLOCK)) == -1)
1227     {
1228         WARN("Can't determine floppy geometry !\n");
1229         DIOC_BX(regs) = 0;
1230         DIOC_CX(regs) = 0;
1231         DIOC_DH(regs) = 0;
1232         DIOC_SET_CARRY(regs);
1233         return;
1234     }
1235     r = ioctl(floppy_fd, FDGETDRVPRM, &floppy_parm);
1236
1237     close(floppy_fd);
1238
1239     if(r<0)
1240     {
1241         DIOC_SET_CARRY(regs);
1242         return;
1243     }
1244
1245     regs->reg_ECX = 0;
1246     DIOC_AL(regs) = 0;
1247     DIOC_BL(regs) = floppy_parm.cmos;
1248
1249     /* CH = low eight bits of max cyl
1250        CL = max sec nr (bits 5-0),
1251        hi two bits of max cyl (bits 7-6)
1252        DH = max head nr */
1253     if(DIOC_BL(regs) && (DIOC_BL(regs)<7))
1254     {
1255         DIOC_DH(regs) = 0x01;
1256         DIOC_CX(regs) = VWIN32_DriveTypeInfo[DIOC_BL(regs)];
1257     }
1258     else
1259     {
1260         DIOC_CX(regs) = 0x0;
1261         DIOC_DX(regs) = 0x0;
1262     }
1263
1264     regs->reg_EDI = (DWORD)floppy_params[drive_nr];
1265
1266     if(!regs->reg_EDI)
1267     {
1268         ERR("Get floppy params failed for drive %d\n",drive_nr);
1269         DIOC_SET_CARRY(regs);
1270     }
1271
1272     TRACE("out [ EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx EDI=%08lx ]\n",
1273           regs->reg_EAX, regs->reg_EBX, regs->reg_ECX, regs->reg_EDX, regs->reg_EDI);
1274
1275     /* FIXME: Word exits quietly if we return with no error. Why? */
1276     FIXME("Returned ERROR!\n");
1277     DIOC_SET_CARRY(regs);
1278
1279 #else
1280     DIOC_AH(regs) = 0x01;
1281     DIOC_SET_CARRY(regs);
1282 #endif
1283 }
1284
1285 /**********************************************************************
1286  *          VWIN32_Int13Handler
1287  *
1288  * Handler for VWIN32_DIOC_DOS_INT13 (disk I/O).
1289  */
1290 static VOID VWIN32_Int13Handler( DIOC_REGISTERS *regs)
1291 {
1292     TRACE("AH=%02x\n",DIOC_AH(regs));
1293     switch(DIOC_AH(regs)) /* AH */
1294     {
1295     case 0x00:             /* RESET DISK SYSTEM     */
1296         break; /* no return ? */
1297
1298     case 0x01:             /* STATUS OF DISK SYSTEM */
1299         DIOC_AL(regs) = 0; /* successful completion */
1300         break;
1301
1302     case 0x02:             /* READ SECTORS INTO MEMORY */
1303         DIOC_AL(regs) = 0; /* number of sectors read */
1304         DIOC_AH(regs) = 0; /* status */
1305         break;
1306
1307     case 0x03:             /* WRITE SECTORS FROM MEMORY */
1308         break; /* no return ? */
1309
1310     case 0x04:             /* VERIFY DISK SECTOR(S) */
1311         DIOC_AL(regs) = 0; /* number of sectors verified */
1312         DIOC_AH(regs) = 0;
1313         break;
1314
1315     case 0x05:             /* FORMAT TRACK */
1316     case 0x06:             /* FORMAT TRACK AND SET BAD SECTOR FLAGS */
1317     case 0x07:             /* FORMAT DRIVE STARTING AT GIVEN TRACK  */
1318         /* despite what Ralf Brown says, 0x06 and 0x07 seem to
1319          * set CFLAG, too (at least my BIOS does that) */
1320         DIOC_AH(regs) = 0x0c;
1321         DIOC_SET_CARRY(regs);
1322         break;
1323
1324     case 0x08:             /* GET DRIVE PARAMETERS  */
1325         if (DIOC_DL(regs) & 0x80) { /* hard disk ? */
1326             DIOC_AH(regs) = 0x07;
1327             DIOC_SET_CARRY(regs);
1328         }
1329         else  /* floppy disk */
1330             VWIN32_ReadFloppyParams(regs);
1331         break;
1332
1333     case 0x09:         /* INITIALIZE CONTROLLER WITH DRIVE PARAMETERS */
1334     case 0x0a:         /* FIXED DISK - READ LONG (XT,AT,XT286,PS)     */
1335     case 0x0b:         /* FIXED DISK - WRITE LONG (XT,AT,XT286,PS)    */
1336     case 0x0c:         /* SEEK TO CYLINDER                            */
1337     case 0x0d:         /* ALTERNATE RESET HARD DISKS                  */
1338     case 0x10:         /* CHECK IF DRIVE READY                        */
1339     case 0x11:         /* RECALIBRATE DRIVE                           */
1340     case 0x14:         /* CONTROLLER INTERNAL DIAGNOSTIC              */
1341         DIOC_AH(regs) = 0;
1342         break;
1343
1344     case 0x15:         /* GET DISK TYPE (AT,XT2,XT286,CONV,PS) */
1345         if (DIOC_DL(regs) & 0x80) { /* hard disk ? */
1346             DIOC_AH(regs) = 3; /* fixed disk */
1347             DIOC_SET_CARRY(regs);
1348         }
1349         else { /* floppy disk ? */
1350             DIOC_AH(regs) = 2; /* floppy with change detection */
1351             DIOC_SET_CARRY(regs);
1352         }
1353         break;
1354
1355     case 0x0e:         /* READ SECTOR BUFFER (XT only)      */
1356     case 0x0f:         /* WRITE SECTOR BUFFER (XT only)     */
1357     case 0x12:         /* CONTROLLER RAM DIAGNOSTIC (XT,PS) */
1358     case 0x13:         /* DRIVE DIAGNOSTIC (XT,PS)          */
1359         DIOC_AH(regs) = 0x01;
1360         DIOC_SET_CARRY(regs);
1361         break;
1362
1363     case 0x16:         /* FLOPPY - CHANGE OF DISK STATUS */
1364         DIOC_AH(regs) = 0; /* FIXME - no change */
1365         break;
1366
1367     case 0x17:         /* SET DISK TYPE FOR FORMAT */
1368         if (DIOC_DL(regs) < 4)
1369             DIOC_AH(regs) = 0x00; /* successful completion */
1370         else
1371             DIOC_AH(regs) = 0x01; /* error */
1372         break;
1373
1374     case 0x18:         /* SET MEDIA TYPE FOR FORMAT */
1375         if (DIOC_DL(regs) < 4)
1376             DIOC_AH(regs) = 0x00; /* successful completion */
1377         else
1378             DIOC_AH(regs) = 0x01; /* error */
1379         break;
1380
1381     case 0x19:       /* FIXED DISK - PARK HEADS */
1382         break;
1383
1384     default:
1385         FIXME("Unknown VWIN32 INT13 call AX=%04X\n",DIOC_AX(regs));
1386     }
1387 }
1388
1389 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
1390                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1391                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1392                               LPDWORD lpcbBytesReturned,
1393                               LPOVERLAPPED lpOverlapped)
1394 {
1395     BOOL retv = TRUE;
1396
1397     switch (dwIoControlCode)
1398     {
1399     case VWIN32_DIOC_DOS_INT13:
1400     {
1401         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
1402         DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;
1403
1404         memcpy(pOut, pIn, sizeof (DIOC_REGISTERS));
1405         VWIN32_Int13Handler(pOut);
1406         break;
1407     }
1408
1409     case VWIN32_DIOC_DOS_IOCTL:
1410     case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
1411     case VWIN32_DIOC_DOS_INT25:
1412     case VWIN32_DIOC_DOS_INT26:
1413     case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
1414     case VWIN32_DIOC_DOS_DRIVEINFO:
1415     {
1416         CONTEXT86 cxt;
1417         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
1418         DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;
1419
1420         TRACE( "Control '%s': "
1421                "eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
1422                "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx \n",
1423                (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" :
1424                (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" :
1425                (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" :
1426                (dwIoControlCode == VWIN32_DIOC_DOS_DRIVEINFO)? "VWIN32_DIOC_DOS_DRIVEINFO" :  "???",
1427                pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX,
1428                pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI );
1429
1430         DIOCRegs_2_CONTEXT( pIn, &cxt );
1431
1432         switch (dwIoControlCode)
1433         {
1434         case VWIN32_DIOC_DOS_IOCTL: DOS3Call( &cxt ); break; /* Call int 21h */
1435         case VWIN32_DIOC_DOS_INT13: INT_Int13Handler( &cxt ); break;
1436         case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
1437                                     DOS3Call( &cxt ); break;
1438         case VWIN32_DIOC_DOS_INT25: INT_Int25Handler( &cxt ); break;
1439         case VWIN32_DIOC_DOS_INT26: INT_Int26Handler( &cxt ); break;
1440         case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
1441                                     INT_Int31Handler( &cxt ); break;
1442         case VWIN32_DIOC_DOS_DRIVEINFO: DOS3Call( &cxt ); break; /* Call int 21h 730x */
1443         }
1444
1445         CONTEXT_2_DIOCRegs( &cxt, pOut );
1446     }
1447     break;
1448
1449     case VWIN32_DIOC_SIMCTRLC:
1450         FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n");
1451         retv = FALSE;
1452         break;
1453
1454     default:
1455         FIXME( "Unknown Control %ld\n", dwIoControlCode);
1456         retv = FALSE;
1457         break;
1458     }
1459
1460     return retv;
1461 }
1462
1463 /* this is the main multimedia device loader */
1464 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
1465                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1466                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1467                               LPDWORD lpcbBytesReturned,
1468                               LPOVERLAPPED lpOverlapped)
1469 {
1470         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1471             dwIoControlCode,
1472             lpvInBuffer,cbInBuffer,
1473             lpvOutBuffer,cbOutBuffer,
1474             lpcbBytesReturned,
1475             lpOverlapped
1476         );
1477         switch (dwIoControlCode) {
1478         case 5:
1479                 /* Hmm. */
1480                 *(DWORD*)lpvOutBuffer=0;
1481                 *lpcbBytesReturned=4;
1482                 return TRUE;
1483         }
1484         return FALSE;
1485 }
1486 /* this is used by some Origin games */
1487 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
1488                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1489                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1490                               LPDWORD lpcbBytesReturned,
1491                               LPOVERLAPPED lpOverlapped)
1492 {
1493         switch (dwIoControlCode) {
1494         case 1: /* version */
1495                 *(LPDWORD)lpvOutBuffer = 0x20004; /* WC SecretOps */
1496                 break;
1497         case 9: /* debug output */
1498                 ERR("MONODEBG: %s\n",debugstr_a(lpvInBuffer));
1499                 break;
1500         default:
1501                 FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1502                         dwIoControlCode,
1503                         lpvInBuffer,cbInBuffer,
1504                         lpvOutBuffer,cbOutBuffer,
1505                         lpcbBytesReturned,
1506                         lpOverlapped
1507                 );
1508                 break;
1509         }
1510         return TRUE;
1511 }
1512 /* pccard */
1513 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
1514                               LPVOID lpvInBuffer, DWORD cbInBuffer,
1515                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1516                               LPDWORD lpcbBytesReturned,
1517                               LPOVERLAPPED lpOverlapped)
1518 {
1519         switch (dwIoControlCode) {
1520         case 0x0000: /* PCCARD_Get_Version */
1521         case 0x0001: /* PCCARD_Card_Services */
1522         default:
1523                 FIXME( "(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1524                         dwIoControlCode,
1525                         lpvInBuffer,cbInBuffer,
1526                         lpvOutBuffer,cbOutBuffer,
1527                         lpcbBytesReturned,
1528                         lpOverlapped
1529                 );
1530                 break;
1531         }
1532         return FALSE;
1533 }
1534
1535 /***********************************************************************
1536  *              OpenVxDHandle (KERNEL32.@)
1537  *
1538  *      This function is supposed to return the corresponding Ring 0
1539  *      ("kernel") handle for a Ring 3 handle in Win9x.
1540  *      Evidently, Wine will have problems with this. But we try anyway,
1541  *      maybe it helps...
1542  */
1543 HANDLE  WINAPI  OpenVxDHandle(HANDLE hHandleRing3)
1544 {
1545         FIXME( "(0x%08x), stub! (returning Ring 3 handle instead of Ring 0)\n", hHandleRing3);
1546         return hHandleRing3;
1547 }
1548
1549 static BOOL DeviceIo_HASP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
1550                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
1551                               LPDWORD lpcbBytesReturned,
1552                               LPOVERLAPPED lpOverlapped)
1553 {
1554     BOOL retv = TRUE;
1555         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1556                         dwIoControlCode,
1557                         lpvInBuffer,cbInBuffer,
1558                         lpvOutBuffer,cbOutBuffer,
1559                         lpcbBytesReturned,
1560                         lpOverlapped);
1561
1562     return retv;
1563 }
1564