From 06b97d2d116b622bc067b245f81b2857767d598e Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Fri, 26 Feb 2010 21:07:59 +0000 Subject: Add OPL hardware playback support for Windows NT-based systems. Subversion-branch: /branches/opl-branch Subversion-revision: 1871 --- opl/ioperm_sys.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 opl/ioperm_sys.c (limited to 'opl/ioperm_sys.c') diff --git a/opl/ioperm_sys.c b/opl/ioperm_sys.c new file mode 100644 index 00000000..37512b63 --- /dev/null +++ b/opl/ioperm_sys.c @@ -0,0 +1,255 @@ +// 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 + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include + +#define IOPERM_FILE "\\\\.\\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; +}; + +static SC_HANDLE scm = NULL; +static SC_HANDLE svc = NULL; +static int service_was_created = 0; +static int service_was_started = 0; + +int IOperm_EnablePortRange(unsigned int from, unsigned int num, int turn_on) +{ + HANDLE h; + struct ioperm_data ioperm_data; + DWORD BytesReturned; + BOOL r; + + h = CreateFile(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) +{ + int error; + int result = 1; + + scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + + if (scm == NULL) + { + error = GetLastError(); + fprintf(stderr, "IOperm_InstallDriver: OpenSCManager failed (%i)\n", + error); + return 0; + } + + svc = CreateService(scm, + TEXT("ioperm"), + TEXT("I/O port access driver"), + SERVICE_ALL_ACCESS, + SERVICE_KERNEL_DRIVER, + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, + "ioperm.sys", + 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 = OpenService(scm, TEXT("ioperm"), SERVICE_ALL_ACCESS); + + if (svc == NULL) + { + error = GetLastError(); + + fprintf(stderr, + "IOperm_InstallDriver: Failed to open service (%i)\n", + error); + } + } + + if (svc == NULL) + { + CloseServiceHandle(scm); + return 0; + } + } + else + { + service_was_created = 1; + } + + if (!StartService(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 (result == 0) + { + CloseServiceHandle(svc); + CloseServiceHandle(scm); + } + + 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 (!ControlService(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 (!DeleteService(svc)) + { + error = GetLastError(); + + fprintf(stderr, + "IOperm_UninstallDriver: DeleteService failed (%i)\n", + error); + + result = 0; + } + } + + // Close handles. + + if (svc != NULL) + { + CloseServiceHandle(svc); + svc = NULL; + } + + if (scm != NULL) + { + CloseServiceHandle(scm); + scm = NULL; + } + + service_was_created = 0; + service_was_started = 0; + + return result; +} + +#endif /* #ifndef _WIN32 */ + -- cgit v1.2.3 From 77ea97c6277cc7261e332deec5d48fbddd88821a Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 27 Feb 2010 18:57:46 +0000 Subject: When loading driver, pass the full path to the ioperm.sys file. Subversion-branch: /branches/opl-branch Subversion-revision: 1874 --- opl/ioperm_sys.c | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'opl/ioperm_sys.c') diff --git a/opl/ioperm_sys.c b/opl/ioperm_sys.c index 37512b63..4c06d97a 100644 --- a/opl/ioperm_sys.c +++ b/opl/ioperm_sys.c @@ -93,6 +93,7 @@ int IOperm_EnablePortRange(unsigned int from, unsigned int num, int turn_on) int IOperm_InstallDriver(void) { + wchar_t driver_path[MAX_PATH]; int error; int result = 1; @@ -106,19 +107,25 @@ int IOperm_InstallDriver(void) return 0; } - svc = CreateService(scm, - TEXT("ioperm"), - TEXT("I/O port access driver"), - SERVICE_ALL_ACCESS, - SERVICE_KERNEL_DRIVER, - SERVICE_AUTO_START, - SERVICE_ERROR_NORMAL, - "ioperm.sys", - NULL, - NULL, - NULL, - NULL, - NULL); + // Get the full path to the driver file. + + GetFullPathNameW(L"ioperm.sys", MAX_PATH, driver_path, NULL); + + // Create the service. + + svc = CreateServiceW(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) { @@ -229,6 +236,10 @@ int IOperm_UninstallDriver(void) result = 0; } + else + { + printf("IOperm_InstallDriver: ioperm driver uninstalled.\n"); + } } // Close handles. -- cgit v1.2.3 From 92c9d5c388ab91ade416539438fb0b8da9cd50bb Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Sat, 27 Feb 2010 19:11:24 +0000 Subject: Use wide-character versions of Win32 API functions. Clean up properly if it was not possible to start the ioperm service. Subversion-branch: /branches/opl-branch Subversion-revision: 1875 --- opl/ioperm_sys.c | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) (limited to 'opl/ioperm_sys.c') diff --git a/opl/ioperm_sys.c b/opl/ioperm_sys.c index 4c06d97a..0e1ecfd5 100644 --- a/opl/ioperm_sys.c +++ b/opl/ioperm_sys.c @@ -35,7 +35,9 @@ #include -#define IOPERM_FILE "\\\\.\\ioperm" +#include "ioperm_sys.h" + +#define IOPERM_FILE L"\\\\.\\ioperm" #define IOCTL_IOPERM \ CTL_CODE(FILE_DEVICE_UNKNOWN, 0xA00, METHOD_BUFFERED, FILE_ANY_ACCESS) @@ -59,8 +61,8 @@ int IOperm_EnablePortRange(unsigned int from, unsigned int num, int turn_on) DWORD BytesReturned; BOOL r; - h = CreateFile(IOPERM_FILE, GENERIC_READ, 0, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + h = CreateFileW(IOPERM_FILE, GENERIC_READ, 0, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (h == INVALID_HANDLE_VALUE) { @@ -97,12 +99,12 @@ int IOperm_InstallDriver(void) int error; int result = 1; - scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (scm == NULL) { error = GetLastError(); - fprintf(stderr, "IOperm_InstallDriver: OpenSCManager failed (%i)\n", + fprintf(stderr, "IOperm_InstallDriver: OpenSCManager failed (%i).\n", error); return 0; } @@ -134,19 +136,19 @@ int IOperm_InstallDriver(void) if (error != ERROR_SERVICE_EXISTS) { fprintf(stderr, - "IOperm_InstallDriver: Failed to create service (%i)\n", + "IOperm_InstallDriver: Failed to create service (%i).\n", error); } else { - svc = OpenService(scm, TEXT("ioperm"), SERVICE_ALL_ACCESS); + svc = OpenServiceW(scm, L"ioperm", SERVICE_ALL_ACCESS); if (svc == NULL) { error = GetLastError(); fprintf(stderr, - "IOperm_InstallDriver: Failed to open service (%i)\n", + "IOperm_InstallDriver: Failed to open service (%i).\n", error); } } @@ -162,31 +164,37 @@ int IOperm_InstallDriver(void) service_was_created = 1; } - if (!StartService(svc, 0, NULL)) + // Start the service. If the service already existed, it might have + // already been running as well. + + if (!StartServiceW(svc, 0, NULL)) { error = GetLastError(); if (error != ERROR_SERVICE_ALREADY_RUNNING) { - fprintf(stderr, "IOperm_InstallDriver: Failed to start service (%i)\n", + fprintf(stderr, "IOperm_InstallDriver: Failed to start service (%i).\n", error); + result = 0; } else { - printf("IOperm_InstallDriver: ioperm driver already running\n"); + printf("IOperm_InstallDriver: ioperm driver already running.\n"); } } else { - printf("IOperm_InstallDriver: ioperm driver installed\n"); + 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) { - CloseServiceHandle(svc); - CloseServiceHandle(scm); + IOperm_UninstallDriver(); } return result; @@ -215,7 +223,7 @@ int IOperm_UninstallDriver(void) else { fprintf(stderr, - "IOperm_UninstallDriver: Failed to stop service (%i)\n", + "IOperm_UninstallDriver: Failed to stop service (%i).\n", error); result = 0; } @@ -231,14 +239,14 @@ int IOperm_UninstallDriver(void) error = GetLastError(); fprintf(stderr, - "IOperm_UninstallDriver: DeleteService failed (%i)\n", + "IOperm_UninstallDriver: DeleteService failed (%i).\n", error); result = 0; } - else + else if (service_was_started) { - printf("IOperm_InstallDriver: ioperm driver uninstalled.\n"); + printf("IOperm_UnInstallDriver: ioperm driver uninstalled.\n"); } } -- cgit v1.2.3 From b9e18229624500d6d2a6112a5c00882d7b7051de Mon Sep 17 00:00:00 2001 From: Simon Howard Date: Mon, 8 Mar 2010 00:51:00 +0000 Subject: Load advapi32.dll pointers dynamically at runtime. This should fix any potential problems with that library not existing on Win9x. Subversion-branch: /branches/opl-branch Subversion-revision: 1877 --- opl/ioperm_sys.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 108 insertions(+), 21 deletions(-) (limited to 'opl/ioperm_sys.c') diff --git a/opl/ioperm_sys.c b/opl/ioperm_sys.c index 0e1ecfd5..8f50bcd3 100644 --- a/opl/ioperm_sys.c +++ b/opl/ioperm_sys.c @@ -49,11 +49,93 @@ struct ioperm_data 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; @@ -99,7 +181,12 @@ int IOperm_InstallDriver(void) int error; int result = 1; - scm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!LoadLibraryPointers()) + { + return 0; + } + + scm = MyOpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (scm == NULL) { @@ -115,19 +202,19 @@ int IOperm_InstallDriver(void) // Create the service. - svc = CreateServiceW(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); + 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) { @@ -141,7 +228,7 @@ int IOperm_InstallDriver(void) } else { - svc = OpenServiceW(scm, L"ioperm", SERVICE_ALL_ACCESS); + svc = MyOpenServiceW(scm, L"ioperm", SERVICE_ALL_ACCESS); if (svc == NULL) { @@ -155,7 +242,7 @@ int IOperm_InstallDriver(void) if (svc == NULL) { - CloseServiceHandle(scm); + MyCloseServiceHandle(scm); return 0; } } @@ -167,7 +254,7 @@ int IOperm_InstallDriver(void) // Start the service. If the service already existed, it might have // already been running as well. - if (!StartServiceW(svc, 0, NULL)) + if (!MyStartServiceW(svc, 0, NULL)) { error = GetLastError(); @@ -210,7 +297,7 @@ int IOperm_UninstallDriver(void) if (service_was_started) { - if (!ControlService(svc, SERVICE_CONTROL_STOP, &stat)) + if (!MyControlService(svc, SERVICE_CONTROL_STOP, &stat)) { error = GetLastError(); @@ -234,7 +321,7 @@ int IOperm_UninstallDriver(void) if (service_was_created) { - if (!DeleteService(svc)) + if (!MyDeleteService(svc)) { error = GetLastError(); @@ -254,13 +341,13 @@ int IOperm_UninstallDriver(void) if (svc != NULL) { - CloseServiceHandle(svc); + MyCloseServiceHandle(svc); svc = NULL; } if (scm != NULL) { - CloseServiceHandle(scm); + MyCloseServiceHandle(scm); scm = NULL; } -- cgit v1.2.3