device.c 67.8 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * Win32 device functions
 *
 * Copyright 1998 Marcus Meissner
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 * Copyright 1998 Ulrich Weigand
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 * Copyright 1998 Patrik Stridvall
Alexandre Julliard's avatar
Alexandre Julliard committed
7
 *
8 9 10 11 12 13 14 15 16 17 18 19 20
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Alexandre Julliard's avatar
Alexandre Julliard committed
21 22
 */

23
#include "config.h"
24
#include "wine/port.h"
25

Alexandre Julliard's avatar
Alexandre Julliard committed
26
#include <stdlib.h>
27 28 29
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
Alexandre Julliard's avatar
Alexandre Julliard committed
30 31
#include <sys/types.h>
#include <string.h>
32
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
33
#include <time.h>
34

35
#include "windef.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
36
#include "winbase.h"
37
#include "winreg.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
38 39
#include "winerror.h"
#include "file.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
40
#include "winioctl.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
41 42 43
#include "winnt.h"
#include "msdos.h"
#include "miscemu.h"
44
#include "stackframe.h"
45
#include "wine/server.h"
46
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
47

48
/* int 13 stuff */
49 50 51
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
52 53 54 55 56 57 58
#include <fcntl.h>
#ifdef linux
# include <linux/fd.h>
#endif
#include "drive.h"

WINE_DEFAULT_DEBUG_CHANNEL(file);
59

60

61
static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode,
Alexandre Julliard's avatar
Alexandre Julliard committed
62 63 64 65
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped);
66
static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
67 68 69 70
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped);
71
static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
72 73 74 75
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped);
Alexandre Julliard's avatar
Alexandre Julliard committed
76

77
static DWORD VxDCall_VMM( DWORD service, CONTEXT86 *context );
Alexandre Julliard's avatar
Alexandre Julliard committed
78

79
static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode,
Alexandre Julliard's avatar
Alexandre Julliard committed
80 81 82 83 84
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped);

85
static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
86 87 88 89 90
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped);

91
static DWORD VxDCall_VWin32( DWORD service, CONTEXT86 *context );
92

93
static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
94 95 96 97 98
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped);

99
static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
100 101 102 103
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped);
104

105
static BOOL DeviceIo_HASP (DWORD dwIoControlCode,
106 107 108 109
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped);
Alexandre Julliard's avatar
Alexandre Julliard committed
110 111 112 113 114 115 116 117
/*
 * VxD names are taken from the Win95 DDK
 */

