Subversion Repositories f9daq

Rev

Blame | Last modification | View Log | RSS feed

/*
   cc32lib_NT.c -- a simple access library for the PCICC32 PCI to CAMAC Interface
                   from ARW Elektronik - the WINNT parts

   (c) 2000 ARW Elektronik

   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

   derived from the previous WIN95 library                              AR   30.07.2000
   added buffer, UNTIL_NOT_Q and AUTOREAD functionality                 AR   17.03.2001
*/

 
/*--- INCLUDES -----------------------------------------------------------------------------------*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <winioctl.h>

#include "pcicc32.h"  /* PCI common ioctl commands and structures between driver and library  */
#include "libcc32_NT.h"          /* shared header bewteen applictaion and library                        */

/*--- DEFINES ------------------------------------------------------------------------------------*/
#define DEFDEVICENAME "\\\\.\\PCICC32:\\CC32_xx"

/*--- EXTERNALS ----------------------------------------------------------------------------------*/

/*--- TYPEDEFS -----------------------------------------------------------------------------------*/
typedef struct
{
        HANDLE nHandle;                     /* the handle of this device */
        int    nModuleNumber;               /* the number of the module */
        unsigned short wLastAccessWidth;    /* the last parametrized data access width */
        unsigned short wLastAttributes;     /* the last Attributes to this channel */
        unsigned long  dwLastAccessAddress; /* the last access address to speed up */
} CC32_DEVICE_NT;

/*--- FUNCTIONS -----------------------------------------------------------------------*/

//--------------------------------------------------------------------------------------
// get the PCIADA status from the PCI side of the interface
//
static int getStatus(HANDLE nHandle, DWORD dwInterface, char *nTimeout, char *nLAM)
{
        PCICC32_STATUS status;
        DWORD DIOC_count;             // count of returned bytes of DeviceIoControl
        DWORD result;

        if (nHandle == (HANDLE)-1) return -1;

        *nTimeout = *nLAM = 0;

        // attach a window into the CC32 space ----------------
        result = DeviceIoControl(nHandle, PCICC32_GET_STATUS,
                                                &dwInterface, sizeof(dwInterface),
                                                &status,      sizeof(status), &DIOC_count, NULL);

    if (!result)
                return GetLastError();
        else
        {
                *nTimeout = (char)status.bTimeout;
                *nLAM     = (char)status.bInterrupt;

                return 0;
        }
}

//--------------------------------------------------------------------------------------
// clear the PCIADA status
//
static int clearStatus(HANDLE nHandle, DWORD dwInterface)
{
        DWORD DIOC_count;             // count of returned bytes of DeviceIoControl
        DWORD result;

        if (nHandle == (HANDLE)-1) return -1;

        // attach a window into the CC32 space ----------------
        result = DeviceIoControl(nHandle, PCICC32_CLEAR_STATUS,
                                                &dwInterface, sizeof(dwInterface),
                                                NULL,      0, &DIOC_count, NULL);

    if (!result)
                return GetLastError();
        else
                return 0;
}

//-------------------------------------------------------------------------
// set the future access parameters - override the current
//
static int setAccessParameter(HANDLE hHandle, USHORT wAccessType, USHORT wBlockTransfer)
{
        DWORD result;
        DWORD   DIOC_count;     // count of returned bytes of DeviceIoControl
    PCICC32_ACCESS_COMMAND access_parameter;

        access_parameter.wAccessType            = wAccessType;
        access_parameter.wBlockTransfer         = wBlockTransfer;

        result = DeviceIoControl(hHandle, PCICC32_SET_ACCESS_PARA,
                                        &access_parameter, (DWORD)sizeof(access_parameter), NULL,
                                                   0, &DIOC_count, NULL);      
        if (!result)
                return GetLastError();
        else
                return 0;
}

//-------------------------------------------------------------------------
// create a DeviceName out of cszDeviceName and nIfcNum
//
static char *DeviceName(int nIfcNum)
{
        static char buffer[255];
        char *ptr = buffer;

        strncpy(buffer, DEFDEVICENAME, strlen(DEFDEVICENAME));

        while (*ptr) ptr++;
       
        do
        {
                ptr--;
        } while (*ptr != '_');  // step back until '-'

        ptr++;
       
        if (nIfcNum >= 10)      // add the interface number
        {
                *ptr++   = '1';
                nIfcNum -= 10;
        }

        *ptr++ = '0' + nIfcNum;
        *ptr = 0;

        // a little help for the users
    return buffer;
}

