/*
cc32lib_NT.c -- a simple access library for the PCICC32 PCI to CAMAC Interface
from ARW Elektronik - the WINNT parts
(c) 2000 ARW Elektronik
this source code is published under GPL (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
derived from the previous WIN95 library AR 30.07.2000
added buffer, UNTIL_NOT_Q and AUTOREAD functionality AR 17.03.2001
*/
/*--- INCLUDES -----------------------------------------------------------------------------------*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <winioctl.h>
#include "pcicc32.h" /* PCI common ioctl commands and structures between driver and library */
#include "libcc32_NT.h" /* shared header bewteen applictaion and library */
/*--- DEFINES ------------------------------------------------------------------------------------*/
#define DEFDEVICENAME "\\\\.\\PCICC32:\\CC32_xx"
/*--- EXTERNALS ----------------------------------------------------------------------------------*/
/*--- TYPEDEFS -----------------------------------------------------------------------------------*/
typedef struct
{
HANDLE nHandle; /* the handle of this device */
int nModuleNumber; /* the number of the module */
unsigned short wLastAccessWidth; /* the last parametrized data access width */
unsigned short wLastAttributes; /* the last Attributes to this channel */
unsigned long dwLastAccessAddress; /* the last access address to speed up */
} CC32_DEVICE_NT;
/*--- FUNCTIONS -----------------------------------------------------------------------*/
//--------------------------------------------------------------------------------------
// get the PCIADA status from the PCI side of the interface
//
static int getStatus(HANDLE nHandle, DWORD dwInterface, char *nTimeout, char *nLAM)
{
PCICC32_STATUS status;
DWORD DIOC_count; // count of returned bytes of DeviceIoControl
DWORD result;
if (nHandle == (HANDLE)-1) return -1;
*nTimeout = *nLAM = 0;
// attach a window into the CC32 space ----------------
result = DeviceIoControl(nHandle, PCICC32_GET_STATUS,
&dwInterface, sizeof(dwInterface),
&status, sizeof(status), &DIOC_count, NULL);
if (!result)
return GetLastError();
else
{
*nTimeout = (char)status.bTimeout;
*nLAM = (char)status.bInterrupt;
return 0;
}
}
//--------------------------------------------------------------------------------------
// clear the PCIADA status
//
static int clearStatus(HANDLE nHandle, DWORD dwInterface)
{
DWORD DIOC_count; // count of returned bytes of DeviceIoControl
DWORD result;
if (nHandle == (HANDLE)-1) return -1;
// attach a window into the CC32 space ----------------
result = DeviceIoControl(nHandle, PCICC32_CLEAR_STATUS,
&dwInterface, sizeof(dwInterface),
NULL, 0, &DIOC_count, NULL);
if (!result)
return GetLastError();
else
return 0;
}
//-------------------------------------------------------------------------
// set the future access parameters - override the current
//
static int setAccessParameter(HANDLE hHandle, USHORT wAccessType, USHORT wBlockTransfer)
{
DWORD result;
DWORD DIOC_count; // count of returned bytes of DeviceIoControl
PCICC32_ACCESS_COMMAND access_parameter;
access_parameter.wAccessType = wAccessType;
access_parameter.wBlockTransfer = wBlockTransfer;
result = DeviceIoControl(hHandle, PCICC32_SET_ACCESS_PARA,
&access_parameter, (DWORD)sizeof(access_parameter), NULL,
0, &DIOC_count, NULL);
if (!result)
return GetLastError();
else
return 0;
}
//-------------------------------------------------------------------------
// create a DeviceName out of cszDeviceName and nIfcNum
//
static char *DeviceName(int nIfcNum)
{
static char buffer[255];
char *ptr = buffer;
while (*ptr) ptr++;
do
{
ptr--;
} while (*ptr != '_'); // step back until '-'
ptr++;
if (nIfcNum >= 10) // add the interface number
{
*ptr++ = '1';
nIfcNum -= 10;
}
*ptr++ = '0' + nIfcNum;
*ptr = 0;
// a little help for the users
return buffer;
}
//-------------------------------------------------------------------------
// open my path to the interface
//
static HANDLE openPath(char *name)
{
return (HANDLE)CreateFile(
name,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
}
//--------------------------------------------------------------------------------------
// open the device
//
int cc32_open_NT(char *cszPath, int nModuleNumber, void **handle)
{
CC32_DEVICE_NT *dev;
int error = 0;
*handle = (void *)0;
dev
= (CC32_DEVICE_NT
*)malloc(sizeof(CC32_DEVICE_NT
));
if (!dev) return errno;
dev->nModuleNumber = nModuleNumber;
dev->nHandle = INVALID_HANDLE_VALUE;
dev->wLastAccessWidth = 0xffff; /* invalidate for future use */
// start the driver ------------------
dev->nHandle = openPath(DeviceName(nModuleNumber));
if (dev->nHandle == INVALID_HANDLE_VALUE)
error = GetLastError();
else
{
SetFilePointer(dev->nHandle, 0, NULL, FILE_BEGIN);
dev->dwLastAccessAddress = 0;
dev->wLastAttributes = 0;
dev->wLastAccessWidth = 0;
}
if (error)
{
return error;
}
*handle = (void *)dev;
return NO_ERROR;
}
//--------------------------------------------------------------------------------------
// close the device
//
int cc32_close_NT(void *handle)
{
CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
int error = NO_ERROR;
if (dev)
{
if (dev->nHandle != INVALID_HANDLE_VALUE)
CloseHandle(dev->nHandle);
}
else
error = ERROR_INVALID_FUNCTION;
return error;
}
//--------------------------------------------------------------------------------------
// read a word
//
unsigned short cc32_read_word_NT(void *handle, unsigned int N, unsigned int A, unsigned int F)
{
register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
unsigned long adr = NAF(N,A,F);
unsigned short buffer;
unsigned long bytesRead;
// cache the data access width
if (dev->wLastAccessWidth != WORD_ACCESS)
{
dev->wLastAccessWidth = WORD_ACCESS;
setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
}
// cache the address
if (dev->dwLastAccessAddress != adr)
{
SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
dev->dwLastAccessAddress = adr;
}
ReadFile(dev->nHandle, &buffer, WORD_ACCESS, &bytesRead, NULL);
return buffer;
}
//--------------------------------------------------------------------------------------
// read a long
//
unsigned long cc32_read_long_all_NT(void *handle, unsigned int N, unsigned int A, unsigned int F)
{
register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
unsigned long adr = NAF(N,A,F);
unsigned long buffer;
unsigned long bytesRead;
// cache the data access width
if (dev->wLastAccessWidth != LONG_ACCESS)
{
dev->wLastAccessWidth = LONG_ACCESS;
setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
}
// cache the address
if (dev->dwLastAccessAddress != adr)
{
SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
dev->dwLastAccessAddress = adr;
}
ReadFile(dev->nHandle, &buffer, LONG_ACCESS, &bytesRead, NULL);
return buffer;
}
//--------------------------------------------------------------------------------------
// read a long and get Q and X
//
unsigned long cc32_read_long_NT(void *handle, unsigned int N, unsigned int A, unsigned int F, char *Q, char *X)
{
unsigned long erg = cc32_read_long_all_NT(handle, N, A, F);
*Q = (erg & 0x80000000) ? 1 : 0;
*X = (erg & 0x40000000) ? 1 : 0;
return erg & 0x00FFFFFF;
}
//--------------------------------------------------------------------------------------
// write a word
//
void cc32_write_word_NT(void *handle, unsigned int N, unsigned int A, unsigned int F, unsigned short uwData)
{
register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
unsigned long adr = NAF(N,A,F);
DWORD bytesWritten;
// cache the data access width
if (dev->wLastAccessWidth != WORD_ACCESS)
{
dev->wLastAccessWidth = WORD_ACCESS;
setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
}
// cache the address
if (dev->dwLastAccessAddress != adr)
{
SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
dev->dwLastAccessAddress = adr;
}
WriteFile(dev->nHandle, &uwData, WORD_ACCESS, &bytesWritten, NULL);
}
//--------------------------------------------------------------------------------------
// write a long
//
void cc32_write_long_NT(void *handle, unsigned int N, unsigned int A, unsigned int F, unsigned long ulData)
{
register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
unsigned long adr = NAF(N,A,F);
DWORD bytesWritten;
// cache the data access width
if (dev->wLastAccessWidth != LONG_ACCESS)
{
dev->wLastAccessWidth = LONG_ACCESS;
setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
}
// cache the address
if (dev->dwLastAccessAddress != adr)
{
SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
dev->dwLastAccessAddress = adr;
}
WriteFile(dev->nHandle, &ulData, LONG_ACCESS, &bytesWritten, NULL);
}
//--------------------------------------------------------------------------------------
// clear the PCIADA status
//
int cc32_poll_error_NT(void *handle, char *nTimeout, char *nLam)
{
CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
int error;
if ((error = getStatus(dev->nHandle, dev->nModuleNumber, nTimeout, nLam)))
return error;
if (*nTimeout) /* clear error */
{
if ((error = clearStatus(dev->nHandle, dev->nModuleNumber)))
return error;
}
return NO_ERROR;
}
//--------------------------------------------------------------------------------------
// read 'len' words or 'UNTIL_NOT_Q' from a address made out of N,A,F
//
int cc32_read_word_buffer_NT(void * handle, unsigned int N, unsigned int A, unsigned int F,
unsigned short *pwBuffer, unsigned long *pdwLen)
{
register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
unsigned long adr = NAF(N,A,F);
unsigned long dwLen;
// cache the data access width
if (dev->wLastAccessWidth != WORD_ACCESS)
{
dev->wLastAccessWidth = WORD_ACCESS;
setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
}
// cache the address
if (dev->dwLastAccessAddress != adr)
{
SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
dev->dwLastAccessAddress = adr;
}
*pdwLen <<= 1; // make bytes
dwLen = *pdwLen;
if (!ReadFile(dev->nHandle, pwBuffer, dwLen, pdwLen, NULL))
return GetLastError();
*pdwLen >>= 1; // make words
return 0;
}
//--------------------------------------------------------------------------------------
// read 'len' longs or 'UNTIL_NOT_Q' from a address made out of N,A,F, mask 24 bits out
//
int cc32_read_long_buffer_NT(void * handle, unsigned int N, unsigned int A, unsigned int F,
unsigned long *pdwBuffer, unsigned long *pdwLen)
{
register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
unsigned long adr = NAF(N,A,F);
unsigned long *pdwPtr = pdwBuffer;
unsigned long *pdwEnd = pdwBuffer;
unsigned long dwLen;
// cache the data access width
if (dev->wLastAccessWidth != LONG_ACCESS)
{
dev->wLastAccessWidth = LONG_ACCESS;
setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
}
// cache the address
if (dev->dwLastAccessAddress != adr)
{
SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
dev->dwLastAccessAddress = adr;
}
*pdwLen <<= 2; // make bytes
dwLen = *pdwLen;
if (!ReadFile(dev->nHandle, pdwBuffer, dwLen, pdwLen, NULL))
return GetLastError();
pdwEnd += *pdwLen;
while (pdwEnd < pdwPtr)
*pdwPtr++ &= 0x00FFFFFF; // mask Q and X bits
*pdwLen >>= 2; // make longs
return 0;
}
//--------------------------------------------------------------------------------------
// read 'len' longs or 'UNTIL_NOT_Q' from a address made out of N,A,F, without interpretation
//
int cc32_read_long_all_buffer_NT(void * handle, unsigned int N, unsigned int A, unsigned int F,
unsigned long *pdwBuffer, unsigned long *pdwLen)
{
register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
unsigned long adr = NAF(N,A,F);
unsigned long dwLen;
// cache the data access width
if (dev->wLastAccessWidth != LONG_ACCESS)
{
dev->wLastAccessWidth = LONG_ACCESS;
setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
}
// cache the address
if (dev->dwLastAccessAddress != adr)
{
SetFilePointer(dev->nHandle, adr, NULL, FILE_BEGIN);
dev->dwLastAccessAddress = adr;
}
*pdwLen <<= 2; // make bytes
dwLen = *pdwLen;
if (!ReadFile(dev->nHandle, pdwBuffer, dwLen, pdwLen, NULL))
return GetLastError();
*pdwLen >>= 2; // make longs
return 0;
}
//--------------------------------------------------------------------------------------
// switch UNTIL_NOT_Q or AUTOREAD on or off
//
int cc32_access_switch_NT(void *handle, unsigned short uwSwitch)
{
register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
dev->wLastAttributes = uwSwitch;
return setAccessParameter(dev->nHandle, dev->wLastAccessWidth, dev->wLastAttributes);
}
//--------------------------------------------------------------------------------------
// switch interrupts on
//
int cc32_enable_interrupt_NT(void *handle)
{
register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
DWORD result;
DWORD DIOC_count; // count of returned bytes of DeviceIoControl
PCICC32_IRQ_CONTROL irqCntrl;
irqCntrl.dwInterface = 0; // don't bother at WINNT
irqCntrl.wEnable = 1; // enable it
result = DeviceIoControl(dev->nHandle, PCICC32_CONTROL_INTERRUPTS,
&irqCntrl, sizeof(irqCntrl), NULL, 0, &DIOC_count, NULL);
if (!result)
return GetLastError();
else
return NO_ERROR;
}
//--------------------------------------------------------------------------------------
// switch interrupts off
//
int cc32_disable_interrupt_NT(void *handle)
{
register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
DWORD result;
DWORD DIOC_count; // count of returned bytes of DeviceIoControl
PCICC32_IRQ_CONTROL irqCntrl;
irqCntrl.dwInterface = 0; // don't bother at WINNT
irqCntrl.wEnable = 0; // disable it
result = DeviceIoControl(dev->nHandle, PCICC32_CONTROL_INTERRUPTS,
&irqCntrl, sizeof(irqCntrl), NULL, 0, &DIOC_count, NULL);
if (!result)
return GetLastError();
else
return NO_ERROR;
}
//--------------------------------------------------------------------------------------
// wait blocking for the next interrupt
//
int cc32_get_interrupt_NT(void *handle, unsigned long *dwStatus)
{
register CC32_DEVICE_NT *dev = (CC32_DEVICE_NT *)handle;
DWORD result;
DWORD DIOC_count; // count of returned bytes of DeviceIoControl
PCICC32_IRQ_RESPONSE response;
int nError;
OVERLAPPED sOverlapped;
sOverlapped.hEvent = NULL;
result = DeviceIoControl(dev->nHandle, PCICC32_INSTALL_IRQ_BLOCK,
NULL, 0, &response, sizeof(response), &DIOC_count, NULL);
*dwStatus = response.dwInterruptFlags;
if (!result)
{
nError = GetLastError();
// a real error
if ((nError != ERROR_IO_PENDING) && (nError != ERROR_SUCCESS))
return nError;
// my IO is pending - wait for it
if (nError == ERROR_IO_PENDING)
{
result = GetOverlappedResult(dev->nHandle, &sOverlapped, &DIOC_count, TRUE);
*dwStatus = response.dwInterruptFlags;
if (!result)
{
nError = GetLastError(); // if it was cancelled
if (nError == ERROR_OPERATION_ABORTED)
return NO_ERROR; // accept it as 'normal'
else
return nError;
}
}
}
return NO_ERROR;
}