struct VxDInfo
{
    LPCSTR  name;
    WORD    id;
118
    DWORD (*vxdcall)(DWORD, CONTEXT86 *);
119
    BOOL  (*deviceio)(DWORD, LPVOID, DWORD,
Alexandre Julliard's avatar
Alexandre Julliard committed
120
                        LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
121 122
};

123
static const struct VxDInfo VxDList[] =
Alexandre Julliard's avatar
Alexandre Julliard committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
{
    /* Standard VxD IDs */
    { "VMM",      0x0001, VxDCall_VMM, NULL },
    { "DEBUG",    0x0002, NULL, NULL },
    { "VPICD",    0x0003, NULL, NULL },
    { "VDMAD",    0x0004, NULL, NULL },
    { "VTD",      0x0005, NULL, NULL },
    { "V86MMGR",  0x0006, NULL, NULL },
    { "PAGESWAP", 0x0007, NULL, NULL },
    { "PARITY",   0x0008, NULL, NULL },
    { "REBOOT",   0x0009, NULL, NULL },
    { "VDD",      0x000A, NULL, NULL },
    { "VSD",      0x000B, NULL, NULL },
    { "VMD",      0x000C, NULL, NULL },
    { "VKD",      0x000D, NULL, NULL },
139
    { "VCD",      0x000E, NULL, DeviceIo_VCD },
Alexandre Julliard's avatar
Alexandre Julliard committed
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
    { "VPD",      0x000F, NULL, NULL },
    { "BLOCKDEV", 0x0010, NULL, NULL },
    { "VMCPD",    0x0011, NULL, NULL },
    { "EBIOS",    0x0012, NULL, NULL },
    { "BIOSXLAT", 0x0013, NULL, NULL },
    { "VNETBIOS", 0x0014, NULL, NULL },
    { "DOSMGR",   0x0015, NULL, NULL },
    { "WINLOAD",  0x0016, NULL, NULL },
    { "SHELL",    0x0017, NULL, NULL },
    { "VMPOLL",   0x0018, NULL, NULL },
    { "VPROD",    0x0019, NULL, NULL },
    { "DOSNET",   0x001A, NULL, NULL },
    { "VFD",      0x001B, NULL, NULL },
    { "VDD2",     0x001C, NULL, NULL },
    { "WINDEBUG", 0x001D, NULL, NULL },
    { "TSRLOAD",  0x001E, NULL, NULL },
    { "BIOSHOOK", 0x001F, NULL, NULL },
    { "INT13",    0x0020, NULL, NULL },
    { "PAGEFILE", 0x0021, NULL, NULL },
    { "SCSI",     0x0022, NULL, NULL },
    { "MCA_POS",  0x0023, NULL, NULL },
    { "SCSIFD",   0x0024, NULL, NULL },
    { "VPEND",    0x0025, NULL, NULL },
    { "VPOWERD",  0x0026, NULL, NULL },
    { "VXDLDR",   0x0027, NULL, NULL },
    { "NDIS",     0x0028, NULL, NULL },
    { "BIOS_EXT", 0x0029, NULL, NULL },
167
    { "VWIN32",   0x002A, VxDCall_VWin32, DeviceIo_VWin32 },
Alexandre Julliard's avatar
Alexandre Julliard committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    { "VCOMM",    0x002B, NULL, NULL },
    { "SPOOLER",  0x002C, NULL, NULL },
    { "WIN32S",   0x002D, NULL, NULL },
    { "DEBUGCMD", 0x002E, NULL, NULL },

    { "VNB",      0x0031, NULL, NULL },
    { "SERVER",   0x0032, NULL, NULL },
    { "CONFIGMG", 0x0033, NULL, NULL },
    { "DWCFGMG",  0x0034, NULL, NULL },
    { "SCSIPORT", 0x0035, NULL, NULL },
    { "VFBACKUP", 0x0036, NULL, NULL },
    { "ENABLE",   0x0037, NULL, NULL },
    { "VCOND",    0x0038, NULL, NULL },

    { "EFAX",     0x003A, NULL, NULL },
    { "DSVXD",    0x003B, NULL, NULL },
    { "ISAPNP",   0x003C, NULL, NULL },
    { "BIOS",     0x003D, NULL, NULL },
    { "WINSOCK",  0x003E, NULL, NULL },
    { "WSOCK",    0x003E, NULL, NULL },
    { "WSIPX",    0x003F, NULL, NULL },
189
    { "IFSMgr",   0x0040, NULL, DeviceIo_IFSMgr },
Alexandre Julliard's avatar
Alexandre Julliard committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
    { "VCDFSD",   0x0041, NULL, NULL },
    { "MRCI2",    0x0042, NULL, NULL },
    { "PCI",      0x0043, NULL, NULL },
    { "PELOADER", 0x0044, NULL, NULL },
    { "EISA",     0x0045, NULL, NULL },
    { "DRAGCLI",  0x0046, NULL, NULL },
    { "DRAGSRV",  0x0047, NULL, NULL },
    { "PERF",     0x0048, NULL, NULL },
    { "AWREDIR",  0x0049, NULL, NULL },

    /* Far East support */
    { "ETEN",     0x0060, NULL, NULL },
    { "CHBIOS",   0x0061, NULL, NULL },
    { "VMSGD",    0x0062, NULL, NULL },
    { "VPPID",    0x0063, NULL, NULL },
    { "VIME",     0x0064, NULL, NULL },
    { "VHBIOSD",  0x0065, NULL, NULL },

    /* Multimedia OEM IDs */
    { "VTDAPI",   0x0442, NULL, DeviceIo_VTDAPI },
210
    { "MMDEVLDR", 0x044A, NULL, DeviceIo_MMDEVLDR },
Alexandre Julliard's avatar
Alexandre Julliard committed
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249

    /* Network Device IDs */
    { "VNetSup",  0x0480, NULL, NULL },
    { "VRedir",   0x0481, NULL, NULL },
    { "VBrowse",  0x0482, NULL, NULL },
    { "VSHARE",   0x0483, NULL, NULL },
    { "IFSMgr",   0x0484, NULL, NULL },
    { "MEMPROBE", 0x0485, NULL, NULL },
    { "VFAT",     0x0486, NULL, NULL },
    { "NWLINK",   0x0487, NULL, NULL },
    { "VNWLINK",  0x0487, NULL, NULL },
    { "NWSUP",    0x0487, NULL, NULL },
    { "VTDI",     0x0488, NULL, NULL },
    { "VIP",      0x0489, NULL, NULL },
    { "VTCP",     0x048A, NULL, NULL },
    { "VCache",   0x048B, NULL, NULL },
    { "VUDP",     0x048C, NULL, NULL },
    { "VAsync",   0x048D, NULL, NULL },
    { "NWREDIR",  0x048E, NULL, NULL },
    { "STAT80",   0x048F, NULL, NULL },
    { "SCSIPORT", 0x0490, NULL, NULL },
    { "FILESEC",  0x0491, NULL, NULL },
    { "NWSERVER", 0x0492, NULL, NULL },
    { "SECPROV",  0x0493, NULL, NULL },
    { "NSCL",     0x0494, NULL, NULL },
    { "WSTCP",    0x0495, NULL, NULL },
    { "NDIS2SUP", 0x0496, NULL, NULL },
    { "MSODISUP", 0x0497, NULL, NULL },
    { "Splitter", 0x0498, NULL, NULL },
    { "PPP",      0x0499, NULL, NULL },
    { "VDHCP",    0x049A, NULL, NULL },
    { "VNBT",     0x049B, NULL, NULL },
    { "LOGGER",   0x049D, NULL, NULL },
    { "EFILTER",  0x049E, NULL, NULL },
    { "FFILTER",  0x049F, NULL, NULL },
    { "TFILTER",  0x04A0, NULL, NULL },
    { "AFILTER",  0x04A1, NULL, NULL },
    { "IRLAMP",   0x04A2, NULL, NULL },

250
    { "PCCARD",   0x097C, NULL, DeviceIo_PCCARD },
251
    { "HASP95",   0x3721, NULL, DeviceIo_HASP },
252

253
    /* WINE additions, ids unknown */
254 255
    { "MONODEBG.VXD", 0x4242, NULL, DeviceIo_MONODEBG },

Alexandre Julliard's avatar
Alexandre Julliard committed
256 257 258 259 260 261 262 263 264 265 266
    { NULL,       0,      NULL, NULL }
};

/*
 * VMM VxDCall service names are (mostly) taken from Stan Mitchell's
 * "Inside the Windows 95 File System"
 */

#define N_VMM_SERVICE 41

LPCSTR VMM_Service_Name[N_VMM_SERVICE] =
267
{
Alexandre Julliard's avatar
Alexandre Julliard committed
268 269 270 271 272 273 274 275 276 277 278 279 280
    "PageReserve",            /* 0x0000 */
    "PageCommit",             /* 0x0001 */
    "PageDecommit",           /* 0x0002 */
    "PagerRegister",          /* 0x0003 */
    "PagerQuery",             /* 0x0004 */
    "HeapAllocate",           /* 0x0005 */
    "ContextCreate",          /* 0x0006 */
    "ContextDestroy",         /* 0x0007 */
    "PageAttach",             /* 0x0008 */
    "PageFlush",              /* 0x0009 */
    "PageFree",               /* 0x000A */
    "ContextSwitch",          /* 0x000B */
    "HeapReAllocate",         /* 0x000C */
281
    "PageModifyPermissions",  /* 0x000D */
Alexandre Julliard's avatar
Alexandre Julliard committed
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
    "PageQuery",              /* 0x000E */
    "GetCurrentContext",      /* 0x000F */
    "HeapFree",               /* 0x0010 */
    "RegOpenKey",             /* 0x0011 */
    "RegCreateKey",           /* 0x0012 */
    "RegCloseKey",            /* 0x0013 */
    "RegDeleteKey",           /* 0x0014 */
    "RegSetValue",            /* 0x0015 */
    "RegDeleteValue",         /* 0x0016 */
    "RegQueryValue",          /* 0x0017 */
    "RegEnumKey",             /* 0x0018 */
    "RegEnumValue",           /* 0x0019 */
    "RegQueryValueEx",        /* 0x001A */
    "RegSetValueEx",          /* 0x001B */
    "RegFlushKey",            /* 0x001C */
    "RegQueryInfoKey",        /* 0x001D */
    "GetDemandPageInfo",      /* 0x001E */
    "BlockOnID",              /* 0x001F */
    "SignalID",               /* 0x0020 */
    "RegLoadKey",             /* 0x0021 */
    "RegUnLoadKey",           /* 0x0022 */
    "RegSaveKey",             /* 0x0023 */
    "RegRemapPreDefKey",      /* 0x0024 */
    "PageChangePager",        /* 0x0025 */
    "RegQueryMultipleValues", /* 0x0026 */
    "RegReplaceKey",          /* 0x0027 */
    "<KERNEL32.101>"          /* 0x0028 -- What does this do??? */
};

311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
/* PageReserve arena values */
#define PR_PRIVATE  0x80000400	/* anywhere in private arena */
#define PR_SHARED   0x80060000	/* anywhere in shared arena */
#define PR_SYSTEM   0x80080000	/* anywhere in system arena */

/* PageReserve flags */
#define PR_FIXED    0x00000008	/* don't move during PageReAllocate */
#define PR_4MEG     0x00000001	/* allocate on 4mb boundary */
#define PR_STATIC   0x00000010	/* see PageReserve documentation */

/* PageCommit default pager handle values */
#define PD_ZEROINIT 0x00000001	/* swappable zero-initialized pages */
#define PD_NOINIT   0x00000002	/* swappable uninitialized pages */
#define PD_FIXEDZERO	0x00000003  /* fixed zero-initialized pages */
#define PD_FIXED    0x00000004	/* fixed uninitialized pages */

/* PageCommit flags */
#define PC_FIXED    0x00000008	/* pages are permanently locked */
329
#define PC_LOCKED   0x00000080	/* pages are made present and locked */
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
#define PC_LOCKEDIFDP	0x00000100  /* pages are locked if swap via DOS */
#define PC_WRITEABLE	0x00020000  /* make the pages writeable */
#define PC_USER     0x00040000	/* make the pages ring 3 accessible */
#define PC_INCR     0x40000000	/* increment "pagerdata" each page */
#define PC_PRESENT  0x80000000	/* make pages initially present */
#define PC_STATIC   0x20000000	/* allow commit in PR_STATIC object */
#define PC_DIRTY    0x08000000	/* make pages initially dirty */
#define PC_CACHEDIS 0x00100000  /* Allocate uncached pages - new for WDM */
#define PC_CACHEWT  0x00080000  /* Allocate write through cache pages - new for WDM */
#define PC_PAGEFLUSH 0x00008000 /* Touch device mapped pages on alloc - new for WDM */

/* PageCommitContig additional flags */
#define PCC_ZEROINIT	0x00000001  /* zero-initialize new pages */
#define PCC_NOLIN   0x10000000	/* don't map to any linear address */



347
HANDLE DEVICE_Open( LPCWSTR filenameW, DWORD access, LPSECURITY_ATTRIBUTES sa )
Alexandre Julliard's avatar
Alexandre Julliard committed
348
{
349
    const struct VxDInfo *info;
350 351 352 353 354 355 356
    char filename[MAX_PATH];

    if (!WideCharToMultiByte(CP_ACP, 0, filenameW, -1, filename, MAX_PATH, NULL, NULL))
    {
        SetLastError( ERROR_FILE_NOT_FOUND );
        return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
357

358
    for (info = VxDList; info->name; info++)
359
        if (!strncasecmp( info->name, filename, strlen(info->name) ))
360
            return FILE_CreateDevice( info->id | 0x10000, access, sa );
Alexandre Julliard's avatar
Alexandre Julliard committed
361

362 363
    FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
           filename);
364
    SetLastError( ERROR_FILE_NOT_FOUND );
365
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
366 367
}

368
static DWORD DEVICE_GetClientID( HANDLE handle )
Alexandre Julliard's avatar
Alexandre Julliard committed
369
{
370
    DWORD       ret = 0;
371
    SERVER_START_REQ( get_file_info )
372
    {
373
        req->handle = handle;
374 375
        if (!wine_server_call( req ) && (reply->type == FILE_TYPE_UNKNOWN))
            ret = reply->attr;
376
    }
377
    SERVER_END_REQ;
378 379 380 381 382 383
    return ret;
}

static const struct VxDInfo *DEVICE_GetInfo( DWORD clientID )
{
    const struct VxDInfo *info = NULL;
384

385 386 387 388 389
    if (clientID & 0x10000)
    {
        for (info = VxDList; info->name; info++)
            if (info->id == LOWORD(clientID)) break;
    }
390
    return info;
Alexandre Julliard's avatar
Alexandre Julliard committed
391 392 393
}

/****************************************************************************
394
 *		DeviceIoControl (KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
395 396 397 398 399
 * This is one of those big ugly nasty procedure which can do
 * a million and one things when it comes to devices. It can also be
 * used for VxD communication.
 *
 * A return value of FALSE indicates that something has gone wrong which
400
 * GetLastError can decipher.
Alexandre Julliard's avatar
Alexandre Julliard committed
401
 */
402
BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
Alexandre Julliard's avatar
Alexandre Julliard committed
403
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
Alexandre Julliard's avatar
Alexandre Julliard committed
404 405 406 407
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped)
{
408
        DWORD clientID;
Alexandre Julliard's avatar
Alexandre Julliard committed
409

410 411 412
        TRACE( "(%d,%ld,%p,%ld,%p,%ld,%p,%p)\n",
               hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
               lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped	);
Alexandre Julliard's avatar
Alexandre Julliard committed
413

414
	if (!(clientID = DEVICE_GetClientID( hDevice )))
Alexandre Julliard's avatar
Alexandre Julliard committed
415 416
	{
		SetLastError( ERROR_INVALID_PARAMETER );
Alexandre Julliard's avatar
Alexandre Julliard committed
417
		return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
418 419 420
	}

	/* Check if this is a user defined control code for a VxD */
Alexandre Julliard's avatar
Alexandre Julliard committed
421 422
	if( HIWORD( dwIoControlCode ) == 0 )
	{
423 424 425 426 427 428
                const struct VxDInfo *info;
                if (!(info = DEVICE_GetInfo( clientID )))
                {
                        FIXME( "No device found for id %lx\n", clientID);
                }
                else if ( info->deviceio )
Alexandre Julliard's avatar
Alexandre Julliard committed
429
		{
430 431 432
			return info->deviceio( dwIoControlCode,
                                        lpvInBuffer, cbInBuffer,
                                        lpvOutBuffer, cbOutBuffer,
Alexandre Julliard's avatar
Alexandre Julliard committed
433 434 435 436
                                        lpcbBytesReturned, lpOverlapped );
		}
		else
		{
437
			FIXME( "Unimplemented control %ld for VxD device %s\n",
438
                               dwIoControlCode, info->name ? info->name : "???" );
439 440 441 442
			/* FIXME: this is for invalid calls on W98SE,
			 * but maybe we should use ERROR_CALL_NOT_IMPLEMENTED
			 * instead ? */
			SetLastError( ERROR_INVALID_FUNCTION );
Alexandre Julliard's avatar
Alexandre Julliard committed
443
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
444 445 446
	}
	else
	{
447 448 449 450 451 452 453 454 455
                char str[3];

                strcpy(str,  "A:");
                str[0] += LOBYTE(clientID);
                if (GetDriveTypeA(str) == DRIVE_CDROM)
                    return CDROM_DeviceIoControl(clientID, hDevice, dwIoControlCode, lpvInBuffer, cbInBuffer,
                                                 lpvOutBuffer, cbOutBuffer, lpcbBytesReturned,
                                                 lpOverlapped);
                else switch( dwIoControlCode )
Alexandre Julliard's avatar
Alexandre Julliard committed
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
		{
		case FSCTL_DELETE_REPARSE_POINT:
		case FSCTL_DISMOUNT_VOLUME:
		case FSCTL_GET_COMPRESSION:
		case FSCTL_GET_REPARSE_POINT:
		case FSCTL_LOCK_VOLUME:
		case FSCTL_QUERY_ALLOCATED_RANGES:
		case FSCTL_SET_COMPRESSION:
		case FSCTL_SET_REPARSE_POINT:
		case FSCTL_SET_SPARSE:
		case FSCTL_SET_ZERO_DATA:
		case FSCTL_UNLOCK_VOLUME:
		case IOCTL_DISK_CHECK_VERIFY:
		case IOCTL_DISK_EJECT_MEDIA:
		case IOCTL_DISK_FORMAT_TRACKS:
		case IOCTL_DISK_GET_DRIVE_GEOMETRY:
		case IOCTL_DISK_GET_DRIVE_LAYOUT:
		case IOCTL_DISK_GET_MEDIA_TYPES:
		case IOCTL_DISK_GET_PARTITION_INFO:
		case IOCTL_DISK_LOAD_MEDIA:
		case IOCTL_DISK_MEDIA_REMOVAL:
		case IOCTL_DISK_PERFORMANCE:
		case IOCTL_DISK_REASSIGN_BLOCKS:
		case IOCTL_DISK_SET_DRIVE_LAYOUT:
		case IOCTL_DISK_SET_PARTITION_INFO:
		case IOCTL_DISK_VERIFY:
		case IOCTL_SERIAL_LSRMST_INSERT:
		case IOCTL_STORAGE_CHECK_VERIFY:
		case IOCTL_STORAGE_EJECT_MEDIA:
		case IOCTL_STORAGE_GET_MEDIA_TYPES:
		case IOCTL_STORAGE_LOAD_MEDIA:
		case IOCTL_STORAGE_MEDIA_REMOVAL:
488
    			FIXME( "unimplemented dwIoControlCode=%08lx\n", dwIoControlCode);
Alexandre Julliard's avatar
Alexandre Julliard committed
489 490 491 492
    			SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
    			return FALSE;
    			break;
		default:
493
    			FIXME( "ignored dwIoControlCode=%08lx\n",dwIoControlCode);
Alexandre Julliard's avatar
Alexandre Julliard committed
494 495 496 497
    			SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
    			return FALSE;
    			break;
		}
Alexandre Julliard's avatar
Alexandre Julliard committed
498
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
499
   	return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
500
}
501

Alexandre Julliard's avatar
Alexandre Julliard committed
502 503 504
/***********************************************************************
 *           DeviceIo_VTDAPI
 */
505
static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
Alexandre Julliard's avatar
Alexandre Julliard committed
506 507 508 509
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped)
{
510
    BOOL retv = TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
511 512 513 514 515

    switch (dwIoControlCode)
    {
    case 5:
        if (lpvOutBuffer && (cbOutBuffer>=4))
516
            *(DWORD*)lpvOutBuffer = GetTickCount();
Alexandre Julliard's avatar
Alexandre Julliard committed
517 518 519 520 521 522 523

        if (lpcbBytesReturned)
            *lpcbBytesReturned = 4;

        break;

    default:
524
        FIXME( "Control %ld not implemented\n", dwIoControlCode);
Alexandre Julliard's avatar
Alexandre Julliard committed
525 526 527 528 529 530 531 532
        retv = FALSE;
        break;
    }

    return retv;
}

/***********************************************************************
533 534 535 536 537 538 539 540 541
 *		VxDCall0 (KERNEL32.1)
 *		VxDCall1 (KERNEL32.2)
 *		VxDCall2 (KERNEL32.3)
 *		VxDCall3 (KERNEL32.4)
 *		VxDCall4 (KERNEL32.5)
 *		VxDCall5 (KERNEL32.6)
 *		VxDCall6 (KERNEL32.7)
 *		VxDCall7 (KERNEL32.8)
 *		VxDCall8 (KERNEL32.9)
Alexandre Julliard's avatar
Alexandre Julliard committed
542
 */
543
void VxDCall( DWORD service, CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
544
{
545 546
    DWORD ret = 0xffffffff; /* FIXME */
    int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
547

548
    TRACE( "(%08lx, ...)\n", service);
Alexandre Julliard's avatar
Alexandre Julliard committed
549 550 551 552 553 554

    for (i = 0; VxDList[i].name; i++)
        if (VxDList[i].id == HIWORD(service))
            break;

    if (!VxDList[i].name)
555
        FIXME( "Unknown VxD (%08lx)\n", service);
Alexandre Julliard's avatar
Alexandre Julliard committed
556
    else if (!VxDList[i].vxdcall)
557
        FIXME( "Unimplemented VxD (%08lx)\n", service);
Alexandre Julliard's avatar
Alexandre Julliard committed
558
    else
559
        ret = VxDList[i].vxdcall( service, context );
560

561
    context->Eax = ret;
562 563
}

Alexandre Julliard's avatar
Alexandre Julliard committed
564

565 566 567 568 569 570 571 572
/******************************************************************************
 * The following is a massive duplication of the advapi32 code.
 * Unfortunately sharing the code is not possible since the native
 * Win95 advapi32 depends on it. Someday we should probably stop
 * supporting native Win95 advapi32 altogether...
 */


573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
#define HKEY_SPECIAL_ROOT_FIRST   HKEY_CLASSES_ROOT
#define HKEY_SPECIAL_ROOT_LAST    HKEY_DYN_DATA
#define NB_SPECIAL_ROOT_KEYS      ((UINT)HKEY_SPECIAL_ROOT_LAST - (UINT)HKEY_SPECIAL_ROOT_FIRST + 1)

static HKEY special_root_keys[NB_SPECIAL_ROOT_KEYS];

static const WCHAR name_CLASSES_ROOT[] =
    {'M','a','c','h','i','n','e','\\',
     'S','o','f','t','w','a','r','e','\\',
     'C','l','a','s','s','e','s',0};
static const WCHAR name_LOCAL_MACHINE[] =
    {'M','a','c','h','i','n','e',0};
static const WCHAR name_USERS[] =
    {'U','s','e','r',0};
static const WCHAR name_PERFORMANCE_DATA[] =
    {'P','e','r','f','D','a','t','a',0};
static const WCHAR name_CURRENT_CONFIG[] =
    {'M','a','c','h','i','n','e','\\',
     'S','y','s','t','e','m','\\',
     'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
     'H','a','r','d','w','a','r','e','P','r','o','f','i','l','e','s','\\',
     'C','u','r','r','e','n','t',0};
static const WCHAR name_DYN_DATA[] =
    {'D','y','n','D','a','t','a',0};

#define DECL_STR(key) { sizeof(name_##key)-sizeof(WCHAR), sizeof(name_##key), (LPWSTR)name_##key }
static UNICODE_STRING root_key_names[NB_SPECIAL_ROOT_KEYS] =
{
    DECL_STR(CLASSES_ROOT),
    { 0, 0, NULL },         /* HKEY_CURRENT_USER is determined dynamically */
    DECL_STR(LOCAL_MACHINE),
    DECL_STR(USERS),
    DECL_STR(PERFORMANCE_DATA),
    DECL_STR(CURRENT_CONFIG),
    DECL_STR(DYN_DATA)
};
#undef DECL_STR


612 613 614 615 616 617
/* check if value type needs string conversion (Ansi<->Unicode) */
inline static int is_string( DWORD type )
{
    return (type == REG_SZ) || (type == REG_EXPAND_SZ) || (type == REG_MULTI_SZ);
}

618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
/* create one of the HKEY_* special root keys */
static HKEY create_special_root_hkey( HKEY hkey, DWORD access )
{
    HKEY ret = 0;
    int idx = (UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST;

    if (hkey == HKEY_CURRENT_USER)
    {
        if (RtlOpenCurrentUser( access, &hkey )) return 0;
    }
    else
    {
        OBJECT_ATTRIBUTES attr;

        attr.Length = sizeof(attr);
        attr.RootDirectory = 0;
        attr.ObjectName = &root_key_names[idx];
        attr.Attributes = 0;
        attr.SecurityDescriptor = NULL;
        attr.SecurityQualityOfService = NULL;
        if (NtCreateKey( &hkey, access, &attr, 0, NULL, 0, NULL )) return 0;
    }

    if (!(ret = InterlockedCompareExchange( (PLONG)&special_root_keys[idx], hkey, 0 )))
        ret = hkey;
    else
        NtClose( hkey );  /* somebody beat us to it */
    return ret;
}

/* map the hkey from special root to normal key if necessary */
inline static HKEY get_special_root_hkey( HKEY hkey )
{
    HKEY ret = hkey;

    if ((hkey >= HKEY_SPECIAL_ROOT_FIRST) && (hkey <= HKEY_SPECIAL_ROOT_LAST))
    {
        if (!(ret = special_root_keys[(UINT)hkey - (UINT)HKEY_SPECIAL_ROOT_FIRST]))
            ret = create_special_root_hkey( hkey, KEY_ALL_ACCESS );
    }
    return ret;
}


662 663 664
/******************************************************************************
 *           VMM_RegCreateKeyA
 */
665
static DWORD VMM_RegCreateKeyA( HKEY hkey, LPCSTR name, PHKEY retkey )
666 667 668 669 670 671
{
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING nameW;
    ANSI_STRING nameA;
    NTSTATUS status;

672 673
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
    attr.Length = sizeof(attr);
    attr.RootDirectory = hkey;
    attr.ObjectName = &nameW;
    attr.Attributes = 0;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;
    RtlInitAnsiString( &nameA, name );

    if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
    {
        status = NtCreateKey( retkey, KEY_ALL_ACCESS, &attr, 0, NULL,
                              REG_OPTION_NON_VOLATILE, NULL );
        RtlFreeUnicodeString( &nameW );
    }
    return RtlNtStatusToDosError( status );
}


/******************************************************************************
 *           VMM_RegOpenKeyExA
 */
695
DWORD WINAPI VMM_RegOpenKeyExA(HKEY hkey, LPCSTR name, DWORD reserved, REGSAM access, PHKEY retkey)
696 697 698 699 700 701
{
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING nameW;
    STRING nameA;
    NTSTATUS status;

702 703
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
    attr.Length = sizeof(attr);
    attr.RootDirectory = hkey;
    attr.ObjectName = &nameW;
    attr.Attributes = 0;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;

    RtlInitAnsiString( &nameA, name );
    if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
    {
        status = NtOpenKey( retkey, access, &attr );
        RtlFreeUnicodeString( &nameW );
    }
    return RtlNtStatusToDosError( status );
}


/******************************************************************************
 *           VMM_RegCloseKey
 */
static DWORD VMM_RegCloseKey( HKEY hkey )
{
    if (!hkey || hkey >= (HKEY)0x80000000) return ERROR_SUCCESS;
    return RtlNtStatusToDosError( NtClose( hkey ) );
}


/******************************************************************************
 *           VMM_RegDeleteKeyA
 */
static DWORD VMM_RegDeleteKeyA( HKEY hkey, LPCSTR name )
{
    DWORD ret;
    HKEY tmp;

739 740 741
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

    if (!name || !*name) return RtlNtStatusToDosError( NtDeleteKey( hkey ) );
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761
    if (!(ret = VMM_RegOpenKeyExA( hkey, name, 0, 0, &tmp )))
    {
        ret = RtlNtStatusToDosError( NtDeleteKey( tmp ) );
        NtClose( tmp );
    }
    return ret;
}


/******************************************************************************
 *           VMM_RegSetValueExA
 */
static DWORD VMM_RegSetValueExA( HKEY hkey, LPCSTR name, DWORD reserved, DWORD type,
                                 CONST BYTE *data, DWORD count )
{
    UNICODE_STRING nameW;
    ANSI_STRING nameA;
    WCHAR *dataW = NULL;
    NTSTATUS status;

762 763
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819
    if (is_string(type))
    {
        DWORD lenW;

        if (count)
        {
            /* if user forgot to count terminating null, add it (yes NT does this) */
            if (data[count-1] && !data[count]) count++;
        }
        RtlMultiByteToUnicodeSize( &lenW, data, count );
        if (!(dataW = HeapAlloc( GetProcessHeap(), 0, lenW ))) return ERROR_OUTOFMEMORY;
        RtlMultiByteToUnicodeN( dataW, lenW, NULL, data, count );
        count = lenW;
        data = (BYTE *)dataW;
    }

    RtlInitAnsiString( &nameA, name );
    if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
    {
        status = NtSetValueKey( hkey, &nameW, 0, type, data, count );
        RtlFreeUnicodeString( &nameW );
    }
    if (dataW) HeapFree( GetProcessHeap(), 0, dataW );
    return RtlNtStatusToDosError( status );
}


/******************************************************************************
 *           VMM_RegSetValueA
 */
static DWORD VMM_RegSetValueA( HKEY hkey, LPCSTR name, DWORD type, LPCSTR data, DWORD count )
{
    HKEY subkey = hkey;
    DWORD ret;

    if (type != REG_SZ) return ERROR_INVALID_PARAMETER;

    if (name && name[0])  /* need to create the subkey */
    {
        if ((ret = VMM_RegCreateKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret;
    }
    ret = VMM_RegSetValueExA( subkey, NULL, 0, REG_SZ, (LPBYTE)data, strlen(data)+1 );
    if (subkey != hkey) NtClose( subkey );
    return ret;
}


/******************************************************************************
 *           VMM_RegDeleteValueA
 */
static DWORD VMM_RegDeleteValueA( HKEY hkey, LPCSTR name )
{
    UNICODE_STRING nameW;
    STRING nameA;
    NTSTATUS status;

820 821
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
    RtlInitAnsiString( &nameA, name );
    if (!(status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
    {
        status = NtDeleteValueKey( hkey, &nameW );
        RtlFreeUnicodeString( &nameW );
    }
    return RtlNtStatusToDosError( status );
}


/******************************************************************************
 *           VMM_RegQueryValueExA
 */
static DWORD VMM_RegQueryValueExA( HKEY hkey, LPCSTR name, LPDWORD reserved, LPDWORD type,
                                   LPBYTE data, LPDWORD count )
{
    NTSTATUS status;
    ANSI_STRING nameA;
    UNICODE_STRING nameW;
    DWORD total_size;
    char buffer[256], *buf_ptr = buffer;
    KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
    static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );

    if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
847
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958

    RtlInitAnsiString( &nameA, name );
    if ((status = RtlAnsiStringToUnicodeString( &nameW, &nameA, TRUE )))
        return RtlNtStatusToDosError(status);

    status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
                              buffer, sizeof(buffer), &total_size );
    if (status && status != STATUS_BUFFER_OVERFLOW) goto done;

    /* we need to fetch the contents for a string type even if not requested,
     * because we need to compute the length of the ASCII string. */
    if (data || is_string(info->Type))
    {
        /* retry with a dynamically allocated buffer */
        while (status == STATUS_BUFFER_OVERFLOW)
        {
            if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
            if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
            {
                status = STATUS_NO_MEMORY;
                goto done;
            }
            info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;
            status = NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation,
                                      buf_ptr, total_size, &total_size );
        }

        if (!status)
        {
            if (is_string(info->Type))
            {
                DWORD len = WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
                                                 (total_size - info_size) /sizeof(WCHAR),
                                                 NULL, 0, NULL, NULL );
                if (data && len)
                {
                    if (len > *count) status = STATUS_BUFFER_OVERFLOW;
                    else
                    {
                        WideCharToMultiByte( CP_ACP, 0, (WCHAR *)(buf_ptr + info_size),
                                             (total_size - info_size) /sizeof(WCHAR),
                                             data, len, NULL, NULL );
                        /* if the type is REG_SZ and data is not 0-terminated
                         * and there is enough space in the buffer NT appends a \0 */
                        if (len < *count && data[len-1]) data[len] = 0;
                    }
                }
                total_size = len + info_size;
            }
            else if (data)
            {
                if (total_size - info_size > *count) status = STATUS_BUFFER_OVERFLOW;
                else memcpy( data, buf_ptr + info_size, total_size - info_size );
            }
        }
        else if (status != STATUS_BUFFER_OVERFLOW) goto done;
    }

    if (type) *type = info->Type;
    if (count) *count = total_size - info_size;

 done:
    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
    RtlFreeUnicodeString( &nameW );
    return RtlNtStatusToDosError(status);
}


/******************************************************************************
 *           VMM_RegQueryValueA
 */
static DWORD VMM_RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count )
{
    DWORD ret;
    HKEY subkey = hkey;

    if (name && name[0])
    {
        if ((ret = VMM_RegOpenKeyExA( hkey, name, 0, KEY_ALL_ACCESS, &subkey )) != ERROR_SUCCESS)
            return ret;
    }
    ret = VMM_RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, count );
    if (subkey != hkey) NtClose( subkey );
    if (ret == ERROR_FILE_NOT_FOUND)
    {
        /* return empty string if default value not found */
        if (data) *data = 0;
        if (count) *count = 1;
        ret = ERROR_SUCCESS;
    }
    return ret;
}


/******************************************************************************
 *           VMM_RegEnumValueA
 */
static DWORD VMM_RegEnumValueA( HKEY hkey, DWORD index, LPSTR value, LPDWORD val_count,
                                LPDWORD reserved, LPDWORD type, LPBYTE data, LPDWORD count )
{
    NTSTATUS status;
    DWORD total_size;
    char buffer[256], *buf_ptr = buffer;
    KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
    static const int info_size = offsetof( KEY_VALUE_FULL_INFORMATION, Name );

    TRACE("(%x,%ld,%p,%p,%p,%p,%p,%p)\n",
          hkey, index, value, val_count, reserved, type, data, count );

    /* NT only checks count, not val_count */
    if ((data && !count) || reserved) return ERROR_INVALID_PARAMETER;
959
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;
960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054

    total_size = info_size + (MAX_PATH + 1) * sizeof(WCHAR);
    if (data) total_size += *count;
    total_size = min( sizeof(buffer), total_size );

    status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
                                  buffer, total_size, &total_size );
    if (status && status != STATUS_BUFFER_OVERFLOW) goto done;

    /* we need to fetch the contents for a string type even if not requested,
     * because we need to compute the length of the ASCII string. */
    if (value || data || is_string(info->Type))
    {
        /* retry with a dynamically allocated buffer */
        while (status == STATUS_BUFFER_OVERFLOW)
        {
            if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
            if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
                return ERROR_NOT_ENOUGH_MEMORY;
            info = (KEY_VALUE_FULL_INFORMATION *)buf_ptr;
            status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
                                          buf_ptr, total_size, &total_size );
        }

        if (status) goto done;

        if (is_string(info->Type))
        {
            DWORD len;
            RtlUnicodeToMultiByteSize( &len, (WCHAR *)(buf_ptr + info->DataOffset),
                                       total_size - info->DataOffset );
            if (data && len)
            {
                if (len > *count) status = STATUS_BUFFER_OVERFLOW;
                else
                {
                    RtlUnicodeToMultiByteN( data, len, NULL, (WCHAR *)(buf_ptr + info->DataOffset),
                                            total_size - info->DataOffset );
                    /* if the type is REG_SZ and data is not 0-terminated
                     * and there is enough space in the buffer NT appends a \0 */
                    if (len < *count && data[len-1]) data[len] = 0;
                }
            }
            info->DataLength = len;
        }
        else if (data)
        {
            if (total_size - info->DataOffset > *count) status = STATUS_BUFFER_OVERFLOW;
            else memcpy( data, buf_ptr + info->DataOffset, total_size - info->DataOffset );
        }

        if (value && !status)
        {
            DWORD len;

            RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
            if (len >= *val_count)
            {
                status = STATUS_BUFFER_OVERFLOW;
                if (*val_count)
                {
                    len = *val_count - 1;
                    RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
                    value[len] = 0;
                }
            }
            else
            {
                RtlUnicodeToMultiByteN( value, len, NULL, info->Name, info->NameLength );
                value[len] = 0;
                *val_count = len;
            }
        }
    }
    else status = STATUS_SUCCESS;

    if (type) *type = info->Type;
    if (count) *count = info->DataLength;

 done:
    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
    return RtlNtStatusToDosError(status);
}


