diff options
Diffstat (limited to 'opl/ioperm_sys.c')
-rw-r--r-- | opl/ioperm_sys.c | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/opl/ioperm_sys.c b/opl/ioperm_sys.c new file mode 100644 index 00000000..8f50bcd3 --- /dev/null +++ b/opl/ioperm_sys.c @@ -0,0 +1,361 @@ +// Emacs style mode select -*- C++ -*- +//----------------------------------------------------------------------------- +// +// Copyright(C) 2002, 2003 Marcel Telka +// Copyright(C) 2009 Simon Howard +// +// 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., 59 Temple Place - Suite 330, Boston, MA +// 02111-1307, USA. +// +// DESCRIPTION: +// Interface to the ioperm.sys driver, based on code from the +// Cygwin ioperm library. +// +//----------------------------------------------------------------------------- + +#ifdef _WIN32 + +#include <stdio.h> + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <winioctl.h> + +#include <errno.h> + +#include "ioperm_sys.h" + +#define IOPERM_FILE L"\\\\.\\ioperm" + +#define IOCTL_IOPERM \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0xA00, METHOD_BUFFERED, FILE_ANY_ACCESS) + +struct ioperm_data +{ + unsigned long from; + unsigned long num; + int turn_on; +}; + +// Function pointers for advapi32.dll. This DLL does not exist on +// Windows 9x, so they are dynamically loaded from the DLL at runtime. + +static SC_HANDLE WINAPI (*MyOpenSCManagerW)(wchar_t *lpMachineName, + wchar_t *lpDatabaseName, + DWORD dwDesiredAccess) = NULL; +static SC_HANDLE WINAPI (*MyCreateServiceW)(SC_HANDLE hSCManager, + wchar_t *lpServiceName, + wchar_t *lpDisplayName, + DWORD dwDesiredAccess, + DWORD dwServiceType, + DWORD dwStartType, + DWORD dwErrorControl, + wchar_t *lpBinaryPathName, + wchar_t *lpLoadOrderGroup, + LPDWORD lpdwTagId, + wchar_t *lpDependencies, + wchar_t *lpServiceStartName, + wchar_t *lpPassword); +static SC_HANDLE WINAPI (*MyOpenServiceW)(SC_HANDLE hSCManager, + wchar_t *lpServiceName, + DWORD dwDesiredAccess); +static BOOL WINAPI (*MyStartServiceW)(SC_HANDLE hService, + DWORD dwNumServiceArgs, + wchar_t **lpServiceArgVectors); +static BOOL WINAPI (*MyControlService)(SC_HANDLE hService, + DWORD dwControl, + LPSERVICE_STATUS lpServiceStatus); +static BOOL WINAPI (*MyCloseServiceHandle)(SC_HANDLE hSCObject); +static BOOL WINAPI (*MyDeleteService)(SC_HANDLE hService); + +static struct +{ + char *name; + void **fn; +} dll_functions[] = { + { "OpenSCManagerW", (void **) &MyOpenSCManagerW }, + { "CreateServiceW", (void **) &MyCreateServiceW }, + { "OpenServiceW", (void **) &MyOpenServiceW }, + { "StartServiceW", (void **) &MyStartServiceW }, + { "ControlService", (void **) &MyControlService }, + { "CloseServiceHandle", (void **) &MyCloseServiceHandle }, + { "DeleteService", (void **) &MyDeleteService }, +}; + +// Globals + +static SC_HANDLE scm = NULL; +static SC_HANDLE svc = NULL; +static int service_was_created = 0; +static int service_was_started = 0; + +static int LoadLibraryPointers(void) +{ + HMODULE dll; + int i; + + // Already loaded? + + if (MyOpenSCManagerW != NULL) + { + return 1; + } + + dll = LoadLibraryW(L"advapi32.dll"); + + if (dll == NULL) + { + fprintf(stderr, "LoadLibraryPointers: Failed to open advapi32.dll\n"); + return 0; + } + + for (i = 0; i < sizeof(dll_functions) / sizeof(*dll_functions); ++i) + { + *dll_functions[i].fn = GetProcAddress(dll, dll_functions[i].name); + + if (*dll_functions[i].fn == NULL) + { + fprintf(stderr, "LoadLibraryPointers: Failed to get address " + "for '%s'\n", dll_functions[i].name); + return 0; + } + } + + return 1; +} + +int IOperm_EnablePortRange(unsigned int from, unsigned int num, int turn_on) +{ + HANDLE h; + struct ioperm_data ioperm_data; + DWORD BytesReturned; + BOOL r; + + h = CreateFileW(IOPERM_FILE, GENERIC_READ, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (h == INVALID_HANDLE_VALUE) + { + errno = ENODEV; + return -1; + } + + ioperm_data.from = from; + ioperm_data.num = num; + ioperm_data.turn_on = turn_on; + + r = DeviceIoControl(h, IOCTL_IOPERM, + &ioperm_data, sizeof ioperm_data, + NULL, 0, + &BytesReturned, NULL); + + if (!r) + { + errno = EPERM; + } + + CloseHandle(h); + + return r != 0; +} + +// Load ioperm.sys driver. +// Returns 1 for success, 0 for failure. +// Remember to call IOperm_UninstallDriver to uninstall the driver later. + +int IOperm_InstallDriver(void) +{ + wchar_t driver_path[MAX_PATH]; + int error; + int result = 1; + + if (!LoadLibraryPointers()) + { + return 0; + } + + scm = MyOpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); + + if (scm == NULL) + { + error = GetLastError(); + fprintf(stderr, "IOperm_InstallDriver: OpenSCManager failed (%i).\n", + error); + return 0; + } + + // Get the full path to the driver file. + + GetFullPathNameW(L"ioperm.sys", MAX_PATH, driver_path, NULL); + + // Create the service. + + svc = MyCreateServiceW(scm, + L"ioperm", + L"ioperm support for Cygwin driver", + SERVICE_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, + driver_path, + NULL, + NULL, + NULL, + NULL, + NULL); + + if (svc == NULL) + { + error = GetLastError(); + + if (error != ERROR_SERVICE_EXISTS) + { + fprintf(stderr, + "IOperm_InstallDriver: Failed to create service (%i).\n", + error); + } + else + { + svc = MyOpenServiceW(scm, L"ioperm", SERVICE_ALL_ACCESS); + + if (svc == NULL) + { + error = GetLastError(); + + fprintf(stderr, + "IOperm_InstallDriver: Failed to open service (%i).\n", + error); + } + } + + if (svc == NULL) + { + MyCloseServiceHandle(scm); + return 0; + } + } + else + { + service_was_created = 1; + } + + // Start the service. If the service already existed, it might have + // already been running as well. + + if (!MyStartServiceW(svc, 0, NULL)) + { + error = GetLastError(); + + if (error != ERROR_SERVICE_ALREADY_RUNNING) + { + fprintf(stderr, "IOperm_InstallDriver: Failed to start service (%i).\n", + error); + + result = 0; + } + else + { + printf("IOperm_InstallDriver: ioperm driver already running.\n"); + } + } + else + { + printf("IOperm_InstallDriver: ioperm driver installed.\n"); + service_was_started = 1; + } + + // If we failed to start the driver running, we need to clean up + // before finishing. + + if (result == 0) + { + IOperm_UninstallDriver(); + } + + return result; +} + +int IOperm_UninstallDriver(void) +{ + SERVICE_STATUS stat; + int result = 1; + int error; + + // If we started the service, stop it. + + if (service_was_started) + { + if (!MyControlService(svc, SERVICE_CONTROL_STOP, &stat)) + { + error = GetLastError(); + + if (error == ERROR_SERVICE_NOT_ACTIVE) + { + fprintf(stderr, + "IOperm_UninstallDriver: Service not active? (%i)\n", + error); + } + else + { + fprintf(stderr, + "IOperm_UninstallDriver: Failed to stop service (%i).\n", + error); + result = 0; + } + } + } + + // If we created the service, delete it. + + if (service_was_created) + { + if (!MyDeleteService(svc)) + { + error = GetLastError(); + + fprintf(stderr, + "IOperm_UninstallDriver: DeleteService failed (%i).\n", + error); + + result = 0; + } + else if (service_was_started) + { + printf("IOperm_UnInstallDriver: ioperm driver uninstalled.\n"); + } + } + + // Close handles. + + if (svc != NULL) + { + MyCloseServiceHandle(svc); + svc = NULL; + } + + if (scm != NULL) + { + MyCloseServiceHandle(scm); + scm = NULL; + } + + service_was_created = 0; + service_was_started = 0; + + return result; +} + +#endif /* #ifndef _WIN32 */ + |