/* * Win32 device functions * * Copyright 1998 Marcus Meissner * Copyright 1998 Ulrich Weigand * Copyright 1998 Patrik Stridvall * * 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 */ #include "config.h" #include "wine/port.h" #include #ifdef HAVE_UNISTD_H # include #endif #include #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_ARPA_INET_H # include #endif #include #include #include #include "ntstatus.h" #include "windef.h" #include "winbase.h" #include "winreg.h" #include "winerror.h" #include "winnls.h" #include "file.h" #include "winioctl.h" #include "winnt.h" #include "iphlpapi.h" #include "kernel_private.h" #include "wine/server.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(file); static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped); static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped); static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped); static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped); static BOOL DeviceIo_VCD(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped); static BOOL DeviceIo_VWin32(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped); static BOOL DeviceIo_DHCP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped); static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped); static BOOL DeviceIo_HASP (DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped); static BOOL DeviceIo_NetBIOS(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped); static BOOL DeviceIo_VNB(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped); /* * VxD names are taken from the Win95 DDK */ struct VxDInfo { LPCSTR name; WORD id; BOOL (*deviceio)(DWORD, LPVOID, DWORD, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); }; static const struct VxDInfo VxDList[] = { /* Standard VxD IDs */ { "VMM", 0x0001, NULL }, { "DEBUG", 0x0002, NULL }, { "VPICD", 0x0003, NULL }, { "VDMAD", 0x0004, NULL }, { "VTD", 0x0005, NULL }, { "V86MMGR", 0x0006, NULL }, { "PAGESWAP", 0x0007, NULL }, { "PARITY", 0x0008, NULL }, { "REBOOT", 0x0009, NULL }, { "VDD", 0x000A, NULL }, { "VSD", 0x000B, NULL }, { "VMD", 0x000C, NULL }, { "VKD", 0x000D, NULL }, { "VCD", 0x000E, DeviceIo_VCD }, { "VPD", 0x000F, NULL }, { "BLOCKDEV", 0x0010, NULL }, { "VMCPD", 0x0011, NULL }, { "EBIOS", 0x0012, NULL }, { "BIOSXLAT", 0x0013, NULL }, { "VNETBIOS", 0x0014, DeviceIo_NetBIOS }, { "DOSMGR", 0x0015, NULL }, { "WINLOAD", 0x0016, NULL }, { "SHELL", 0x0017, NULL }, { "VMPOLL", 0x0018, NULL }, { "VPROD", 0x0019, NULL }, { "DOSNET", 0x001A, NULL }, { "VFD", 0x001B, NULL }, { "VDD2", 0x001C, NULL }, { "WINDEBUG", 0x001D, NULL }, { "TSRLOAD", 0x001E, NULL }, { "BIOSHOOK", 0x001F, NULL }, { "INT13", 0x0020, NULL }, { "PAGEFILE", 0x0021, NULL }, { "SCSI", 0x0022, NULL }, { "MCA_POS", 0x0023, NULL }, { "SCSIFD", 0x0024, NULL }, { "VPEND", 0x0025, NULL }, { "VPOWERD", 0x0026, NULL }, { "VXDLDR", 0x0027, NULL }, { "NDIS", 0x0028, NULL }, { "BIOS_EXT", 0x0029, NULL }, { "VWIN32", 0x002A, DeviceIo_VWin32 }, { "VCOMM", 0x002B, NULL }, { "SPOOLER", 0x002C, NULL }, { "WIN32S", 0x002D, NULL }, { "DEBUGCMD", 0x002E, NULL }, { "VNB", 0x0031, DeviceIo_VNB }, { "SERVER", 0x0032, NULL }, { "CONFIGMG", 0x0033, NULL }, { "DWCFGMG", 0x0034, NULL }, { "SCSIPORT", 0x0035, NULL }, { "VFBACKUP", 0x0036, NULL }, { "ENABLE", 0x0037, NULL }, { "VCOND", 0x0038, NULL }, { "EFAX", 0x003A, NULL }, { "DSVXD", 0x003B, NULL }, { "ISAPNP", 0x003C, NULL }, { "BIOS", 0x003D, NULL }, { "WINSOCK", 0x003E, NULL }, { "WSOCK", 0x003E, NULL }, { "WSIPX", 0x003F, NULL }, { "IFSMgr", 0x0040, DeviceIo_IFSMgr }, { "VCDFSD", 0x0041, NULL }, { "MRCI2", 0x0042, NULL }, { "PCI", 0x0043, NULL }, { "PELOADER", 0x0044, NULL }, { "EISA", 0x0045, NULL }, { "DRAGCLI", 0x0046, NULL }, { "DRAGSRV", 0x0047, NULL }, { "PERF", 0x0048, NULL }, { "AWREDIR", 0x0049, NULL }, /* Far East support */ { "ETEN", 0x0060, NULL }, { "CHBIOS", 0x0061, NULL }, { "VMSGD", 0x0062, NULL }, { "VPPID", 0x0063, NULL }, { "VIME", 0x0064, NULL }, { "VHBIOSD", 0x0065, NULL }, /* Multimedia OEM IDs */ { "VTDAPI", 0x0442, DeviceIo_VTDAPI }, { "MMDEVLDR", 0x044A, DeviceIo_MMDEVLDR }, /* Network Device IDs */ { "VNetSup", 0x0480, NULL }, { "VRedir", 0x0481, NULL }, { "VBrowse", 0x0482, NULL }, { "VSHARE", 0x0483, NULL }, { "IFSMgr", 0x0484, NULL }, { "MEMPROBE", 0x0485, NULL }, { "VFAT", 0x0486, NULL }, { "NWLINK", 0x0487, NULL }, { "VNWLINK", 0x0487, NULL }, { "NWSUP", 0x0487, NULL }, { "VTDI", 0x0488, NULL }, { "VIP", 0x0489, NULL }, { "VTCP", 0x048A, NULL }, { "VCache", 0x048B, NULL }, { "VUDP", 0x048C, NULL }, { "VAsync", 0x048D, NULL }, { "NWREDIR", 0x048E, NULL }, { "STAT80", 0x048F, NULL }, { "SCSIPORT", 0x0490, NULL }, { "FILESEC", 0x0491, NULL }, { "NWSERVER", 0x0492, NULL }, { "SECPROV", 0x0493, NULL }, { "NSCL", 0x0494, NULL }, { "WSTCP", 0x0495, NULL }, { "NDIS2SUP", 0x0496, NULL }, { "MSODISUP", 0x0497, NULL }, { "Splitter", 0x0498, NULL }, { "PPP", 0x0499, NULL }, { "VDHCP", 0x049A, DeviceIo_DHCP }, { "VNBT", 0x049B, NULL }, { "LOGGER", 0x049D, NULL }, { "EFILTER", 0x049E, NULL }, { "FFILTER", 0x049F, NULL }, { "TFILTER", 0x04A0, NULL }, { "AFILTER", 0x04A1, NULL }, { "IRLAMP", 0x04A2, NULL }, { "PCCARD", 0x097C, DeviceIo_PCCARD }, { "HASP95", 0x3721, DeviceIo_HASP }, /* WINE additions, ids unknown */ { "MONODEBG.VXD", 0x4242, DeviceIo_MONODEBG }, { NULL, 0, NULL } }; HANDLE DEVICE_Open( LPCWSTR filenameW, DWORD access, LPSECURITY_ATTRIBUTES sa ) { const struct VxDInfo *info; char filename[MAX_PATH]; if (!WideCharToMultiByte(CP_ACP, 0, filenameW, -1, filename, MAX_PATH, NULL, NULL)) { SetLastError( ERROR_FILE_NOT_FOUND ); return 0; } for (info = VxDList; info->name; info++) if (!strncasecmp( info->name, filename, strlen(info->name) )) return FILE_CreateDevice( info->id | 0x10000, access, sa ); FIXME( "Unknown/unsupported VxD %s. Try setting Windows version to 'nt40' or 'win31'.\n", filename); SetLastError( ERROR_FILE_NOT_FOUND ); return 0; } static DWORD DEVICE_GetClientID( HANDLE handle ) { DWORD ret = 0; SERVER_START_REQ( get_device_id ) { req->handle = handle; if (!wine_server_call( req )) ret = reply->id; } SERVER_END_REQ; return ret; } static const struct VxDInfo *DEVICE_GetInfo( DWORD clientID ) { const struct VxDInfo *info = NULL; if (clientID & 0x10000) { for (info = VxDList; info->name; info++) if (info->id == LOWORD(clientID)) break; } return info; } /**************************************************************************** * DeviceIoControl (KERNEL32.@) * 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 * GetLastError can decipher. */ BOOL WINAPI DeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped) { DWORD clientID; TRACE( "(%p,%ld,%p,%ld,%p,%ld,%p,%p)\n", hDevice,dwIoControlCode,lpvInBuffer,cbInBuffer, lpvOutBuffer,cbOutBuffer,lpcbBytesReturned,lpOverlapped ); if (!(clientID = DEVICE_GetClientID( hDevice ))) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } /* Check if this is a user defined control code for a VxD */ if( HIWORD( dwIoControlCode ) == 0 ) { const struct VxDInfo *info; if (!(info = DEVICE_GetInfo( clientID ))) { FIXME( "No device found for id %lx\n", clientID); } else if ( info->deviceio ) { return info->deviceio( dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer, lpcbBytesReturned, lpOverlapped ); } else { FIXME( "Unimplemented control %ld for VxD device %s\n", dwIoControlCode, info->name ? info->name : "???" ); /* FIXME: this is for invalid calls on W98SE, * but maybe we should use ERROR_CALL_NOT_IMPLEMENTED * instead ? */ SetLastError( ERROR_INVALID_FUNCTION ); } } else { NTSTATUS status; if (lpOverlapped) { status = NtDeviceIoControlFile(hDevice, lpOverlapped->hEvent, NULL, NULL, (PIO_STATUS_BLOCK)lpOverlapped, dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer); if (status) SetLastError(RtlNtStatusToDosError(status)); if (lpcbBytesReturned) *lpcbBytesReturned = lpOverlapped->InternalHigh; return !status; } else { IO_STATUS_BLOCK iosb; status = NtDeviceIoControlFile(hDevice, NULL, NULL, NULL, &iosb, dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer); if (status) SetLastError(RtlNtStatusToDosError(status)); if (lpcbBytesReturned) *lpcbBytesReturned = iosb.Information; return !status; } } return FALSE; } /*********************************************************************** * DeviceIo_VTDAPI */ static BOOL DeviceIo_VTDAPI(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped) { BOOL retv = TRUE; switch (dwIoControlCode) { case 5: if (lpvOutBuffer && (cbOutBuffer>=4)) *(DWORD*)lpvOutBuffer = GetTickCount(); if (lpcbBytesReturned) *lpcbBytesReturned = 4; break; default: FIXME( "Control %ld not implemented\n", dwIoControlCode); retv = FALSE; break; } return retv; } /*********************************************************************** * DeviceIo_IFSMgr * NOTES * These ioctls are used by 'MSNET32.DLL'. * * I have been unable to uncover any documentation about the ioctls so * the implementation of the cases IFS_IOCTL_21 and IFS_IOCTL_2F are * based on reasonable guesses on information found in the Windows 95 DDK. * */ /* * 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 struct win32apireq { unsigned long ar_proid; unsigned long ar_eax; unsigned long ar_ebx; unsigned long ar_ecx; unsigned long ar_edx; unsigned long ar_esi; unsigned long ar_edi; unsigned long ar_ebp; unsigned short ar_error; unsigned short ar_pad; }; static void win32apieq_2_CONTEXT(struct win32apireq *pIn,CONTEXT86 *pCxt) { memset(pCxt,0,sizeof(*pCxt)); pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL; 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; /* FIXME: Only partial CONTEXT86_CONTROL */ pCxt->Ebp = pIn->ar_ebp; /* FIXME: pIn->ar_proid ignored */ /* FIXME: pIn->ar_error ignored */ /* FIXME: pIn->ar_pad ignored */ } static void CONTEXT_2_win32apieq(CONTEXT86 *pCxt,struct win32apireq *pOut) { 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; /* FIXME: Only partial CONTEXT86_CONTROL */ pOut->ar_ebp = pCxt->Ebp; /* FIXME: pOut->ar_proid ignored */ /* FIXME: pOut->ar_error ignored */ /* FIXME: pOut->ar_pad ignored */ } static BOOL DeviceIo_IFSMgr(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped) { BOOL retv = TRUE; TRACE("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n", dwIoControlCode, lpvInBuffer,cbInBuffer, lpvOutBuffer,cbOutBuffer, lpcbBytesReturned, lpOverlapped); switch (dwIoControlCode) { case IFS_IOCTL_21: case IFS_IOCTL_2F:{ CONTEXT86 cxt; struct win32apireq *pIn=(struct win32apireq *) lpvInBuffer; struct win32apireq *pOut=(struct win32apireq *) lpvOutBuffer; TRACE( "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 ); win32apieq_2_CONTEXT(pIn,&cxt); if(dwIoControlCode==IFS_IOCTL_21) INSTR_CallBuiltinHandler( &cxt, 0x21 ); else INSTR_CallBuiltinHandler( &cxt, 0x2f ); CONTEXT_2_win32apieq(&cxt,pOut); retv = TRUE; } break; case IFS_IOCTL_GET_RES:{ FIXME( "Control 'IFS_IOCTL_GET_RES' not implemented\n"); retv = FALSE; } break; case IFS_IOCTL_GET_NETPRO_NAME_A:{ FIXME( "Control 'IFS_IOCTL_GET_NETPRO_NAME_A' not implemented\n"); retv = FALSE; } break; default: FIXME( "Control %ld not implemented\n", dwIoControlCode); retv = FALSE; } return retv; } /*********************************************************************** * DeviceIo_VCD */ static BOOL DeviceIo_VCD(DWORD dwIoControlCode, 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; } /*********************************************************************** * DeviceIo_VWin32 */ static void DIOCRegs_2_CONTEXT( DIOC_REGISTERS *pIn, CONTEXT86 *pCxt ) { memset( pCxt, 0, sizeof(*pCxt) ); /* Note: segment registers == 0 means that CTX_SEG_OFF_TO_LIN will interpret 32-bit register contents as linear pointers */ pCxt->ContextFlags=CONTEXT86_INTEGER|CONTEXT86_CONTROL; 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; /* FIXME: Only partial CONTEXT86_CONTROL */ pCxt->EFlags = pIn->reg_Flags & ~0x00020000; /* clear vm86 mode */ } static void CONTEXT_2_DIOCRegs( CONTEXT86 *pCxt, DIOC_REGISTERS *pOut ) { 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; /* FIXME: Only partial CONTEXT86_CONTROL */ pOut->reg_Flags = pCxt->EFlags; } #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 BOOL DeviceIo_VWin32(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped) { BOOL retv = TRUE; switch (dwIoControlCode) { case VWIN32_DIOC_DOS_IOCTL: case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */ case VWIN32_DIOC_DOS_INT13: case VWIN32_DIOC_DOS_INT25: case VWIN32_DIOC_DOS_INT26: case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */ case VWIN32_DIOC_DOS_DRIVEINFO: { CONTEXT86 cxt; DIOC_REGISTERS *pIn = (DIOC_REGISTERS *)lpvInBuffer; DIOC_REGISTERS *pOut = (DIOC_REGISTERS *)lpvOutBuffer; BYTE intnum = 0; TRACE( "Control '%s': " "eax=0x%08lx, ebx=0x%08lx, ecx=0x%08lx, " "edx=0x%08lx, esi=0x%08lx, edi=0x%08lx \n", (dwIoControlCode == VWIN32_DIOC_DOS_IOCTL)? "VWIN32_DIOC_DOS_IOCTL" : (dwIoControlCode == VWIN32_DIOC_DOS_INT25)? "VWIN32_DIOC_DOS_INT25" : (dwIoControlCode == VWIN32_DIOC_DOS_INT26)? "VWIN32_DIOC_DOS_INT26" : (dwIoControlCode == VWIN32_DIOC_DOS_DRIVEINFO)? "VWIN32_DIOC_DOS_DRIVEINFO" : "???", pIn->reg_EAX, pIn->reg_EBX, pIn->reg_ECX, pIn->reg_EDX, pIn->reg_ESI, pIn->reg_EDI ); DIOCRegs_2_CONTEXT( pIn, &cxt ); switch (dwIoControlCode) { case VWIN32_DIOC_DOS_IOCTL: /* Call int 21h */ case 0x10: /* Int 0x21 call, call it VWIN_DIOC_INT21 ? */ case VWIN32_DIOC_DOS_DRIVEINFO: /* Call int 21h 730x */ intnum = 0x21; break; case VWIN32_DIOC_DOS_INT13: intnum = 0x13; break; case VWIN32_DIOC_DOS_INT25: intnum = 0x25; break; case VWIN32_DIOC_DOS_INT26: intnum = 0x26; break; case 0x29: /* Int 0x31 call, call it VWIN_DIOC_INT31 ? */ intnum = 0x31; break; } INSTR_CallBuiltinHandler( &cxt, intnum ); CONTEXT_2_DIOCRegs( &cxt, pOut ); } break; case VWIN32_DIOC_SIMCTRLC: FIXME( "Control VWIN32_DIOC_SIMCTRLC not implemented\n"); retv = FALSE; break; default: FIXME( "Unknown Control %ld\n", dwIoControlCode); retv = FALSE; break; } return retv; } /* this is the main multimedia device loader */ static BOOL DeviceIo_MMDEVLDR(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped) { FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n", dwIoControlCode, lpvInBuffer,cbInBuffer, lpvOutBuffer,cbOutBuffer, lpcbBytesReturned, lpOverlapped ); switch (dwIoControlCode) { case 5: /* Hmm. */ *(DWORD*)lpvOutBuffer=0; *lpcbBytesReturned=4; return TRUE; } return FALSE; } /* this is used by some Origin games */ static BOOL DeviceIo_MONODEBG(DWORD dwIoControlCode, 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 */ ERR("MONODEBG: %s\n",debugstr_a(lpvInBuffer)); break; default: FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n", dwIoControlCode, lpvInBuffer,cbInBuffer, lpvOutBuffer,cbOutBuffer, lpcbBytesReturned, lpOverlapped ); break; } return TRUE; } /* pccard */ static BOOL DeviceIo_PCCARD (DWORD dwIoControlCode, 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; } 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; } typedef UCHAR (WINAPI *NetbiosFunc)(LPVOID); static BOOL DeviceIo_NetBIOS(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped) { static HMODULE netapi; static NetbiosFunc pNetbios; if (dwIoControlCode != 256) { FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n", dwIoControlCode, lpvInBuffer,cbInBuffer, lpvOutBuffer,cbOutBuffer, lpcbBytesReturned, lpOverlapped); } else { if (!pNetbios) { if (!netapi) netapi = LoadLibraryA("netapi32.dll"); if (netapi) pNetbios = (NetbiosFunc)GetProcAddress(netapi, "Netbios"); } if (pNetbios) { pNetbios(lpvInBuffer); return TRUE; } } return FALSE; } static BOOL DeviceIo_DHCP(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped) { DWORD error; switch (dwIoControlCode) { case 1: { /* since IpReleaseAddress/IpRenewAddress are not implemented, say there * are no DHCP adapters */ error = ERROR_FILE_NOT_FOUND; break; } /* FIXME: don't know what this means */ case 5: if (lpcbBytesReturned) *lpcbBytesReturned = sizeof(DWORD); if (lpvOutBuffer && cbOutBuffer >= 4) { *(LPDWORD)lpvOutBuffer = 0; error = NO_ERROR; } else error = ERROR_BUFFER_OVERFLOW; break; default: FIXME("(%ld,%p,%ld,%p,%ld,%p,%p): stub\n", dwIoControlCode, lpvInBuffer,cbInBuffer, lpvOutBuffer,cbOutBuffer, lpcbBytesReturned, lpOverlapped); error = ERROR_NOT_SUPPORTED; break; } if (error) SetLastError(error); return error == NO_ERROR; } typedef DWORD (WINAPI *GetNetworkParamsFunc)(PFIXED_INFO, PDWORD); typedef DWORD (WINAPI *GetAdaptersInfoFunc)(PIP_ADAPTER_INFO, PDWORD); typedef struct _nbtInfo { DWORD ip; DWORD winsPrimary; DWORD winsSecondary; DWORD dnsPrimary; DWORD dnsSecondary; DWORD unk0; } nbtInfo; #define MAX_NBT_ENTRIES 7 typedef struct _nbtTable { DWORD numEntries; nbtInfo table[MAX_NBT_ENTRIES]; UCHAR pad[6]; WORD nodeType; WORD scopeLen; char scope[254]; } nbtTable; static BOOL DeviceIo_VNB(DWORD dwIoControlCode, LPVOID lpvInBuffer, DWORD cbInBuffer, LPVOID lpvOutBuffer, DWORD cbOutBuffer, LPDWORD lpcbBytesReturned, LPOVERLAPPED lpOverlapped) { static HMODULE iphlpapi; static GetNetworkParamsFunc pGetNetworkParams; static GetAdaptersInfoFunc pGetAdaptersInfo; DWORD error; switch (dwIoControlCode) { case 116: if (lpcbBytesReturned) *lpcbBytesReturned = sizeof(nbtTable); if (!lpvOutBuffer || cbOutBuffer < sizeof(nbtTable)) error = ERROR_BUFFER_OVERFLOW; else { nbtTable *info = (nbtTable *)lpvOutBuffer; memset(info, 0, sizeof(nbtTable)); if (!iphlpapi) { iphlpapi = LoadLibraryA("iphlpapi.dll"); pGetNetworkParams = (GetNetworkParamsFunc)GetProcAddress(iphlpapi,"GetNetworkParams"); pGetAdaptersInfo = (GetAdaptersInfoFunc)GetProcAddress(iphlpapi, "GetAdaptersInfo"); } if (iphlpapi) { DWORD size = 0; error = pGetNetworkParams(NULL, &size); if (ERROR_BUFFER_OVERFLOW == error) { PFIXED_INFO fixedInfo = (PFIXED_INFO)HeapAlloc( GetProcessHeap(), 0, size); error = pGetNetworkParams(fixedInfo, &size); if (NO_ERROR == error) { info->nodeType = (WORD)fixedInfo->NodeType; info->scopeLen = min(strlen(fixedInfo->ScopeId) + 1, sizeof(info->scope) - 2); memcpy(info->scope + 1, fixedInfo->ScopeId, info->scopeLen); info->scope[info->scopeLen + 1] = '\0'; { /* convert into L2-encoded version */ char *ptr, *lenPtr; for (ptr = info->scope + 1; *ptr && ptr - info->scope < sizeof(info->scope); ) { for (lenPtr = ptr - 1, *lenPtr = 0; *ptr && *ptr != '.' && ptr - info->scope < sizeof(info->scope); ptr++) *lenPtr += 1; ptr++; } } /* could set DNS servers here too, but since * ipconfig.exe and winipcfg.exe read these from the * registry, there's no point */ } if (fixedInfo) HeapFree(GetProcessHeap(), 0, fixedInfo); } size = 0; error = pGetAdaptersInfo(NULL, &size); if (ERROR_BUFFER_OVERFLOW == error) { PIP_ADAPTER_INFO adapterInfo = (PIP_ADAPTER_INFO) HeapAlloc(GetProcessHeap(), 0, size); error = pGetAdaptersInfo(adapterInfo, &size); if (NO_ERROR == error) { PIP_ADAPTER_INFO ptr = adapterInfo; for (ptr = adapterInfo; ptr && info->numEntries < MAX_NBT_ENTRIES; ptr = ptr->Next) { unsigned long addr; addr = inet_addr( ptr->IpAddressList.IpAddress.String); if (addr != 0 && addr != INADDR_NONE) info->table[info->numEntries].ip = ntohl(addr); addr = inet_addr( ptr->PrimaryWinsServer.IpAddress.String); if (addr != 0 && addr != INADDR_NONE) info->table[info->numEntries].winsPrimary = ntohl(addr); addr = inet_addr( ptr->SecondaryWinsServer.IpAddress.String); if (addr != 0 && addr != INADDR_NONE) info->table[info->numEntries].winsSecondary = ntohl(addr); info->numEntries++; } } if (adapterInfo) HeapFree(GetProcessHeap(), 0, adapterInfo); } } else error = GetLastError(); } break; case 119: /* nbtstat.exe uses this, but the return seems to be a bunch of * pointers, so it's not so easy to reverse engineer. Fall through * to unimplemented... */ default: FIXME( "Unimplemented control %ld for VxD device VNB\n", dwIoControlCode ); error = ERROR_NOT_SUPPORTED; break; } if (error) SetLastError(error); return error == NO_ERROR; }