//-------------------------------------------------------------------------------------------
// 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
;
printf("initHardware:err=%d %s\n" , errno
, strerror(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
;
printf("deInitHardware:err=%d %s\n" , errno
, strerror(errno
) );
return errno
;
}
return 0;
}
int VMEopen
(const char *cszDeviceName
, unsigned char ubAddressModifier
, ptrdiff_t
*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
;
printf("VMEopen:err=%d %s\n" , error
, strerror(error
) );
free(dev
);
return error
;
}
dev
->cAddressModifier
= ubAddressModifier
;
*pnHandle
= (ptrdiff_t
)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
, ptrdiff_t
*pnHandle
)
{
char *szLocalDeviceName
= szDeviceName
(cszDeviceName
, nVMEMM
);
return VMEopen
(szLocalDeviceName
, ubAddressModifier
, pnHandle
);
}
int setAccessProperties
(ptrdiff_t 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
;
printf("setAccessProperties:err=%d %s\n" , errno
, strerror(errno
) );
return errno
;
}
dev
->cAddressModifier
= bModifier
;
dev
->cAccessWidth
= bAccessType
;
return 0;
}
int VMEread
(ptrdiff_t 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
(ptrdiff_t 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
(ptrdiff_t 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
(ptrdiff_t 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
(ptrdiff_t 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
(ptrdiff_t 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
(ptrdiff_t 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
(ptrdiff_t 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
(ptrdiff_t nHandle
)
{
__u8 ubVector
;
VMEinterrupt
(nHandle
, &ubVector
);
if (ubVector
== 7)
return EFAULT
; // it's a bus error
else
return 0;
}
int VMEclose
(ptrdiff_t 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
;
free(dev
);
}
return error
;
}
int VMEcontrolInterrupt
(ptrdiff_t 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
(ptrdiff_t nHandle
)
{
VMEMM_DEVICE
*dev
= (VMEMM_DEVICE
*)nHandle
;
int nLocalError
;
nLocalError
= dev
->nLastError
;
dev
->nLastError
= 0;
return nLocalError
;
}