//-------------------------------------------------------------------------------------------
 
// pcivme_ni.c - shared library for ARW pcivme interface (libpcivme.so)
 
//
 
// Copyright (C) 2002-2004 ARW Elektronik Germany
 
//
 
// this source code is published under LGPL (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.c,v $
 
// Revision 1.8  2004/08/13 19:23:45  klaus
 
// conversion to kernel-version 2.6, released version 3.0
 
//
 
// Revision 1.7  2002/10/20 18:07:18  klaus
 
// changed error handling
 
//
 
// Revision 1.6  2002/10/18 21:56:28  klaus
 
// completed functional features, untested
 
//
 
// Revision 1.5  2002/10/18 21:56:28  klaus
 
// completed functional features, untested
 
//
 
// Revision 1.4  2002/10/17 21:16:03  klaus
 
// filled function bodies
 
//
 
// Revision 1.3  2002/10/17 21:16:03  klaus
 
// filled function bodies
 
//
 
// Revision 1.2  2002/10/17 19:05:03  klaus
 
// VME access is working through test to lib to driver
 
//
 
// Revision 1.1  2002/10/12 22:04:30  klaus
 
// first work done
 
//
 
 
 
//-------------------------------------------------------------------------------------------
 
// INCLUDES
 
//
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <string.h>
 
#include <unistd.h>
 
#include <linux/types.h>
 
#include <sys/ioctl.h>
 
#include <errno.h>
 
#include <ctype.h>
 
#include <sys/types.h>
 
#include <sys/stat.h>
 
#include <fcntl.h>
 
 
 
#include <../driver/pcivme.h>
 
#include <../driver/vic.h>
 
#include <pcivme_ni.h>
 
 
 
//-------------------------------------------------------------------------------------------
 
// DEFINES
 
//
 
#define LOCAL_STRING_LEN 40
 
 
 
//-------------------------------------------------------------------------------------------
 
// TYPEDEFS
 
//
 
 
 
// storage for path specific data
 
typedef struct
 
{
 
    int nFileNo;              // file number to f
 
    __u8 cAddressModifier;    // associated VME address modifier
 
    __u8 cAccessWidth;        // current access width
 
    int  nLastError;          // != 0 if a previous error occurred
 
} VMEMM_DEVICE;
 
 
 
//-------------------------------------------------------------------------------------------
 
// FUNCTIONS
 
//
 
 
 
// construct a device file name
 
static char *szDeviceName(const char *cszBaseName, int nVMEMM)
 
{
 
  static char path[LOCAL_STRING_LEN];
 
  int i = LOCAL_STRING_LEN - 1;
 
 
 
  path[0] = 0;
 
 
 
  memset(path
, 0, LOCAL_STRING_LEN
);  
 
 
  if (strlen(cszBaseName
) >= (LOCAL_STRING_LEN 
- 3))  
      return "";
 
 
 
  if (nVMEMM > 15)
 
      return "";
 
 
 
  strncpy(path
, cszBaseName
, LOCAL_STRING_LEN 
- 3);  
 
 
  while ((i--) && (path[i] != '_'));  // search for '_'
 
 
 
  if (i)
 
  {
 
      i++; // go after '_'
 
      if (nVMEMM >= 10)
 
      {
 
          path[i] = '1';
 
          nVMEMM -= 10;
 
          i++;
 
      }
 
      path[i] = '0' + nVMEMM;
 
      i++;
 
      path[i] = 0; // trailing 0
 
  }
 
  else
 
      return "";
 
 
 
  return path;
 
}
 
 
 
static int initHardware(VMEMM_DEVICE *dev)
 
{
 
    PCIVME_INIT_COMMAND init;
 
 
 
    init.sVie[0].bDestination = STOP;
 
    init.sVie[0].bAccessType  =
 
    init.sVie[0].dwValue      = 
 
    init.sVie[0].wOffset      = 0;
 
 
 
    if (ioctl(dev->nFileNo, PCIVME_INIT_HARDWARE, &init) < 0)
 
    {
 
        dev->nLastError = errno;
 
        return errno;
 
    }
 
 
 
    return 0;
 
}
 
 
 
static int deInitHardware(VMEMM_DEVICE *dev)
 
