[atlastdaq] / DAQ / DataFlow / vme_rcc / src / lib / vme_rcc_lib.cpp Repository:
ViewVC logotype

View of /DAQ/DataFlow/vme_rcc/src/lib/vme_rcc_lib.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.14 - (download) (annotate)
Tue Mar 9 08:09:34 2004 UTC (5 years, 8 months ago) by joos
Branch: MAIN
CVS Tags: v1r0p24, v1r0p25, v1r0p22, v1r0p23, v1r0p20, v1r0p21
Branch point for: DF-01-00-00_patches, DF-00-09-00_patches, DF-00-09-01_patches, DF-00-10-00_patches
Changes since 1.13: +3 -3 lines
minor modifications
// $Id: vme_rcc_lib.cpp,v 1.14 2004/03/09 08:09:34 joos Exp $
/********************************************************************************/
/*										*/
/* File: vme_rcc_lib.c								*/
/*										*/
/* This is the RCC VMEbus library						*/
/*										*/
/* 24. Oct. 01  MAJO  created							*/
/* 01. Nov. 01  JOP   interrupts						*/
/* 26. Nov. 01  JOP   bus errors						*/
/* 09. Jan. 02  JOP   replace parameters by structure pointer in wait/getinfo	*/
/*										*/
/************ C 2001 - The software with that certain something *****************/

#include <iostream>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <asm/page.h>
#include <linux/pci.h>
#include "rcc_error/rcc_error.h"
#include "vme_rcc.h"
#include "vme_rcc_lib.h"
#include "cmem_rcc/cmem_rcc.h"
#include "io_rcc/io_rcc.h"
#include "DFDebug/DFDebug.h"

//globals
static u_int is_open = 0;
static int gahandle,dev_handle;
static VME_MasterMap_t ga_master_map;
static VME_MasterMapInt_t mastermap_table[VME_MAX_MASTERMAP];
static VME_SlaveMapInt_t slavemap_table[VME_MAX_SLAVEMAP];
static int shandle;
static unsigned int crcsrok, shandle_size, shandle_paddr, shandle_uaddr;
static u_int universe_handle, chains[VME_MAXCHAIN];
static VME_IntHandle_t int_handle[VME_MAX_INTHANDLE];   // the interrupt handles


/********************************************/
int VME_ErrorPrint(VME_ErrorCode_t error_code)
/********************************************/
{
  unsigned int ret;
  
  ret = rcc_error_print(stdout, error_code);
  
  return(ret);
}


/*****************************************************************/
int VME_ErrorString(VME_ErrorCode_t error_code, char *error_string)
/*****************************************************************/
{
  unsigned int ret;
  
  ret = rcc_error_string(error_string, error_code);

  return(ret);
}


/****************************************************************/
int VME_ErrorNumber(VME_ErrorCode_t error_code, int *error_number)
/****************************************************************/
{
  *error_number = RCC_ERROR_MINOR(error_code);

  return(0);
}


