/*
 * @(#)Rev.1.05 - vcioscm.cpp
 *
 * I/O Service Control Manager for VC++6.
 * This program enables to use '_inp/_outb' directly 
 * under Windows2000/XP.
 *
 * VCIOSCM needs a Device Driver 'IOSCM.SYS', which
 * should be placed in Current Directory, 
 * the same as Executable Programs.
 *
 * This file should be used for WindowsNT/2000/XP.
 *
 * Copyright (C) 2003-2007 by mag44(JE1TSN/M.Watanabe), all rights reserved.
 *
 */

/* 
 * To use VCIOSCM, just call IOSCM_Start() first and 
 * IOSCM_Stop() last from user functions. 
 *
 * After call IOSCM_Start(), just check return value.
 * bit0(mask with 0x0001) is not zero, this means 
 * start process could not initialize IOSCM 
 * manager, so you cannot access any I/O port, 
 * please quit program. Else you can use IOSCM.
 *
 * There is no problem calling IOSCM_Start/Stop() 
 * under Windows95/98/Me.
 */

#include "stdafx.h"
#include "ioscm.h"

#include <windows.h>
//#include <winbase.h>
#include <stdio.h>
#include <string.h>

unsigned char szVersion[] = "Ver.1.05";

/* IOSCM CTL Names for Windows2000/XP */
const char IOSCM_dname[] = "\\\\.\\ioscm"; /* Device Name     */
const char IOSCM_fname[] = "ioscm.sys";    /* Driver Filename */
const char IOSCM_sname[] = "ioscm";        /* Service Name    */

/* IOSCM Device Full Path Filename */
char szFullPath[MAX_PATH];

/* Windows OS Type Flag */
static int  wOStype;

/* IOSCM Status Flag */
static int  wIOSCMflag;

/*  Service Control Manager Handler */
static SC_HANDLE hSCM = NULL;

/* Open Service Control Manager */
/* Returns : 0 = OK */
/*        else = NG */
static int OpenSCM(void)
{
    if (hSCM == NULL)
       {
       if ((hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS)) == NULL) 
          return(GetLastError()); // Error
       }
    return(IOSCM_NOERR); // OK
}

/* Close Service Control Manager */
static void CloseSCM(void)
{
    if (hSCM != NULL)
        CloseServiceHandle(hSCM);
    hSCM = NULL;
    wIOSCMflag &= ~IOSCM_INSTALL;
}


/* Prototypes */
static DWORD DriverStop(LPCTSTR szDriver);
static DWORD DriverDelete(LPCTSTR szDriver);

/* IOSCM Install */
/* Returns : 0 = OK */
/*        else = NG */
static DWORD IOSCM_Install(LPCTSTR szFname, LPCTSTR szDriver)
{
    BOOL status;
    SC_HANDLE hSvc;
    char *filename;

    status = 0;
    hSvc = NULL;

    /* Open Service Control Manager */
    if(OpenSCM())
        return(IOSCM_ERROR); // Error

    /* Get IOSCM Device Full Path Filename */
    GetFullPathName(szFname, MAX_PATH, szFullPath, &filename);
//printf("\n%s\n\n", szFullPath); // For DEBUG

    /* Registers to  Service Control Database */ 
    if ((hSvc = CreateService(hSCM, szDriver, szDriver, 
        SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, 
        SERVICE_ERROR_NORMAL, szFullPath, NULL, NULL, NULL, 
        NULL, NULL)) == NULL)
        {
        status = GetLastError(); // Error
        if (status == 1073) // Service Already Exists, then Stop & Delete
           {
           DriverStop(IOSCM_sname);
           DriverDelete(IOSCM_sname);
           }
        }
    else 
       {
       CloseServiceHandle(hSvc); // OK
       wIOSCMflag &= ~IOSCM_INSTALL;
       }

    return(status);
}

/* IOSCM Driver Start */
/* Returns : 0 = OK */
/*        else = NG */
static DWORD DriverStart(LPCTSTR szDriver)
{
    BOOL status;
    SC_HANDLE hSvc;

    status = 0;
    hSvc = NULL;

    /* Open Service Control Manager */
    if (OpenSCM())
       return(IOSCM_ERROR);

    /* IOSCM Open Service */
    if ((hSvc = OpenService(hSCM, szDriver, SERVICE_ALL_ACCESS)) != NULL) 
       {
       if (StartService(hSvc, 0, NULL) == 0) // Error
          status = GetLastError();
       else
           ; // OK
       }
    else
        status = GetLastError(); // Error

    if (hSvc != NULL) 
       CloseServiceHandle(hSvc);

    return(status);
}

/* IOSCM Driver Stop */
/* Returns : 0 = OK */
/*        else = NG */
static DWORD DriverStop(LPCTSTR szDriver)
{
    BOOL status;
    SC_HANDLE hSvc;
    SERVICE_STATUS svc_status;

    status = 0;
    hSvc = NULL;

    /* Open Service Control Manager */
    if (OpenSCM())
       return(IOSCM_ERROR);

    /* Check if Service available or not */
    if ((hSvc = OpenService(hSCM, szDriver, SERVICE_ALL_ACCESS)) != NULL) 
       {
       if (ControlService(hSvc, SERVICE_CONTROL_STOP, &svc_status) == 0)
            status = GetLastError(); // Error
       else
           ; // OK
       }
    else
       status = GetLastError(); // Error

    if (hSvc != NULL) 
       CloseServiceHandle(hSvc);

    wIOSCMflag &= ~IOSCM_START;
    return(status);
}