{
 
    PCIVME_INIT_COMMAND deinit;
 
 
 
    deinit.sVie[0].bDestination = STOP;
 
    deinit.sVie[0].bAccessType  =
 
    deinit.sVie[0].dwValue      = 
 
    deinit.sVie[0].wOffset      = 0;
 
 
 
    if (ioctl(dev->nFileNo, PCIVME_DEINIT_HARDWARE, &deinit) < 0)
 
    {
 
        dev->nLastError = errno;
 
        return errno;
 
    }
 
 
 
    return 0;
 
}
 
 
 
int VMEopen(const char *cszDeviceName, unsigned char ubAddressModifier, int *pnHandle)
 
{
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)NULL;
 
    int error;
 
 
 
    *pnHandle = 0;
 
 
 
    dev 
= (VMEMM_DEVICE 
*)malloc(sizeof(*dev
)); 
    if (!dev)
 
        return errno;
 
 
 
    dev->nFileNo = open(cszDeviceName, O_RDWR);
 
    //printf("VMEopen: dev->nFileNo %d size=%d %s\n" , dev->nFileNo,sizeof(*dev),  cszDeviceName );
 
    if (dev->nFileNo == -1)
 
    {
 
        error = errno;
 
        return error;
 
    }
 
 
 
    dev->cAddressModifier = ubAddressModifier;
 
    *pnHandle             = (int)dev;
 
 
 
    error = initHardware(dev);
 
    if (error) 
 
        return error;
 
 
 
    dev->nLastError = 0;
 
 
 
    return setAccessProperties(*pnHandle, dev->cAddressModifier, BYTE_ACCESS); // set access properties to default
 
}
 
 
 
int VMEinit(const char *cszDeviceName, unsigned short nVMEMM, unsigned char ubAddressModifier, int *pnHandle)
 
{
 
    char *szLocalDeviceName = szDeviceName(cszDeviceName, nVMEMM);
 
 
 
    return VMEopen(szLocalDeviceName, ubAddressModifier, pnHandle);
 
}
 
 
 
int setAccessProperties(int nHandle, unsigned char bModifier, unsigned char bAccessType)
 
{
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)nHandle;
 
 
 
    PCIVME_ACCESS_COMMAND access_command;
 
                
 
    access_command.bAccessType = 
 
    access_command.bIncrement  = bAccessType;  // increment and accessType are the same
 
    access_command.bModifier   = bModifier;
 
 
 
    if (ioctl(dev->nFileNo, PCIVME_SET_ACCESS_PARA, &access_command) < 0)
 
    {
 
        dev->nLastError = errno;
 
        return errno;
 
    }
 
 
 
    dev->cAddressModifier = bModifier;
 
    dev->cAccessWidth     = bAccessType;
 
 
 
    return 0;
 
}
 
 
 
int VMEread(int nHandle, unsigned long ulAddress, unsigned char ubAccessWidth, unsigned long ulElementCount, void *pvBuffer)
 
{
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)nHandle;
 
    size_t count      = (size_t)(ulElementCount * ubAccessWidth);
 
    ssize_t result;
 
    int error;
 
    long pos;
 
 
 
//    printf("VMEread:  AW 0x%0x 0x%0x  , AM 0x%0x \n", dev->cAccessWidth, ubAccessWidth, dev->cAddressModifier);
 
    if (dev->cAccessWidth != ubAccessWidth)
 
    {
 
        if ((error = setAccessProperties(nHandle, dev->cAddressModifier, ubAccessWidth)))
 
            return error;
 
    }
 
    pos = lseek(dev->nFileNo, ulAddress, SEEK_SET);
 
   
 
    if ( pos < 0){
 
        printf("VMEread: pos=0x%08lx dev->nFileNo=%d ADDR=0x%08lx %s\n",pos
, dev
->nFileNo
, ulAddress
, strerror(errno
));  
        switch (errno){
 
          case EBADF
:printf("errno =EBADF\n");break;  
          case EINVAL
:printf("errno =EINVAL\n");break;  
          case EOVERFLOW
:printf("errno =EOVERFLOW\n");break;  
          case ESPIPE
:printf("errno =ESPIPE\n");break;  
          case ENXIO
:printf("errno =ENXIO\n");break;  
        }
 
        //return errno;
 
    }
 
 
 
   
 
    result = read(dev->nFileNo, pvBuffer, count);
 
