//-------------------------------------------------------------------------------------------
 
// pcivme_ni_NT.c - a ni labview dll skeleton for the ARW pcivme interface, winNT
 
//
 
// (c) 1999-2004 ARW Elektronik, Germany
 
//
 
// this source code is published under GPL (Open Source). You can use, redistrubute and 
 
// modify it unless this header  is  not modified or deleted. No warranty is given that 
 
// this software will work like expected.
 
// This product is not authorized for use as critical component in life support systems
 
// wihout the express written approval of ARW Elektronik Germany.
 
//
 
// Please announce changes and hints to ARW Elektronik
 
// 
 
// $Log: pcivme_ni_NT.c,v $
 
// Revision 1.2  2004/07/24 07:47:00  klaus
 
// Update copyright to 2004
 
//
 
// Revision 1.1.1.1  2003/11/14 23:17:18  klaus
 
// First put into repository
 
//
 
// Revision 1.4  2002/10/27 21:32:35  klaus
 
// compatibility improved
 
//
 
// Revision 1.3  2002/10/27 19:22:58  klaus
 
// backward compatibilty problem for 2 Gbyte limit solved
 
//
 
// Revision 1.2  2002/10/27 17:05:33  klaus
 
// CVS log added, file addressing bug > 2 Gbtye circumvent
 
//
 
// what                                                              who    when
 
// first steps                                                       AR     07.11.1999
 
//
 
 
 
//-------------------------------------------------------------------------------------------
 
// INCLUDES
 
//
 
#include <windows.h>
 
#include <winioctl.h>
 
#include <pcivme.h>    // header for win-NT
 
#include <vic.h>
 
#include <vme.h>
 
#include <pcivme_ni_NT.h>
 
#include <Klist.h>
 
 
 
#include <stdio.h>
 
FILE *vmefp;
 
//-------------------------------------------------------------------------------------------
 
// DEFINES
 
//
 
#define DEFDEVICENAME "\\\\.\\PCIVME:\\VMEMMxx"
 
#define LIMIT_2GBYTE  0x80000000       // 2 GByte addressing limit of WINNT ...
 
 
 
//-------------------------------------------------------------------------------------------
 
// TYPEDEFS
 
//
 
typedef struct // a element associated to a open path (between VMEinit and VMEclose)
 
{
 
        HANDLE                                  nHandle;
 
        PCIVME_ACCESS_COMMAND   access;
 
} OPEN_PATH;
 
 
 
//-------------------------------------------------------------------------------------------
 
// LOCALS
 
//
 
// user initialisation table for pcivme
 
static PCIVME_INIT_COMMAND sUserInitStruct   = {2, {{STOP, WORD_ACCESS, 0,    0}}};            
 
// user deinitialisation table
 
static PCIVME_INIT_COMMAND sUserDeInitStruct = {2, {{STOP, WORD_ACCESS, 0,    0}}};
 
 
 
// the list of Path specific data (a element lives between VMEinit and VMEclose) 
 
static LIST liPathList          = (LIST)NULL;
 
 
 
//-------------------------------------------------------------------------------------------
 
// EXTERNALS
 
//
 
 
 
//-------------------------------------------------------------------------------------------
 
// GLOBALS
 
//
 
 
 
//-------------------------------------------------------------------------------------------
 
// FUNCTIONS
 
//
 
// not only delete a element - even remove the whole list if it is empty
 
static void removeListElement(OPEN_PATH *open_path)
 
{
 
        List_Delete((LPVOID)open_path);
 
 
 
        // remove the list if the last item was deleted ----
 
        if ((liPathList != NULL) && (List_IsEmpty(liPathList) == TRUE)) 
 
        {
 
                List_Destroy(&liPathList);
 
                liPathList = (LIST)NULL;
 
        }
 
}
 
 
 
//-------------------------------------------------------------------------
 
// create a DeviceName out of cszDeviceName and nIfcNum
 
static char *DeviceName(const char *cszDeviceName, int nIfcNum)
 
{
 
        static char buffer[255];
 
        char *ptr = buffer;
 
 
 
        if (cszDeviceName == NULL)
 
                strcpy_s(buffer, 255 , DEFDEVICENAME);
 
        else
 
                strcpy_s(buffer, 255 , cszDeviceName);
 
 
 
        while (*ptr) ptr++;
 
        
 
        do
 
        {
 
                ptr--;
 
        } while (*ptr != 'M');
 
 
 
        ptr++;
 
        
 
        if (nIfcNum >= 10)
 
        {
 
                *ptr++   = '1';
 
                nIfcNum -= 10;
 
        }
 
 
 
        *ptr++ = '0' + nIfcNum;
 
        *ptr = 0;
 
 
 
    return buffer;
 
}
 
 
 