/******************************************************************************
 *           VMM_RegEnumKeyA
 */
static DWORD VMM_RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len )
{
    NTSTATUS status;
    char buffer[256], *buf_ptr = buffer;
    KEY_NODE_INFORMATION *info = (KEY_NODE_INFORMATION *)buffer;
    DWORD total_size;

1055 1056
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102
    status = NtEnumerateKey( hkey, index, KeyNodeInformation,
                             buffer, sizeof(buffer), &total_size );

    while (status == STATUS_BUFFER_OVERFLOW)
    {
        /* retry with a dynamically allocated buffer */
        if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
        if (!(buf_ptr = HeapAlloc( GetProcessHeap(), 0, total_size )))
            return ERROR_NOT_ENOUGH_MEMORY;
        info = (KEY_NODE_INFORMATION *)buf_ptr;
        status = NtEnumerateKey( hkey, index, KeyNodeInformation,
                                 buf_ptr, total_size, &total_size );
    }

    if (!status)
    {
        DWORD len;

        RtlUnicodeToMultiByteSize( &len, info->Name, info->NameLength );
        if (len >= name_len) status = STATUS_BUFFER_OVERFLOW;
        else
        {
            RtlUnicodeToMultiByteN( name, len, NULL, info->Name, info->NameLength );
            name[len] = 0;
        }
    }

    if (buf_ptr != buffer) HeapFree( GetProcessHeap(), 0, buf_ptr );
    return RtlNtStatusToDosError( status );
}