/****************************/
VME_ErrorCode_t VME_Open(void)
/****************************/
{
  int loop,ret;
  u_int *ptr;

  DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_Open: Start of function");

  //we need to open the driver only once
  if (is_open)
  {
    is_open++;             //keep track of multiple open calls
    return(RCC_ERROR_RETURN(0, VME_SUCCESS));
  }
  
  is_open = 1;

  //open the error package
  ret = rcc_error_init(P_ID_VMERCC,vmercc_err_get);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_Open: Failed to open error package");
    is_open = 0;
    return(RCC_ERROR_RETURN(0, VME_ERROR_FAIL)); 
  }
  DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_Open: error package opened");   

  dev_handle = open(DEVICE, O_RDWR, 0);
  if (dev_handle < 0)
  {
    is_open = 0;
    return(RCC_ERROR_RETURN(0, VME_FILE));
  }

  //initialize the master map table
  for (loop = 0; loop < VME_MAX_MASTERMAP; loop++)
    mastermap_table[loop].used = 0;

  //initialize the slave map table
  for (loop = 0; loop < VME_MAX_SLAVEMAP; loop++)
    slavemap_table[loop].used = 0;

  //Open the IO package
  ret = IO_Open();
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_Open: Error from IO_Open");
    is_open = 0;
    return(RCC_ERROR_RETURN(ret, VME_IO_FAIL));
  }

  //allocate memory for chain descriptors
  ret = CMEM_Open();
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_Open: Error from CMEM_Open");
    is_open = 0;
    return(RCC_ERROR_RETURN(ret, VME_CMEM_FAIL));
  }
  
  shandle_size = DMA_DESC_SIZE; 
  ret = CMEM_SegmentAllocate(shandle_size, "VME_RCC_DMA_INTERNAL", &shandle);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_Open: Error from CMEM_SegmentAllocate");
    is_open = 0;
    return(RCC_ERROR_RETURN(ret, VME_CMEM_FAIL));
  } 

  ret = CMEM_SegmentPhysicalAddress(shandle, &shandle_paddr);
  ret = CMEM_SegmentVirtualAddress(shandle, &shandle_uaddr);

  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_Open: shandle_uaddr=0x" << std::hex << (u_int)shandle_uaddr << std::dec);
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_Open: shandle_paddr=0x" << std::hex << (u_int)shandle_paddr << std::dec);

  //initialize the DMA chain descriptors
  ptr = (u_int *)shandle_uaddr;
  for (loop = 0; loop < ((VME_MAXCHAINEL * VME_MAXCHAIN * sizeof(VME_DmaChain_t)) >> 2); loop++)
    *ptr ++= 0;

  //initialize the DMA chain descriptor handles
  for (loop = 0; loop < VME_MAXCHAIN; loop++)
    chains[loop] = 0; 
  
  //Get a permanent mapping for CR/CSR space access
  //An error here should not kill us as we have to be able to open the library
  //in vmeconfig
  crcsrok = 1;
  ga_master_map.vmebus_address  = CRCSR_BASE;
  ga_master_map.window_size     = CRCSR_SIZE;
  ga_master_map.address_modifier= VME_CRCSR;
  ga_master_map.options         = CRCSR_OPT;

  ret = VME_MasterMap(&ga_master_map, &gahandle);
  if (ret != VME_SUCCESS)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_Open: Error received from VME_MasterMap for CR/CSR window");
    crcsrok = 0;
  }
  else
    DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_Open: Mapping created for CR/CSR space access");

  DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_Open: End of function");
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*****************************/
VME_ErrorCode_t VME_Close(void)
/*****************************/
{
  int ret;

  DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_Close: Start of function");
  ISOPEN;

  if (is_open > 1)
  {
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_Close: is_open = " << is_open);
    is_open--;
  }
  else
  {
    DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_Close: Now closing the library");
    //Close master mapping for CR/CSR space access
    if (crcsrok)
    {
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_Close: gahandle = " << gahandle);
      ret = VME_MasterUnmap(gahandle);
      if (ret != VME_SUCCESS)
  	  return(RCC_ERROR_RETURN(0, ret));
    } 

    ret = CMEM_SegmentFree(shandle);
    if (ret)
    { 
      DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_Close: Error from CMEM_SegmentFree");
      return(RCC_ERROR_RETURN(ret, VME_CMEM_FAIL));
    }

    ret = CMEM_Close();
    if (ret)
    { 
      DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_Close: Error from CMEM_Close");
      return(RCC_ERROR_RETURN(ret, VME_CMEM_FAIL));
    }
    
    ret = IO_Close();
    if (ret)
    { 
      DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_Close: Error from IO_Close");
      return(RCC_ERROR_RETURN(ret, VME_IO_FAIL));
    }

    ret = close(dev_handle);
    if (ret < 0)
      return(RCC_ERROR_RETURN(0, VME_FILE));

    is_open = 0;
  }

  DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_Close: End of function");
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/**********************************************************************************/
VME_ErrorCode_t VME_ReadCRCSR(int slot_number, u_int crcsr_identifier, u_int *value)
/**********************************************************************************/
{
  u_int offset, nbytes, ret;
  u_char bdata1, bdata2, bdata3, bdata4;
  
  ISOPEN;

  if (!crcsrok)
    return(RCC_ERROR_RETURN(0, VME_NOCRCSRMAP));
 
  if (slot_number < 1 && slot_number > 21)
    return(RCC_ERROR_RETURN(0, VME_RANGE));
    
  nbytes = crcsr_identifier >> 28;
  offset = crcsr_identifier & 0x0fffffff;
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_ReadCRCSR: nbytes         = " << nbytes);
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_ReadCRCSR: offset         = 0x" << std::hex << offset << std::dec);
  
  //Add the board offset
  offset += CRCSR_OFF * slot_number;
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_ReadCRCSR: VMEbus address = 0x" << std::hex << offset << std::dec);
  
  bdata1 = 0;
  bdata2 = 0;
  bdata3 = 0;
  bdata4 = 0;
  
  ret = VME_ReadSafeUChar(gahandle, offset, &bdata1);
  if (ret)
    return(RCC_ERROR_RETURN(0, ret));
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_ReadCRCSR: bdata1 = 0x" << std::hex << bdata1 << std::dec);

  if (nbytes > 1)
  {
    ret = VME_ReadSafeUChar(gahandle, offset + 0x4, &bdata2);
    if (ret)
      return(RCC_ERROR_RETURN(0, ret));
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_ReadCRCSR: bdata2 = 0x" << std::hex << bdata2 << std::dec);
  }
      
  if (nbytes > 2)
  {
    ret = VME_ReadSafeUChar(gahandle, offset + 0x8, &bdata3);
    if (ret)
      return(RCC_ERROR_RETURN(0, ret));  
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_ReadCRCSR: bdata3 = 0x" << std::hex << bdata3 << std::dec);
  }
      
  if (nbytes > 3)
  {
    ret = VME_ReadSafeUChar(gahandle, offset + 0xc, &bdata4);
    if (ret)
      return(RCC_ERROR_RETURN(0, ret));    
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_ReadCRCSR: bdata4 = 0x" << std::hex << bdata4 << std::dec);
  }
    
  if (nbytes == 1)  
    *value = bdata1;
  if (nbytes == 2)  
    *value = (bdata1 << 8) | bdata2;
  if (nbytes == 3)  
    *value = (bdata1 << 16) | (bdata2 << 8) | bdata3;
  if (nbytes == 4)  
    *value = (bdata1 << 24) | (bdata2 << 16) | (bdata3 << 8) | bdata4;
    
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/**********************************************************************************/
VME_ErrorCode_t VME_WriteCRCSR(int slot_number, u_int crcsr_identifier, u_int value)
/**********************************************************************************/
{  
  u_int offset,nbytes,ret;
  u_char bdata1,bdata2,bdata3,bdata4;
  
  ISOPEN;
 
  if (!crcsrok)
    return(RCC_ERROR_RETURN(0, VME_NOCRCSRMAP));
  
  if (slot_number < 1 && slot_number > 21)
    return(RCC_ERROR_RETURN(0, VME_RANGE));
    
  nbytes = crcsr_identifier >> 28;
  offset = crcsr_identifier & 0x0fffffff;
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_WriteCRCSR: nbytes         = " << nbytes);
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_WriteCRCSR: offset         = 0x" << std::hex << offset << std::dec);
  
  //Add the board offset
  offset += CRCSR_OFF * slot_number;
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_WriteCRCSR: VMEbus address = 0x" << std::hex << offset << std::dec);
  
  if (nbytes == 1)  
    bdata1 = value & 0xff;
    
  if (nbytes == 2)
  {
    bdata1 = (value >> 8) & 0xff;
    bdata2 = value & 0xff;
  }  
    
  if (nbytes == 3)
  {
    bdata1 = (value >> 16) & 0xff;
    bdata2 = (value >> 8) & 0xff;
    bdata3 = value & 0xff;
  } 
   
  if (nbytes == 4)  
  {  
    bdata1 = (value >> 24) & 0xff;
    bdata2 = (value >> 16) & 0xff;
    bdata3 = (value >> 8) & 0xff;
    bdata4 = value & 0xff;
  }  
  
  ret = VME_WriteSafeUChar(gahandle, offset, bdata1);
  if (ret)
    return(RCC_ERROR_RETURN(0, ret));

  if (nbytes > 1)
  {
    ret = VME_WriteSafeUChar(gahandle, offset + 0x4, bdata2);
    if (ret)
      return(RCC_ERROR_RETURN(0, ret));
  }
      
  if (nbytes > 2)
  {
    ret = VME_WriteSafeUChar(gahandle, offset + 0x8, bdata3);
    if (ret)
      return(RCC_ERROR_RETURN(0, ret));
  }
  
  if (nbytes > 3)
  {
    ret = VME_WriteSafeUChar(gahandle, offset + 0xc, bdata4);
    if (ret)
      return(RCC_ERROR_RETURN(0, ret));
  }
    
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*****************************************************************************/
VME_ErrorCode_t VME_MasterMap(VME_MasterMap_t *master_map, int *master_mapping)
/*****************************************************************************/
{
  int loop, ret, ok, paddr;
  u_int size, rest;

  ISOPEN;
  DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_MasterMap: Start of function");

  //check the input in master_map for consistency
  //MJ: to be done

  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterMap: vmebus_address   = 0x" << std::hex << master_map->vmebus_address << std::dec);  
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterMap: window_size      = 0x" << std::hex << master_map->window_size << std::dec);  
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterMap: address_modifier = 0x" << std::hex << master_map->address_modifier << std::dec);  
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterMap: options          = " << master_map->options);  
  //look for a free slot in the master map table
  ok = 0;
  for (loop = 0; loop < VME_MAX_MASTERMAP; loop++)
  {
    if (mastermap_table[loop].used == 0)
    {
      mastermap_table[loop].used                = 1;
      mastermap_table[loop].in.vmebus_address   = master_map->vmebus_address;
      mastermap_table[loop].in.window_size      = master_map->window_size;
      mastermap_table[loop].in.address_modifier = master_map->address_modifier;
      mastermap_table[loop].in.options          = master_map->options;
      ok=1;
      break;
    }
  }
  if (!ok)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_MasterMap: No entry found in master map table");
    return(RCC_ERROR_RETURN(0, VME_NOMAP));
  }
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterMap: Using entry " << loop << " in master map table");
  *master_mapping = loop;

  ret = ioctl(dev_handle, VMEMASTERMAP, &mastermap_table[loop]);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_MasterMap: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    mastermap_table[loop].used = 0;
    return(RCC_ERROR_RETURN(0, errno));
  }
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterMap: PCI address=0x" << std::hex << mastermap_table[loop].pci_address << std::dec);  

  //get virtual address
  //PCI address must be page aligned
  paddr = mastermap_table[loop].pci_address & ~(PAGE_SIZE - 1);
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterMap: aligned PCI address=0x" << std::hex << paddr << std::dec);
  rest = mastermap_table[loop].pci_address - paddr;
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterMap: rest=0x" << std::hex << rest << std::dec);

  //size must be page aligned
  size = master_map->window_size + rest;
  if (size % PAGE_SIZE)
    size = (size + PAGE_SIZE) & ~(PAGE_SIZE - 1);
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterMap: aligned size=0x" << std::hex << size << std::dec);

  mastermap_table[loop].virt_address = (u_int)mmap(0, size, (PROT_READ|PROT_WRITE), MAP_SHARED, dev_handle, paddr);
  if ((int)mastermap_table[loop].virt_address <= 0)
  {
    mastermap_table[loop].virt_address = 0;
    return(RCC_ERROR_RETURN(0, VME_VIRT));
  }                                   

  //add offset
  mastermap_table[loop].virt_address += rest;
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterMap: virtual address = 0x" << std::hex << mastermap_table[loop].virt_address << std::dec);

  DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_MasterMap: End of function");
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*************************************************************************************/
VME_ErrorCode_t VME_MasterMapVirtualAddress(int master_mapping, u_int *virtual_address)
/*************************************************************************************/
{
  ISOPEN;

  if (mastermap_table[master_mapping].used == 0)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  *virtual_address = mastermap_table[master_mapping].virt_address;

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/**************************************************************************************/
VME_ErrorCode_t VME_ReadSafeUInt(int master_mapping, u_int address_offset, u_int *value)
/**************************************************************************************/
{
  int ret;
  VME_SingleCycle_t sc;

  ISOPEN;

  if (mastermap_table[master_mapping].used == 0)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));
    
  if (address_offset & 0x3)
    return(RCC_ERROR_RETURN(0, VME_ALIGN));
    
  if (address_offset >= mastermap_table[master_mapping].in.window_size)
    return(RCC_ERROR_RETURN(0, VME_RANGE));

  sc.kvirt_address = mastermap_table[master_mapping].kvirt_address;
  sc.offset        = address_offset;
  sc.nbytes        = 4;         //transfer 32 bits
  sc.rw            = 1;         //read

  DEBUG_TEXT(DFDB_VMERCC, 20, "VME_ReadSafeUInt: master_mapping = " << master_mapping << " address_offset = 0x" << std::hex << address_offset << std::dec);

  ret = ioctl(dev_handle, VMESCSAFE, &sc);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_ReadSafeUInt: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }
  *value = sc.data; 

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/******************************************************************************************/
VME_ErrorCode_t VME_ReadSafeUShort(int master_mapping, u_int address_offset, u_short *value)
/******************************************************************************************/
{
  int ret;
  VME_SingleCycle_t sc;

  ISOPEN;

  if (mastermap_table[master_mapping].used == 0)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));
    
  if (address_offset & 0x1)
    return(RCC_ERROR_RETURN(0, VME_ALIGN));
    
  if (address_offset >= mastermap_table[master_mapping].in.window_size)
    return(RCC_ERROR_RETURN(0, VME_RANGE));

  sc.kvirt_address = mastermap_table[master_mapping].kvirt_address;
  sc.offset        = address_offset;
  sc.nbytes        = 2;         //transfer 16 bits
  sc.rw            = 1;         //read

  DEBUG_TEXT(DFDB_VMERCC, 20, "VME_ReadSafeUShort: master_mapping = " << master_mapping << " address_offset = 0x" << std::hex << address_offset << std::dec);
  ret = ioctl(dev_handle, VMESCSAFE, &sc);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_ReadSafeUShort: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }
  *value = sc.data & 0xffff;  
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/****************************************************************************************/
VME_ErrorCode_t VME_ReadSafeUChar(int master_mapping, u_int address_offset, u_char *value)
/****************************************************************************************/
{
  int ret;
  VME_SingleCycle_t sc;

  ISOPEN;

  if (mastermap_table[master_mapping].used == 0)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));
    
  if (address_offset >= mastermap_table[master_mapping].in.window_size)
    return(RCC_ERROR_RETURN(0, VME_RANGE));

  sc.kvirt_address = mastermap_table[master_mapping].kvirt_address;
  sc.offset        = address_offset;
  sc.nbytes        = 1;         //transfer 8 bits
  sc.rw            = 1;         //read

  DEBUG_TEXT(DFDB_VMERCC, 20, "VME_ReadSafeUChar: master_mapping = " << master_mapping << " address_offset = 0x" << std::hex << address_offset << std::dec);
  ret = ioctl(dev_handle, VMESCSAFE, &sc);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_ReadSafeUChar: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }
  *value = sc.data & 0xff;  
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/**************************************************************************************/
VME_ErrorCode_t VME_WriteSafeUInt(int master_mapping, u_int address_offset, u_int value)
/**************************************************************************************/
{
  int ret;
  VME_SingleCycle_t sc;

  ISOPEN;

  if (mastermap_table[master_mapping].used == 0)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));
  
  if (address_offset & 0x3)
    return(RCC_ERROR_RETURN(0, VME_ALIGN));
    
  if (address_offset >= mastermap_table[master_mapping].in.window_size)
    return(RCC_ERROR_RETURN(0, VME_RANGE));
    
  sc.kvirt_address = mastermap_table[master_mapping].kvirt_address;
  sc.offset        = address_offset;
  sc.nbytes        = 4;         //transfer 32 bits
  sc.rw            = 0;         //write
  sc.data          = value;

  DEBUG_TEXT(DFDB_VMERCC, 20, "VME_WriteSafeUInt: master_mapping = " << master_mapping << " address_offset = 0x" << std::hex << address_offset << std::dec);
  ret = ioctl(dev_handle, VMESCSAFE, &sc);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_WriteSafeUInt: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/******************************************************************************************/