//-------------------------------------------------------------------------
// open my path to the interface
//
static HANDLE openPath(char *name)
{
    return (HANDLE)CreateFile(
                     name,
                     GENERIC_READ | GENERIC_WRITE,
                     0,
                     NULL,
                     OPEN_EXISTING,
                     FILE_ATTRIBUTE_NORMAL,
                     NULL
                     );
}

//--------------------------------------------------------------------------------------
// open the device
//
int cc32_open_NT(char *cszPath, int nModuleNumber, void **handle)
{
        CC32_DEVICE_NT *dev;
        int error = 0;
       
        *handle = (void *)0;
       
        dev = (CC32_DEVICE_NT *)malloc(sizeof(CC32_DEVICE_NT));
        if (!dev) return errno;
       
        dev->nModuleNumber = nModuleNumber;
        dev->nHandle = INVALID_HANDLE_VALUE;
        dev->wLastAccessWidth    = 0xffff;         /* invalidate for future use */

        // start the driver ------------------
        dev->nHandle = openPath(DeviceName(nModuleNumber));
       
        if (dev->nHandle == INVALID_HANDLE_VALUE)
                error = GetLastError();
        else
        {
                SetFilePointer(dev->nHandle, 0, NULL, FILE_BEGIN);
                dev->dwLastAccessAddress = 0;
                dev->wLastAttributes = 0;
                dev->wLastAccessWidth = 0;
        }

        if (error)
        {
                free(dev);
                return error;
        }

        *handle = (void *)dev;
       
        return NO_ERROR;
}

//--------------------------------------------------------------------------------------
// close the device
//
int cc32_close_NT(void *handle)
{
        CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        int error = NO_ERROR;
       
        if (dev)
        {
                if (dev->nHandle != INVALID_HANDLE_VALUE)
                        CloseHandle(dev->nHandle);
       
                free(dev);
        }
        else
                error = ERROR_INVALID_FUNCTION;
               
        return error;
}

//--------------------------------------------------------------------------------------
// read a word
//
unsigned short cc32_read_word_NT(void *handle, unsigned int N, unsigned int A, unsigned int F)
{
        register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        unsigned long  adr = NAF(N,A,F);
        unsigned short buffer;
        unsigned long  bytesRead;

        // cache the data access width
        if (dev->wLastAccessWidth != WORD_ACCESS)
        {
                dev->wLastAccessWidth = WORD_ACCESS;
                setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
        }

        // cache the address
        if (dev->dwLastAccessAddress != adr)
        {
          SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
          dev->dwLastAccessAddress = adr;
        }

        ReadFile(dev->nHandle, &buffer, WORD_ACCESS, &bytesRead, NULL);

        return buffer;
}

//--------------------------------------------------------------------------------------
// read a long
//
unsigned long cc32_read_long_all_NT(void *handle, unsigned int N, unsigned int A, unsigned int F)
{
        register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        unsigned long  adr = NAF(N,A,F);
        unsigned long  buffer;
        unsigned long  bytesRead;

        // cache the data access width
        if (dev->wLastAccessWidth != LONG_ACCESS)
        {
                dev->wLastAccessWidth = LONG_ACCESS;
                setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
        }

        // cache the address
        if (dev->dwLastAccessAddress != adr)
        {
          SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
          dev->dwLastAccessAddress = adr;
        }

        ReadFile(dev->nHandle, &buffer, LONG_ACCESS, &bytesRead, NULL);

        return buffer;
}

//--------------------------------------------------------------------------------------
// read a long and get Q and X
//
unsigned long cc32_read_long_NT(void *handle, unsigned int N, unsigned int A, unsigned int F, char *Q, char *X)
{
        unsigned long erg = cc32_read_long_all_NT(handle, N, A, F);
       
        *Q = (erg & 0x80000000) ? 1 : 0;
        *X = (erg & 0x40000000) ? 1 : 0;

        return erg & 0x00FFFFFF;
}