/******************************************************************************
 *           VMM_RegQueryInfoKeyA
 *
 * NOTE: This VxDCall takes only a subset of the parameters that the
 * corresponding Win32 API call does. The implementation in Win95
 * ADVAPI32 sets all output parameters not mentioned here to zero.
 */
static DWORD VMM_RegQueryInfoKeyA( HKEY hkey, LPDWORD subkeys, LPDWORD max_subkey,
                                   LPDWORD values, LPDWORD max_value, LPDWORD max_data )
{
    NTSTATUS status;
    KEY_FULL_INFORMATION info;
    DWORD total_size;

1103 1104
    if (!(hkey = get_special_root_hkey( hkey ))) return ERROR_INVALID_HANDLE;

1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116
    status = NtQueryKey( hkey, KeyFullInformation, &info, sizeof(info), &total_size );
    if (status && status != STATUS_BUFFER_OVERFLOW) return RtlNtStatusToDosError( status );

    if (subkeys) *subkeys = info.SubKeys;
    if (max_subkey) *max_subkey = info.MaxNameLen;
    if (values) *values = info.Values;
    if (max_value) *max_value = info.MaxValueNameLen;
    if (max_data) *max_data = info.MaxValueDataLen;
    return ERROR_SUCCESS;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1117 1118 1119
/***********************************************************************
 *           VxDCall_VMM
 */
1120
static DWORD VxDCall_VMM( DWORD service, CONTEXT86 *context )
Alexandre Julliard's avatar
Alexandre Julliard committed
1121 1122 1123 1124 1125
{
    switch ( LOWORD(service) )
    {
    case 0x0011:  /* RegOpenKey */
    {
1126 1127
        HKEY    hkey       = (HKEY)  stack32_pop( context );
        LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1128
        PHKEY   retkey     = (PHKEY)stack32_pop( context );
1129
        return VMM_RegOpenKeyExA( hkey, lpszSubKey, 0, KEY_ALL_ACCESS, retkey );
Alexandre Julliard's avatar
Alexandre Julliard committed
1130 1131 1132 1133
    }

    case 0x0012:  /* RegCreateKey */
    {
1134 1135
        HKEY    hkey       = (HKEY)  stack32_pop( context );
        LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1136
        PHKEY   retkey     = (PHKEY)stack32_pop( context );
1137
        return VMM_RegCreateKeyA( hkey, lpszSubKey, retkey );
Alexandre Julliard's avatar
Alexandre Julliard committed
1138 1139 1140 1141
    }

    case 0x0013:  /* RegCloseKey */
    {
1142
        HKEY    hkey       = (HKEY)stack32_pop( context );
1143
        return VMM_RegCloseKey( hkey );
Alexandre Julliard's avatar
Alexandre Julliard committed
1144 1145 1146 1147
    }

    case 0x0014:  /* RegDeleteKey */
    {
1148 1149
        HKEY    hkey       = (HKEY)  stack32_pop( context );
        LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1150
        return VMM_RegDeleteKeyA( hkey, lpszSubKey );
Alexandre Julliard's avatar
Alexandre Julliard committed
1151 1152 1153 1154
    }

    case 0x0015:  /* RegSetValue */
    {
1155 1156 1157 1158 1159
        HKEY    hkey       = (HKEY)  stack32_pop( context );
        LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
        DWORD   dwType     = (DWORD) stack32_pop( context );
        LPCSTR  lpszData   = (LPCSTR)stack32_pop( context );
        DWORD   cbData     = (DWORD) stack32_pop( context );
1160
        return VMM_RegSetValueA( hkey, lpszSubKey, dwType, lpszData, cbData );
Alexandre Julliard's avatar
Alexandre Julliard committed
1161 1162 1163 1164
    }

    case 0x0016:  /* RegDeleteValue */
    {
1165 1166
        HKEY    hkey       = (HKEY) stack32_pop( context );
        LPSTR   lpszValue  = (LPSTR)stack32_pop( context );
1167
        return VMM_RegDeleteValueA( hkey, lpszValue );
Alexandre Julliard's avatar
Alexandre Julliard committed
1168 1169 1170 1171
    }

    case 0x0017:  /* RegQueryValue */
    {
1172 1173 1174 1175
        HKEY    hkey       = (HKEY)   stack32_pop( context );
        LPSTR   lpszSubKey = (LPSTR)  stack32_pop( context );
        LPSTR   lpszData   = (LPSTR)  stack32_pop( context );
        LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
1176
        return VMM_RegQueryValueA( hkey, lpszSubKey, lpszData, lpcbData );
Alexandre Julliard's avatar
Alexandre Julliard committed
1177 1178 1179 1180
    }

    case 0x0018:  /* RegEnumKey */
    {
1181 1182 1183 1184
        HKEY    hkey       = (HKEY) stack32_pop( context );
        DWORD   iSubkey    = (DWORD)stack32_pop( context );
        LPSTR   lpszName   = (LPSTR)stack32_pop( context );
        DWORD   lpcchName  = (DWORD)stack32_pop( context );
1185
        return VMM_RegEnumKeyA( hkey, iSubkey, lpszName, lpcchName );
Alexandre Julliard's avatar
Alexandre Julliard committed
1186 1187 1188 1189
    }

    case 0x0019:  /* RegEnumValue */
    {
1190 1191 1192 1193 1194 1195 1196 1197
        HKEY    hkey       = (HKEY)   stack32_pop( context );
        DWORD   iValue     = (DWORD)  stack32_pop( context );
        LPSTR   lpszValue  = (LPSTR)  stack32_pop( context );
        LPDWORD lpcchValue = (LPDWORD)stack32_pop( context );
        LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
        LPDWORD lpdwType   = (LPDWORD)stack32_pop( context );
        LPBYTE  lpbData    = (LPBYTE) stack32_pop( context );
        LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
1198 1199
        return VMM_RegEnumValueA( hkey, iValue, lpszValue, lpcchValue,
                                  lpReserved, lpdwType, lpbData, lpcbData );
Alexandre Julliard's avatar
Alexandre Julliard committed
1200 1201 1202 1203
    }

    case 0x001A:  /* RegQueryValueEx */
    {
1204 1205 1206 1207 1208 1209
        HKEY    hkey       = (HKEY)   stack32_pop( context );
        LPSTR   lpszValue  = (LPSTR)  stack32_pop( context );
        LPDWORD lpReserved = (LPDWORD)stack32_pop( context );
        LPDWORD lpdwType   = (LPDWORD)stack32_pop( context );
        LPBYTE  lpbData    = (LPBYTE) stack32_pop( context );
        LPDWORD lpcbData   = (LPDWORD)stack32_pop( context );
1210 1211
        return VMM_RegQueryValueExA( hkey, lpszValue, lpReserved,
                                     lpdwType, lpbData, lpcbData );
Alexandre Julliard's avatar
Alexandre Julliard committed
1212 1213 1214 1215
    }

    case 0x001B:  /* RegSetValueEx */
    {
1216 1217 1218 1219 1220 1221
        HKEY    hkey       = (HKEY)  stack32_pop( context );
        LPSTR   lpszValue  = (LPSTR) stack32_pop( context );
        DWORD   dwReserved = (DWORD) stack32_pop( context );
        DWORD   dwType     = (DWORD) stack32_pop( context );
        LPBYTE  lpbData    = (LPBYTE)stack32_pop( context );
        DWORD   cbData     = (DWORD) stack32_pop( context );
1222 1223
        return VMM_RegSetValueExA( hkey, lpszValue, dwReserved,
                                   dwType, lpbData, cbData );
Alexandre Julliard's avatar
Alexandre Julliard committed
1224 1225 1226 1227
    }

    case 0x001C:  /* RegFlushKey */
    {
1228 1229 1230
        HKEY hkey = (HKEY)stack32_pop( context );
        FIXME( "RegFlushKey(%x): stub\n", hkey );
        return ERROR_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1231 1232 1233 1234 1235 1236 1237 1238
    }

    case 0x001D:  /* RegQueryInfoKey */
    {
        /* NOTE: This VxDCall takes only a subset of the parameters that the
                 corresponding Win32 API call does. The implementation in Win95
                 ADVAPI32 sets all output parameters not mentioned here to zero. */

1239 1240 1241 1242 1243 1244
        HKEY    hkey              = (HKEY)   stack32_pop( context );
        LPDWORD lpcSubKeys        = (LPDWORD)stack32_pop( context );
        LPDWORD lpcchMaxSubKey    = (LPDWORD)stack32_pop( context );
        LPDWORD lpcValues         = (LPDWORD)stack32_pop( context );
        LPDWORD lpcchMaxValueName = (LPDWORD)stack32_pop( context );
        LPDWORD lpcchMaxValueData = (LPDWORD)stack32_pop( context );
1245 1246
        return VMM_RegQueryInfoKeyA( hkey, lpcSubKeys, lpcchMaxSubKey,
                                     lpcValues, lpcchMaxValueName, lpcchMaxValueData );
Alexandre Julliard's avatar
Alexandre Julliard committed
1247 1248 1249 1250
    }

    case 0x0021:  /* RegLoadKey */
    {
1251 1252 1253
        HKEY    hkey       = (HKEY)  stack32_pop( context );
        LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
        LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
1254 1255
        FIXME("RegLoadKey(%x,%s,%s): stub\n",hkey, debugstr_a(lpszSubKey), debugstr_a(lpszFile));
        return ERROR_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1256 1257 1258 1259
    }

    case 0x0022:  /* RegUnLoadKey */
    {
1260 1261
        HKEY    hkey       = (HKEY)  stack32_pop( context );
        LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
1262 1263
        FIXME("RegUnLoadKey(%x,%s): stub\n",hkey, debugstr_a(lpszSubKey));
        return ERROR_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1264 1265 1266 1267
    }

    case 0x0023:  /* RegSaveKey */
    {
1268 1269 1270
        HKEY    hkey       = (HKEY)  stack32_pop( context );
        LPCSTR  lpszFile   = (LPCSTR)stack32_pop( context );
        LPSECURITY_ATTRIBUTES sa = (LPSECURITY_ATTRIBUTES)stack32_pop( context );
1271 1272
        FIXME("RegSaveKey(%x,%s,%p): stub\n",hkey, debugstr_a(lpszFile),sa);
        return ERROR_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1273 1274 1275 1276 1277 1278 1279 1280 1281
    }

#if 0 /* Functions are not yet implemented in misc/registry.c */
    case 0x0024:  /* RegRemapPreDefKey */
    case 0x0026:  /* RegQueryMultipleValues */
#endif

    case 0x0027:  /* RegReplaceKey */
    {
1282 1283 1284 1285
        HKEY    hkey       = (HKEY)  stack32_pop( context );
        LPCSTR  lpszSubKey = (LPCSTR)stack32_pop( context );
        LPCSTR  lpszNewFile= (LPCSTR)stack32_pop( context );
        LPCSTR  lpszOldFile= (LPCSTR)stack32_pop( context );
1286 1287 1288
        FIXME("RegReplaceKey(%x,%s,%s,%s): stub\n", hkey, debugstr_a(lpszSubKey),
              debugstr_a(lpszNewFile),debugstr_a(lpszOldFile));
        return ERROR_SUCCESS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1289
    }
1290

1291 1292 1293 1294
    case 0x0000: /* PageReserve */
      {
	LPVOID address;
	LPVOID ret;
1295
	DWORD psize = getpagesize();
1296 1297 1298 1299
	ULONG page   = (ULONG) stack32_pop( context );
	ULONG npages = (ULONG) stack32_pop( context );
	ULONG flags  = (ULONG) stack32_pop( context );

1300
	TRACE("PageReserve: page: %08lx, npages: %08lx, flags: %08lx partial stub!\n",
1301 1302 1303 1304 1305 1306
	      page, npages, flags );

	if ( page == PR_SYSTEM ) {
	  ERR("Can't reserve ring 1 memory\n");
	  return -1;
	}
1307 1308
	/* FIXME: This has to be handled separately for the separate
	   address-spaces we now have */
1309 1310
	if ( page == PR_PRIVATE || page == PR_SHARED ) page = 0;
	/* FIXME: Handle flags in some way */
1311
	address = (LPVOID )(page * psize);
1312
	ret = VirtualAlloc ( address, ( npages * psize ), MEM_RESERVE, 0 );
1313
	TRACE("PageReserve: returning: %08lx\n", (DWORD )ret );
1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324
	if ( ret == NULL )
	  return -1;
	else
	  return (DWORD )ret;
      }

    case 0x0001: /* PageCommit */
      {
	LPVOID address;
	LPVOID ret;
	DWORD virt_perm;
1325
	DWORD psize = getpagesize();
1326 1327 1328 1329 1330 1331
	ULONG page   = (ULONG) stack32_pop( context );
	ULONG npages = (ULONG) stack32_pop( context );
	ULONG hpd  = (ULONG) stack32_pop( context );
	ULONG pagerdata   = (ULONG) stack32_pop( context );
	ULONG flags  = (ULONG) stack32_pop( context );

1332
	TRACE("PageCommit: page: %08lx, npages: %08lx, hpd: %08lx pagerdata: "
1333 1334
	      "%08lx, flags: %08lx partial stub\n",
	      page, npages, hpd, pagerdata, flags );
1335

1336 1337 1338 1339 1340 1341 1342 1343
	if ( flags & PC_USER )
	  if ( flags & PC_WRITEABLE )
	    virt_perm = PAGE_EXECUTE_READWRITE;
	  else
	    virt_perm = PAGE_EXECUTE_READ;
	else
	  virt_perm = PAGE_NOACCESS;

1344
	address = (LPVOID )(page * psize);
1345
	ret = VirtualAlloc ( address, ( npages * psize ), MEM_COMMIT, virt_perm );
1346
	TRACE("PageCommit: Returning: %08lx\n", (DWORD )ret );
1347 1348 1349 1350 1351 1352 1353
	return (DWORD )ret;

      }
    case 0x0002: /* PageDecommit */
      {
	LPVOID address;
	BOOL ret;
1354
	DWORD psize = getpagesize();
1355 1356 1357 1358
	ULONG page = (ULONG) stack32_pop( context );
	ULONG npages = (ULONG) stack32_pop( context );
	ULONG flags = (ULONG) stack32_pop( context );

1359
	TRACE("PageDecommit: page: %08lx, npages: %08lx, flags: %08lx partial stub\n",
1360 1361
	      page, npages, flags );
	address = (LPVOID )( page * psize );
1362
	ret = VirtualFree ( address, ( npages * psize ), MEM_DECOMMIT );
1363
	TRACE("PageDecommit: Returning: %s\n", ret ? "TRUE" : "FALSE" );
1364 1365 1366
	return ret;
      }
    case 0x000d: /* PageModifyPermissions */
1367
      {
1368 1369 1370 1371 1372 1373
	DWORD pg_old_perm;
	DWORD pg_new_perm;
	DWORD virt_old_perm;
	DWORD virt_new_perm;
	MEMORY_BASIC_INFORMATION mbi;
	LPVOID address;
1374
	DWORD psize = getpagesize();
1375 1376 1377 1378 1379
	ULONG page = stack32_pop ( context );
	ULONG npages = stack32_pop ( context );
	ULONG permand = stack32_pop ( context );
	ULONG permor = stack32_pop ( context );

1380
	TRACE("PageModifyPermissions %08lx %08lx %08lx %08lx partial stub\n",
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397
	      page, npages, permand, permor );
	address = (LPVOID )( page * psize );

	VirtualQuery ( address, &mbi, sizeof ( MEMORY_BASIC_INFORMATION ));
	virt_old_perm = mbi.Protect;

	switch ( virt_old_perm & mbi.Protect ) {
	case PAGE_READONLY:
	case PAGE_EXECUTE:
	case PAGE_EXECUTE_READ:
	  pg_old_perm = PC_USER;
	  break;
	case PAGE_READWRITE:
	case PAGE_WRITECOPY:
	case PAGE_EXECUTE_READWRITE:
	case PAGE_EXECUTE_WRITECOPY:
	  pg_old_perm = PC_USER | PC_WRITEABLE;
1398
	  break;
1399 1400 1401 1402
	case PAGE_NOACCESS:
	default:
	  pg_old_perm = 0;
	  break;
1403
	}
1404 1405 1406 1407 1408 1409
	pg_new_perm = pg_old_perm;
	pg_new_perm &= permand & ~PC_STATIC;
	pg_new_perm |= permor  & ~PC_STATIC;

	virt_new_perm = ( virt_old_perm )  & ~0xff;
	if ( pg_new_perm & PC_USER )
1410
	{
1411 1412 1413 1414
	  if ( pg_new_perm & PC_WRITEABLE )
	    virt_new_perm |= PAGE_EXECUTE_READWRITE;
	  else
	    virt_new_perm |= PAGE_EXECUTE_READ;
1415
	}
1416

1417 1418 1419 1420
	if ( ! VirtualProtect ( address, ( npages * psize ), virt_new_perm, &virt_old_perm ) ) {
	  ERR("Can't change page permissions for %08lx\n", (DWORD )address );
	  return 0xffffffff;
	}
1421
	TRACE("Returning: %08lx\n", pg_old_perm );
1422 1423 1424 1425 1426 1427 1428
	return pg_old_perm;
      }
    case 0x000a: /* PageFree */
      {
	BOOL ret;
	LPVOID hmem = (LPVOID) stack32_pop( context );
	DWORD flags = (DWORD ) stack32_pop( context );
1429

1430
	TRACE("PageFree: hmem: %08lx, flags: %08lx partial stub\n",
1431 1432 1433
	      (DWORD )hmem, flags );

	ret = VirtualFree ( hmem, 0, MEM_RELEASE );
1434
	context->Eax = ret;
1435
	TRACE("Returning: %d\n", ret );
1436 1437 1438

	return 0;
      }
1439 1440 1441
    case 0x001e: /* GetDemandPageInfo */
      {
	 DWORD dinfo = (DWORD)stack32_pop( context );
1442
         DWORD flags = (DWORD)stack32_pop( context );
1443

1444 1445 1446 1447 1448 1449 1450
	 /* GetDemandPageInfo is supposed to fill out the struct at
          * "dinfo" with various low-level memory management information.
          * Apps are certainly not supposed to call this, although it's
          * demoed and documented by Pietrek on pages 441-443 of "Windows
          * 95 System Programming Secrets" if any program needs a real
          * implementation of this.
	  */
Alexandre Julliard's avatar
Alexandre Julliard committed
1451

1452 1453 1454 1455
	 FIXME("GetDemandPageInfo(%08lx %08lx): stub!\n", dinfo, flags);

	 return 0;
      }
Alexandre Julliard's avatar
Alexandre Julliard committed
1456 1457
    default:
        if (LOWORD(service) < N_VMM_SERVICE)
1458
            FIXME( "Unimplemented service %s (%08lx)\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
1459 1460
                          VMM_Service_Name[LOWORD(service)], service);
        else
1461
            FIXME( "Unknown service %08lx\n", service);
Alexandre Julliard's avatar
Alexandre Julliard committed
1462 1463 1464
        break;
    }

1465
    return 0xffffffff;  /* FIXME */
Alexandre Julliard's avatar
Alexandre Julliard committed
1466 1467
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1468 1469 1470
/***********************************************************************
 *           DeviceIo_IFSMgr
 * NOTES
1471
 *   These ioctls are used by 'MSNET32.DLL'.
Alexandre Julliard's avatar
Alexandre Julliard committed
1472
 *
1473
 *   I have been unable to uncover any documentation about the ioctls so
Alexandre Julliard's avatar
Alexandre Julliard committed
1474
 *   the implementation of the cases IFS_IOCTL_21 and IFS_IOCTL_2F are
1475
 *   based on reasonable guesses on information found in the Windows 95 DDK.
1476
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1477 1478
 */

1479 1480 1481 1482 1483 1484 1485 1486 1487
/*
 * IFSMgr DeviceIO service
 */

#define IFS_IOCTL_21                100
#define IFS_IOCTL_2F                101
#define	IFS_IOCTL_GET_RES           102
#define IFS_IOCTL_GET_NETPRO_NAME_A 103

Alexandre Julliard's avatar
Alexandre Julliard committed
1488 1489
struct win32apireq {
	unsigned long 	ar_proid;
1490 1491 1492 1493 1494
	unsigned long  	ar_eax;
	unsigned long  	ar_ebx;
	unsigned long  	ar_ecx;
	unsigned long  	ar_edx;
	unsigned long  	ar_esi;
Alexandre Julliard's avatar
Alexandre Julliard committed
1495
	unsigned long  	ar_edi;
1496
	unsigned long  	ar_ebp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1497 1498 1499 1500
	unsigned short 	ar_error;
	unsigned short  ar_pad;
};

1501
static void win32apieq_2_CONTEXT(struct win32apireq *pIn,CONTEXT86 *pCxt)
Alexandre Julliard's avatar
Alexandre Julliard committed
1502
{
1503
	memset(pCxt,0,sizeof(*pCxt));
Alexandre Julliard's avatar
Alexandre Julliard committed
1504

1505
	pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
Alexandre Julliard's avatar
Alexandre Julliard committed
1506 1507 1508 1509 1510 1511 1512
	pCxt->Eax = pIn->ar_eax;
	pCxt->Ebx = pIn->ar_ebx;
	pCxt->Ecx = pIn->ar_ecx;
	pCxt->Edx = pIn->ar_edx;
	pCxt->Esi = pIn->ar_esi;
	pCxt->Edi = pIn->ar_edi;

1513
	/* FIXME: Only partial CONTEXT86_CONTROL */
Alexandre Julliard's avatar
Alexandre Julliard committed
1514 1515 1516 1517 1518 1519 1520
	pCxt->Ebp = pIn->ar_ebp;

	/* FIXME: pIn->ar_proid ignored */
	/* FIXME: pIn->ar_error ignored */
	/* FIXME: pIn->ar_pad ignored */
}

1521
static void CONTEXT_2_win32apieq(CONTEXT86 *pCxt,struct win32apireq *pOut)
Alexandre Julliard's avatar
Alexandre Julliard committed
1522 1523 1524 1525 1526 1527 1528 1529 1530 1531
{
	memset(pOut,0,sizeof(struct win32apireq));

	pOut->ar_eax = pCxt->Eax;
	pOut->ar_ebx = pCxt->Ebx;
	pOut->ar_ecx = pCxt->Ecx;
	pOut->ar_edx = pCxt->Edx;
	pOut->ar_esi = pCxt->Esi;
	pOut->ar_edi = pCxt->Edi;

1532
	/* FIXME: Only partial CONTEXT86_CONTROL */
Alexandre Julliard's avatar
Alexandre Julliard committed
1533 1534 1535 1536 1537 1538 1539
	pOut->ar_ebp = pCxt->Ebp;

	/* FIXME: pOut->ar_proid ignored */
	/* FIXME: pOut->ar_error ignored */
	/* FIXME: pOut->ar_pad ignored */
}

1540
static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
Alexandre Julliard's avatar
Alexandre Julliard committed
1541 1542 1543 1544
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped)
{
1545
    BOOL retv = TRUE;
1546
	TRACE("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
1547
			dwIoControlCode,
Alexandre Julliard's avatar
Alexandre Julliard committed
1548 1549 1550 1551 1552 1553 1554 1555 1556
			lpvInBuffer,cbInBuffer,
			lpvOutBuffer,cbOutBuffer,
			lpcbBytesReturned,
			lpOverlapped);

    switch (dwIoControlCode)
    {
	case IFS_IOCTL_21:
	case IFS_IOCTL_2F:{
1557
		CONTEXT86 cxt;
Alexandre Julliard's avatar
Alexandre Julliard committed
1558 1559 1560
		struct win32apireq *pIn=(struct win32apireq *) lpvInBuffer;
		struct win32apireq *pOut=(struct win32apireq *) lpvOutBuffer;

1561
		TRACE(
Alexandre Julliard's avatar
Alexandre Julliard committed
1562 1563 1564 1565 1566 1567 1568 1569
			"Control '%s': "
			"proid=0x%08lx, eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
			"edx=0x%08lx, esi=0x%08lx, edi=0x%08lx, ebp=0x%08lx, "
			"error=0x%04x, pad=0x%04x\n",
			(dwIoControlCode==IFS_IOCTL_21)?"IFS_IOCTL_21":"IFS_IOCTL_2F",
			pIn->ar_proid, pIn->ar_eax, pIn->ar_ebx, pIn->ar_ecx,
			pIn->ar_edx, pIn->ar_esi, pIn->ar_edi, pIn->ar_ebp,
			pIn->ar_error, pIn->ar_pad
1570 1571
		);

Alexandre Julliard's avatar
Alexandre Julliard committed
1572 1573 1574 1575 1576 1577 1578 1579
		win32apieq_2_CONTEXT(pIn,&cxt);

		if(dwIoControlCode==IFS_IOCTL_21)
		{
			DOS3Call(&cxt); /* Call int 21h */
		} else {
			INT_Int2fHandler(&cxt); /* Call int 2Fh */
		}
1580

Alexandre Julliard's avatar
Alexandre Julliard committed
1581
		CONTEXT_2_win32apieq(&cxt,pOut);
1582

Alexandre Julliard's avatar
Alexandre Julliard committed
1583 1584 1585
        retv = TRUE;
	} break;
	case IFS_IOCTL_GET_RES:{
1586
        FIXME( "Control 'IFS_IOCTL_GET_RES' not implemented\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1587 1588 1589
        retv = FALSE;
	} break;
	case IFS_IOCTL_GET_NETPRO_NAME_A:{
1590
        FIXME( "Control 'IFS_IOCTL_GET_NETPRO_NAME_A' not implemented\n");
Alexandre Julliard's avatar
Alexandre Julliard committed
1591
        retv = FALSE;
1592
	} break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1593
    default:
1594
        FIXME( "Control %ld not implemented\n", dwIoControlCode);
Alexandre Julliard's avatar
Alexandre Julliard committed
1595 1596 1597 1598 1599
        retv = FALSE;
    }

    return retv;
}
1600

1601 1602 1603 1604
/********************************************************************************
 *      VxDCall_VWin32
 *
 *  Service numbers taken from page 448 of Pietrek's "Windows 95 System
1605
 *  Programming Secrets".  Parameters from experimentation on real Win98.
1606 1607 1608
 *
 */

1609
static DWORD VxDCall_VWin32( DWORD service, CONTEXT86 *context )
1610 1611 1612 1613 1614
{
  switch ( LOWORD(service) )
    {
    case 0x0000: /* GetVersion */
    {
1615 1616
        DWORD vers = GetVersion();
        return (LOBYTE(vers) << 8) | HIBYTE(vers);
1617 1618 1619
    }
    break;

1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637
    case 0x0020: /* Get VMCPD Version */
    {
	DWORD parm = (DWORD) stack32_pop(context);

	FIXME("Get VMCPD Version(%08lx): partial stub!\n", parm);

	/* FIXME: This is what Win98 returns, it may
         *        not be correct in all situations.
         *        It makes Bleem! happy though.
         */

	return 0x0405;
    }

    case 0x0029: /* Int31/DPMI dispatch */
    {
	DWORD callnum = (DWORD) stack32_pop(context);
        DWORD parm    = (DWORD) stack32_pop(context);
1638

1639 1640
        TRACE("Int31/DPMI dispatch(%08lx)\n", callnum);

1641 1642
	SET_AX( context, callnum );
        SET_CX( context, parm );
1643 1644
	INT_Int31Handler(context);

1645
	return LOWORD(context->Eax);
1646 1647 1648
    }
    break;

1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663
    case 0x002a: /* Int41 dispatch - parm = int41 service number */
    {
	DWORD callnum = (DWORD) stack32_pop(context);

	return callnum; /* FIXME: should really call INT_Int41Handler() */
    }
    break;

    default:
      FIXME("Unknown VWin32 service %08lx\n", service);
      break;
    }

  return 0xffffffff;
}
1664

1665

1666 1667 1668
/***********************************************************************
 *           DeviceIo_VCD
 */
1669
static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped)
{
    BOOL retv = TRUE;

    switch (dwIoControlCode)
    {
    case IOCTL_SERIAL_LSRMST_INSERT:
    {
        FIXME( "IOCTL_SERIAL_LSRMST_INSERT NIY !\n");
        retv = FALSE;
    }
    break;

    default:
        FIXME( "Unknown Control %ld\n", dwIoControlCode);
        retv = FALSE;
        break;
    }

    return retv;
}

1695

1696 1697 1698 1699
/***********************************************************************
 *           DeviceIo_VWin32
 */

1700
static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
1701
{
1702
    memset( pCxt, 0, sizeof(*pCxt) );
1703 1704 1705
    /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN
             will interpret 32-bit register contents as linear pointers */

1706
    pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
1707 1708 1709 1710 1711 1712 1713
    pCxt->Eax = pIn->reg_EAX;
    pCxt->Ebx = pIn->reg_EBX;
    pCxt->Ecx = pIn->reg_ECX;
    pCxt->Edx = pIn->reg_EDX;
    pCxt->Esi = pIn->reg_ESI;
    pCxt->Edi = pIn->reg_EDI;

1714
    /* FIXME: Only partial CONTEXT86_CONTROL */
1715 1716 1717
    pCxt->EFlags = pIn->reg_Flags;
}

1718
static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut )
1719 1720 1721 1722 1723 1724 1725 1726 1727 1728
{
    memset( pOut, 0, sizeof(DIOC_REGISTERS) );

    pOut->reg_EAX = pCxt->Eax;
    pOut->reg_EBX = pCxt->Ebx;
    pOut->reg_ECX = pCxt->Ecx;
    pOut->reg_EDX = pCxt->Edx;
    pOut->reg_ESI = pCxt->Esi;
    pOut->reg_EDI = pCxt->Edi;

1729
    /* FIXME: Only partial CONTEXT86_CONTROL */
1730 1731 1732
    pOut->reg_Flags = pCxt->EFlags;
}

