//****************************************************************************
// 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);
}