//--------------------------------------------------------------------------------------
// write a word
//
void cc32_write_word_NT(void *handle, unsigned int N, unsigned int A, unsigned int F, unsigned short uwData)
{
        register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        unsigned long adr = NAF(N,A,F);
        DWORD bytesWritten;
       
        // cache the data access width
        if (dev->wLastAccessWidth != WORD_ACCESS)
        {
                dev->wLastAccessWidth = WORD_ACCESS;
                setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
        }

        // cache the address
        if (dev->dwLastAccessAddress != adr)
        {
          SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
          dev->dwLastAccessAddress = adr;
        }

        WriteFile(dev->nHandle, &uwData, WORD_ACCESS, &bytesWritten, NULL);
}

//--------------------------------------------------------------------------------------
// write a long
//
void cc32_write_long_NT(void *handle, unsigned int N, unsigned int A, unsigned int F, unsigned long ulData)
{
        register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        unsigned long adr = NAF(N,A,F);
        DWORD bytesWritten;
       
        // cache the data access width
        if (dev->wLastAccessWidth != LONG_ACCESS)
        {
                dev->wLastAccessWidth = LONG_ACCESS;
                setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
        }

        // cache the address
        if (dev->dwLastAccessAddress != adr)
        {
          SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
          dev->dwLastAccessAddress = adr;
        }

        WriteFile(dev->nHandle, &ulData, LONG_ACCESS, &bytesWritten, NULL);
}

//--------------------------------------------------------------------------------------
// clear the PCIADA status
//
int cc32_poll_error_NT(void *handle, char *nTimeout, char *nLam)
{
        CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        int error;
       
    if ((error = getStatus(dev->nHandle, dev->nModuleNumber, nTimeout, nLam)))
                return error;
               
        if (*nTimeout)  /* clear error */
        {
                if ((error = clearStatus(dev->nHandle, dev->nModuleNumber)))
                        return error;  
        }
       
        return NO_ERROR;
}

//--------------------------------------------------------------------------------------
// read 'len' words or 'UNTIL_NOT_Q' from a address made out of N,A,F
//
int cc32_read_word_buffer_NT(void * handle, unsigned int N, unsigned int A, unsigned int F,
                                                                                                                                unsigned short *pwBuffer, unsigned long *pdwLen)
{
        register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        unsigned long  adr = NAF(N,A,F);
        unsigned long dwLen;

        // cache the data access width
        if (dev->wLastAccessWidth != WORD_ACCESS)
        {
                dev->wLastAccessWidth = WORD_ACCESS;
                setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
        }

        // cache the address
        if (dev->dwLastAccessAddress != adr)
        {
          SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
          dev->dwLastAccessAddress = adr;
        }

        *pdwLen <<= 1;  // make bytes
        dwLen = *pdwLen;
        if (!ReadFile(dev->nHandle, pwBuffer, dwLen, pdwLen, NULL))
                return GetLastError();

        *pdwLen >>= 1;  // make words
        return 0;
}

//--------------------------------------------------------------------------------------
// read 'len' longs or 'UNTIL_NOT_Q' from a address made out of N,A,F, mask 24 bits out
//
int cc32_read_long_buffer_NT(void * handle, unsigned int N, unsigned int A, unsigned int F,
                                                                                                                                unsigned long *pdwBuffer, unsigned long *pdwLen)
{
        register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        unsigned long  adr = NAF(N,A,F);
        unsigned long *pdwPtr = pdwBuffer;
        unsigned long *pdwEnd = pdwBuffer;
        unsigned long dwLen;

        // cache the data access width
        if (dev->wLastAccessWidth != LONG_ACCESS)
        {
                dev->wLastAccessWidth = LONG_ACCESS;
                setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
        }

        // cache the address
        if (dev->dwLastAccessAddress != adr)
        {
          SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
          dev->dwLastAccessAddress = adr;
        }

        *pdwLen <<= 2;   // make bytes
        dwLen = *pdwLen;
        if (!ReadFile(dev->nHandle, pdwBuffer, dwLen, pdwLen, NULL))
                return GetLastError();

        pdwEnd += *pdwLen;
        while (pdwEnd < pdwPtr)
                *pdwPtr++ &= 0x00FFFFFF;  // mask Q and X bits

        *pdwLen >>= 2;   // make longs
        return 0;
}