1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
#define DIOC_AH(regs) (((unsigned char*)&((regs)->reg_EAX))[1])
#define DIOC_AL(regs) (((unsigned char*)&((regs)->reg_EAX))[0])
#define DIOC_BH(regs) (((unsigned char*)&((regs)->reg_EBX))[1])
#define DIOC_BL(regs) (((unsigned char*)&((regs)->reg_EBX))[0])
#define DIOC_DH(regs) (((unsigned char*)&((regs)->reg_EDX))[1])
#define DIOC_DL(regs) (((unsigned char*)&((regs)->reg_EDX))[0])

#define DIOC_AX(regs) (((unsigned short*)&((regs)->reg_EAX))[0])
#define DIOC_BX(regs) (((unsigned short*)&((regs)->reg_EBX))[0])
#define DIOC_CX(regs) (((unsigned short*)&((regs)->reg_ECX))[0])
#define DIOC_DX(regs) (((unsigned short*)&((regs)->reg_EDX))[0])

#define DIOC_SET_CARRY(regs) (((regs)->reg_Flags)|=0x00000001)

static const DWORD VWIN32_DriveTypeInfo[7]={
    0x0000, /* none */
    0x2709, /* 360 K */
    0x4f0f, /* 1.2 M */
    0x4f09, /* 720 K */
    0x4f12, /* 1.44 M */
    0x4f24, /* 2.88 M */
    0x4f24  /* 2.88 M */
};

