/* Hey EMACS -*- win32-c -*- */ /* $Id: ioports.c 4392 2011-08-01 09:24:05Z debrouxl $ */ /* libticables2 - link cable library, a part of the TiLP project * Copyright (C) 1999-2005 Romain Liévin * Copyright (c) 2002, Kevin Kofler for the __MINGW32__ & __GNUC__ extensions. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /* * This unit manages direct low-level I/O operations depending on the * platform type: * - Windows 9x/Me: assembly routines, * - Windows NT4/2000: assembly routines with a kernel driver for * granting I/O permissions. */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "../error.h" #include "../logging.h" #include "detect.h" #include "ioports.h" #include "../win32/dha.h" #include "../win64/rwp.h" /* Variables */ static int instance = 0; // Instance counter /* Function pointers */ int (*io_rd) (unsigned int addr); void (*io_wr) (unsigned int addr, int data); /* Error helper */ #ifdef __WIN32__ static void print_last_error(char *s) { LPTSTR lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) & lpMsgBuf, 0, NULL); lpMsgBuf[strlen(lpMsgBuf)-2] = '\0'; ticables_info("%s (%i -> %s)", s, GetLastError(), lpMsgBuf); } #endif //__WIN32__ #ifndef _WIN64 /* I/O thru assembly code */ static int win32_read_io(unsigned int addr) { int c; #ifdef __GNUC__ asm("movl $0,%%eax \n movw %1,%%dx \n inb %%dx,%%al \n movl %%eax,%0": "=g"(c): "g"(addr):"eax", "dx"); #else __asm { mov eax, 0 mov edx, addr in al, dx mov c, eax} #endif return c; } static void win32_write_io(unsigned int addr, int data) { #ifdef __GNUC__ asm("movw %0,%%dx \n movw %1,%%ax \n outb %%al,%%dx"::"g"(addr), "g"(data):"ax", "dx"); #else __asm { mov edx, addr mov eax, data out dx, al} #endif } #endif /* I/O thru device driver IOCTL calls */ static int win64_read_io(unsigned int addr) { unsigned char data; rwp_read_byte((unsigned short)addr, &data); return data; } static void win64_write_io(unsigned int addr, int data) { rwp_write_byte((unsigned short)addr, (unsigned char)data); } /* Functions used for initializing the I/O routines */ int io_open(unsigned long from) { int ret; #ifndef _WIN64 if(win32_check_os() == WIN_9X) { io_rd = win32_read_io; io_wr = win32_write_io; } else if(win32_check_os() == WIN_NT) { ret = dha_enable(); if(ret) return ERR_DHA_NOT_FOUND; io_rd = win32_read_io; io_wr = win32_write_io; instance++; } else if(win32_check_os() == WIN_64) #endif { ret = rwp_open(); if(ret) return ERR_DHA_NOT_FOUND; io_rd = win64_read_io; io_wr = win64_write_io; instance++; } return 0; } int io_close(unsigned long from) { int ret; #ifndef _WIN64 if(win32_check_os() == WIN_NT) { instance--; if(!instance) { ret = dha_disable(); if(ret) return ERR_DHA_NOT_FOUND; } } else if(win32_check_os() == WIN_64) #endif { instance--; if(!instance) { ret = rwp_close(); if(ret) return ERR_DHA_NOT_FOUND; } } return 0; } /* Used by ser_link.c only (should be used by this module and tig_link.c) */ int win32_comport_open(char *comPort, PHANDLE hCom) { DCB dcb; BOOL fSuccess; COMMTIMEOUTS cto; /* Open COM port */ *hCom = CreateFile(comPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hCom == INVALID_HANDLE_VALUE) { ticables_info("CreateFile"); print_last_error("CreateFile"); return ERR_GRY_CREATEFILE; } // Setup buffer size fSuccess = SetupComm(*hCom, 1024, 1024); if (!fSuccess) { ticables_info("SetupComm"); print_last_error("SetupComm"); return ERR_GRY_SETUPCOMM; } // Retrieve config structure fSuccess = GetCommState(*hCom, &dcb); if (!fSuccess) { ticables_info("GetCommState"); print_last_error("GetCOmmState"); return ERR_GRY_GETCOMMSTATE; } // Fills the structure with config dcb.BaudRate = CBR_9600; // 9600 bauds dcb.fBinary = TRUE; // Binary mode dcb.fParity = FALSE; // Parity checking disabled dcb.fOutxCtsFlow = FALSE; // No output flow control dcb.fOutxDsrFlow = FALSE; // Idem dcb.fDtrControl = DTR_CONTROL_DISABLE; // Provide power supply dcb.fDsrSensitivity = FALSE; // ignore DSR status dcb.fOutX = FALSE; // no XON/XOFF flow control dcb.fInX = FALSE; // idem dcb.fErrorChar = FALSE; // no replacement dcb.fNull = FALSE; // don't discard null chars dcb.fRtsControl = RTS_CONTROL_ENABLE; // Provide power supply dcb.fAbortOnError = FALSE; // do not report errors dcb.ByteSize = 8; // 8 bits dcb.Parity = NOPARITY; // no parity checking dcb.StopBits = ONESTOPBIT; // 1 stop bit // Config COM port fSuccess = SetCommState(*hCom, &dcb); if (!fSuccess) { ticables_info("SetCommState"); print_last_error("SetCOmmState"); return ERR_GRY_SETCOMMSTATE; } fSuccess = GetCommTimeouts(*hCom, &cto); if (!fSuccess) { ticables_info("GetCommTimeouts"); print_last_error("GetCommTimeouts"); return ERR_GRY_GETCOMMTIMEOUT; } cto.ReadIntervalTimeout = MAXDWORD; cto.ReadTotalTimeoutMultiplier = 0; cto.ReadTotalTimeoutConstant = 100 * 10/*time_out*/; cto.WriteTotalTimeoutMultiplier = 0; cto.WriteTotalTimeoutConstant = 0; // 0 make non-blocking fSuccess = SetCommTimeouts(*hCom, &cto); if (!fSuccess) { ticables_info("SetCommTimeouts"); print_last_error("SetCommTimeouts"); return ERR_GRY_SETCOMMTIMEOUT; } return 0; } int win32_comport_close(PHANDLE hCom) { if (*hCom) { CloseHandle(*hCom); *hCom = INVALID_HANDLE_VALUE; } return 0; } int win_serbb_put(HANDLE hComPort, int data) { int value; DWORD dwFunc; const char *name; /* handle DTR */ value = (data & 1); dwFunc = value? SETDTR: CLRDTR; name = value? "SETDTR": "CLRDTR"; //dtr = value; //Cache dtr value, may want to use this for a speed boost in the future // ticables_debug("EscapeCommFunction(%s)", name); if (!EscapeCommFunction(hComPort, dwFunc)){ ticables_critical("EscapeCommFunction(%s)", name); return -1; } /* handle rts */ value = (data & 2); /* rts */ dwFunc = value? SETRTS: CLRRTS; name = value? "SETRTS": "CLRRTS"; // ticables_debug("EscapeCommFunction(%s)", name); if (!EscapeCommFunction(hComPort, dwFunc)){ ticables_critical("EscapeCommFunction(%s)", name); return -1; } return 0; } int win_serbb_get(HANDLE hComPort) { LPVOID lpMsgBuf; int rv; const char *name; DWORD modemstate; if (!GetCommModemStatus(hComPort, &modemstate)) { ticables_critical("GetCommModemStatus() failed!"); return -1; } // ticables_debug("GetCommState() => 0x%lx", modemstate); rv = (modemstate & 0x30); return rv; }