VME_ErrorCode_t VME_WriteSafeUShort(int master_mapping, u_int address_offset, u_short value)
/******************************************************************************************/
{
  int ret;
  VME_SingleCycle_t sc;

  ISOPEN;

  if (mastermap_table[master_mapping].used == 0)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  if (address_offset & 0x1)
    return(RCC_ERROR_RETURN(0, VME_ALIGN));
    
  if (address_offset >= mastermap_table[master_mapping].in.window_size)
    return(RCC_ERROR_RETURN(0, VME_RANGE));
    
  sc.kvirt_address = mastermap_table[master_mapping].kvirt_address;
  sc.offset        = address_offset;
  sc.nbytes        = 2;         //transfer 16 bits
  sc.rw            = 0;         //write
  sc.data          = (u_int)value;

  DEBUG_TEXT(DFDB_VMERCC, 20, "VME_WriteSafeUShort: master_mapping = " << master_mapping << " address_offset = 0x" << std::hex << address_offset << std::dec);
  ret = ioctl(dev_handle, VMESCSAFE, &sc);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_WriteSafeUShort: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/****************************************************************************************/
VME_ErrorCode_t VME_WriteSafeUChar(int master_mapping, u_int address_offset, u_char value)
/****************************************************************************************/
{
  int ret;
  VME_SingleCycle_t sc;

  ISOPEN;

  if (mastermap_table[master_mapping].used == 0)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));
    
  if (address_offset >= mastermap_table[master_mapping].in.window_size)
    return(RCC_ERROR_RETURN(0, VME_RANGE));
    
  sc.kvirt_address = mastermap_table[master_mapping].kvirt_address;
  sc.offset        = address_offset;
  sc.nbytes        = 1;         //transfer 8 bits
  sc.rw            = 0;         //write
  sc.data          = (u_int)value;

  DEBUG_TEXT(DFDB_VMERCC, 20, "VME_WriteSafeUChar: master_mapping = " << master_mapping << " address_offset = 0x" << std::hex << address_offset << std::dec);
  ret = ioctl(dev_handle, VMESCSAFE, &sc);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_WriteSafeUChar: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/***************************************************************************/
void VME_ReadFastUInt(int master_mapping, u_int address_offset, u_int *value)
/***************************************************************************/
{
  u_int ret, virtual_address;
  
  ret = VME_MasterMapVirtualAddress(master_mapping, &virtual_address);
  
  if (!ret)
    *value = *(u_int *)(virtual_address + address_offset);
  else
    *value = 0xffffffff;
}


/*******************************************************************************/
void VME_ReadFastUShort(int master_mapping, u_int address_offset, u_short *value)
/*******************************************************************************/
{
  u_int ret, virtual_address;
  
  ret = VME_MasterMapVirtualAddress(master_mapping, &virtual_address);
  
  if (!ret)
    *value = *(u_short *)(virtual_address + address_offset);
  else
    *value = 0xffff;
}


