//****************************************************************************
 
// Copyright (C) 2000-2004  ARW Elektronik Germany
 
//
 
//
 
// This program is free software; you can redistribute it and/or modify
 
// it under the terms of the GNU Lesser General Public License as published by
 
// the Free Software Foundation; either version 2 of the License, or
 
// (at your option) any later version.
 
//
 
// This program is distributed in the hope that it will be useful,
 
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
// GNU General Public License for more details.
 
//
 
// You should have received a copy of the GNU General Public License
 
// along with this program; if not, write to the Free Software
 
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
//
 
// This product is not authorized for use as critical component in 
 
// life support systems without the express written approval of 
 
// ARW Elektronik Germany.
 
//  
 
// Please announce changes and hints to ARW Elektronik
 
//
 
// Maintainer(s): Klaus Hitschler (klaus.hitschler@gmx.de)
 
//
 
//****************************************************************************
 
 
 
//****************************************************************************
 
//
 
// cc32lib.c -- a simple access library for the PCICC32 PCI to CAMAC Interface
 
//
 
// $Log: libcc32.c,v $
 
// Revision 1.9  2004/11/29 20:45:36  klaus
 
// Bug remove. Still release libcc32.so.2.
 
//
 
// Revision 1.8  2004/11/29 20:43:12  klaus
 
// added _qx functions to get Q and X for every transfer. Release libcc32.so.2.
 
//
 
// Revision 1.7  2004/08/13 19:48:25  klaus
 
// changed license from GPL to LGPL
 
//
 
// Revision 1.6  2004/08/12 20:00:41  klaus
 
// conversion to kernel-version 2.6, released version 6.0
 
//
 
// Revision 1.5  2002/05/20 21:24:19  klaus
 
// Small changes for kernel 2.4.18
 
//
 
// Revision 1.4  2002/04/17 19:41:06  klaus
 
// added support for autoread
 
//
 
// Revision 1.3  2002/04/14 18:25:38  klaus
 
// added interrupt handling, driver 4.4. ...3.5.tar.gz
 
//
 
// Revision 1.2  2001/11/20 20:12:50  klaus
 
// included new header and CVS log
 
//
 
//
 
// first steps                                                 AR   25.02.2000
 
//
 
//****************************************************************************
 
 
 
/*--- INCLUDES -----------------------------------------------------------------------------------*/
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <string.h>
 
#include <unistd.h>
 
#include <sys/mman.h>
 
#include <errno.h>
 
#include <ctype.h>
 
#include <sys/ioctl.h>
 
#include "../driver/pcicc32.h" /* PCI common ioctl commands and structures between driver and library  */
 
#include "libcc32.h"      /* shared header bewteen application and library                        */
 
 
 
/*--- DEFINES ------------------------------------------------------------------------------------*/
 
#define pwCC32_ADR(adr, N, A, F) (__u16 *)((N << 10) + (A << 6) + ((F & 0xF) << 2) + adr)
 
#define plCC32_ADR(adr, N, A, F) (__u32 *)((N << 10) + (A << 6) + ((F & 0xF) << 2) + adr)
 
#define WINDOW_SIZE 32768
 
 
 
/*--- EXTERNALS ----------------------------------------------------------------------------------*/
 
 
 
/*--- TYPEDEFS -----------------------------------------------------------------------------------*/
 
typedef struct
 
{
 
        FILE *f;                  /* the handle of this device */
 
  int  fileNo;  /* equals fileno(f)          */
 
        char *base;             /* base of range, got with mmap */
 
} CC32_DEVICE;
 
 
 
/*--- FUNCTIONS ----------------------------------------------------------------------------------*/
 
static int cc32_interrupt_control(CC32_HANDLE handle, int enable)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        PCICC32_IRQ_CONTROL control;
 
 
 
  control.bEnable = enable;
 
 
 
  return ioctl(dev->fileNo, PCICC32_CONTROL_INTERRUPTS, &control);
 
}
 
 
 
static int cc32_xxxx_event(CC32_HANDLE handle, int *nTimeout, int *nLam, int nCode)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        PCICC32_STATUS state;
 
        int error;
 
        
 
  if ((error = ioctl(dev->fileNo, nCode, &state)))
 
          return error;
 
                
 
        *nTimeout = state.bFail;
 
        *nLam     = state.bIrq;
 
        
 
        if (state.bFail)  /* clear error */
 
        {
 
                if ((error = ioctl(dev->fileNo, PCICC32_IOCNTRL, 0)))
 
                        return error;   
 
        }
 
        
 
        return 0;
 
}
 
 
 
static int cc32_autoread_control(CC32_HANDLE handle, int nOn)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        PCICC32_AUTOREAD control;
 
 
 
  control.bOn = nOn;
 
 
 
  return ioctl(dev->fileNo, PCICC32_AUTOREAD_SWITCH, &control);
 
}
 
 
 
static void cc32_get_qx(CC32_DEVICE *dev, int *Q,  int *X)
 
{
 
  __u16 wstatus = *pwCC32_ADR(dev->base, 0, 0, 0);
 
        
 
  *Q = (wstatus & 8) ? 1 : 0;
 
  *X = (wstatus & 4) ? 1 : 0;
 
}
 
 
 
int cc32_open(char *cszPath, CC32_HANDLE *handle)
 