//    printf("VMEread: read %d dev->nFileNo=%d err=%d %s\n",count, dev->nFileNo, errno, strerror(errno));
 
    if (result != count)
 
    {
 
        if (result < 0)
 
        {
 
            dev->nLastError = errno;
 
            return errno;
 
        }
 
        else
 
            return EFAULT;
 
    }
 
 
 
    return 0;
 
}
 
 
 
int VMEwrite(int nHandle, unsigned long ulAddress, unsigned char ubAccessWidth, unsigned long ulElementCount, void *pvBuffer)
 
{
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)nHandle;
 
    size_t count      = (size_t)(ulElementCount * ubAccessWidth);
 
    ssize_t result;
 
    int error;
 
    long pos;
 
 
 
//    printf("VMEwrite:  AW 0x%0x 0x%0x  , AM 0x%0x \n", dev->cAccessWidth, ubAccessWidth, dev->cAddressModifier);
 
    if (dev->cAccessWidth != ubAccessWidth)
 
    {
 
        if ((error = setAccessProperties(nHandle, dev->cAddressModifier, ubAccessWidth)))
 
            return error;
 
    }
 
 
 
    pos = lseek(dev->nFileNo, ulAddress, SEEK_SET);
 
    if (pos < 0){
 
        printf("VMEwrite: pos=0x%08lx  dev->nFileNo=%d ADDR=0x%08lx %s\n",pos
, dev
->nFileNo
, ulAddress
, strerror(errno
));  
        switch (errno){
 
          case EBADF
:printf("errno =EBADF\n");break;  
          case EINVAL
:printf("errno =EINVAL\n");break;  
          case EOVERFLOW
:printf("errno =EOVERFLOW\n");break;  
          case ESPIPE
:printf("errno =ESPIPE\n");break;  
          case ENXIO
:printf("errno =ENXIO\n");break;  
        }
 
        //return errno;
 
    }
 
    result = write(dev->nFileNo, pvBuffer, count);
 
//    printf("VMEwrite: write %d dev->nFileNo=%d err=%d %s\n",count, dev->nFileNo,errno, strerror(errno));
 
    if (result != count)
 
    {
 
        if (result < 0)
 
        {
 
            dev->nLastError = errno;
 
            
 
            return errno;
 
        }
 
        else
 
            return EFAULT;
 
    }
 
 
 
    return 0;
 
}
 
 
 
int VMEaccessVIC(int nHandle, unsigned char ubAccessMode, unsigned short uwAddress, unsigned char *ubContent)
 
{
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)nHandle;
 
    PCIVME_VIC68A_ACTION vic68a_action;
 
 
 
    vic68a_action.bAccessMode      = ubAccessMode;
 
    vic68a_action.bContent         = *ubContent;  
 
    vic68a_action.wRegisterAddress = uwAddress;
 
 
 
    if (ioctl(dev->nFileNo, PCIVME_ACCESS_VIC68A, &vic68a_action) < 0)
 
    {
 
        dev->nLastError = errno;
 
        return errno;
 
    }
 
 
 
    *ubContent = vic68a_action.bContent;
 
 
 
    return 0;
 
}
 
 
 
int VMEreset(int nHandle)
 
{
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)nHandle;
 
    PCIVME_RESET_COMMAND reset_command;
 
    int i = 10;
 
 
 
    reset_command.bCommand = GLOBAL_RESET_CMD;
 
    reset_command.bResult  = 0xff;  
 
 
 
    if (ioctl(dev->nFileNo, PCIVME_RESET, &reset_command) < 0)
 
    {
 
        dev->nLastError = errno;
 
        return errno;
 
    }
 
 
 
    do
 
    {
 
        usleep(100);
 
        reset_command.bCommand = POLL_RESET_CMD;
 
        reset_command.bResult  = 0xff;  
 
    
 
        if (ioctl(dev->nFileNo, PCIVME_RESET, &reset_command) < 0)
 
        {
 
            dev->nLastError = errno;
 
            return errno;
 
        }
 
    } while ((reset_command.bResult) && (i--));
 
 
 
    if (!i)
 
        return ETIME;
 
 
 
    dev->nLastError = 0;
 
 
 
    return 0;
 
}
 
 
 
int VMETAS(int nHandle, unsigned long ulAddress, unsigned char *ubResult)
 