/* IOSCM Driver Delete */
/* Returns : 0 = OK */
/*        else = NG */
static DWORD DriverDelete(LPCTSTR szDriver)
{
    BOOL status;
    SC_HANDLE hSvc;

    status = 0;
    hSvc = NULL;

    /* Open Service Control Manager */
    if (OpenSCM())
       return(IOSCM_ERROR);

    /* Put Delete Mark to  Service Control Database */ 
    hSvc = CreateService(hSCM, szDriver, szDriver, 
        DELETE, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, 
        SERVICE_ERROR_NORMAL, szFullPath, NULL, NULL, NULL, 
        NULL, NULL);

    /* Check if Service available or not */
    if ((hSvc = OpenService(hSCM, szDriver, SERVICE_ALL_ACCESS)) != NULL) 
       {
       if (DeleteService(hSvc) == 0) // Error
          status = GetLastError();
       else
           ; // OK
       }
    else
       status = GetLastError(); // Error

    if (hSvc != NULL) 
       CloseServiceHandle(hSvc);

    wIOSCMflag &= ~IOSCM_OPEN;
    return(status);
}

/* Distinguish Windows OS-Type, */ 
/* for IOSCM CTL is necessary or not. */
static int CheckWindowsType(void)
{
    OSVERSIONINFO osvinfo;
//	int ret; // For Test

    osvinfo.dwOSVersionInfoSize = sizeof(osvinfo);
    if( GetVersionEx(&osvinfo) == 0) //V1.01
	{
//		ret = GetLastError(); // For Test
//      return(OS_WIN95); // For Test 
      return(OS_UNKNOWN);
	}

    if (osvinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
       return(OS_WINNT);

    return(OS_WIN95);
}

/* IOSCM Start Process */
/* Returns : bit0 = Error Detected */
/*           bit1 = Device Opened */
/*           bit2 = Device Started */
/*           bit3 = Device Installed */
int IOSCM_Start(void)
{
    HANDLE h;
    int    i;
	int    os;

    /* Init Ret val */
    wIOSCMflag = 0;

    /* Exit if Windows OS Type is Win95/98/Me */
    if ((os = CheckWindowsType()) == OS_WIN95)
       {
       wOStype = OS_WIN95;
       return(wIOSCMflag); // OK, No need to CTL IOSCM
       }
    else
	if (os == OS_WINNT)
	   wOStype = OS_WINNT;
	else
	   {
	   wIOSCMflag |= IOSCM_ERROR;
	   wIOSCMflag |= IOSCM_INVOS;
       return(wIOSCMflag); // NG, No need to CTL IOSCM
	   }

    /* WinNT , try IOSCM */
    for (i=0; i<3; i++)
        {
        if (i >= 2)
        { // Device Install
           if (IOSCM_Install(IOSCM_fname, IOSCM_sname)) // Error
              goto err_detect; // Unable to open IOSCM Device
           else
               wIOSCMflag |= IOSCM_INSTALL; // OK(Installed)
           }
        if (i >= 1)
           { // Device Start
           if (DriverStart(IOSCM_sname)) // Error
              continue; // Next, Device Install
           else
               wIOSCMflag |= IOSCM_START;  // OK(Started)
           }
        // Device Open
        h = CreateFile(IOSCM_dname, GENERIC_READ, 0, NULL,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if ( h != INVALID_HANDLE_VALUE)
           { // OK(Opened)
           CloseHandle(h);
           //wIOSCMflag |= IOSCM_OPEN;
           //if (i == 0)
              { // Set all flags to terminate in final process 
              wIOSCMflag |= IOSCM_OPEN;
              wIOSCMflag |= IOSCM_START;
              wIOSCMflag |= IOSCM_INSTALL;
              }
           return(wIOSCMflag); // OK Return
           }
        else
            continue; // Error
        }
err_detect:
    IOSCM_Stop();
    wIOSCMflag |= IOSCM_ERROR; // Error
    return(wIOSCMflag); // NG Return
}

/* IOSCM Stop Process */
int IOSCM_Stop(void)
{
    /* No Operation if OS is Win95/98/Me */
    if (CheckWindowsType() == OS_WIN95)
       return(IOSCM_NOERR);

    if (wIOSCMflag & IOSCM_START) // Started ?
       {
       if (DriverStop(IOSCM_sname)) // Then Stop Device
          return(wIOSCMflag & IOSCM_START); // Error
       }
    if (wIOSCMflag & IOSCM_INSTALL) // Installed ?
       {
       if (DriverDelete(IOSCM_sname)) // Then Delete Device
          return(wIOSCMflag & IOSCM_INSTALL); // Error
       }

    CloseSCM();

    return(IOSCM_NOERR);
}