Correct the test for the ODS_SELECTED bit in the WM_DRAWITEM message
[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     SetLastError( ERROR_FILE_NOT_FOUND );
291     return 0;
292 }
293
294 static DWORD DEVICE_GetClientID( HANDLE handle )
295 {
296     DWORD       ret = 0;
297     SERVER_START_REQ( get_device_id )
298     {
299         req->handle = handle;
300         if (!wine_server_call( req )) ret = reply->id;
301     }
302     SERVER_END_REQ;
303     return ret;
304 }
305
306 static const struct VxDInfo *DEVICE_GetInfo( DWORD clientID )
307 {
308     const struct VxDInfo *info = NULL;
309
310     if (clientID & 0x10000)
311     {
312         for (info = VxDList; info->name; info++)
313             if (info->id == LOWORD(clientID)) break;
314     }
315     return info;
316 }
317
318 /****************************************************************************
319  *              DeviceIoControl (KERNEL32.@)
320  * This is one of those big ugly nasty procedure which can do
321  * a million and one things when it comes to devices. It can also be
322  * used for VxD communication.
323  *
324  * A return value of FALSE indicates that something has gone wrong which
325  * GetLastError can decipher.
326  */
327 BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode,
328                               LPVOID lpvInBuffer, DWORD cbInBuffer,
329                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
330                               LPDWORD lpcbBytesReturned,
331                               LPOVERLAPPED lpOverlapped)
332 {
333         DWORD clientID;
334
335         TRACE( "(%p,%ld,%p,%ld,%p,%ld,%p,%p)\n",
336                hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer,
337                lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped  );
338
339         if (!(clientID = DEVICE_GetClientID( hDevice )))
340         {
341                 SetLastError( ERROR_INVALID_PARAMETER );
342                 return FALSE;
343         }
344
345         /* Check if this is a user defined control code for a VxD */
346         if( HIWORD( dwIoControlCode ) == 0 )
347         {
348                 const struct VxDInfo *info;
349                 if (!(info = DEVICE_GetInfo( clientID )))
350                 {
351                         FIXME( "No device found for id %lx\n", clientID);
352                 }
353                 else if ( info->deviceio )
354                 {
355                         return info->deviceio( dwIoControlCode,
356                                         lpvInBuffer, cbInBuffer,
357                                         lpvOutBuffer, cbOutBuffer,
358                                         lpcbBytesReturned, lpOverlapped );
359                 }
360                 else
361                 {
362                         FIXME( "Unimplemented control %ld for VxD device %s\n",
363                                dwIoControlCode, info->name ? info->name : "???" );
364                         /* FIXME: this is for invalid calls on W98SE,
365                          * but maybe we should use ERROR_CALL_NOT_IMPLEMENTED
366                          * instead ? */
367                         SetLastError( ERROR_INVALID_FUNCTION );
368                 }
369         }
370         else
371         {       
372             NTSTATUS            status;
373
374             if (lpOverlapped)
375             {
376                 status = NtDeviceIoControlFile(hDevice, lpOverlapped->hEvent, 
377                                                NULL, NULL, 
378                                                (PIO_STATUS_BLOCK)lpOverlapped,
379                                                dwIoControlCode, 
380                                                lpvInBuffer, cbInBuffer,
381                                                lpvOutBuffer, cbOutBuffer);
382                 if (status) SetLastError(RtlNtStatusToDosError(status));
383                 if (lpcbBytesReturned) *lpcbBytesReturned = lpOverlapped->InternalHigh;
384                 return !status;
385             }
386             else
387             {
388                 IO_STATUS_BLOCK     iosb;
389
390                 status = NtDeviceIoControlFile(hDevice, NULL, NULL, NULL, &iosb,
391                                                dwIoControlCode, 
392                                                lpvInBuffer, cbInBuffer,
393                                                lpvOutBuffer, cbOutBuffer);
394                 if (status) SetLastError(RtlNtStatusToDosError(status));
395                 if (lpcbBytesReturned) *lpcbBytesReturned = iosb.Information;
396                 return !status;
397             }
398         }
399         return FALSE;
400 }
401
402 /***********************************************************************
403  *           DeviceIo_VTDAPI
404  */
405 static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
406                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
407                               LPDWORD lpcbBytesReturned,
408                               LPOVERLAPPED lpOverlapped)
409 {
410     BOOL retv = TRUE;
411
412     switch (dwIoControlCode)
413     {
414     case 5:
415         if (lpvOutBuffer && (cbOutBuffer>=4))
416             *(DWORD*)lpvOutBuffer = GetTickCount();
417
418         if (lpcbBytesReturned)
419             *lpcbBytesReturned = 4;
420
421         break;
422
423     default:
424         FIXME( "Control %ld not implemented\n", dwIoControlCode);
425         retv = FALSE;
426         break;
427     }
428
429     return retv;
430 }
431
432 /***********************************************************************
433  *           DeviceIo_IFSMgr
434  * NOTES
435  *   These ioctls are used by 'MSNET32.DLL'.
436  *
437  *   I have been unable to uncover any documentation about the ioctls so
438  *   the implementation of the cases IFS_IOCTL_21 and IFS_IOCTL_2F are
439  *   based on reasonable guesses on information found in the Windows 95 DDK.
440  *
441  */
442
443 /*
444  * IFSMgr DeviceIO service
445  */
446
447 #define IFS_IOCTL_21                100
448 #define IFS_IOCTL_2F                101
449 #define IFS_IOCTL_GET_RES           102
450 #define IFS_IOCTL_GET_NETPRO_NAME_A 103
451
452 struct win32apireq {
453         unsigned long   ar_proid;
454         unsigned long   ar_eax;
455         unsigned long   ar_ebx;
456         unsigned long   ar_ecx;
457         unsigned long   ar_edx;
458         unsigned long   ar_esi;
459         unsigned long   ar_edi;
460         unsigned long   ar_ebp;
461         unsigned short  ar_error;
462         unsigned short  ar_pad;
463 };
464
465 static void win32apieq_2_CONTEXT(struct win32apireq *pIn,CONTEXT86 *pCxt)
466 {
467         memset(pCxt,0,sizeof(*pCxt));
468
469         pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
470         pCxt->Eax = pIn->ar_eax;
471         pCxt->Ebx = pIn->ar_ebx;
472         pCxt->Ecx = pIn->ar_ecx;
473         pCxt->Edx = pIn->ar_edx;
474         pCxt->Esi = pIn->ar_esi;
475         pCxt->Edi = pIn->ar_edi;
476
477         /* FIXME: Only partial CONTEXT86_CONTROL */
478         pCxt->Ebp = pIn->ar_ebp;
479
480         /* FIXME: pIn->ar_proid ignored */
481         /* FIXME: pIn->ar_error ignored */
482         /* FIXME: pIn->ar_pad ignored */
483 }
484
485 static void CONTEXT_2_win32apieq(CONTEXT86 *pCxt,struct win32apireq *pOut)
486 {
487         memset(pOut,0,sizeof(struct win32apireq));
488
489         pOut->ar_eax = pCxt->Eax;
490         pOut->ar_ebx = pCxt->Ebx;
491         pOut->ar_ecx = pCxt->Ecx;
492         pOut->ar_edx = pCxt->Edx;
493         pOut->ar_esi = pCxt->Esi;
494         pOut->ar_edi = pCxt->Edi;
495
496         /* FIXME: Only partial CONTEXT86_CONTROL */
497         pOut->ar_ebp = pCxt->Ebp;
498
499         /* FIXME: pOut->ar_proid ignored */
500         /* FIXME: pOut->ar_error ignored */
501         /* FIXME: pOut->ar_pad ignored */
502 }
503
504 static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
505                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
506                               LPDWORD lpcbBytesReturned,
507                               LPOVERLAPPED lpOverlapped)
508 {
509     BOOL retv = TRUE;
510         TRACE("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
511                         dwIoControlCode,
512                         lpvInBuffer,cbInBuffer,
513                         lpvOutBuffer,cbOutBuffer,
514                         lpcbBytesReturned,
515                         lpOverlapped);
516
517     switch (dwIoControlCode)
518     {
519         case IFS_IOCTL_21:
520         case IFS_IOCTL_2F:{
521                 CONTEXT86 cxt;
522                 struct win32apireq *pIn=(struct win32apireq *) lpvInBuffer;
523                 struct win32apireq *pOut=(struct win32apireq *) lpvOutBuffer;
524
525                 TRACE(
526                         "Control '%s': "
527                         "proid=0x%08lx, eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
528                         "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx, ebp=0x%08lx, "
529                         "error=0x%04x, pad=0x%04x\n",
530                         (dwIoControlCode==IFS_IOCTL_21)?"IFS_IOCTL_21":"IFS_IOCTL_2F",
531                         pIn->ar_proid, pIn->ar_eax, pIn->ar_ebx, pIn->ar_ecx,
532                         pIn->ar_edx, pIn->ar_esi, pIn->ar_edi, pIn->ar_ebp,
533                         pIn->ar_error, pIn->ar_pad
534                 );
535
536                 win32apieq_2_CONTEXT(pIn,&cxt);
537
538                 if(dwIoControlCode==IFS_IOCTL_21)
539                     INSTR_CallBuiltinHandler( &cxt, 0x21 );
540                 else
541                     INSTR_CallBuiltinHandler( &cxt, 0x2f );
542
543                 CONTEXT_2_win32apieq(&cxt,pOut);
544
545         retv = TRUE;
546         } break;
547         case IFS_IOCTL_GET_RES:{
548         FIXME( "Control 'IFS_IOCTL_GET_RES' not implemented\n");
549         retv = FALSE;
550         } break;
551         case IFS_IOCTL_GET_NETPRO_NAME_A:{
552         FIXME( "Control 'IFS_IOCTL_GET_NETPRO_NAME_A' not implemented\n");
553         retv = FALSE;
554         } break;
555     default:
556         FIXME( "Control %ld not implemented\n", dwIoControlCode);
557         retv = FALSE;
558     }
559
560     return retv;
561 }
562
563 /***********************************************************************
564  *           DeviceIo_VCD
565  */
566 static BOOL DeviceIo_VCD(DWORD dwIoControlCode,
567                               LPVOID lpvInBuffer, DWORD cbInBuffer,
568                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
569                               LPDWORD lpcbBytesReturned,
570                               LPOVERLAPPED lpOverlapped)
571 {
572     BOOL retv = TRUE;
573
574     switch (dwIoControlCode)
575     {
576     case IOCTL_SERIAL_LSRMST_INSERT:
577     {
578         FIXME( "IOCTL_SERIAL_LSRMST_INSERT NIY !\n");
579         retv = FALSE;
580     }
581     break;
582
583     default:
584         FIXME( "Unknown Control %ld\n", dwIoControlCode);
585         retv = FALSE;
586         break;
587     }
588
589     return retv;
590 }
591
592
593 /***********************************************************************
594  *           DeviceIo_VWin32
595  */
596
597 static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt )
598 {
599     memset( pCxt, 0, sizeof(*pCxt) );
600     /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN
601              will interpret 32-bit register contents as linear pointers */
602
603     pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL;
604     pCxt->Eax = pIn->reg_EAX;
605     pCxt->Ebx = pIn->reg_EBX;
606     pCxt->Ecx = pIn->reg_ECX;
607     pCxt->Edx = pIn->reg_EDX;
608     pCxt->Esi = pIn->reg_ESI;
609     pCxt->Edi = pIn->reg_EDI;
610
611     /* FIXME: Only partial CONTEXT86_CONTROL */
612     pCxt->EFlags = pIn->reg_Flags;
613 }
614
615 static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut )
616 {
617     memset( pOut, 0, sizeof(DIOC_REGISTERS) );
618
619     pOut->reg_EAX = pCxt->Eax;
620     pOut->reg_EBX = pCxt->Ebx;
621     pOut->reg_ECX = pCxt->Ecx;
622     pOut->reg_EDX = pCxt->Edx;
623     pOut->reg_ESI = pCxt->Esi;
624     pOut->reg_EDI = pCxt->Edi;
625
626     /* FIXME: Only partial CONTEXT86_CONTROL */
627     pOut->reg_Flags = pCxt->EFlags;
628 }
629
630 #define DIOC_AH(regs) (((unsigned char*)&((regs)->reg_EAX))[1])
631 #define DIOC_AL(regs) (((unsigned char*)&((regs)->reg_EAX))[0])
632 #define DIOC_BH(regs) (((unsigned char*)&((regs)->reg_EBX))[1])
633 #define DIOC_BL(regs) (((unsigned char*)&((regs)->reg_EBX))[0])
634 #define DIOC_DH(regs) (((unsigned char*)&((regs)->reg_EDX))[1])
635 #define DIOC_DL(regs) (((unsigned char*)&((regs)->reg_EDX))[0])
636
637 #define DIOC_AX(regs) (((unsigned short*)&((regs)->reg_EAX))[0])
638 #define DIOC_BX(regs) (((unsigned short*)&((regs)->reg_EBX))[0])
639 #define DIOC_CX(regs) (((unsigned short*)&((regs)->reg_ECX))[0])
640 #define DIOC_DX(regs) (((unsigned short*)&((regs)->reg_EDX))[0])
641
642 #define DIOC_SET_CARRY(regs) (((regs)->reg_Flags)|=0x00000001)
643
644 static BOOL DeviceIo_VWin32(DWORD dwIoControlCode,
645                               LPVOID lpvInBuffer, DWORD cbInBuffer,
646                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
647                               LPDWORD lpcbBytesReturned,
648                               LPOVERLAPPED lpOverlapped)
649 {
650     BOOL retv = TRUE;
651
652     switch (dwIoControlCode)
653     {
654     case VWIN32_DIOC_DOS_IOCTL:
655     case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
656     case VWIN32_DIOC_DOS_INT13:
657     case VWIN32_DIOC_DOS_INT25:
658     case VWIN32_DIOC_DOS_INT26:
659     case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
660     case VWIN32_DIOC_DOS_DRIVEINFO:
661     {
662         CONTEXT86 cxt;
663         DIOC_REGISTERS *pIn  = (DIOC_REGISTERS *)lpvInBuffer;
664         DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer;
665         BYTE intnum = 0;
666
667         TRACE( "Control '%s': "
668                "eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, "
669                "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx \n",
670                (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" :
671                (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" :
672                (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" :
673                (dwIoControlCode == VWIN32_DIOC_DOS_DRIVEINFO)? "VWIN32_DIOC_DOS_DRIVEINFO" :  "???",
674                pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX,
675                pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI );
676
677         DIOCRegs_2_CONTEXT( pIn, &cxt );
678
679         switch (dwIoControlCode)
680         {
681         case VWIN32_DIOC_DOS_IOCTL: /* Call int 21h */
682         case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */
683         case VWIN32_DIOC_DOS_DRIVEINFO:        /* Call int 21h 730x */
684             intnum = 0x21;
685             break;
686         case VWIN32_DIOC_DOS_INT13:
687             intnum = 0x13;
688             break;
689         case VWIN32_DIOC_DOS_INT25: 
690             intnum = 0x25;
691             break;
692         case VWIN32_DIOC_DOS_INT26:
693             intnum = 0x26;
694             break;
695         case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */
696             intnum = 0x31;
697             break;
698         }
699
700         INSTR_CallBuiltinHandler( &cxt, intnum );
701         CONTEXT_2_DIOCRegs( &cxt, pOut );
702     }
703     break;
704
705     case VWIN32_DIOC_SIMCTRLC:
706         FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n");
707         retv = FALSE;
708         break;
709
710     default:
711         FIXME( "Unknown Control %ld\n", dwIoControlCode);
712         retv = FALSE;
713         break;
714     }
715
716     return retv;
717 }
718
719 /* this is the main multimedia device loader */
720 static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode,
721                               LPVOID lpvInBuffer, DWORD cbInBuffer,
722                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
723                               LPDWORD lpcbBytesReturned,
724                               LPOVERLAPPED lpOverlapped)
725 {
726         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
727             dwIoControlCode,
728             lpvInBuffer,cbInBuffer,
729             lpvOutBuffer,cbOutBuffer,
730             lpcbBytesReturned,
731             lpOverlapped
732         );
733         switch (dwIoControlCode) {
734         case 5:
735                 /* Hmm. */
736                 *(DWORD*)lpvOutBuffer=0;
737                 *lpcbBytesReturned=4;
738                 return TRUE;
739         }
740         return FALSE;
741 }
742 /* this is used by some Origin games */
743 static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode,
744                               LPVOID lpvInBuffer, DWORD cbInBuffer,
745                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
746                               LPDWORD lpcbBytesReturned,
747                               LPOVERLAPPED lpOverlapped)
748 {
749         switch (dwIoControlCode) {
750         case 1: /* version */
751                 *(LPDWORD)lpvOutBuffer = 0x20004; /* WC SecretOps */
752                 break;
753         case 9: /* debug output */
754                 ERR("MONODEBG: %s\n",debugstr_a(lpvInBuffer));
755                 break;
756         default:
757                 FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
758                         dwIoControlCode,
759                         lpvInBuffer,cbInBuffer,
760                         lpvOutBuffer,cbOutBuffer,
761                         lpcbBytesReturned,
762                         lpOverlapped
763                 );
764                 break;
765         }
766         return TRUE;
767 }
768
769 /* pccard */
770 static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode,
771                               LPVOID lpvInBuffer, DWORD cbInBuffer,
772                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
773                               LPDWORD lpcbBytesReturned,
774                               LPOVERLAPPED lpOverlapped)
775 {
776         switch (dwIoControlCode) {
777         case 0x0000: /* PCCARD_Get_Version */
778         case 0x0001: /* PCCARD_Card_Services */
779         default:
780                 FIXME( "(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
781                         dwIoControlCode,
782                         lpvInBuffer,cbInBuffer,
783                         lpvOutBuffer,cbOutBuffer,
784                         lpcbBytesReturned,
785                         lpOverlapped
786                 );
787                 break;
788         }
789         return FALSE;
790 }
791
792 static BOOL DeviceIo_HASP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer,
793                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
794                               LPDWORD lpcbBytesReturned,
795                               LPOVERLAPPED lpOverlapped)
796 {
797     BOOL retv = TRUE;
798         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
799                         dwIoControlCode,
800                         lpvInBuffer,cbInBuffer,
801                         lpvOutBuffer,cbOutBuffer,
802                         lpcbBytesReturned,
803                         lpOverlapped);
804
805     return retv;
806 }
807
808 typedef UCHAR (WINAPI *NetbiosFunc)(LPVOID);
809
810 static BOOL DeviceIo_NetBIOS(DWORD dwIoControlCode,
811                               LPVOID lpvInBuffer, DWORD cbInBuffer,
812                               LPVOID lpvOutBuffer, DWORD cbOutBuffer,
813                               LPDWORD lpcbBytesReturned,
814                               LPOVERLAPPED lpOverlapped)
815 {
816     static HMODULE netapi;
817     static NetbiosFunc pNetbios;
818
819     if (dwIoControlCode != 256)
820     {
821         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
822                 dwIoControlCode,
823                 lpvInBuffer,cbInBuffer,
824                 lpvOutBuffer,cbOutBuffer,
825                 lpcbBytesReturned,
826                 lpOverlapped);
827     }
828     else
829     {
830         if (!pNetbios)
831         {
832             if (!netapi) netapi = LoadLibraryA("netapi32.dll");
833             if (netapi) pNetbios = (NetbiosFunc)GetProcAddress(netapi, "Netbios");
834         }
835         if (pNetbios)
836         {
837             pNetbios(lpvInBuffer);
838             return TRUE;
839         }
840     }
841     return FALSE;
842 }
843
844 static BOOL DeviceIo_DHCP(DWORD dwIoControlCode, LPVOID lpvInBuffer,
845                           DWORD cbInBuffer,
846                           LPVOID lpvOutBuffer, DWORD cbOutBuffer,
847                           LPDWORD lpcbBytesReturned,
848                           LPOVERLAPPED lpOverlapped)
849 {
850     DWORD error;
851
852     switch (dwIoControlCode) {
853     case 1:
854     {
855         /* since IpReleaseAddress/IpRenewAddress are not implemented, say there
856          * are no DHCP adapters
857          */
858         error = ERROR_FILE_NOT_FOUND;
859         break;
860     }
861
862     /* FIXME: don't know what this means */
863     case 5:
864         if (lpcbBytesReturned)
865             *lpcbBytesReturned = sizeof(DWORD);
866         if (lpvOutBuffer && cbOutBuffer >= 4)
867         {
868             *(LPDWORD)lpvOutBuffer = 0;
869             error = NO_ERROR;
870         }
871         else
872             error = ERROR_BUFFER_OVERFLOW;
873         break;
874
875     default:
876         FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n",
877                 dwIoControlCode,
878                 lpvInBuffer,cbInBuffer,
879                 lpvOutBuffer,cbOutBuffer,
880                 lpcbBytesReturned,
881                 lpOverlapped);
882         error = ERROR_NOT_SUPPORTED;
883         break;
884     }
885     if (error)
886         SetLastError(error);
887     return error == NO_ERROR;
888 }
889
890 typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO, PDWORD);
891 typedef DWORD (WINAPI *GetAdaptersInfoFunc)(PIP_ADAPTER_INFO, PDWORD);
892
893 typedef struct _nbtInfo
894 {
895     DWORD ip;
896     DWORD winsPrimary;
897     DWORD winsSecondary;
898     DWORD dnsPrimary;
899     DWORD dnsSecondary;
900     DWORD unk0;
901 } nbtInfo;
902
903 #define MAX_NBT_ENTRIES 7
904
905 typedef struct _nbtTable
906 {
907     DWORD   numEntries;
908     nbtInfo table[MAX_NBT_ENTRIES];
909     UCHAR   pad[6];
910     WORD    nodeType;
911     WORD    scopeLen;
912     char    scope[254];
913 } nbtTable;
914
915 static BOOL DeviceIo_VNB(DWORD dwIoControlCode,
916                          LPVOID lpvInBuffer, DWORD cbInBuffer,
917                          LPVOID lpvOutBuffer, DWORD cbOutBuffer,
918                          LPDWORD lpcbBytesReturned,
919                          LPOVERLAPPED lpOverlapped)
920 {
921     static HMODULE iphlpapi;
922     static GetNetworkParamsFunc pGetNetworkParams;
923     static GetAdaptersInfoFunc pGetAdaptersInfo;
924     DWORD error;
925
926     switch (dwIoControlCode)
927     {
928         case 116:
929             if (lpcbBytesReturned)
930                 *lpcbBytesReturned = sizeof(nbtTable);
931             if (!lpvOutBuffer || cbOutBuffer < sizeof(nbtTable))
932                 error = ERROR_BUFFER_OVERFLOW;
933             else
934             {
935                 nbtTable *info = (nbtTable *)lpvOutBuffer;
936
937                 memset(info, 0, sizeof(nbtTable));
938                 if (!iphlpapi)
939                 {
940                     iphlpapi = LoadLibraryA("iphlpapi.dll");
941                     pGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(iphlpapi,"GetNetworkParams");
942                     pGetAdaptersInfo = (GetAdaptersInfoFunc)GetProcAddress(iphlpapi, "GetAdaptersInfo");
943                 }
944                 if (iphlpapi)
945                 {
946                     DWORD size = 0;
947
948                     error = pGetNetworkParams(NULL, &size);
949                     if (ERROR_BUFFER_OVERFLOW == error)
950                     {
951                         PFIXED_INFO fixedInfo = (PFIXED_INFO)HeapAlloc(
952                          GetProcessHeap(), 0, size);
953
954                         error = pGetNetworkParams(fixedInfo, &size);
955                         if (NO_ERROR == error)
956                         {
957                             info->nodeType = (WORD)fixedInfo->NodeType;
958                             info->scopeLen = max(strlen(fixedInfo->ScopeId) + 1,
959                              sizeof(info->scope) - 1);
960                             memcpy(info->scope, fixedInfo->ScopeId,
961                              info->scopeLen);
962                             info->scope[info->scopeLen] = '\0';
963                             /* FIXME: gotta L2-encode the scope ID */
964                             /* could set DNS servers here too, but since
965                              * ipconfig.exe and winipcfg.exe read these from the
966                              * registry, there's no point */
967                         }
968                         if (fixedInfo)
969                             HeapFree(GetProcessHeap(), 0, fixedInfo);
970                     }
971                     size = 0;
972                     error = pGetAdaptersInfo(NULL, &size);
973                     if (ERROR_BUFFER_OVERFLOW == error)
974                     {
975                         PIP_ADAPTER_INFO adapterInfo = (PIP_ADAPTER_INFO)
976                          HeapAlloc(GetProcessHeap(), 0, size);
977
978                         error = pGetAdaptersInfo(adapterInfo, &size);
979                         if (NO_ERROR == error)
980                         {
981                             PIP_ADAPTER_INFO ptr = adapterInfo;
982
983                             for (ptr = adapterInfo; ptr && info->numEntries <
984                              MAX_NBT_ENTRIES; ptr = ptr->Next)
985                             {
986                                 unsigned long addr;
987
988                                 addr = inet_addr(
989                                  ptr->IpAddressList.IpAddress.String);
990                                 if (addr != 0 && addr != INADDR_NONE)
991                                     info->table[info->numEntries].ip =
992                                      ntohl(addr);
993                                 addr = inet_addr(
994                                  ptr->PrimaryWinsServer.IpAddress.String);
995                                 if (addr != 0 && addr != INADDR_NONE)
996                                     info->table[info->numEntries].winsPrimary
997                                      = ntohl(addr);
998                                 addr = inet_addr(
999                                  ptr->SecondaryWinsServer.IpAddress.String);
1000                                 if (addr != 0 && addr != INADDR_NONE)
1001                                     info->table[info->numEntries].winsSecondary
1002                                      = ntohl(addr);
1003                                 info->numEntries++;
1004                             }
1005                         }
1006                         if (adapterInfo)
1007                             HeapFree(GetProcessHeap(), 0, adapterInfo);
1008                     }
1009                 }
1010                 else
1011                     error = GetLastError();
1012             }
1013             break;
1014
1015         case 119:
1016             /* nbtstat.exe uses this, but the return seems to be a bunch of
1017              * pointers, so it's not so easy to reverse engineer.  Fall through
1018              * to unimplemented...
1019              */
1020         default:
1021             FIXME( "Unimplemented control %ld for VxD device VNB\n",
1022                                dwIoControlCode );
1023             error = ERROR_NOT_SUPPORTED;
1024             break;
1025     }
1026     if (error)
1027         SetLastError(error);
1028     return error == NO_ERROR;
1029 }