/*****************************************************************************/
void VME_ReadFastUChar(int master_mapping, u_int address_offset, u_char *value)
/*****************************************************************************/
{
  u_int ret, virtual_address;
  
  ret = VME_MasterMapVirtualAddress(master_mapping, &virtual_address);
  
  if (!ret)
    *value = *(u_char *)(virtual_address + address_offset);
  else
    *value = 0xff;
}


/***************************************************************************/
void VME_WriteFastUInt(int master_mapping, u_int address_offset, u_int value)
/***************************************************************************/
{
  u_int ret, virtual_address;
  
  ret = VME_MasterMapVirtualAddress(master_mapping, &virtual_address);
  
  if (!ret)
    *(u_int *)(virtual_address + address_offset) = value;
}


/*******************************************************************************/
void VME_WriteFastUShort(int master_mapping, u_int address_offset, u_short value)
/*******************************************************************************/
{
  u_int ret, virtual_address;
  
  ret = VME_MasterMapVirtualAddress(master_mapping, &virtual_address);
  
  if (!ret)
    *(u_short *)(virtual_address + address_offset) = value;
}


/*****************************************************************************/
void VME_WriteFastUChar(int master_mapping, u_int address_offset, u_char value)
/*****************************************************************************/
{
  u_int ret, virtual_address;
  
  ret = VME_MasterMapVirtualAddress(master_mapping, &virtual_address);
  
  if (!ret)
    *(u_char *)(virtual_address + address_offset) = value;
}



/*************************************************/
VME_ErrorCode_t VME_MasterUnmap(int master_mapping)
/*************************************************/
{
  int ret;
  u_int vaddr, size;

  ISOPEN;

  if (!mastermap_table[master_mapping].used)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  mastermap_table[master_mapping].used = 0;

  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterUnmap: mastermap_table[" << master_mapping << "].kvirt_address = 0x" << std::hex << mastermap_table[master_mapping].kvirt_address << std::dec);
  ret = ioctl(dev_handle, VMEMASTERUNMAP, &mastermap_table[master_mapping].kvirt_address);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_MasterUnmap: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  //compute values for munmap  
  vaddr = mastermap_table[master_mapping].virt_address - (mastermap_table[master_mapping].pci_address & (PAGE_SIZE - 1));
  size = mastermap_table[master_mapping].in.window_size + (mastermap_table[master_mapping].pci_address & (PAGE_SIZE - 1));
  if (size % PAGE_SIZE)
    size = (size + PAGE_SIZE) & ~(PAGE_SIZE - 1);

  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterUnmap: size          = 0x" << std::hex << size << std::dec);
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_MasterUnmap: virt. address = 0x" << std::hex << vaddr << std::dec);

  ret = munmap((char *)vaddr, size);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_MasterUnmap: Error from munmap, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, VME_MUNMAP));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*************************************/