int VMEinitNT(const char *cszDeviceName, unsigned short nVMEMM, unsigned char ubAddressModifier, int *pnHandle)
 
{
 
        OPEN_PATH *open_path;
 
        DWORD   DIOC_count;                     // count of returned bytes of DeviceIoControl
 
        DWORD   result = 0;
 
        vmefp 
= fopen("pcivme_ni.log","w"); 
        if (liPathList == NULL)         // create a list to hold the paths and its variables
 
        {
 
                liPathList = List_Create();
 
                if (liPathList == (LIST)NULL)
 
                        return GetLastError();
 
        }
 
        
 
        open_path = (OPEN_PATH *)List_NewFirst(liPathList, sizeof(OPEN_PATH));
 
 
 
        *pnHandle = -1;
 
 
 
    if ((open_path->nHandle = CreateFile( 
 
                                                DeviceName(cszDeviceName, nVMEMM), 
 
                                                GENERIC_READ | GENERIC_WRITE, 
 
                                                0, 
 
                                                NULL, 
 
                                                OPEN_EXISTING, 
 
                                                FILE_ATTRIBUTE_NORMAL, 
 
                                                NULL)) != ((HANDLE)-1)) 
 
        { 
 
                // init hardware (only one time after the first init it works OK)
 
                result = DeviceIoControl(open_path->nHandle, 
 
                                                PCIVME_INIT_HARDWARE,
 
                                                &sUserInitStruct, 
 
                                                (DWORD)sizeof(sUserInitStruct), 
 
                                                NULL,
 
                                                (DWORD)0, 
 
                                                &DIOC_count, 
 
                                                NULL);
 
 
 
                // set the current access parameters ------------------
 
                open_path->access.bAddressModifier      = ubAddressModifier;
 
                open_path->access.bAccessType           = 
 
                open_path->access.bIncrement            = BYTE_ACCESS;
 
                open_path->access.dwAccessBase  = 0;
 
 
 
                result = DeviceIoControl(open_path->nHandle, 
 
                                                PCIVME_SET_ACCESS_PARA,
 
                                                &open_path->access, 
 
                                                (DWORD)sizeof(open_path->access), 
 
                                                NULL,
 
                                                0, 
 
                                                &DIOC_count, 
 
                                                NULL);  
 
                
 
 
 
                if (!result) 
 
                {
 
                        
 
                        result = GetLastError();
 
                        fprintf(vmefp
, "DeviceIoControl result=%d\n", result
);  
                        CloseHandle(open_path->nHandle); 
 
                        removeListElement(open_path);
 
                        return result;
 
                }
 
 
 
                *pnHandle    = (int)open_path;
 
 
 
                return 0;
 
        }
 
        else 
 
        {
 
                
 
                result = GetLastError();
 
                fprintf(vmefp
, "CreateFile error  result=%d %s\n", result
, DeviceName
(cszDeviceName
, nVMEMM
));  
                removeListElement(open_path);
 
                return result;
 
        }
 
}
 
 
 
int VMEreadNT(int nHandle, unsigned long ulAddress, unsigned char ubAccessWidth, unsigned long ulElementCount, void *pvBuffer)
 
{
 
        DWORD    DIOC_count;     // count of returned bytes of DeviceIoControl
 
        unsigned long ulNumberOfBytes = ulElementCount * ubAccessWidth;
 
        unsigned long bytesRead;
 
        OPEN_PATH *open_path = (OPEN_PATH *)nHandle;
 
 
 
        if (nHandle == -1) return ERROR_PATH_NOT_FOUND;
 
 
 
        // set the current access parameters ------------------
 
        open_path->access.bAccessType                   = 
 
        open_path->access.bIncrement                    = ubAccessWidth;
 
 
 
        // take care of only 2 Gbyte addressing capabilities of WINNT ...
 
        if (ulAddress >= LIMIT_2GBYTE)
 
        {
 
                ulAddress -= LIMIT_2GBYTE;
 
                open_path->access.dwAccessBase = LIMIT_2GBYTE;
 
        }
 
        else
 
                open_path->access.dwAccessBase = 0;
 
 
 
        if (!DeviceIoControl(open_path->nHandle, 
 
                                                PCIVME_SET_ACCESS_PARA,
 
                                                &open_path->access, 
 
                                                (DWORD)sizeof(open_path->access), 
 
                                                NULL,
 
                                                0, 
 
                                                &DIOC_count, 
 
                                                NULL))   
 
                return GetLastError();
 
 
 
        SetFilePointer(open_path->nHandle, ulAddress, NULL, FILE_BEGIN);
 
 
 
        if (!ReadFile(open_path->nHandle, pvBuffer, ulNumberOfBytes, &bytesRead, NULL))
 
                return GetLastError();
 
 
 
        return 0;
 
}
 
 
 