{
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)nHandle;
 
    PCIVME_TAS_STRUCT tas;
 
 
 
    tas.bContent  = *ubResult;
 
    tas.bModifier = dev->cAddressModifier;  
 
    tas.dwAddress = ulAddress;
 
 
 
    if (ioctl(dev->nFileNo, PCIVME_TAS, &tas) < 0)
 
    {
 
        dev->nLastError = errno;
 
        return errno;
 
    }
 
 
 
    *ubResult = tas.bContent;
 
 
 
    return 0;
 
}
 
 
 
int VMEinterrupt(int nHandle, unsigned char *ubVector)
 
{
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)nHandle;
 
        PCIVME_VECTOR_LEVEL ubLocalVector; 
 
 
 
    if (ioctl(dev->nFileNo, PCIVME_READ_VECTOR_POLL, &ubLocalVector) < 0)
 
    {
 
        dev->nLastError = errno;
 
        return errno;
 
    }
 
 
 
    *ubVector = (__u8)ubLocalVector.dwStatusID;
 
 
 
    return 0;
 
}
 
 
 
int VMEsysfailGet(int nHandle, BOOLEAN *bResult)
 
{
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)nHandle;
 
        PCIVME_VIC68A_ACTION sAction;    // structure to access vic chip
 
 
 
        sAction.wRegisterAddress = EGICR;
 
        sAction.bAccessMode      = VIC68A_READ;
 
        sAction.bContent         = 0;
 
 
 
    if (ioctl(dev->nFileNo, PCIVME_ACCESS_VIC68A, &sAction) < 0)
 
    {
 
        dev->nLastError = errno;
 
        return errno;
 
    }
 
 
 
        *bResult = (sAction.bContent & 0x08) ? FALSE : TRUE;
 
 
 
    return 0;
 
}
 
 
 
int VMEsysfailSet(int nHandle, BOOLEAN bForce)
 
{
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)nHandle;
 
        PCIVME_VIC68A_ACTION sAction;    // structure to access vic chip
 
 
 
        sAction.wRegisterAddress = ICR7;
 
        sAction.bAccessMode      = (bForce == TRUE) ? VIC68A_AND : VIC68A_OR;
 
        sAction.bContent         = (bForce == TRUE) ? 0x3F               : 0x80;
 
 
 
    if (ioctl(dev->nFileNo, PCIVME_ACCESS_VIC68A, &sAction) < 0)
 
    {
 
        dev->nLastError = errno;
 
        return errno;
 
    }
 
 
 
    return 0;
 
}
 
 
 
int VMEerror(int nHandle)
 
{
 
    __u8 ubVector;
 
 
 
    VMEinterrupt(nHandle, &ubVector);
 
 
 
    if (ubVector == 7)
 
        return EFAULT;  // it's a bus error
 
    else
 
        return 0;
 
}
 
 
 
int VMEclose(int nHandle)
 
{
 
    int error = 0;
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)nHandle;
 
 
 
    if (dev != (VMEMM_DEVICE *)NULL)
 
    {
 
        deInitHardware(dev);
 
 
 
        if (dev->nFileNo != -1)
 
            close(dev->nFileNo);
 
        else
 
            error = -EINVAL;
 
 
 
    }
 
 
 
    return error;
 
}
 
 
 
int VMEcontrolInterrupt(int nHandle, BOOLEAN *bEnable)
 
{
 
    VMEMM_DEVICE *dev = (VMEMM_DEVICE *)nHandle;
 
        PCIVME_IRQ_CONTROL  control; 
 
 
 
    control.bEnable = *bEnable;
 
 
 
    if (ioctl(dev->nFileNo, PCIVME_CONTROL_INTERRUPTS, &control) < 0)
 
    {
 
        dev->nLastError = errno;
 
        return errno;
 
    }
 
 
 
    // status of interrupt enable before set
 
    *bEnable = control.bEnable;
 
 
 
    return 0;
 
}
 
 
 
int GetLastError(int nHandle)
 
{
 
    VMEMM_DEVICE *dev  = (VMEMM_DEVICE *)nHandle;
 
    int nLocalError;
 
 
 
    nLocalError = dev->nLastError;
 
    dev->nLastError = 0;
 
 
 
    return nLocalError;
 
}