VME_ErrorCode_t VME_MasterMapDump(void)
/*************************************/
{
  int ret;
  char mytext[TEXT_SIZE1];

  ISOPEN;

  ret = ioctl(dev_handle, VMEMASTERMAPDUMP, mytext);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_MasterMapDump: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }
  printf("%s", mytext);

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/***********************************************************/
VME_ErrorCode_t VME_BusErrorRegisterSignal(int signal_number)
/***********************************************************/
{
  int  ret;
  VME_RegSig_t reg_sig_arg;

  ISOPEN;

  reg_sig_arg.signum = signal_number;

  ret = ioctl(dev_handle, VMEBERRREGISTERSIGNAL, &reg_sig_arg);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BerrRegisterSignal: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*********************************************************************/
VME_ErrorCode_t VME_BusErrorInfoGet(VME_BusErrorInfo_t *bus_error_info)
/*********************************************************************/
{
  int ret;

  ISOPEN;

  // pass the structure unchanged ..
  ret = ioctl(dev_handle, VMEBERRINFO, bus_error_info);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BusErrorInfoGet: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*************************************************************************/
VME_ErrorCode_t VME_SlaveMap(VME_SlaveMap_t *slave_map, int *slave_mapping)
/*************************************************************************/
{
  int loop, ret, ok;

  ISOPEN;
  DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_SlaveMap: Start of function");

  //check the input in slave_map for consistency
  //MJ: to be done

  //look for a free slot in the slave map table
  ok = 0;
  for (loop = 0; loop < VME_MAX_SLAVEMAP; loop++)
  {
    if (slavemap_table[loop].used == 0)
    {
      slavemap_table[loop].used                    = 1;
      slavemap_table[loop].in.system_iobus_address = slave_map->system_iobus_address;
      slavemap_table[loop].in.window_size          = slave_map->window_size;
      slavemap_table[loop].in.address_width        = slave_map->address_width;
      slavemap_table[loop].in.options              = slave_map->options;
      ok = 1;
      break;
    }
  }
  if (!ok)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_SlaveMap: No entry found in slave map table");
    return(RCC_ERROR_RETURN(0, VME_NOMAP));
  }
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_SlaveMap: Using entry " << loop << " in slave map table");
  *slave_mapping = loop;

  ret = ioctl(dev_handle, VMESLAVEMAP, &slavemap_table[loop]);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_SlaveMap: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    slavemap_table[loop].used = 0;
    return(RCC_ERROR_RETURN(0, errno));
  }
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_SlaveMap: VME address=0x" << std::hex << slavemap_table[loop].vme_address << std::dec);  

  DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_SlaveMap: End of function");
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*********************************************************************************/
VME_ErrorCode_t VME_SlaveMapVmebusAddress(int slave_mapping, u_int *vmebus_address)
/*********************************************************************************/
{
  ISOPEN;

  if (!slavemap_table[slave_mapping].used)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_SlaveMapVmebusAddress: VME address=0x" << std::hex << slavemap_table[slave_mapping].vme_address << std::dec);
  *vmebus_address = slavemap_table[slave_mapping].vme_address;

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/***********************************************/
VME_ErrorCode_t VME_SlaveUnmap(int slave_mapping)
/***********************************************/
{
  ISOPEN;

  if (slavemap_table[slave_mapping].used == 0)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  slavemap_table[slave_mapping].used = 0;

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/************************************/
VME_ErrorCode_t VME_SlaveMapDump(void)
/************************************/
{
  int ret;
  char mytext[TEXT_SIZE1];

  ISOPEN;

  ret = ioctl(dev_handle, VMESLAVEMAPDUMP, mytext);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_SlaveMapDump: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }
  printf("%s", mytext);

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/******************************************************************************************************/
VME_ErrorCode_t VME_BlockTransferInit(VME_BlockTransferList_t *block_transfer_list, int *block_transfer)
/******************************************************************************************************/
{
  int loop, ok, celem, cnum;
  u_int offset, vaddr, paddr, size, msize, ctrl, fcap, next;
  VME_DmaChain_t *chain;

  ISOPEN;

  //look for a free dma chain
  ok = 0;
  for (cnum = 0; cnum < VME_MAXCHAIN; cnum++)
  {
    if(chains[cnum] == 0)
    {
      chains[cnum] = 1;
      ok = 1;
      break;
    }
  }
  if (!ok)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferInit: No free chain found");
    return(RCC_ERROR_RETURN(0, VME_NOCHAINMEM));
  }
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: Using chain " << cnum);
  *block_transfer = cnum;

  //fill the chain with information from block_transfer_list
  celem = 0;

  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: List contains " << block_transfer_list->number_of_items << " elements");

  for (loop = 0; loop < block_transfer_list->number_of_items; loop++)
  {
    vaddr = block_transfer_list->list_of_items[loop].vmebus_address;
    paddr = block_transfer_list->list_of_items[loop].system_iobus_address;
    size  = block_transfer_list->list_of_items[loop].size_requested;
    ctrl  = block_transfer_list->list_of_items[loop].control_word;
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: vaddr = 0x" << std::hex << vaddr << std::dec);
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: paddr = 0x" << std::hex << paddr << std::dec);
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: size  = 0x" << std::hex << size << std::dec);
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: ctrl  = 0x" << std::hex << ctrl << std::dec);

    if (!size)
    {
      DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferInit: Size=0 in item " << loop);
      return(RCC_ERROR_RETURN(0, VME_NOSIZE));
    }

    if (size & 0x7)
    {
      DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferInit: Size not 8 byte aligned in item " << loop);
      return(RCC_ERROR_RETURN(0, VME_ALIGN));
    }

    if ((vaddr & 0x7) != (paddr & 0x7))
    {
      DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferInit: VME/PCI addresses not 8 byte aligned in item " << loop);
      return(RCC_ERROR_RETURN(0, VME_ALIGN));
    }

    if ((ctrl & VME_DMA_D64) && (vaddr & 0x7)) 
    {
      DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferInit: VMEbus address not 8 byte aligned in item " << loop);
      return(RCC_ERROR_RETURN(0, VME_ALIGN));
    }

    if ((ctrl & VME_DMA_D64) && (paddr & 0x7))
    {
      DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferInit: PCI address not 8 byte aligned in item " << loop);
      return(RCC_ERROR_RETURN(0, VME_ALIGN));
    }
    else if (size & 0x3)  //Check size alignment for D32 transfers
    {
      DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferInit: Size address not 4 byte aligned in item " << loop);
      return(RCC_ERROR_RETURN(0, VME_ALIGN));
    }

    while (size)
    {
      if (celem > VME_MAXCHAINEL)
      {
	DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferInit: Chain overflow");
	return(RCC_ERROR_RETURN(0, VME_TOOLONG));
      }

      msize = size;
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: msize = 0x" << std::hex << msize << std::dec);

      //check for size overflow
      if (msize > VME_DMA_MAX_BLOCK_SIZE)
      msize = VME_DMA_MAX_BLOCK_SIZE;   
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: msize(2) = 0x" << std::hex << msize << std::dec);

      //reduce remaining size
      size -= msize;

      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: Current chain          = " << cnum); 
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: Current element        = " << celem);
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: sizeof(VME_DmaChain_t) = 0x" << std::hex << sizeof(VME_DmaChain_t) << std::dec);

      //calculate the offset of the current chain element
      offset = cnum * VME_MAXCHAINEL * sizeof(VME_DmaChain_t) + celem * sizeof(VME_DmaChain_t);
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: offset of chain element = 0x" << std::hex << offset << std::dec);

      //get the user address of the current chain element
      chain = (VME_DmaChain_t *)(shandle_uaddr + offset);
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: Virtual address of first chain descriptor = 0x" << std::hex << (u_int)chain << std::dec);

      //calculate the PCI address of the next chain element
      next = shandle_paddr + offset + sizeof(VME_DmaChain_t);
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: PCI address of next element = 0x" << std::hex << next << std::dec);

      if (size == 0 && (loop + 1) == block_transfer_list->number_of_items)    //last element in the chain
	fcap = DMA_CHAIN_END;
      else
	fcap = next;                           //address of next cap

      //MJ: Use the line below on 64bit PCI busses
      //ctrl |= 0x80;

      chain->dtbc = BSWAP(msize);
      chain->dctl = BSWAP(ctrl);
      chain->dla  = BSWAP(paddr);
      chain->dva  = BSWAP(vaddr);   
      chain->dcpp = BSWAP(fcap); 
      chain->ref  = loop;

      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: dctl=0x" << std::hex << BSWAP(chain->dctl) << std::dec);
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: dtbc=0x" << std::hex << BSWAP(chain->dtbc) << std::dec);
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: dla =0x" << std::hex << BSWAP(chain->dla) << std::dec); 
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: dva =0x" << std::hex << BSWAP(chain->dva) << std::dec); 
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: dcpp=0x" << std::hex << BSWAP(chain->dcpp) << std::dec);
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: ref =0x" << std::hex << BSWAP(chain->ref) << std::dec);
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferInit: blocklet = 0x" << std::hex << msize << "   rest = 0x" << size << "    Address of chain = 0x" << (u_int)chain << std::dec);
      //update addresses
      paddr += msize;
      vaddr += msize;
      celem++;
    }    
  }
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/********************************************************/
VME_ErrorCode_t VME_BlockTransferStart(int block_transfer)
/********************************************************/
{
  int ret;
  u_int paddr;
  VME_DMAstart_t params;
  
  ISOPEN;
    
  //does this list exist?
  if (chains[block_transfer] != 1)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  //calculate the PCI address of the first chain element
  paddr = shandle_paddr + block_transfer * VME_MAXCHAINEL * sizeof(VME_DmaChain_t);
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferStart: PCI address of first chain element = 0x" << std::hex << paddr << std::dec);

  params.paddr = paddr;
  params.handle = block_transfer;

  ret = ioctl(dev_handle, VMEDMASTART, &params);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferStart: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*******************************************************************************************************************/
VME_ErrorCode_t VME_BlockTransferWait(int block_transfer, int time_out, VME_BlockTransferList_t *block_transfer_list)
/*******************************************************************************************************************/
{
  u_int celem, offset, ok, ret;
  int tics;
  VME_DmaChain_t *chain;
  VME_DMAhandle_t poll;

  ISOPEN;

  //does this list exist?
  if (chains[block_transfer] != 1)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));
  
  if (time_out > 0)
    tics = (time_out + 9) / 10;
  else if (time_out == 0)
    tics = 0;
  else if (time_out == -1)
    tics = -1;
  else
    return(RCC_ERROR_RETURN(0, VME_ILL_TO));
  
  poll.handle     = block_transfer;
  poll.timeoutval = tics;
  
  ret = ioctl(dev_handle, VMEDMAPOLL, &poll);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferWait: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: After poll/wait poll.ctrl    =0x" << std::hex << poll.ctrl << std::dec);
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: After poll/wait poll.counter =0x" << std::hex << poll.counter << std::dec);
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: After poll/wait poll.timeout =0x" << std::hex << poll.timeout << std::dec);

  //are we still busy 
  if (poll.ctrl == 0 && time_out == 0)
    return(RCC_ERROR_RETURN(0, VME_DMABUSY));  
  
  //was there a time-out
  //if (poll.ctrl == 0 && time_out > 0)
    //return(RCC_ERROR_RETURN(0, VME_TIMEOUT));  

  //DMA has ended. Analyze result
  ok = 1;
  for (celem = 0; celem < VME_MAXCHAINEL; celem++)
  {     
    //calculate the offset of the current chain element
    offset = block_transfer * VME_MAXCHAINEL * sizeof(VME_DmaChain_t) + celem * sizeof(VME_DmaChain_t);
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: offset of chain element = 0x" << std::hex << offset << std::dec);

    //get the user address of the current chain element
    chain = (VME_DmaChain_t *)(shandle_uaddr + offset);
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: Virtual address of first chain descriptor = 0x" << std::hex << (u_int)chain << std::dec);

    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: Dumping chain element " << celem);
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: dctl = 0x" << std::hex << BSWAP(chain->dctl) << std::dec);
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: dtbc = 0x" << std::hex << BSWAP(chain->dtbc) << std::dec);
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: dla  = 0x" << std::hex << BSWAP(chain->dla) << std::dec); 
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: dva  = 0x" << std::hex << BSWAP(chain->dva) << std::dec); 
    DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: dcpp = 0x" << std::hex << BSWAP(chain->dcpp) << std::dec);

    if (!ok) //there was already an error in a previous block
    {
      block_transfer_list->list_of_items[chain->ref].status_word=  VME_NOT_EXECUTED;
      block_transfer_list->list_of_items[chain->ref].size_remaining = block_transfer_list->list_of_items[chain->ref].size_requested;
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: Element not executed");
    }
    else if (BSWAP(chain->dcpp) & 0x2)           //element successfully completed
    {
      block_transfer_list->list_of_items[chain->ref].status_word = VME_SUCCESS;
      block_transfer_list->list_of_items[chain->ref].size_remaining = 0;
      DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_BlockTransferWait: Element OK");
    }
    else
    { 
      if (poll.ctrl & 0x400) 
      {
	block_transfer_list->list_of_items[chain->ref].status_word = VME_PCI_ERR;
	block_transfer_list->list_of_items[chain->ref].size_remaining = poll.counter;
        DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferWait: Element has PCI error");
      }
      else if (poll.ctrl & 0x200) 
      {
	block_transfer_list->list_of_items[chain->ref].status_word = VME_VME_ERR;
	block_transfer_list->list_of_items[chain->ref].size_remaining = poll.counter;
        DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferWait: Element has VMEbus error");
      }
      else if (poll.ctrl & 0x100) 
      {
	block_transfer_list->list_of_items[chain->ref].status_word = VME_PROTOCOL_ERR;
	block_transfer_list->list_of_items[chain->ref].size_remaining = poll.counter;
        DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferWait: Element has protocol error");
      }
      ok = 0;
    }

    if (BSWAP(chain->dcpp) & 0x1)  //end of chain
      break;  
  }

  if (poll.ctrl != 0x800)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferWait: Transfer had an error. poll.ctrl is 0x" << std::hex << poll.ctrl << std::dec);
    return(RCC_ERROR_RETURN(0, VME_DMAERR));
  }

  if (!poll.timeout)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_BlockTransferWait: transfer timed out");
    return(RCC_ERROR_RETURN(0, VME_TIMEOUT));
  }


  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/******************************************************/
VME_ErrorCode_t VME_BlockTransferEnd(int block_transfer)
/******************************************************/
{
  ISOPEN;

  //does this list exist?
  if (chains[block_transfer] != 1)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  chains[block_transfer] = 0;

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*******************************************************************************************/
VME_ErrorCode_t VME_BlockTransfer(VME_BlockTransferList_t *block_transfer_list, int time_out)
/*******************************************************************************************/
{
  u_int ret;
  int handle, errnum;

  ISOPEN;
  
  if (time_out == 0)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));
  
  ret = VME_BlockTransferInit(block_transfer_list, &handle);
  if (ret != VME_SUCCESS)
    return(RCC_ERROR_RETURN(0, ret));
  else
    DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_BlockTransfer: VME_BlockTransferInit OK");

  // We do not want VME_BlockTransfer to fail because VME_BlockTransferStart return
  // VME_DMABUSY. Therefore we wait for the DMA controller to become available.
  // This is aceptable because VME_BlockTransfer is a blocking function anyway.
  // The while() loop could only be endless if the DMA semaphore gets lost. This is
  // a fatal error anyway. One could discuss putting a yield() into the loop to preserve
  // some CPU time.
  while(1)
  {
    ret = VME_BlockTransferStart(handle);       
    VME_ErrorNumber(ret, &errnum); 
    if (errnum != VME_SUCCESS && errnum != VME_DMABUSY)
    {
      VME_BlockTransferEnd(handle);
      return(RCC_ERROR_RETURN(0, ret));
    }
    if (errnum == VME_SUCCESS)
    {
      DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_BlockTransfer: VME_BlockTransferStart OK");
      break;
    }
  }
  
  ret = VME_BlockTransferWait(handle, time_out, block_transfer_list);      
  if (ret != VME_SUCCESS)  
  {
    VME_BlockTransferEnd(handle);
    return(RCC_ERROR_RETURN(0, ret));
  }
  else
    DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_BlockTransfer: VME_BlockTransferWait OK");

  ret = VME_BlockTransferEnd(handle);       
  if (ret != VME_SUCCESS)
    return(RCC_ERROR_RETURN(0, ret));
  else
    DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_BlockTransfer: VME_BlockTransferEnd OK");    
 
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/**************************************************************************************/
VME_ErrorCode_t VME_BlockTransferStatus(VME_BlockTransferList_t *block_transfer_list, 
                                        int  position_of_block, VME_ErrorCode_t *status)
/**************************************************************************************/
{
  ISOPEN;

  if (position_of_block > block_transfer_list->number_of_items)
    return(RCC_ERROR_RETURN(0, VME_RANGE));

  *status = block_transfer_list->list_of_items[position_of_block].status_word;
  
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/**************************************************************************************/
VME_ErrorCode_t VME_BlockTransferRemaining(VME_BlockTransferList_t *block_transfer_list,
                                           int position_of_block, int *remaining) 
/**************************************************************************************/
{
  ISOPEN;

  if (position_of_block > block_transfer_list->number_of_items)
    return(RCC_ERROR_RETURN(0, VME_RANGE));

  *remaining = block_transfer_list->list_of_items[position_of_block].size_remaining;
  
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*****************************************/
VME_ErrorCode_t VME_BlockTransferDump(void)
/*****************************************/
{
  int ret;
  char mytext[TEXT_SIZE2];

  ISOPEN;

  ret = ioctl(dev_handle, VMEDMADUMP, mytext);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_MasterMapDump: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }
  printf("%s", mytext);

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/********************************************/
VME_ErrorCode_t VME_SysfailInterruptLink(void)
/********************************************/
{
  int ret, dummy;

  ISOPEN;

  ret = ioctl(dev_handle, VMESYSFAILLINK, &dummy);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_SysfailInterruptLink: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/***********************************************************************/
VME_ErrorCode_t VME_SysfailInterruptRegisterSignal(int signal_number)
/***********************************************************************/
{
  int  ret;
  VME_RegSig_t reg_sig_arg;

  ISOPEN;

  reg_sig_arg.signum = signal_number;

  ret = ioctl(dev_handle, VMESYSFAILREGISTERSIGNAL, &reg_sig_arg);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_SysfailInterruptRegisterSignal: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/****************************************************/
VME_ErrorCode_t VME_SysfailInterruptWait(int time_out)
/****************************************************/
{
  int  ret;
  VME_WaitInt_t wait_arg;

  ISOPEN;

  if (time_out > 0)
    wait_arg.timeout = (time_out + 9) / 10;		// ms to ticks;
  else
    wait_arg.timeout = time_out;

  ret = ioctl(dev_handle, VMESYSFAILWAIT, &wait_arg);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_SysfailInterruptWait: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  if (wait_arg.multiple == 0)				// no pending vector found
    return(RCC_ERROR_RETURN(0, VME_NOINTERRUPT));

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/**********************************************/
VME_ErrorCode_t VME_SysfailInterruptUnlink(void)
/**********************************************/
{
  int ret, dummy;

  ISOPEN;

  ret = ioctl(dev_handle, VMESYSFAILUNLINK, &dummy);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_SysfailInterruptUnlink: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/************************************************/
VME_ErrorCode_t VME_SysfailInterruptReenable(void)
/************************************************/
{
  int ret, dummy;
 
  ISOPEN;

  ret = ioctl(dev_handle, VMESYSFAILREENABLE, &dummy);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_SysfailInterruptReenable: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/****************************************/
VME_ErrorCode_t VME_SysfailPoll(int *flag)
/****************************************/
{
  int ret;

  ISOPEN;

  ret = ioctl(dev_handle, VMESYSFAILPOLL, flag);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_SysfailPoll: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/**********************************/
VME_ErrorCode_t VME_SysfailSet(void)
/**********************************/
{
  int ret, dummy;

  ISOPEN;

  ret = ioctl(dev_handle, VMESYSFAILSET, &dummy);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_SysfailSet: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/************************************/
VME_ErrorCode_t VME_SysfailReset(void)
/************************************/
{
  int ret, dummy;

  ISOPEN;

  ret = ioctl(dev_handle, VMESYSFAILRESET, &dummy);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_SysfailRest: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}

/**********************************************************************************/
VME_ErrorCode_t VME_InterruptLink(VME_InterruptList_t* vme_irq_list, int *interrupt)
/**********************************************************************************/
{
  int i, ret;
  int index;
  int first_level, first_type;

  ISOPEN;

  if ( vme_irq_list->number_of_items > VME_MAXINTERRUPT)
    return(RCC_ERROR_RETURN(0, VME_TOOMANYINT));

  // find a free slot
  index = -1;
  for (i = 0; i < VME_MAX_INTHANDLE; i++)
  {
    if (int_handle[i].nvectors == 0)
    {
      index = i;
      break;
    }
  }
  if (index == -1)
    return(RCC_ERROR_RETURN(0, VME_TOOMANYHDL));

  int_handle[index].nvectors = vme_irq_list->number_of_items;
  for (i = 0; i < vme_irq_list->number_of_items; i++)
  {
    int_handle[index].vector[i] = (int)vme_irq_list->list_of_items[i].vector;	// no check

    if (vme_irq_list->list_of_items[i].level < 1 || vme_irq_list->list_of_items[i].level > 7)
      return(RCC_ERROR_RETURN(0, VME_ILLINTLEVEL));

    if (vme_irq_list->list_of_items[i].type != VME_INT_ROAK && 
        vme_irq_list->list_of_items[i].type != VME_INT_RORA)
      return(RCC_ERROR_RETURN(0, VME_ILLINTTYPE));

    if ( i == 0)
    {
      first_level = vme_irq_list->list_of_items[i].level;
      first_type = vme_irq_list->list_of_items[i].type;
    }
    else
    {
      if (vme_irq_list->list_of_items[i].level != first_level)
        return(RCC_ERROR_RETURN(0, VME_ILLINTLEVEL));
      if (vme_irq_list->list_of_items[i].type != first_type)
        return(RCC_ERROR_RETURN(0, VME_ILLINTTYPE));
    }
  }

  int_handle[index].level = first_level;
  int_handle[index].type = first_type;

  ret = ioctl(dev_handle, VMELINK, &int_handle[index]);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_InterruptLink: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  *interrupt = index;

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/**************************************************/
VME_ErrorCode_t VME_InterruptReenable(int interrupt)
/**************************************************/
{
  int  ret;
  VME_IntEnable_t level_arg;

  ISOPEN;

  if (interrupt < 0 || interrupt > VME_MAX_INTHANDLE)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  level_arg.level = int_handle[interrupt].level;
  level_arg.type = 0;		//dummy

  ret = ioctl(dev_handle, VMEINTENABLE, &level_arg);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_InterruptEnable: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/******************************************************************************************/
VME_ErrorCode_t VME_InterruptWait(int interrupt, int time_out, VME_InterruptInfo_t* ir_info)
/******************************************************************************************/
{
  int  ret;
  VME_WaitInt_t wait_arg;

  ISOPEN;

  if (interrupt < 0 || interrupt > VME_MAX_INTHANDLE)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  wait_arg.int_handle = int_handle[interrupt];
  if (time_out > 0)
    wait_arg.timeout = (time_out + 9)/10;		// ms to ticks;
  else
    wait_arg.timeout = time_out;

  wait_arg.vector = 0;

  ret = ioctl(dev_handle, VMEWAIT, &wait_arg);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_InterruptWait: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  ir_info->vector = (u_char)wait_arg.vector;
  ir_info->level = wait_arg.level;
  ir_info->type = wait_arg.type;
  ir_info->multiple = wait_arg.multiple;

  if (wait_arg.multiple == 0)				// no pending vector found
    return(RCC_ERROR_RETURN(0, VME_NOINTERRUPT));

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/***************************************************************************/
VME_ErrorCode_t VME_InterruptRegisterSignal(int interrupt, int signal_number)
/***************************************************************************/
{
  int  ret;
  VME_RegSig_t reg_sig_arg;

  ISOPEN;

  if (interrupt < 0 || interrupt > VME_MAX_INTHANDLE)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  reg_sig_arg.int_handle = int_handle[interrupt];
  reg_sig_arg.signum = signal_number;

  ret = ioctl(dev_handle, VMEREGISTERSIGNAL, &reg_sig_arg);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_InterruptRegisterSignal: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/********************************************************************************/
VME_ErrorCode_t VME_InterruptInfoGet(int interrupt, VME_InterruptInfo_t* ir_info)
/********************************************************************************/
{
  int  ret;
  VME_WaitInt_t wait_arg;

  ISOPEN;

  if (interrupt < 0 || interrupt > VME_MAX_INTHANDLE)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  wait_arg.int_handle = int_handle[interrupt];
  wait_arg.timeout = 0;		//  dummy
  wait_arg.vector = 0;

  ret = ioctl(dev_handle, VMEINTERRUPTINFOGET, &wait_arg);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_InterruptInfoGet: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

  ir_info->vector = (u_char)wait_arg.vector;
  ir_info->level = wait_arg.level;
  ir_info->type = wait_arg.type;
  ir_info->multiple = wait_arg.multiple;

  if (wait_arg.multiple == 0)				// no pending vector found
    return(RCC_ERROR_RETURN(0, VME_NOINTERRUPT));

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/************************************************/
VME_ErrorCode_t VME_InterruptUnlink(int interrupt)
/************************************************/
{
  int i, ret;

  ISOPEN;

  if (interrupt < 0 || interrupt > VME_MAX_INTHANDLE)
    return(RCC_ERROR_RETURN(0, VME_NOTKNOWN));

  if (int_handle[interrupt].nvectors == 0)
    return(RCC_ERROR_RETURN(0, VME_ILLINTHANDLE));

  ret = ioctl(dev_handle, VMEUNLINK, &int_handle[interrupt]);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_InterruptUnlink: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }

   // clean the entry in the handle array
  int_handle[interrupt].nvectors = 0;
  for (i = 0; i < VME_MAX_INTHANDLE; i++)
  {
    int_handle[interrupt].vector[i] = 0;
  }

  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*************************************************************/
VME_ErrorCode_t VME_InterruptGenerate(int level, u_char vector)
/*************************************************************/
{
  ISOPEN;
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*************************************/
VME_ErrorCode_t VME_InterruptDump(void)
/*************************************/
{
  ISOPEN;
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*******************/
/*Service functions*/
/*******************/

/*****************************************************/
VME_ErrorCode_t VME_UniverseMap(u_int *virtual_address)
/*****************************************************/
{
  int ret;
  u_int idata, vaddr;
  
  ret = IO_PCIDeviceLink(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_CA91C042, 1, &universe_handle);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_UniverseUnmap: Error from IO_PCIDeviceLink");
    return(RCC_ERROR_RETURN(ret, VME_IO_FAIL));
  }
  
  ret = IO_PCIConfigReadUInt(universe_handle, 0x10, &idata);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_UniverseUnmap: Error from IO_PCIConfigReadUInt");
    return(RCC_ERROR_RETURN(ret, VME_IO_FAIL));
  }
  
  ret = IO_PCIMemMap(idata, 0x1000, &vaddr);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_UniverseUnmap: Error from IO_PCIMemMap");
    return(RCC_ERROR_RETURN(ret, VME_IO_FAIL));
  }   
  
  *virtual_address = vaddr;
  DEBUG_TEXT(DFDB_VMERCC, 20 ,"VME_UniverseMap: virtual address = 0x" << std::hex << *virtual_address << std::dec);
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/******************************************************/
VME_ErrorCode_t VME_UniverseUnmap(u_int virtual_address)
/******************************************************/
{
  int ret;
  
  ret = IO_PCIMemUnmap(virtual_address, 0x1000);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_UniverseUnmap: Error from IO_PCIMemUnmap");
    return(RCC_ERROR_RETURN(ret, VME_IO_FAIL));
  } 
   
  ret = IO_PCIDeviceUnlink(universe_handle);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_UniverseUnmap: Error from IO_PCIDeviceUnlink");
    return(RCC_ERROR_RETURN(ret, VME_IO_FAIL));
  }
  
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}
  

/*****************************************/
VME_ErrorCode_t VME_CCTSetSwap(u_char swap)
/*****************************************/
{  
  int ret;
  u_char data;
          
  ret = IO_IOPeekUChar(0x210, &data);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_CCTSetSwap: Error from IO_IOPeekUChar");
    return(RCC_ERROR_RETURN(ret, VME_IO_FAIL));
  }

  data &= 0xc7;
  data |= swap;
    
  ret = IO_IOPokeUChar(0x210, data);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_CCTSetSwap: Error from IO_IOPokeUChar");
    return(RCC_ERROR_RETURN(ret, VME_IO_FAIL));
  }
  
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/********************************************/
VME_ErrorCode_t VME_Update(unsigned int *data)
/********************************************/
{
  int ret, i;
  VME_Update_t idata;
  
  for(i = 0; i < 9; i++)
  idata.irq_mode[i] = data[i];

  DEBUG_TEXT(DFDB_VMERCC, 15 ,"VME_Update: Function called");
  ret = ioctl(dev_handle, VMEUPDATE, &idata);
  if (ret)
  {
    DEBUG_TEXT(DFDB_VMERCC, 5 ,"VME_Update: Error from ioctl, errno = 0x" << std::hex << errno << std::dec);
    return(RCC_ERROR_RETURN(0, errno));
  }
  
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/*********************************************************************/
VME_ErrorCode_t vmercc_err_get(err_pack err, err_str pid, err_str code)
/*********************************************************************/
{ 
  strcpy(pid, P_ID_VMERCC_STR);

  switch (RCC_ERROR_MINOR(err))
  {  
    case VME_SUCCESS:             strcpy(code, VME_SUCCESS_STR); break;   
    case VME_NOTKNOWN:            strcpy(code, VME_NOTKNOWN_STR); break;
    case VME_UNKNOWN:             strcpy(code, VME_UNKNOWN_STR); break;
    case VME_NOTOPEN:             strcpy(code, VME_NOTOPEN_STR); break;
    case VME_RANGE:               strcpy(code, VME_RANGE_STR); break;
    case VME_BUSERROR:            strcpy(code, VME_BUSERROR_STR); break;
    case VME_ALIGN:               strcpy(code, VME_ALIGN_STR); break;
    case VME_NOCHAINMEM:          strcpy(code, VME_NOCHAINMEM_STR); break;
    case VME_NOBUSERROR:          strcpy(code, VME_NOBUSERROR_STR); break;
    case VME_TOOLONG:             strcpy(code, VME_TOOLONG_STR); break;
    case VME_DMABUSY:             strcpy(code, VME_DMABUSY_STR); break;
    case VME_TIMEOUT:             strcpy(code, VME_TIMEOUT_STR); break;
    case VME_FILE:                strcpy(code, VME_FILE_STR); break;
    case VME_NOMAP:               strcpy(code, VME_NOMAP_STR); break;
    case VME_NOSTATMAP:           strcpy(code, VME_NOSTATMAP_STR); break;    
    case VME_IRGBUSY:             strcpy(code, VME_IRGBUSY_STR); break;
    case VME_EIO:                 strcpy(code, VME_EIO_STR); break;
    case VME_EFAULT:              strcpy(code, VME_EFAULT_STR); break;
    case VME_VIRT:                strcpy(code, VME_VIRT_STR); break;
    case VME_REMAP:               strcpy(code, VME_REMAP_STR); break;
    case VME_ENOSYS:              strcpy(code, VME_ENOSYS_STR); break;
    case VME_NOSIZE:              strcpy(code, VME_NOSIZE_STR); break;
    case VME_CMEM_FAIL:           strcpy(code, VME_CMEM_FAIL_STR); break;
    case VME_ERESTARTSYS:         strcpy(code, VME_ERESTARTSYS_STR); break;
    case VME_DMAERR:              strcpy(code, VME_DMAERR_STR); break;
    case VME_PCI_ERR:             strcpy(code, VME_PCI_ERR_STR); break;
    case VME_VME_ERR:             strcpy(code, VME_VME_ERR_STR); break;
    case VME_PROTOCOL_ERR:        strcpy(code, VME_PROTOCOL_ERR_STR); break;
    case VME_NOT_EXECUTED:        strcpy(code, VME_NOT_EXECUTED_STR); break;
    case VME_MUNMAP:              strcpy(code, VME_MUNMAP_STR); break;  
    case VME_ILLREV:              strcpy(code, VME_ILLREV_STR); break;
    case VME_IOREMAP:             strcpy(code, VME_IOREMAP_STR); break;
    case VME_REQIRQ:              strcpy(code, VME_REQIRQ_STR); break;
    case VME_TOOMANYINT:          strcpy(code, VME_TOOMANYINT_STR); break;
    case VME_TOOMANYHDL:          strcpy(code, VME_TOOMANYHDL_STR); break;
    case VME_INTUSED:             strcpy(code, VME_INTUSED_STR); break;
    case VME_ILLINTLEVEL:         strcpy(code, VME_ILLINTLEVEL_STR); break;
    case VME_ILLINTTYPE:          strcpy(code, VME_ILLINTTYPE_STR); break;
    case VME_INTCONF:             strcpy(code, VME_INTCONF_STR); break;
    case VME_LVLDISABLED:         strcpy(code, VME_LVLDISABLED_STR); break;
    case VME_LVLISNOTRORA:        strcpy(code, VME_LVLISNOTRORA_STR); break;
    case VME_ILLINTHANDLE:        strcpy(code, VME_ILLINTHANDLE_STR); break;
    case VME_INTBYSIGNAL:         strcpy(code, VME_INTBYSIGNAL_STR); break;
    case VME_NOINTERRUPT:         strcpy(code, VME_NOINTERRUPT_STR); break;
    case VME_ENOMEM:              strcpy(code, VME_ENOMEM_STR); break;
    case VME_KMALLOC:             strcpy(code, VME_KMALLOC_STR); break;
    case VME_BERRTBLFULL:         strcpy(code, VME_BERRTBLFULL_STR); break;
    case VME_BERRNOTFOUND:        strcpy(code, VME_BERRNOTFOUND_STR); break;
    case VME_ILL_TO:              strcpy(code, VME_ILL_TO_STR); break;
    case VME_NODOMEMEM:           strcpy(code, VME_NODOMEMEM_STR); break;
    case VME_UNKNOWN_BOARD:       strcpy(code, VME_UNKNOWN_BOARD_STR); break;
    case VME_NOCRCSRMAP:          strcpy(code, VME_NOCRCSRMAP_STR); break;
    case VME_IO_FAIL:             strcpy(code, VME_IO_FAIL_STR); break;
    case VME_SYSFAILTBLFULL:      strcpy(code, VME_SYSFAILTBLFULL_STR); break;
    case VME_SYSFAILTBLNOTLINKED: strcpy(code, VME_SYSFAILTBLNOTLINKED_STR); break;
    case VME_SYSFAILNOTLINKED:    strcpy(code, VME_SYSFAILNOTLINKED_STR); break;
    case VME_NOSTATMAP2:          strcpy(code, VME_NOSTATMAP2_STR); break;
    case VME_IOUNMAP:             strcpy(code, VME_IOUNMAP_STR); break;
    default:                      strcpy(code, VME_NO_CODE_STR); return(RCC_ERROR_RETURN(0,VME_NO_CODE)); break;
  }
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


/**********************************/ 
/*Additional (temporary) functions*/
/**********************************/

/****************************/
VME_ErrorCode_t VME_test(void)
/****************************/
{
  int ret,en;
  static int count = 0;

  ISOPEN;

  ret = ioctl(dev_handle, VMETEST, &count);
  en=errno;
  if (en != VME_ENOSYS)
    printf("Error from VME_test. Return code = %d\n", en);  
  
  return(RCC_ERROR_RETURN(0, VME_SUCCESS));
}


CERN Central CVS service
ViewVC Help
Powered by ViewVC 1.0.4