Always try to load the 32-bit owner dll instead of directly loading
[wine] / dlls / kernel / 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 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30 #include <sys/types.h>
31 #ifdef HAVE_SYS_SOCKET_H
32 # include <sys/socket.h>
33 #endif
34 #ifdef HAVE_NETINET_IN_H
35 # include <netinet/in.h>
36 #endif
37 #ifdef HAVE_ARPA_INET_H
38 # include <arpa/inet.h>
39 #endif
40 #include <string.h>
41 #include <stdarg.h>
42 #include <time.h>
43
44 #include "ntstatus.h"
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winreg.h"
48 #include "winerror.h"
49 #include "winnls.h"
50 #include "file.h"
51 #include "winioctl.h"
52 #include "winnt.h"
53 #include "iphlpapi.h"
54 #include "kernel_private.h"
55 #include "wine/server.h"
56 #include "wine/debug.h"
57
58 WINE_DEFAULT_DEBUG_CHANNEL(file);
59
60
61 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode,
62                               LPVOID lpvInBuffer, DWORD cbInBuffer,
63                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
64                               LPDWORD lpcbBytesReturned,
65                               LPOVERLAPPED lpOverlapped);
66 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
67                               LPVOID lpvInBuffer, DWORD cbInBuffer,
68                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
69                               LPDWORD lpcbBytesReturned,
70                               LPOVERLAPPED lpOverlapped);
71 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
72                               LPVOID lpvInBuffer, DWORD cbInBuffer,
73                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
74                               LPDWORD lpcbBytesReturned,
75                               LPOVERLAPPED lpOverlapped);
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 BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
90                               LPVOID lpvInBuffer, DWORD cbInBuffer,
91                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
92                               LPDWORD lpcbBytesReturned,
93                               LPOVERLAPPED lpOverlapped);
94
95 static BOOL DeviceIo_DHCP(DWORD dwIoControlCode,
96                               LPVOID lpvInBuffer, DWORD cbInBuffer,
97                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
98                               LPDWORD lpcbBytesReturned,
99                               LPOVERLAPPED lpOverlapped);
100
101 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
102                               LPVOID lpvInBuffer, DWORD cbInBuffer,
103                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
104                               LPDWORD lpcbBytesReturned,
105                               LPOVERLAPPED lpOverlapped);
106
107 static BOOL DeviceIo_HASP (DWORD dwIoControlCode,
108                               LPVOID lpvInBuffer, DWORD cbInBuffer,
109                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
110                               LPDWORD lpcbBytesReturned,
111                               LPOVERLAPPED lpOverlapped);
112
113 static BOOL DeviceIo_NetBIOS(DWORD dwIoControlCode,
114                               LPVOID lpvInBuffer, DWORD cbInBuffer,
115                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
116                               LPDWORD lpcbBytesReturned,
117                               LPOVERLAPPED lpOverlapped);
118
119 static BOOL DeviceIo_VNB(DWORD dwIoControlCode,
120                               LPVOID lpvInBuffer, DWORD cbInBuffer,
121                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
122                               LPDWORD lpcbBytesReturned,
123                               LPOVERLAPPED lpOverlapped);
124
125 /*
126  * VxD names are taken from the Win95 DDK
127  */
128
129 struct VxDInfo
130 {
131     LPCSTR  name;
132     WORD    id;
133     BOOL  (*deviceio)(DWORD, LPVOID, DWORD,
134                         LPVOID, DWORD, LPDWORD, LPOVERLAPPED);
135 };
136
137 static const struct VxDInfo VxDList[] =
138 {
139     /* Standard VxD IDs */
140     { "VMM",      0x0001, NULL },
141     { "DEBUG",    0x0002, NULL },
142     { "VPICD",    0x0003, NULL },
143     { "VDMAD",    0x0004, NULL },
144     { "VTD",      0x0005, NULL },
145     { "V86MMGR",  0x0006, NULL },
146     { "PAGESWAP", 0x0007, NULL },
147     { "PARITY",   0x0008, NULL },
148     { "REBOOT",   0x0009, NULL },
149     { "VDD",      0x000A, NULL },
150     { "VSD",      0x000B, NULL },
151     { "VMD",      0x000C, NULL },
152     { "VKD",      0x000D, NULL },
153     { "VCD",      0x000E, DeviceIo_VCD },
154     { "VPD",      0x000F, NULL },
155     { "BLOCKDEV", 0x0010, NULL },
156     { "VMCPD",    0x0011, NULL },
157     { "EBIOS",    0x0012, NULL },
158     { "BIOSXLAT", 0x0013, NULL },
159     { "VNETBIOS", 0x0014, DeviceIo_NetBIOS },
160     { "DOSMGR",   0x0015, NULL },
161     { "WINLOAD",  0x0016, NULL },
162     { "SHELL",    0x0017, NULL },
163     { "VMPOLL",   0x0018, NULL },
164     { "VPROD",    0x0019, NULL },
165     { "DOSNET",   0x001A, NULL },
166     { "VFD",      0x001B, NULL },
167     { "VDD2",     0x001C, NULL },
168     { "WINDEBUG", 0x001D, NULL },
169     { "TSRLOAD",  0x001E, NULL },
170     { "BIOSHOOK", 0x001F, NULL },
171     { "INT13",    0x0020, NULL },
172     { "PAGEFILE", 0x0021, NULL },
173     { "SCSI",     0x0022, NULL },
174     { "MCA_POS",  0x0023, NULL },
175     { "SCSIFD",   0x0024, NULL },
176     { "VPEND",    0x0025, NULL },
177     { "VPOWERD",  0x0026, NULL },
178     { "VXDLDR",   0x0027, NULL },
179     { "NDIS",     0x0028, NULL },
180     { "BIOS_EXT", 0x0029, NULL },
181     { "VWIN32",   0x002A, DeviceIo_VWin32 },
182     { "VCOMM",    0x002B, NULL },
183     { "SPOOLER",  0x002C, NULL },
184     { "WIN32S",   0x002D, NULL },
185     { "DEBUGCMD", 0x002E, NULL },
186
187     { "VNB",      0x0031, DeviceIo_VNB },
188     { "SERVER",   0x0032, NULL },
189     { "CONFIGMG", 0x0033, NULL },
190     { "DWCFGMG",  0x0034, NULL },
191     { "SCSIPORT", 0x0035, NULL },
192     { "VFBACKUP", 0x0036, NULL },
193     { "ENABLE",   0x0037, NULL },
194     { "VCOND",    0x0038, NULL },
195
196     { "EFAX",     0x003A, NULL },
197     { "DSVXD",    0x003B, NULL },
198     { "ISAPNP",   0x003C, NULL },
199     { "BIOS",     0x003D, NULL },
200     { "WINSOCK",  0x003E, NULL },
201     { "WSOCK",    0x003E, NULL },
202     { "WSIPX",    0x003F, NULL },
203     { "IFSMgr",   0x0040, DeviceIo_IFSMgr },
204     { "VCDFSD",   0x0041, NULL },
205     { "MRCI2",    0x0042, NULL },
206     { "PCI",      0x0043, NULL },
207     { "PELOADER", 0x0044, NULL },
208     { "EISA",     0x0045, NULL },
209     { "DRAGCLI",  0x0046, NULL },
210     { "DRAGSRV",  0x0047, NULL },
211     { "PERF",     0x0048, NULL },
212     { "AWREDIR",  0x0049, NULL },
213
214     /* Far East support */
215     { "ETEN",     0x0060, NULL },
216     { "CHBIOS",   0x0061, NULL },
217     { "VMSGD",    0x0062, NULL },
218     { "VPPID",    0x0063, NULL },
219     { "VIME",     0x0064, NULL },
220     { "VHBIOSD",  0x0065, NULL },
221
222     /* Multimedia OEM IDs */
223     { "VTDAPI",   0x0442, DeviceIo_VTDAPI },
224     { "MMDEVLDR", 0x044A, DeviceIo_MMDEVLDR },
225
226     /* Network Device IDs */
227     { "VNetSup",  0x0480, NULL },
228     { "VRedir",   0x0481, NULL },
229     { "VBrowse",  0x0482, NULL },
230     { "VSHARE",   0x0483, NULL },
231     { "IFSMgr",   0x0484, NULL },
232     { "MEMPROBE", 0x0485, NULL },
233     { "VFAT",     0x0486, NULL },
234     { "NWLINK",   0x0487, NULL },
235     { "VNWLINK",  0x0487, NULL },
236     { "NWSUP",    0x0487, NULL },
237     { "VTDI",     0x0488, NULL },
238     { "VIP",      0x0489, NULL },
239     { "VTCP",     0x048A, NULL },
240     { "VCache",   0x048B, NULL },
241     { "VUDP",     0x048C, NULL },
242     { "VAsync",   0x048D, NULL },
243     { "NWREDIR",  0x048E, NULL },
244     { "STAT80",   0x048F, NULL },
245     { "SCSIPORT", 0x0490, NULL },
246     { "FILESEC",  0x0491, NULL },
247     { "NWSERVER", 0x0492, NULL },
248     { "SECPROV",  0x0493, NULL },
249     { "NSCL",     0x0494, NULL },
250     { "WSTCP",    0x0495, NULL },
251     { "NDIS2SUP", 0x0496, NULL },
252     { "MSODISUP", 0x0497, NULL },
253     { "Splitter", 0x0498, NULL },
254     { "PPP",      0x0499, NULL },
255     { "VDHCP",    0x049A, DeviceIo_DHCP },
256     { "VNBT",     0x049B, NULL },
257     { "LOGGER",   0x049D, NULL },
258     { "EFILTER",  0x049E, NULL },
259     { "FFILTER",  0x049F, NULL },
260     { "TFILTER",  0x04A0, NULL },
261     { "AFILTER",  0x04A1, NULL },
262     { "IRLAMP",   0x04A2, NULL },
263
264     { "PCCARD",   0x097C, DeviceIo_PCCARD },
265     { "HASP95",   0x3721, DeviceIo_HASP },
266
267     /* WINE additions, ids unknown */
268     { "MONODEBG.VXD", 0x4242, DeviceIo_MONODEBG },
269
270     { NULL,       0,      NULL }
271 };
272
273 HANDLE DEVICE_Open( LPCWSTR filenameW, DWORD access, LPSECURITY_ATTRIBUTES sa )
274 {
275     const struct VxDInfo *info;
276     char filename[MAX_PATH];
277
278     if (!WideCharToMultiByte(CP_ACP, 0, filenameW, -1, filename, MAX_PATH, NULL, NULL))
279     {
280         SetLastError( ERROR_FILE_NOT_FOUND );
281         return 0;
282     }
283
284     for (info = VxDList; info->name; info++)
285         if (!strncasecmp( info->name, filename, strlen(info->name) ))
286             return FILE_CreateDevice( info->id | 0x10000, access, sa );
287
288     FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n",
289            filename);
290
291     SetLastError( ERROR_FILE_NOT_FOUND );
292     return 0;
293 }
294
295 static DWORD DEVICE_GetClientID( HANDLE handle )
296 {
297     DWORD       ret = 0;
298     SERVER_START_REQ( get_device_id )
299     {
300         req->handle = handle;
301         if (!wine_server_call( req )) ret = reply->id;
302     }
303     SERVER_END_REQ;
304     return ret;
305 }
306
307 static const struct VxDInfo *DEVICE_GetInfo( DWORD clientID )
308 {
309     const struct VxDInfo *info = NULL;
310
311     if (clientID & 0x10000)
312     {
313         for (info = VxDList; info->name; info++)
314             if (info->id == LOWORD(clientID)) break;
315     }
316     return info;
317 }
318
319 /****************************************************************************
320  *              DeviceIoControl (KERNEL32.@)
321  * This is one of those big ugly nasty procedure which can do
322  * a million and one things when it comes to devices. It can also be
323  * used for VxD communication.
324  *
325  * A return value of FALSE indicates that something has gone wrong which
326  * GetLastError can decipher.
327  */
328 BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
329                               LPVOID lpvInBuffer, DWORD cbInBuffer,
330                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
331                               LPDWORD lpcbBytesReturned,
332                               LPOVERLAPPED lpOverlapped)
333 {
334         DWORD clientID;
335
336         TRACE( "(%p,%ld,%p,%ld,%p,%ld,%p,%p)\n",
337                hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
338                lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped  );
339
340         if (!(clientID = DEVICE_GetClientID( hDevice )))
341         {
342                 SetLastError( ERROR_INVALID_PARAMETER );
343                 return FALSE;
344         }
345
346         /* Check if this is a user defined control code for a VxD */
347         if( HIWORD( dwIoControlCode ) == 0 )
348         {
349                 const struct VxDInfo *info;
350                 if (!(info = DEVICE_GetInfo( clientID )))
351                 {
352                         FIXME( "No device found for id %lx\n", clientID);
353                 }
354                 else if ( info->deviceio )
355                 {
356                         return info->deviceio( dwIoControlCode,
357                                         lpvInBuffer, cbInBuffer,
358                                         lpvOutBuffer, cbOutBuffer,
359                                         lpcbBytesReturned, lpOverlapped );
360                 }
361                 else
362                 {
363                         FIXME( "Unimplemented control %ld for VxD device %s\n",
364                                dwIoControlCode, info->name ? info->name : "???" );
365                         /* FIXME: this is for invalid calls on W98SE,
366                          * but maybe we should use ERROR_CALL_NOT_IMPLEMENTED
367                          * instead ? */
368                         SetLastError( ERROR_INVALID_FUNCTION );
369                 }
370         }
371         else
372         {       
373             NTSTATUS            status;
374
375             if (lpOverlapped)
376             {
377                 status = NtDeviceIoControlFile(hDevice, lpOverlapped->hEvent, 
378                                                NULL, NULL, 
379                                                (PIO_STATUS_BLOCK)lpOverlapped,
380                                                dwIoControlCode, 
381                                                lpvInBuffer, cbInBuffer,
382                                                lpvOutBuffer, cbOutBuffer);
383                 if (status) SetLastError(RtlNtStatusToDosError(status));
384                 if (lpcbBytesReturned) *lpcbBytesReturned = lpOverlapped->InternalHigh;
385                 return !status;
386             }
387             else
388             {
389                 IO_STATUS_BLOCK     iosb;
390
391                 status = NtDeviceIoControlFile(hDevice, NULL, NULL, NULL, &iosb,
392                                                dwIoControlCode, 
393                                                lpvInBuffer, cbInBuffer,
394                                                lpvOutBuffer, cbOutBuffer);
395                 if (status) SetLastError(RtlNtStatusToDosError(status));
396                 if (lpcbBytesReturned) *lpcbBytesReturned = iosb.Information;
397                 return !status;
398             }
399         }
400         return FALSE;
401 }
402
403 /***********************************************************************
404  *           DeviceIo_VTDAPI
405  */
406 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
407                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
408                               LPDWORD lpcbBytesReturned,
409                               LPOVERLAPPED lpOverlapped)
410 {
411     BOOL retv = TRUE;
412
413     switch (dwIoControlCode)
414     {
415     case 5:
416         if (lpvOutBuffer && (cbOutBuffer>=4))
417             *(DWORD*)lpvOutBuffer = GetTickCount();
418
419         if (lpcbBytesReturned)
420             *lpcbBytesReturned = 4;
421
422         break;
423
424     default:
425         FIXME( "Control %ld not implemented\n", dwIoControlCode);
426         retv = FALSE;
427         break;
428     }
429
430     return retv;
431 }
432
433 /***********************************************************************
434  *           DeviceIo_IFSMgr
435  * NOTES
436  *   These ioctls are used by 'MSNET32.DLL'.
437  *
438  *   I have been unable to uncover any documentation about the ioctls so
439  *   the implementation of the cases IFS_IOCTL_21 and IFS_IOCTL_2F are
440  *   based on reasonable guesses on information found in the Windows 95 DDK.
441  *
442  */
443
444 /*
445  * IFSMgr DeviceIO service
446  */
447
448 #define IFS_IOCTL_21                100
449 #define IFS_IOCTL_2F                101
450 #define IFS_IOCTL_GET_RES           102
451 #define IFS_IOCTL_GET_NETPRO_NAME_A 103
452
453 struct win32apireq {
454         unsigned long   ar_proid;
455         unsigned long   ar_eax;
456         unsigned long   ar_ebx;
457         unsigned long   ar_ecx;
458         unsigned long   ar_edx;
459         unsigned long   ar_esi;
460         unsigned long   ar_edi;
461         unsigned long   ar_ebp;
462         unsigned short  ar_error;
463         unsigned short  ar_pad;
464 };
465
466 static void win32apieq_2_CONTEXT(struct win32apireq *pIn,CONTEXT86 *pCxt)
467 {
468         memset(pCxt,0,sizeof(*pCxt));
469
470         pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
471         pCxt->Eax = pIn->ar_eax;
472         pCxt->Ebx = pIn->ar_ebx;
473         pCxt->Ecx = pIn->ar_ecx;
474         pCxt->Edx = pIn->ar_edx;
475         pCxt->Esi = pIn->ar_esi;
476         pCxt->Edi = pIn->ar_edi;
477
478         /* FIXME: Only partial CONTEXT86_CONTROL */
479         pCxt->Ebp = pIn->ar_ebp;
480
481         /* FIXME: pIn->ar_proid ignored */
482         /* FIXME: pIn->ar_error ignored */
483         /* FIXME: pIn->ar_pad ignored */
484 }
485
486 static void CONTEXT_2_win32apieq(CONTEXT86 *pCxt,struct win32apireq *pOut)
487 {
488         memset(pOut,0,sizeof(struct win32apireq));
489
490         pOut->ar_eax = pCxt->Eax;
491         pOut->ar_ebx = pCxt->Ebx;
492         pOut->ar_ecx = pCxt->Ecx;
493         pOut->ar_edx = pCxt->Edx;
494         pOut->ar_esi = pCxt->Esi;
495         pOut->ar_edi = pCxt->Edi;
496
497         /* FIXME: Only partial CONTEXT86_CONTROL */
498         pOut->ar_ebp = pCxt->Ebp;
499
500         /* FIXME: pOut->ar_proid ignored */
501         /* FIXME: pOut->ar_error ignored */
502         /* FIXME: pOut->ar_pad ignored */
503 }
504
505 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
506                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
507                               LPDWORD lpcbBytesReturned,
508                               LPOVERLAPPED lpOverlapped)
509 {
510     BOOL retv = TRUE;
511         TRACE("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
512                         dwIoControlCode,
513                         lpvInBuffer,cbInBuffer,
514                         lpvOutBuffer,cbOutBuffer,
515                         lpcbBytesReturned,
516                         lpOverlapped);
517
518     switch (dwIoControlCode)
519     {
520         case IFS_IOCTL_21:
521         case IFS_IOCTL_2F:{
522                 CONTEXT86 cxt;
523                 struct win32apireq *pIn=(struct win32apireq *) lpvInBuffer;
524                 struct win32apireq *pOut=(struct win32apireq *) lpvOutBuffer;
525
526                 TRACE(
527                         "Control '%s': "
528                         "proid=0x%08lx, eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
529                         "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx, ebp=0x%08lx, "
530                         "error=0x%04x, pad=0x%04x\n",
531                         (dwIoControlCode==IFS_IOCTL_21)?"IFS_IOCTL_21":"IFS_IOCTL_2F",
532                         pIn->ar_proid, pIn->ar_eax, pIn->ar_ebx, pIn->ar_ecx,
533                         pIn->ar_edx, pIn->ar_esi, pIn->ar_edi, pIn->ar_ebp,
534                         pIn->ar_error, pIn->ar_pad
535                 );
536
537                 win32apieq_2_CONTEXT(pIn,&cxt);
538
539                 if(dwIoControlCode==IFS_IOCTL_21)
540                     INSTR_CallBuiltinHandler( &cxt, 0x21 );
541                 else
542                     INSTR_CallBuiltinHandler( &cxt, 0x2f );
543
544                 CONTEXT_2_win32apieq(&cxt,pOut);
545
546         retv = TRUE;
547         } break;
548         case IFS_IOCTL_GET_RES:{
549         FIXME( "Control 'IFS_IOCTL_GET_RES' not implemented\n");
550         retv = FALSE;
551         } break;
552         case IFS_IOCTL_GET_NETPRO_NAME_A:{
553         FIXME( "Control 'IFS_IOCTL_GET_NETPRO_NAME_A' not implemented\n");
554         retv = FALSE;
555         } break;
556     default:
557         FIXME( "Control %ld not implemented\n", dwIoControlCode);
558         retv = FALSE;
559     }
560
561     return retv;
562 }
563
564 /***********************************************************************
565  *           DeviceIo_VCD
566  */
567 static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
568                               LPVOID lpvInBuffer, DWORD cbInBuffer,
569                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
570                               LPDWORD lpcbBytesReturned,
571                               LPOVERLAPPED lpOverlapped)
572 {
573     BOOL retv = TRUE;
574
575     switch (dwIoControlCode)
576     {
577     case IOCTL_SERIAL_LSRMST_INSERT:
578     {
579         FIXME( "IOCTL_SERIAL_LSRMST_INSERT NIY !\n");
580         retv = FALSE;
581     }
582     break;
583
584     default:
585         FIXME( "Unknown Control %ld\n", dwIoControlCode);
586         retv = FALSE;
587         break;
588     }
589
590     return retv;
591 }
592
593
594 /***********************************************************************
595  *           DeviceIo_VWin32
596  */
597
598 static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
599 {
600     memset( pCxt, 0, sizeof(*pCxt) );
601     /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN
602              will interpret 32-bit register contents as linear pointers */
603
604     pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
605     pCxt->Eax = pIn->reg_EAX;
606     pCxt->Ebx = pIn->reg_EBX;
607     pCxt->Ecx = pIn->reg_ECX;
608     pCxt->Edx = pIn->reg_EDX;
609     pCxt->Esi = pIn->reg_ESI;
610     pCxt->Edi = pIn->reg_EDI;
611
612     /* FIXME: Only partial CONTEXT86_CONTROL */
613
614     pCxt->EFlags = pIn->reg_Flags & ~0x00020000; /* clear vm86 mode */
615 }
616
617 static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut )
618 {
619     memset( pOut, 0, sizeof(DIOC_REGISTERS) );
620
621     pOut->reg_EAX = pCxt->Eax;
622     pOut->reg_EBX = pCxt->Ebx;
623     pOut->reg_ECX = pCxt->Ecx;
624     pOut->reg_EDX = pCxt->Edx;
625     pOut->reg_ESI = pCxt->Esi;
626     pOut->reg_EDI = pCxt->Edi;
627
628     /* FIXME: Only partial CONTEXT86_CONTROL */
629     pOut->reg_Flags = pCxt->EFlags;
630 }
631
632 #define DIOC_AH(regs) (((unsigned char*)&((regs)->reg_EAX))[1])
633 #define DIOC_AL(regs) (((unsigned char*)&((regs)->reg_EAX))[0])
634 #define DIOC_BH(regs) (((unsigned char*)&((regs)->reg_EBX))[1])
635 #define DIOC_BL(regs) (((unsigned char*)&((regs)->reg_EBX))[0])
636 #define DIOC_DH(regs) (((unsigned char*)&((regs)->reg_EDX))[1])
637 #define DIOC_DL(regs) (((unsigned char*)&((regs)->reg_EDX))[0])
638
639 #define DIOC_AX(regs) (((unsigned short*)&((regs)->reg_EAX))[0])
640 #define DIOC_BX(regs) (((unsigned short*)&((regs)->reg_EBX))[0])
641 #define DIOC_CX(regs) (((unsigned short*)&((regs)->reg_ECX))[0])
642 #define DIOC_DX(regs) (((unsigned short*)&((regs)->reg_EDX))[0])
643
644 #define DIOC_SET_CARRY(regs) (((regs)->reg_Flags)|=0x00000001)
645
646 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
647                               LPVOID lpvInBuffer, DWORD cbInBuffer,
648                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
649                               LPDWORD lpcbBytesReturned,
650                               LPOVERLAPPED lpOverlapped)
651 {
652     BOOL retv = TRUE;
653
654     switch (dwIoControlCode)
655     {
656     case VWIN32_DIOC_DOS_IOCTL:
657     case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
658     case VWIN32_DIOC_DOS_INT13:
659     case VWIN32_DIOC_DOS_INT25:
660     case VWIN32_DIOC_DOS_INT26:
661     case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
662     case VWIN32_DIOC_DOS_DRIVEINFO:
663     {
664         CONTEXT86 cxt;
665         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
666         DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;
667         BYTE intnum = 0;
668
669         TRACE( "Control '%s': "
670                "eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
671                "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx \n",
672                (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" :
673                (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" :
674                (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" :
675                (dwIoControlCode == VWIN32_DIOC_DOS_DRIVEINFO)? "VWIN32_DIOC_DOS_DRIVEINFO" :  "???",
676                pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX,
677                pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI );
678
679         DIOCRegs_2_CONTEXT( pIn, &cxt );
680
681         switch (dwIoControlCode)
682         {
683         case VWIN32_DIOC_DOS_IOCTL: /* Call int 21h */
684         case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
685         case VWIN32_DIOC_DOS_DRIVEINFO:        /* Call int 21h 730x */
686             intnum = 0x21;
687             break;
688         case VWIN32_DIOC_DOS_INT13:
689             intnum = 0x13;
690             break;
691         case VWIN32_DIOC_DOS_INT25: 
692             intnum = 0x25;
693             break;
694         case VWIN32_DIOC_DOS_INT26:
695             intnum = 0x26;
696             break;
697         case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
698             intnum = 0x31;
699             break;
700         }
701
702         INSTR_CallBuiltinHandler( &cxt, intnum );
703         CONTEXT_2_DIOCRegs( &cxt, pOut );
704     }
705     break;
706
707     case VWIN32_DIOC_SIMCTRLC:
708         FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n");
709         retv = FALSE;
710         break;
711
712     default:
713         FIXME( "Unknown Control %ld\n", dwIoControlCode);
714         retv = FALSE;
715         break;
716     }
717
718     return retv;
719 }
720
721 /* this is the main multimedia device loader */
722 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
723                               LPVOID lpvInBuffer, DWORD cbInBuffer,
724                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
725                               LPDWORD lpcbBytesReturned,
726                               LPOVERLAPPED lpOverlapped)
727 {
728         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
729             dwIoControlCode,
730             lpvInBuffer,cbInBuffer,
731             lpvOutBuffer,cbOutBuffer,
732             lpcbBytesReturned,
733             lpOverlapped
734         );
735         switch (dwIoControlCode) {
736         case 5:
737                 /* Hmm. */
738                 *(DWORD*)lpvOutBuffer=0;
739                 *lpcbBytesReturned=4;
740                 return TRUE;
741         }
742         return FALSE;
743 }
744 /* this is used by some Origin games */
745 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
746                               LPVOID lpvInBuffer, DWORD cbInBuffer,
747                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
748                               LPDWORD lpcbBytesReturned,
749                               LPOVERLAPPED lpOverlapped)
750 {
751         switch (dwIoControlCode) {
752         case 1: /* version */
753                 *(LPDWORD)lpvOutBuffer = 0x20004; /* WC SecretOps */
754                 break;
755         case 9: /* debug output */
756                 ERR("MONODEBG: %s\n",debugstr_a(lpvInBuffer));
757                 break;
758         default:
759                 FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
760                         dwIoControlCode,
761                         lpvInBuffer,cbInBuffer,
762                         lpvOutBuffer,cbOutBuffer,
763                         lpcbBytesReturned,
764                         lpOverlapped
765                 );
766                 break;
767         }
768         return TRUE;
769 }
770
771 /* pccard */
772 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
773                               LPVOID lpvInBuffer, DWORD cbInBuffer,
774                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
775                               LPDWORD lpcbBytesReturned,
776                               LPOVERLAPPED lpOverlapped)
777 {
778         switch (dwIoControlCode) {
779         case 0x0000: /* PCCARD_Get_Version */
780         case 0x0001: /* PCCARD_Card_Services */
781         default:
782                 FIXME( "(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
783                         dwIoControlCode,
784                         lpvInBuffer,cbInBuffer,
785                         lpvOutBuffer,cbOutBuffer,
786                         lpcbBytesReturned,
787                         lpOverlapped
788                 );
789                 break;
790         }
791         return FALSE;
792 }
793
794 static BOOL DeviceIo_HASP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
795                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
796                               LPDWORD lpcbBytesReturned,
797                               LPOVERLAPPED lpOverlapped)
798 {
799     BOOL retv = TRUE;
800         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
801                         dwIoControlCode,
802                         lpvInBuffer,cbInBuffer,
803                         lpvOutBuffer,cbOutBuffer,
804                         lpcbBytesReturned,
805                         lpOverlapped);
806
807     return retv;
808 }
809
810 typedef UCHAR (WINAPI *NetbiosFunc)(LPVOID);
811
812 static BOOL DeviceIo_NetBIOS(DWORD dwIoControlCode,
813                               LPVOID lpvInBuffer, DWORD cbInBuffer,
814                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
815                               LPDWORD lpcbBytesReturned,
816                               LPOVERLAPPED lpOverlapped)
817 {
818     static HMODULE netapi;
819     static NetbiosFunc pNetbios;
820
821     if (dwIoControlCode != 256)
822     {
823         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
824                 dwIoControlCode,
825                 lpvInBuffer,cbInBuffer,
826                 lpvOutBuffer,cbOutBuffer,
827                 lpcbBytesReturned,
828                 lpOverlapped);
829     }
830     else
831     {
832         if (!pNetbios)
833         {
834             if (!netapi) netapi = LoadLibraryA("netapi32.dll");
835             if (netapi) pNetbios = (NetbiosFunc)GetProcAddress(netapi, "Netbios");
836         }
837         if (pNetbios)
838         {
839             pNetbios(lpvInBuffer);
840             return TRUE;
841         }
842     }
843     return FALSE;
844 }
845
846 static BOOL DeviceIo_DHCP(DWORD dwIoControlCode, LPVOID lpvInBuffer,
847                           DWORD cbInBuffer,
848                           LPVOID lpvOutBuffer, DWORD cbOutBuffer,
849                           LPDWORD lpcbBytesReturned,
850                           LPOVERLAPPED lpOverlapped)
851 {
852     DWORD error;
853
854     switch (dwIoControlCode) {
855     case 1:
856     {
857         /* since IpReleaseAddress/IpRenewAddress are not implemented, say there
858          * are no DHCP adapters
859          */
860         error = ERROR_FILE_NOT_FOUND;
861         break;
862     }
863
864     /* FIXME: don't know what this means */
865     case 5:
866         if (lpcbBytesReturned)
867             *lpcbBytesReturned = sizeof(DWORD);
868         if (lpvOutBuffer && cbOutBuffer >= 4)
869         {
870             *(LPDWORD)lpvOutBuffer = 0;
871             error = NO_ERROR;
872         }
873         else
874             error = ERROR_BUFFER_OVERFLOW;
875         break;
876
877     default:
878         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
879                 dwIoControlCode,
880                 lpvInBuffer,cbInBuffer,
881                 lpvOutBuffer,cbOutBuffer,
882                 lpcbBytesReturned,
883                 lpOverlapped);
884         error = ERROR_NOT_SUPPORTED;
885         break;
886     }
887     if (error)
888         SetLastError(error);
889     return error == NO_ERROR;
890 }
891
892 typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO, PDWORD);
893 typedef DWORD (WINAPI *GetAdaptersInfoFunc)(PIP_ADAPTER_INFO, PDWORD);
894
895 typedef struct _nbtInfo
896 {
897     DWORD ip;
898     DWORD winsPrimary;
899     DWORD winsSecondary;
900     DWORD dnsPrimary;
901     DWORD dnsSecondary;
902     DWORD unk0;
903 } nbtInfo;
904
905 #define MAX_NBT_ENTRIES 7
906
907 typedef struct _nbtTable
908 {
909     DWORD   numEntries;
910     nbtInfo table[MAX_NBT_ENTRIES];
911     UCHAR   pad[6];
912     WORD    nodeType;
913     WORD    scopeLen;
914     char    scope[254];
915 } nbtTable;
916
917 static BOOL DeviceIo_VNB(DWORD dwIoControlCode,
918                          LPVOID lpvInBuffer, DWORD cbInBuffer,
919                          LPVOID lpvOutBuffer, DWORD cbOutBuffer,
920                          LPDWORD lpcbBytesReturned,
921                          LPOVERLAPPED lpOverlapped)
922 {
923     static HMODULE iphlpapi;
924     static GetNetworkParamsFunc pGetNetworkParams;
925     static GetAdaptersInfoFunc pGetAdaptersInfo;
926     DWORD error;
927
928     switch (dwIoControlCode)
929     {
930         case 116:
931             if (lpcbBytesReturned)
932                 *lpcbBytesReturned = sizeof(nbtTable);
933             if (!lpvOutBuffer || cbOutBuffer < sizeof(nbtTable))
934                 error = ERROR_BUFFER_OVERFLOW;
935             else
936             {
937                 nbtTable *info = (nbtTable *)lpvOutBuffer;
938
939                 memset(info, 0, sizeof(nbtTable));
940                 if (!iphlpapi)
941                 {
942                     iphlpapi = LoadLibraryA("iphlpapi.dll");
943                     pGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(iphlpapi,"GetNetworkParams");
944                     pGetAdaptersInfo = (GetAdaptersInfoFunc)GetProcAddress(iphlpapi, "GetAdaptersInfo");
945                 }
946                 if (iphlpapi)
947                 {
948                     DWORD size = 0;
949
950                     error = pGetNetworkParams(NULL, &size);
951                     if (ERROR_BUFFER_OVERFLOW == error)
952                     {
953                         PFIXED_INFO fixedInfo = (PFIXED_INFO)HeapAlloc(
954                          GetProcessHeap(), 0, size);
955
956                         error = pGetNetworkParams(fixedInfo, &size);
957                         if (NO_ERROR == error)
958                         {
959                             info->nodeType = (WORD)fixedInfo->NodeType;
960                             info->scopeLen = min(strlen(fixedInfo->ScopeId) + 1,
961                              sizeof(info->scope) - 2);
962                             memcpy(info->scope + 1, fixedInfo->ScopeId,
963                              info->scopeLen);
964                             info->scope[info->scopeLen + 1] = '\0';
965                             {
966                                 /* convert into L2-encoded version */
967                                 char *ptr, *lenPtr;
968
969                                 for (ptr = info->scope + 1; *ptr &&
970                                  ptr - info->scope < sizeof(info->scope); )
971                                 {
972                                     for (lenPtr = ptr - 1, *lenPtr = 0;
973                                      *ptr && *ptr != '.' &&
974                                      ptr - info->scope < sizeof(info->scope);
975                                      ptr++)
976                                         *lenPtr += 1;
977                                     ptr++;
978                                 }
979                             }
980                             /* could set DNS servers here too, but since
981                              * ipconfig.exe and winipcfg.exe read these from the
982                              * registry, there's no point */
983                         }
984                         if (fixedInfo)
985                             HeapFree(GetProcessHeap(), 0, fixedInfo);
986                     }
987                     size = 0;
988                     error = pGetAdaptersInfo(NULL, &size);
989                     if (ERROR_BUFFER_OVERFLOW == error)
990                     {
991                         PIP_ADAPTER_INFO adapterInfo = (PIP_ADAPTER_INFO)
992                          HeapAlloc(GetProcessHeap(), 0, size);
993
994                         error = pGetAdaptersInfo(adapterInfo, &size);
995                         if (NO_ERROR == error)
996                         {
997                             PIP_ADAPTER_INFO ptr = adapterInfo;
998
999                             for (ptr = adapterInfo; ptr && info->numEntries <
1000                              MAX_NBT_ENTRIES; ptr = ptr->Next)
1001                             {
1002                                 unsigned long addr;
1003
1004                                 addr = inet_addr(
1005                                  ptr->IpAddressList.IpAddress.String);
1006                                 if (addr != 0 && addr != INADDR_NONE)
1007                                     info->table[info->numEntries].ip =
1008                                      ntohl(addr);
1009                                 addr = inet_addr(
1010                                  ptr->PrimaryWinsServer.IpAddress.String);
1011                                 if (addr != 0 && addr != INADDR_NONE)
1012                                     info->table[info->numEntries].winsPrimary
1013                                      = ntohl(addr);
1014                                 addr = inet_addr(
1015                                  ptr->SecondaryWinsServer.IpAddress.String);
1016                                 if (addr != 0 && addr != INADDR_NONE)
1017                                     info->table[info->numEntries].winsSecondary
1018                                      = ntohl(addr);
1019                                 info->numEntries++;
1020                             }
1021                         }
1022                         if (adapterInfo)
1023                             HeapFree(GetProcessHeap(), 0, adapterInfo);
1024                     }
1025                 }
1026                 else
1027                     error = GetLastError();
1028             }
1029             break;
1030
1031         case 119:
1032             /* nbtstat.exe uses this, but the return seems to be a bunch of
1033              * pointers, so it's not so easy to reverse engineer.  Fall through
1034              * to unimplemented...
1035              */
1036         default:
1037             FIXME( "Unimplemented control %ld for VxD device VNB\n",
1038                                dwIoControlCode );
1039             error = ERROR_NOT_SUPPORTED;
1040             break;
1041     }
1042     if (error)
1043         SetLastError(error);
1044     return error == NO_ERROR;
1045 }