int VMEwriteNT(int nHandle, unsigned long ulAddress, unsigned char ubAccessWidth, unsigned long ulElementCount, void *pvBuffer)
 
{
 
        DWORD    DIOC_count;     // count of returned bytes of DeviceIoControl
 
        unsigned long ulNumberOfBytes = ulElementCount * ubAccessWidth;
 
        unsigned long bytesRead;
 
        OPEN_PATH *open_path = (OPEN_PATH *)nHandle;
 
 
 
        if (nHandle == -1) return ERROR_PATH_NOT_FOUND;
 
 
 
        // set the current access parameters ------------------
 
        open_path->access.bAccessType    = 
 
        open_path->access.bIncrement     = ubAccessWidth;
 
 
 
        // take care of only 2 Gbyte addressing capabilities of WINNT ...
 
        if (ulAddress >= LIMIT_2GBYTE)
 
        {
 
                ulAddress -= LIMIT_2GBYTE;
 
                open_path->access.dwAccessBase = LIMIT_2GBYTE;
 
        }
 
        else
 
                open_path->access.dwAccessBase = 0;
 
 
 
        if (!DeviceIoControl(open_path->nHandle, 
 
                                                        PCIVME_SET_ACCESS_PARA,
 
                                                        &open_path->access, 
 
                                                        (DWORD)sizeof(open_path->access), 
 
                                                        NULL,
 
                                                        0, 
 
                                                        &DIOC_count, 
 
                                                        NULL))   
 
                return GetLastError();
 
 
 
        SetFilePointer(open_path->nHandle, ulAddress, NULL, FILE_BEGIN);
 
 
 
        if (!WriteFile(open_path->nHandle, pvBuffer, ulNumberOfBytes, &bytesRead, NULL))
 
                return GetLastError();
 
 
 
        return 0;
 
}
 
 
 
int VMEaccessVICNT(int nHandle, unsigned char ubAccessMode, unsigned short uwAddress, unsigned char *ubContent)
 
{
 
        DWORD    DIOC_count;     // count of returned bytes of DeviceIoControl
 
        OPEN_PATH *open_path = (OPEN_PATH *)nHandle;
 
        PCIVME_VIC68A_ACTION   sAction;    // structure to access vic chip
 
        DWORD                  result;
 
 
 
        if (nHandle == -1) return ERROR_PATH_NOT_FOUND;
 
 
 
        sAction.wRegisterAddress = uwAddress;
 
        sAction.wAccessMode      = ubAccessMode;
 
        sAction.bContent         = *ubContent;
 
 
 
        result = DeviceIoControl(open_path->nHandle, PCIVME_ACCESS_VIC68A,
 
                                         &sAction, sizeof(sAction), &sAction,
 
                                                        sizeof(sAction), &DIOC_count, NULL);     
 
 
 
        *ubContent = sAction.bContent;
 
 
 
        if (!result) 
 
                return GetLastError();
 
        else
 
                return 0;
 
}
 
 
 
int VMEresetNT(int nHandle)
 
{
 
        DWORD    DIOC_count;     // count of returned bytes of DeviceIoControl
 
        OPEN_PATH *open_path = (OPEN_PATH *)nHandle;
 
        DWORD   result;
 
        PCIVME_RESET_COMMAND reset_command;
 
        PCIVME_RESET_RESULT  reset_result;
 
 
 
        if (nHandle == -1) return ERROR_PATH_NOT_FOUND;
 
 
 
        reset_command.wCommand = VME_RESET_CMD;
 
        reset_result.wResult   = 0;
 
        result = DeviceIoControl(open_path->nHandle, PCIVME_RESET,
 
                &reset_command, sizeof(reset_command), 
 
                                &reset_result,  sizeof(reset_result), 
 
                                   &DIOC_count, NULL);   
 
 
 
        if (!result) 
 
                return GetLastError();
 
        else
 
        {
 
                result = 1;
 
 
 
                while (reset_result.wResult && result)
 
                {
 
                        reset_command.wCommand = POLL_RESET_CMD;
 
                        result = DeviceIoControl(open_path->nHandle, PCIVME_RESET,
 
                                                &reset_command, sizeof(reset_command), 
 
                                                &reset_result,  sizeof(reset_result), 
 
                                                        &DIOC_count, NULL);      
 
                        Sleep(10);
 
                }
 
        }
 
 
 
        if (!result)
 
                return GetLastError();
 
        else
 
                return 0;
 
}
 
 
 