/**********************************************************************
 *	    VWIN32_ReadFloppyParams
 *
 * Handler for int 13h (disk I/O).
 */
static VOID VWIN32_ReadFloppyParams(DIOC_REGISTERS *regs)
{
#ifdef linux
Gerald Pfeifer's avatar
Gerald Pfeifer committed
1765 1766 1767 1768 1769 1770
    static BYTE floppy_params[2][13] =
    {
        { 0xaf, 0x02, 0x25, 0x02, 0x12, 0x1b, 0xff, 0x6c, 0xf6, 0x0f, 0x08 },
        { 0xaf, 0x02, 0x25, 0x02, 0x12, 0x1b, 0xff, 0x6c, 0xf6, 0x0f, 0x08 }
    };

1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954
    unsigned int i, nr_of_drives = 0;
    BYTE drive_nr = DIOC_DL(regs);
    int floppy_fd,r;
    struct floppy_drive_params floppy_parm;
    char root[] = "A:\\";

    TRACE("in  [ EDX=%08lx ]\n", regs->reg_EDX );

    DIOC_AH(regs) = 0x00; /* success */

    for (i = 0; i < MAX_DOS_DRIVES; i++, root[0]++)
        if (GetDriveTypeA(root) == DRIVE_REMOVABLE) nr_of_drives++;
    DIOC_DL(regs) = nr_of_drives;

    if (drive_nr > 1) { /* invalid drive ? */
        DIOC_BX(regs) = 0;
        DIOC_CX(regs) = 0;
        DIOC_DH(regs) = 0;
        DIOC_SET_CARRY(regs);
        return;
    }

    if ( (floppy_fd = DRIVE_OpenDevice( drive_nr, O_NONBLOCK)) == -1)
    {
        WARN("Can't determine floppy geometry !\n");
        DIOC_BX(regs) = 0;
        DIOC_CX(regs) = 0;
        DIOC_DH(regs) = 0;
        DIOC_SET_CARRY(regs);
        return;
    }
    r = ioctl(floppy_fd, FDGETDRVPRM, &floppy_parm);

    close(floppy_fd);

    if(r<0)
    {
        DIOC_SET_CARRY(regs);
        return;
    }

    regs->reg_ECX = 0;
    DIOC_AL(regs) = 0;
    DIOC_BL(regs) = floppy_parm.cmos;

    /* CH = low eight bits of max cyl
       CL = max sec nr (bits 5-0),
       hi two bits of max cyl (bits 7-6)
       DH = max head nr */
    if(DIOC_BL(regs) && (DIOC_BL(regs)<7))
    {
        DIOC_DH(regs) = 0x01;
        DIOC_CX(regs) = VWIN32_DriveTypeInfo[DIOC_BL(regs)];
    }
    else
    {
        DIOC_CX(regs) = 0x0;
        DIOC_DX(regs) = 0x0;
    }

    regs->reg_EDI = (DWORD)floppy_params[drive_nr];

    if(!regs->reg_EDI)
    {
        ERR("Get floppy params failed for drive %d\n",drive_nr);
        DIOC_SET_CARRY(regs);
    }

    TRACE("out [ EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx EDI=%08lx ]\n",
          regs->reg_EAX, regs->reg_EBX, regs->reg_ECX, regs->reg_EDX, regs->reg_EDI);

    /* FIXME: Word exits quietly if we return with no error. Why? */
    FIXME("Returned ERROR!\n");
    DIOC_SET_CARRY(regs);

#else
    DIOC_AH(regs) = 0x01;
    DIOC_SET_CARRY(regs);
#endif
}