{
 
        CC32_DEVICE *dev;
 
        
 
        *handle = (CC32_HANDLE)0;
 
        
 
        dev 
= (CC32_DEVICE 
*)malloc(sizeof(CC32_DEVICE
)); 
        if (!dev) return errno;
 
        
 
        dev->fileNo = 0;
 
        dev->base   = (char *)0;
 
        
 
        if (!(dev
->f 
= fopen(cszPath
,"rw")))   
  {
 
                int error = errno;
 
                
 
                printf("Cannot Open Device %s\n",cszPath
);  
                return error;
 
        }
 
        
 
        dev->fileNo = fileno(dev->f);
 
        
 
        dev->base = (char *)mmap(0, WINDOW_SIZE, PROT_READ, MAP_FILE | MAP_PRIVATE, dev->fileNo, 0);
 
        if (dev->base == (char *)-1)
 
        {
 
                int error = errno;
 
                
 
                printf("Cannot MMap Device %s\n",cszPath
);  
 
 
                return error;   
 
        } 
 
 
 
        *handle = (CC32_HANDLE)dev;
 
        
 
        return 0;
 
}
 
 
 
int cc32_close(CC32_HANDLE handle)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        int error = 0;
 
        
 
        if (dev)
 
        {
 
                munmap(dev->base, WINDOW_SIZE);
 
                        
 
                if (dev->f)
 
                else
 
                        error = -EINVAL;
 
        
 
        }
 
        else
 
                error = -EINVAL;
 
                
 
        return error;
 
}
 
 
 
__u16 cc32_read_word(CC32_HANDLE handle, unsigned int N, unsigned int A, unsigned int F)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        
 
        return *pwCC32_ADR(dev->base, N, A, F);
 
}
 
 
 
__u16 cc32_read_word_qx(CC32_HANDLE handle, unsigned int N, unsigned int A, unsigned int F, int *Q, int *X)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        __u32 erg = *plCC32_ADR(dev->base, N, A, F);
 
        
 
        *Q = (erg & 0x80000000) ? 1 : 0;
 
        *X = (erg & 0x40000000) ? 1 : 0;
 
        
 
        return erg & 0x0000FFFF; // get only the lower 16 bits
 
}
 
 
 
__u32 cc32_read_long_all(CC32_HANDLE handle, unsigned int N, unsigned int A, unsigned int F)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        
 
        return *plCC32_ADR(dev->base, N, A, F);;
 
}
 
 
 
__u32 cc32_read_long(CC32_HANDLE handle, unsigned int N, unsigned int A, unsigned int F)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        __u32 erg = *plCC32_ADR(dev->base, N, A, F);
 
        
 
        return erg & 0x00FFFFFF;
 
}
 
 
 
__u32 cc32_read_long_qx(CC32_HANDLE handle, unsigned int N, unsigned int A, unsigned int F, int *Q, int *X)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        __u32 erg = *plCC32_ADR(dev->base, N, A, F);
 
        
 
        *Q = (erg & 0x80000000) ? 1 : 0;
 
        *X = (erg & 0x40000000) ? 1 : 0;
 
        
 
        return erg & 0x00FFFFFF;
 
}
 
 
 
void cc32_write_word(CC32_HANDLE handle, unsigned int N, unsigned int A, unsigned int F, __u16 uwData)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        
 
        *pwCC32_ADR(dev->base, N, A, F) = uwData;
 
}
 
 
 
void cc32_write_word_qx(CC32_HANDLE handle, unsigned int N, unsigned int A, unsigned int F, __u16 uwData, int *Q, int *X)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        
 
        *pwCC32_ADR(dev->base, N, A, F) = uwData;
 
 
 
  cc32_get_qx(dev, Q,  X);
 
}
 
 
 
void cc32_write_long(CC32_HANDLE handle, unsigned int N, unsigned int A, unsigned int F, __u32 ulData)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
 
 
        *plCC32_ADR(dev->base, N, A, F) = ulData;
 
}
 
 
 
void cc32_write_long_qx(CC32_HANDLE handle, unsigned int N, unsigned int A, unsigned int F, __u32 ulData, int *Q, int *X)
 
{
 
        CC32_DEVICE *dev = (CC32_DEVICE *)handle;
 
        
 
        *plCC32_ADR(dev->base, N, A, F) = ulData;
 
  
 
  cc32_get_qx(dev, Q,  X);
 
}
 
 
 
int cc32_poll_event(CC32_HANDLE handle, int *nTimeout, int *nLam)
 
{
 
  return cc32_xxxx_event(handle, nTimeout, nLam, PCICC32_IOSTATE);
 
}
 
 
 
int cc32_wait_event(CC32_HANDLE handle, int *nTimeout, int *nLam)
 
{
 
  return cc32_xxxx_event(handle, nTimeout, nLam, PCICC32_IOSTATE_BLOCKING);
 
}
 
 
 
int cc32_interrupt_disable(CC32_HANDLE handle)
 
{
 
  return cc32_interrupt_control(handle, 0);
 
}
 
 
 
int cc32_interrupt_enable(CC32_HANDLE handle)
 
{
 
  return cc32_interrupt_control(handle, 1);
 
}
 
 
 
int cc32_autoread_on(CC32_HANDLE handle)
 
{
 
  return cc32_autoread_control(handle, 1);
 
}
 
 
 
int cc32_autoread_off(CC32_HANDLE handle)
 
{
 
  return cc32_autoread_control(handle, 0);
 
}