int VMETASNT(int nHandle, unsigned long ulAddress, unsigned char *ubResult)
 
{
 
        DWORD    DIOC_count;     // count of returned bytes of DeviceIoControl
 
        OPEN_PATH *open_path = (OPEN_PATH *)nHandle;
 
        PCIVME_TAS_STRUCT      sTAS;       // structure to do a Test and Set
 
        DWORD                  result;
 
 
 
        if (nHandle == -1) return ERROR_PATH_NOT_FOUND;
 
 
 
        sTAS.wModifier        = open_path->access.bAddressModifier;
 
        sTAS.dwAddress        = ulAddress;
 
        sTAS.bContent         = 0x80;
 
 
 
        result = DeviceIoControl(open_path->nHandle, PCIVME_TAS,
 
                                         &sTAS, (DWORD)sizeof(sTAS), &sTAS,
 
                                                        (DWORD)sizeof(sTAS), &DIOC_count, NULL); 
 
 
 
        *ubResult = sTAS.bContent; 
 
 
 
        if (!result)
 
                return GetLastError();
 
        else
 
                return 0;
 
}
 
 
 
int VMEinterruptNT(int nHandle, unsigned char *ubVector)
 
{
 
//      DWORD    DIOC_count;     // count of returned bytes of DeviceIoControl
 
        OPEN_PATH *open_path = (OPEN_PATH *)nHandle;
 
 
 
        if (nHandle == -1) return ERROR_PATH_NOT_FOUND;
 
 
 
        return 0;
 
}
 
 
 
int VMEsysfailGetNT(int nHandle, BOOLEAN *bResult)
 
{
 
        DWORD    DIOC_count;     // count of returned bytes of DeviceIoControl
 
        OPEN_PATH *open_path = (OPEN_PATH *)nHandle;
 
        PCIVME_VIC68A_ACTION   sAction;    // structure to access vic chip
 
        DWORD result;
 
 
 
        if (nHandle == -1) return ERROR_PATH_NOT_FOUND;
 
 
 
        sAction.wRegisterAddress = EGICR;
 
        sAction.wAccessMode      = VIC68A_READ;
 
        sAction.bContent         = 0;
 
 
 
        result = DeviceIoControl(open_path->nHandle, PCIVME_ACCESS_VIC68A,
 
                                         &sAction, sizeof(sAction), &sAction,
 
                                                        sizeof(sAction), &DIOC_count, NULL);     
 
 
 
 
 
        *bResult = (sAction.bContent & 0x08) ? FALSE : TRUE;
 
 
 
        if (!result)
 
                return GetLastError();
 
        else
 
                return 0;
 
}
 
 
 
int VMEsysfailSetNT(int nHandle, BOOLEAN bForce)
 
{
 
        DWORD    DIOC_count;     // count of returned bytes of DeviceIoControl
 
        OPEN_PATH *open_path = (OPEN_PATH *)nHandle;
 
        PCIVME_VIC68A_ACTION   sAction;    // structure to access vic chip
 
        DWORD result;
 
 
 
        if (nHandle == -1) return ERROR_PATH_NOT_FOUND;
 
 
 
        sAction.wRegisterAddress = ICR7;
 
        sAction.wAccessMode      = (bForce == TRUE) ? VIC68A_AND : VIC68A_OR;
 
        sAction.bContent         = (bForce == TRUE) ? 0x3F               : 0x80;
 
 
 
        result = DeviceIoControl(open_path->nHandle, PCIVME_ACCESS_VIC68A,
 
                                         &sAction, (DWORD)sizeof(sAction), &sAction,
 
                                                        (DWORD)sizeof(sAction), &DIOC_count, NULL);
 
        if (!result)
 
                return GetLastError();
 
        else
 
                return 0;
 
}
 
 
 
int VMEcloseNT(int nHandle)
 
{
 
        DWORD    DIOC_count;     // count of returned bytes of DeviceIoControl
 
        OPEN_PATH *open_path = (OPEN_PATH *)nHandle;
 
 
 
        if (nHandle == -1) return ERROR_PATH_NOT_FOUND;
 
 
 
        DeviceIoControl(open_path->nHandle, 
 
                                                PCIVME_DEINIT_HARDWARE,
 
                                                &sUserDeInitStruct, 
 
                                                (DWORD)sizeof(sUserDeInitStruct), 
 
                                                NULL,
 
                                                0, 
 
                                                &DIOC_count, 
 
                                                NULL);   
 
 
 
        CloseHandle(open_path->nHandle);
 
        removeListElement(open_path);
 
 
 
        return 0;
 
}