//---------------------------------------------------------------------------- // // Non-network I/O support. // // Copyright (C) Microsoft Corporation, 2000-2002. // //---------------------------------------------------------------------------- #include "pch.hpp" #include #ifndef _WIN32_WCE #include #include #endif //---------------------------------------------------------------------------- // // COM. // //---------------------------------------------------------------------------- HRESULT CreateOverlappedPair(LPOVERLAPPED Read, LPOVERLAPPED Write) { ZeroMemory(Read, sizeof(*Read)); ZeroMemory(Write, sizeof(*Write)); Read->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (Read->hEvent == NULL) { return WIN32_LAST_STATUS(); } Write->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (Write->hEvent == NULL) { CloseHandle(Read->hEvent); return WIN32_LAST_STATUS(); } return S_OK; } BOOL ComPortRead(HANDLE Port, COM_PORT_TYPE Type, ULONG Timeout, PVOID Buffer, ULONG Len, PULONG Done, LPOVERLAPPED Olap) { BOOL Status; if (Type == COM_PORT_SOCKET) { #if defined(NT_NATIVE) || defined(_WIN32_WCE) return FALSE; #else WSABUF Buf; DWORD Flags; // Handle timeouts first. if (Timeout != 0 && Timeout != INFINITE) { FD_SET FdSet; struct timeval TimeVal; FD_ZERO(&FdSet); FD_SET((SOCKET)Port, &FdSet); TimeVal.tv_sec = Timeout / 1000; TimeVal.tv_usec = (Timeout % 1000) * 1000; if (select(1, &FdSet, NULL, NULL, &TimeVal) < 1) { return FALSE; } } Buf.len = Len; Buf.buf = (PSTR)Buffer; Flags = 0; if (WSARecv((SOCKET)Port, &Buf, 1, Done, &Flags, (LPWSAOVERLAPPED)Olap, NULL) != SOCKET_ERROR) { return TRUE; } if (WSAGetLastError() != WSA_IO_PENDING) { return FALSE; } return WSAGetOverlappedResult((SOCKET)Port, (LPWSAOVERLAPPED)Olap, Done, Timeout > 0 ? TRUE : FALSE, &Flags); #endif // #if defined(NT_NATIVE) || defined(_WIN32_WCE) } Status = ReadFile(Port, Buffer, Len, Done, Olap); if (!Status) { if (GetLastError() == ERROR_IO_PENDING) { if (Type == COM_PORT_PIPE) { // We need to explicitly handle timeouts for // pipe reading. First we wait for the I/O to // complete. There's no need to check for // success or failure as I/O success will // be checked later. WaitForSingleObject(Olap->hEvent, Timeout); // Cancel any pending I/Os. If the I/O already // completed this won't do anything. CancelIo(Port); // Now query the resulting I/O status. If it was // cancelled this will return an error. Status = GetOverlappedResult(Port, Olap, Done, FALSE); } else { Status = GetOverlappedResult(Port, Olap, Done, TRUE); } } else if (Type != COM_PORT_PIPE) { DWORD TrashErr; COMSTAT TrashStat; // Device could be locked up. Clear it just in case. ClearCommError(Port, &TrashErr, &TrashStat); } } return Status; } BOOL ComPortWrite(HANDLE Port, COM_PORT_TYPE Type, PVOID Buffer, ULONG Len, PULONG Done, LPOVERLAPPED Olap) { BOOL Status; if (Type == COM_PORT_SOCKET) { #if defined(NT_NATIVE) || defined(_WIN32_WCE) return FALSE; #else WSABUF Buf; DWORD Flags; Buf.len = Len; Buf.buf = (PSTR)Buffer; if (WSASend((SOCKET)Port, &Buf, 1, Done, 0, (LPWSAOVERLAPPED)Olap, NULL) != SOCKET_ERROR) { return TRUE; } if (WSAGetLastError() != WSA_IO_PENDING) { return FALSE; } return WSAGetOverlappedResult((SOCKET)Port, (LPWSAOVERLAPPED)Olap, Done, TRUE, &Flags); #endif // #if defined(NT_NATIVE) || defined(_WIN32_WCE) } Status = WriteFile(Port, Buffer, Len, Done, Olap); if (!Status) { if (GetLastError() == ERROR_IO_PENDING) { Status = GetOverlappedResult(Port, Olap, Done, TRUE); } else if (Type != COM_PORT_PIPE) { DWORD TrashErr; COMSTAT TrashStat; // Device could be locked up. Clear it just in case. ClearCommError(Port, &TrashErr, &TrashStat); } } return Status; } BOOL SetComPortName(PCSTR Name, PSTR Buffer, ULONG BufferSize) { if (*Name == 'c' || *Name == 'C') { return CopyString(Buffer, "\\\\.\\", BufferSize) && CatString(Buffer, Name, BufferSize); } else if (*Name >= '0' && *Name <= '9') { PCSTR Scan = Name + 1; while (*Scan >= '0' && *Scan <= '9') { Scan++; } if (*Scan == 0) { // The name was all digits so assume it's // a plain com port number. #ifndef NT_NATIVE if (!CopyString(Buffer, "\\\\.\\com", BufferSize)) { return FALSE; } #else if (!CopyString(Buffer, "\\Device\\Serial", BufferSize)) { return FALSE; } #endif return CatString(Buffer, Name, BufferSize); } else { return CopyString(Buffer, Name, BufferSize); } } else { return CopyString(Buffer, Name, BufferSize); } } ULONG SelectComPortBaud(ULONG NewRate) { #define NUM_RATES 4 static DWORD s_Rates[NUM_RATES] = {19200, 38400, 57600, 115200}; static DWORD s_CurRate = NUM_RATES; DWORD i; if (NewRate > 0) { for (i = 0; NewRate > s_Rates[i] && i < NUM_RATES - 1; i++) { // Empty. } s_CurRate = (NewRate < s_Rates[i]) ? i : i + 1; } else { s_CurRate++; } if (s_CurRate >= NUM_RATES) { s_CurRate = 0; } return s_Rates[s_CurRate]; } HRESULT SetComPortBaud(HANDLE Port, ULONG NewRate, PULONG RateSet) { ULONG OldRate; DCB LocalDcb; if (Port == NULL) { return E_FAIL; } if (!GetCommState(Port, &LocalDcb)) { return WIN32_LAST_STATUS(); } OldRate = LocalDcb.BaudRate; if (!NewRate) { NewRate = SelectComPortBaud(OldRate); } LocalDcb.BaudRate = NewRate; LocalDcb.ByteSize = 8; LocalDcb.Parity = NOPARITY; LocalDcb.StopBits = ONESTOPBIT; LocalDcb.fDtrControl = DTR_CONTROL_ENABLE; LocalDcb.fRtsControl = RTS_CONTROL_ENABLE; LocalDcb.fBinary = TRUE; LocalDcb.fOutxCtsFlow = FALSE; LocalDcb.fOutxDsrFlow = FALSE; LocalDcb.fOutX = FALSE; LocalDcb.fInX = FALSE; if (!SetCommState(Port, &LocalDcb)) { return WIN32_LAST_STATUS(); } *RateSet = NewRate; return S_OK; } HRESULT OpenComPort(PCOM_PORT_PARAMS Params, PHANDLE Handle, PULONG BaudSet) { HRESULT Status; HANDLE ComHandle; if (Params->Type == COM_PORT_SOCKET) { #if defined(NT_NATIVE) || defined(_WIN32_WCE) return E_NOTIMPL; #else WSADATA WsData; SOCKET Sock; SOCKADDR_STORAGE Addr; int AddrLen; if (WSAStartup(MAKEWORD(2, 0), &WsData) != 0) { return E_FAIL; } if ((Status = InitIpAddress(Params->PortName, Params->IpPort, &Addr, &AddrLen)) != S_OK) { return Status; } Sock = WSASocket(Addr.ss_family, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); if (Sock == INVALID_SOCKET) { return E_FAIL; } if (connect(Sock, (struct sockaddr *)&Addr, AddrLen) == SOCKET_ERROR) { closesocket(Sock); return E_FAIL; } int On = TRUE; setsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, (PSTR)&On, sizeof(On)); *Handle = (HANDLE)Sock; return S_OK; #endif // #if defined(NT_NATIVE) || defined(_WIN32_WCE) } #ifndef NT_NATIVE ComHandle = CreateFile(Params->PortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); #else ComHandle = NtNativeCreateFileA(Params->PortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL, FALSE); #endif if (ComHandle == INVALID_HANDLE_VALUE) { return WIN32_LAST_STATUS(); } if (Params->Type == COM_PORT_PIPE) { *Handle = ComHandle; return S_OK; } if (!SetupComm(ComHandle, 4096, 4096)) { CloseHandle(ComHandle); return WIN32_LAST_STATUS(); } if ((Status = SetComPortBaud(ComHandle, Params->BaudRate, BaudSet)) != S_OK) { CloseHandle(ComHandle); return Status; } COMMTIMEOUTS To; if (Params->Timeout) { To.ReadIntervalTimeout = 0; To.ReadTotalTimeoutMultiplier = 0; To.ReadTotalTimeoutConstant = Params->Timeout; To.WriteTotalTimeoutMultiplier = 0; To.WriteTotalTimeoutConstant = Params->Timeout; } else { To.ReadIntervalTimeout = 0; To.ReadTotalTimeoutMultiplier = 0xffffffff; To.ReadTotalTimeoutConstant = 0xffffffff; To.WriteTotalTimeoutMultiplier = 0xffffffff; To.WriteTotalTimeoutConstant = 0xffffffff; } if (!SetCommTimeouts(ComHandle, &To)) { CloseHandle(ComHandle); return WIN32_LAST_STATUS(); } *Handle = ComHandle; return S_OK; } //---------------------------------------------------------------------------- // // 1394. // //---------------------------------------------------------------------------- HRESULT Create1394Channel(PSTR Symlink, ULONG Channel, PSTR Name, ULONG NameSize, PHANDLE Handle) { #ifdef _WIN32_WCE return E_NOTIMPL; #else char BusName[] = "\\\\.\\1394BUS0"; HANDLE hDevice; // // we need to make sure the 1394vdbg driver is up and loaded. // send the ADD_DEVICE ioctl to eject the VDO // Assume one 1394 host controller... // hDevice = CreateFile(BusName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (hDevice != INVALID_HANDLE_VALUE) { PSTR DeviceId; ULONG ulStrLen; PIEEE1394_API_REQUEST pApiReq; PIEEE1394_VDEV_PNP_REQUEST pDevPnpReq; DWORD dwBytesRet; DRPC(("%s open sucessful\n", BusName)); if (!_stricmp(Symlink, "channel")) { DeviceId = "VIRTUAL_HOST_DEBUGGER"; } else { DeviceId = "HOST_DEBUGGER"; } ulStrLen = strlen(DeviceId) + 1; pApiReq = (PIEEE1394_API_REQUEST) malloc(sizeof(IEEE1394_API_REQUEST) + ulStrLen); if (pApiReq == NULL) { CloseHandle(hDevice); return E_OUTOFMEMORY; } pApiReq->RequestNumber = IEEE1394_API_ADD_VIRTUAL_DEVICE; pApiReq->Flags = IEEE1394_REQUEST_FLAG_PERSISTENT | IEEE1394_REQUEST_FLAG_USE_LOCAL_HOST_EUI; pDevPnpReq = &pApiReq->u.RemoveVirtualDevice; pDevPnpReq->fulFlags = 0; pDevPnpReq->Reserved = 0; pDevPnpReq->InstanceId.QuadPart = 0; memcpy(&pDevPnpReq->DeviceId, DeviceId, ulStrLen); // Failure of this call is not fatal. DeviceIoControl( hDevice, IOCTL_IEEE1394_API_REQUEST, pApiReq, sizeof(IEEE1394_API_REQUEST) + ulStrLen, NULL, 0, &dwBytesRet, NULL ); if (pApiReq) { free(pApiReq); } CloseHandle(hDevice); } else { DRPC(("%s open failed\n", BusName)); return WIN32_LAST_STATUS(); } return Open1394Channel(Symlink, Channel, Name, NameSize, Handle); #endif // #ifdef _WIN32_WCE } HRESULT Open1394Channel(PSTR Symlink, ULONG Channel, PSTR Name, ULONG NameSize, PHANDLE Handle) { if (_snprintf(Name, NameSize, "\\\\.\\DBG1394_%s%02d", Symlink, Channel) < 0) { return E_INVALIDARG; } _strupr(Name); *Handle = CreateFile(Name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); if (*Handle == INVALID_HANDLE_VALUE) { DRPC(("%s open failed\n", Name)); *Handle = NULL; return WIN32_LAST_STATUS(); } DRPC(("%s open Successful\n", Name)); return S_OK; } //---------------------------------------------------------------------------- // // Sockets. // //---------------------------------------------------------------------------- HRESULT InitIpAddress(PCSTR MachineName, ULONG Port, PSOCKADDR_STORAGE Addr, int* AddrLen) { #ifdef NT_NATIVE return E_NOTIMPL; #else ADDRINFO *Info; int Err; if (Port) { ZeroMemory(Addr, sizeof(*Addr)); } else { // If a port wasn't given save the existing // one so it doesn't get lost when we update // the address. Port = ntohs(SS_PORT(Addr)); } // Skip leading \\ if they were given. if (MachineName[0] == '\\' && MachineName[1] == '\\') { MachineName += 2; } // // Note that this file has a problem in some cases since when a // hostname is specified, it throws away all the addresses after // the first one. Instead, when connecting, each should be tried // in order until one succeeds. // if ((Err = getaddrinfo(MachineName, NULL, NULL, &Info)) != NO_ERROR) { return HRESULT_FROM_WIN32(Err); } CopyMemory(Addr, Info->ai_addr, Info->ai_addrlen); *AddrLen = Info->ai_addrlen; freeaddrinfo(Info); // Restore original port or put in passed-in port. SS_PORT(Addr) = htons((USHORT)Port); return S_OK; #endif // #ifdef NT_NATIVE }