/**********************************************************************
 *	    VWIN32_Int13Handler
 *
 * Handler for VWIN32_DIOC_DOS_INT13 (disk I/O).
 */
static VOID VWIN32_Int13Handler( DIOC_REGISTERS *regs)
{
    TRACE("AH=%02x\n",DIOC_AH(regs));
    switch(DIOC_AH(regs)) /* AH */
    {
    case 0x00:             /* RESET DISK SYSTEM     */
        break; /* no return ? */

    case 0x01:             /* STATUS OF DISK SYSTEM */
        DIOC_AL(regs) = 0; /* successful completion */
        break;

    case 0x02:             /* READ SECTORS INTO MEMORY */
        DIOC_AL(regs) = 0; /* number of sectors read */
        DIOC_AH(regs) = 0; /* status */
        break;

    case 0x03:             /* WRITE SECTORS FROM MEMORY */
        break; /* no return ? */

    case 0x04:             /* VERIFY DISK SECTOR(S) */
        DIOC_AL(regs) = 0; /* number of sectors verified */
        DIOC_AH(regs) = 0;
        break;

    case 0x05:             /* FORMAT TRACK */
    case 0x06:             /* FORMAT TRACK AND SET BAD SECTOR FLAGS */
    case 0x07:             /* FORMAT DRIVE STARTING AT GIVEN TRACK  */
        /* despite what Ralf Brown says, 0x06 and 0x07 seem to
         * set CFLAG, too (at least my BIOS does that) */
        DIOC_AH(regs) = 0x0c;
        DIOC_SET_CARRY(regs);
        break;

    case 0x08:             /* GET DRIVE PARAMETERS  */
        if (DIOC_DL(regs) & 0x80) { /* hard disk ? */
            DIOC_AH(regs) = 0x07;
            DIOC_SET_CARRY(regs);
        }
        else  /* floppy disk */
            VWIN32_ReadFloppyParams(regs);
        break;

    case 0x09:         /* INITIALIZE CONTROLLER WITH DRIVE PARAMETERS */
    case 0x0a:         /* FIXED DISK - READ LONG (XT,AT,XT286,PS)     */
    case 0x0b:         /* FIXED DISK - WRITE LONG (XT,AT,XT286,PS)    */
    case 0x0c:         /* SEEK TO CYLINDER                            */
    case 0x0d:         /* ALTERNATE RESET HARD DISKS                  */
    case 0x10:         /* CHECK IF DRIVE READY                        */
    case 0x11:         /* RECALIBRATE DRIVE                           */
    case 0x14:         /* CONTROLLER INTERNAL DIAGNOSTIC              */
        DIOC_AH(regs) = 0;
        break;

    case 0x15:         /* GET DISK TYPE (AT,XT2,XT286,CONV,PS) */
        if (DIOC_DL(regs) & 0x80) { /* hard disk ? */
            DIOC_AH(regs) = 3; /* fixed disk */
            DIOC_SET_CARRY(regs);
        }
        else { /* floppy disk ? */
            DIOC_AH(regs) = 2; /* floppy with change detection */
            DIOC_SET_CARRY(regs);
        }
        break;

    case 0x0e:         /* READ SECTOR BUFFER (XT only)      */
    case 0x0f:         /* WRITE SECTOR BUFFER (XT only)     */
    case 0x12:         /* CONTROLLER RAM DIAGNOSTIC (XT,PS) */
    case 0x13:         /* DRIVE DIAGNOSTIC (XT,PS)          */
        DIOC_AH(regs) = 0x01;
        DIOC_SET_CARRY(regs);
        break;

    case 0x16:         /* FLOPPY - CHANGE OF DISK STATUS */
        DIOC_AH(regs) = 0; /* FIXME - no change */
        break;

    case 0x17:         /* SET DISK TYPE FOR FORMAT */
        if (DIOC_DL(regs) < 4)
            DIOC_AH(regs) = 0x00; /* successful completion */
        else
            DIOC_AH(regs) = 0x01; /* error */
        break;

    case 0x18:         /* SET MEDIA TYPE FOR FORMAT */
        if (DIOC_DL(regs) < 4)
            DIOC_AH(regs) = 0x00; /* successful completion */
        else
            DIOC_AH(regs) = 0x01; /* error */
        break;

    case 0x19:       /* FIXED DISK - PARK HEADS */
        break;

    default:
        FIXME("Unknown VWIN32 INT13 call AX=%04X\n",DIOC_AX(regs));
    }
}
1955