//--------------------------------------------------------------------------------------
// read 'len' longs or 'UNTIL_NOT_Q' from a address made out of N,A,F, without interpretation
//
int cc32_read_long_all_buffer_NT(void * handle, unsigned int N, unsigned int A, unsigned int F,
                                                                                                                                unsigned long *pdwBuffer, unsigned long *pdwLen)
{
        register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        unsigned long  adr = NAF(N,A,F);
        unsigned long dwLen;

        // cache the data access width
        if (dev->wLastAccessWidth != LONG_ACCESS)
        {
                dev->wLastAccessWidth = LONG_ACCESS;
                setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
        }

        // cache the address
        if (dev->dwLastAccessAddress != adr)
        {
          SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
          dev->dwLastAccessAddress = adr;
        }

        *pdwLen <<= 2;   // make bytes
        dwLen = *pdwLen;
        if (!ReadFile(dev->nHandle, pdwBuffer, dwLen, pdwLen, NULL))
                return GetLastError();

        *pdwLen >>= 2;   // make longs
        return 0;
}

//--------------------------------------------------------------------------------------
// switch UNTIL_NOT_Q or AUTOREAD on or off
//
int cc32_access_switch_NT(void *handle, unsigned short uwSwitch)
{
        register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;

        dev->wLastAttributes  = uwSwitch;
        return setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
}

//--------------------------------------------------------------------------------------
// switch interrupts on
//
int cc32_enable_interrupt_NT(void *handle)
{
        register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        DWORD result;
        DWORD   DIOC_count;     // count of returned bytes of DeviceIoControl
        PCICC32_IRQ_CONTROL irqCntrl;

        irqCntrl.dwInterface = 0;  // don't bother at WINNT
        irqCntrl.wEnable     = 1;  // enable it

        result = DeviceIoControl(dev->nHandle, PCICC32_CONTROL_INTERRUPTS,
                                        &irqCntrl, sizeof(irqCntrl), NULL, 0, &DIOC_count, NULL);        

        if (!result)
                return GetLastError();
        else
                return NO_ERROR;
}

//--------------------------------------------------------------------------------------
// switch interrupts off
//
int cc32_disable_interrupt_NT(void *handle)
{
        register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        DWORD result;
        DWORD   DIOC_count;     // count of returned bytes of DeviceIoControl
        PCICC32_IRQ_CONTROL irqCntrl;

        irqCntrl.dwInterface = 0;  // don't bother at WINNT
        irqCntrl.wEnable     = 0;  // disable it

        result = DeviceIoControl(dev->nHandle, PCICC32_CONTROL_INTERRUPTS,
                                        &irqCntrl, sizeof(irqCntrl), NULL, 0, &DIOC_count, NULL);        

        if (!result)
                return GetLastError();
        else
                return NO_ERROR;
}

//--------------------------------------------------------------------------------------
// wait blocking for the next interrupt
//
int cc32_get_interrupt_NT(void *handle, unsigned long *dwStatus)
{
        register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
        DWORD result;
        DWORD   DIOC_count;     // count of returned bytes of DeviceIoControl
        PCICC32_IRQ_RESPONSE response;
        int nError;
        OVERLAPPED sOverlapped;

        sOverlapped.hEvent    = NULL;
        result = DeviceIoControl(dev->nHandle, PCICC32_INSTALL_IRQ_BLOCK,
                                        NULL, 0, &response, sizeof(response), &DIOC_count, NULL);
       
        *dwStatus = response.dwInterruptFlags;

        if (!result)
        {
                nError = GetLastError();

                // a real error
                if ((nError != ERROR_IO_PENDING) && (nError != ERROR_SUCCESS))
                        return nError;

                // my IO is pending - wait for it
                if (nError == ERROR_IO_PENDING)
                {
                        result = GetOverlappedResult(dev->nHandle, &sOverlapped, &DIOC_count, TRUE);
                       
                        *dwStatus = response.dwInterruptFlags;

                        if (!result)
                        {
                                nError = GetLastError();   // if it was cancelled
                                if (nError == ERROR_OPERATION_ABORTED)
                                        return NO_ERROR;       // accept it as 'normal'
                                else
                                        return nError;
                        }
                }
        }

        return NO_ERROR;
}