1956
static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
1957 1958 1959 1960 1961
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped)
{
1962
    BOOL retv = TRUE;
1963 1964 1965 1966

    switch (dwIoControlCode)
    {
    case VWIN32_DIOC_DOS_INT13:
1967 1968 1969 1970 1971 1972 1973 1974 1975 1976
    {
        DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
        DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;

        memcpy(pOut, pIn, sizeof (DIOC_REGISTERS));
        VWIN32_Int13Handler(pOut);
        break;
    }

    case VWIN32_DIOC_DOS_IOCTL:
1977
    case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
1978 1979
    case VWIN32_DIOC_DOS_INT25:
    case VWIN32_DIOC_DOS_INT26:
1980
    case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
1981
    case VWIN32_DIOC_DOS_DRIVEINFO:
1982
    {
1983
        CONTEXT86 cxt;
1984 1985 1986
        DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
        DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;

1987 1988
        TRACE( "Control '%s': "
               "eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
1989
               "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx \n",
1990 1991
               (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" :
               (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" :
1992
               (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" :
1993
               (dwIoControlCode == VWIN32_DIOC_DOS_DRIVEINFO)? "VWIN32_DIOC_DOS_DRIVEINFO" :  "???",
1994 1995
               pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX,
               pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI );
1996 1997 1998 1999 2000 2001

        DIOCRegs_2_CONTEXT( pIn, &cxt );

        switch (dwIoControlCode)
        {
        case VWIN32_DIOC_DOS_IOCTL: DOS3Call( &cxt ); break; /* Call int 21h */
2002 2003 2004
        case VWIN32_DIOC_DOS_INT13: INT_Int13Handler( &cxt ); break;
        case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
				    DOS3Call( &cxt ); break;
2005 2006
        case VWIN32_DIOC_DOS_INT25: INT_Int25Handler( &cxt ); break;
        case VWIN32_DIOC_DOS_INT26: INT_Int26Handler( &cxt ); break;
2007 2008
        case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
				    INT_Int31Handler( &cxt ); break;
2009
        case VWIN32_DIOC_DOS_DRIVEINFO:	DOS3Call( &cxt ); break; /* Call int 21h 730x */
2010 2011 2012 2013 2014 2015 2016
        }

        CONTEXT_2_DIOCRegs( &cxt, pOut );
    }
    break;

    case VWIN32_DIOC_SIMCTRLC:
2017
        FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n");
2018 2019 2020 2021
        retv = FALSE;
        break;

    default:
2022
        FIXME( "Unknown Control %ld\n", dwIoControlCode);
2023 2024 2025 2026 2027 2028 2029
        retv = FALSE;
        break;
    }

    return retv;
}

2030
/* this is the main multimedia device loader */
2031
static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
2032 2033 2034 2035 2036
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped)
{
2037
	FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052
	    dwIoControlCode,
	    lpvInBuffer,cbInBuffer,
	    lpvOutBuffer,cbOutBuffer,
	    lpcbBytesReturned,
	    lpOverlapped
	);
	switch (dwIoControlCode) {
	case 5:
		/* Hmm. */
		*(DWORD*)lpvOutBuffer=0;
		*lpcbBytesReturned=4;
		return TRUE;
	}
	return FALSE;
}
2053
/* this is used by some Origin games */
2054
static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
2055 2056 2057 2058 2059 2060 2061 2062 2063 2064
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped)
{
	switch (dwIoControlCode) {
	case 1:	/* version */
		*(LPDWORD)lpvOutBuffer = 0x20004; /* WC SecretOps */
		break;
	case 9: /* debug output */
2065
		ERR("MONODEBG: %s\n",debugstr_a(lpvInBuffer));
2066 2067
		break;
	default:
2068
		FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
2069
			dwIoControlCode,
2070 2071 2072 2073 2074 2075 2076 2077 2078
			lpvInBuffer,cbInBuffer,
			lpvOutBuffer,cbOutBuffer,
			lpcbBytesReturned,
			lpOverlapped
		);
		break;
	}
	return TRUE;
}
2079
/* pccard */
2080
static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100
			      LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped)
{
	switch (dwIoControlCode) {
	case 0x0000: /* PCCARD_Get_Version */
	case 0x0001: /* PCCARD_Card_Services */
	default:
		FIXME( "(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
			dwIoControlCode,
			lpvInBuffer,cbInBuffer,
			lpvOutBuffer,cbOutBuffer,
			lpcbBytesReturned,
			lpOverlapped
		);
		break;
	}
	return FALSE;
}
2101

2102
/***********************************************************************
2103
 *		OpenVxDHandle (KERNEL32.@)
2104 2105 2106 2107 2108
 *
 *	This function is supposed to return the corresponding Ring 0
 *	("kernel") handle for a Ring 3 handle in Win9x.
 *	Evidently, Wine will have problems with this. But we try anyway,
 *	maybe it helps...
2109
 */
2110
HANDLE	WINAPI	OpenVxDHandle(HANDLE hHandleRing3)
2111
{
Gerald Pfeifer's avatar
Gerald Pfeifer committed
2112
	FIXME( "(0x%08x), stub! (returning Ring 3 handle instead of Ring 0)\n", hHandleRing3);
2113
	return hHandleRing3;
2114
}
2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130

static BOOL DeviceIo_HASP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
			      LPVOID lpvOutBuffer, DWORD cbOutBuffer,
			      LPDWORD lpcbBytesReturned,
			      LPOVERLAPPED lpOverlapped)
{
    BOOL retv = TRUE;
	FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
			dwIoControlCode,
			lpvInBuffer,cbInBuffer,
			lpvOutBuffer,cbOutBuffer,
			lpcbBytesReturned,
			lpOverlapped);

    return retv;
}