1688 lines
57 KiB
C
1688 lines
57 KiB
C
|
|
// SPDX-License-Identifier: MIT
|
||
|
|
/**************************************************************************************
|
||
|
|
*
|
||
|
|
* Copyright (c) 2024, Hilscher Gesellschaft fuer Systemautomation mbH. All Rights Reserved.
|
||
|
|
*
|
||
|
|
* Description: Linux specific driver / toolkit initialization
|
||
|
|
*
|
||
|
|
* Changes:
|
||
|
|
*
|
||
|
|
* Version Date Author Description
|
||
|
|
* ----------------------------------------------------------------------------------
|
||
|
|
* 1 02.01.24 SD changed licensing terms
|
||
|
|
*
|
||
|
|
**************************************************************************************/
|
||
|
|
|
||
|
|
#include "cifXToolkit.h"
|
||
|
|
#include "cifXHWFunctions.h"
|
||
|
|
#include "cifxlinux.h"
|
||
|
|
#include "cifXUser.h"
|
||
|
|
#include "cifxlinux_internal.h"
|
||
|
|
#include "HilPCIDefs.h"
|
||
|
|
#ifdef CIFXETHERNET
|
||
|
|
#include "netx_tap.h"
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef CIFX_PLUGIN_SUPPORT
|
||
|
|
#include <dlfcn.h>
|
||
|
|
#include <sys/queue.h>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#include <sys/types.h>
|
||
|
|
#include <sys/mman.h>
|
||
|
|
#include <sys/stat.h>
|
||
|
|
#include <sys/time.h>
|
||
|
|
#include <sys/resource.h>
|
||
|
|
#include <sys/file.h>
|
||
|
|
|
||
|
|
#include <dirent.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <fcntl.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
#include <pthread.h>
|
||
|
|
#include <time.h>
|
||
|
|
#include <limits.h>
|
||
|
|
|
||
|
|
#include <errno.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
extern char* g_szDriverBaseDir;
|
||
|
|
extern void* g_pvTkitLock;
|
||
|
|
extern unsigned long g_ulDeviceCount;
|
||
|
|
extern PDEVICEINSTANCE* g_pptDevices;
|
||
|
|
#ifdef CIFXETHERNET
|
||
|
|
extern void* g_eth_list_lock;
|
||
|
|
#endif
|
||
|
|
FILE* g_logfd = 0;
|
||
|
|
|
||
|
|
#ifdef CIFX_PLUGIN_SUPPORT
|
||
|
|
struct CIFX_PLUGIN_T
|
||
|
|
{
|
||
|
|
SLIST_ENTRY(CIFX_PLUGIN_T) tList;
|
||
|
|
void* hPluginFile;
|
||
|
|
uint32_t ulDeviceCount;
|
||
|
|
struct CIFX_DEVICE_T** aptDevices;
|
||
|
|
};
|
||
|
|
|
||
|
|
static SLIST_HEAD(PLUGIN_LIST, CIFX_PLUGIN_T) s_tPluginList = SLIST_HEAD_INITIALIZER(PLUGIN_LIST);
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#define COS_THREAD_STACK_MIN 0x1000 /* Stack size needed by Thread for
|
||
|
|
handling Toolkit's cyclic actions */
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! \file cifxlinux.c
|
||
|
|
* Linux specific initialization of toolkit / driver */
|
||
|
|
/*****************************************************************************/
|
||
|
|
|
||
|
|
static void __init() __attribute__((__constructor__));
|
||
|
|
static void __deinit() __attribute__((__destructor__));
|
||
|
|
|
||
|
|
static void* cifXPollingThread(void *arg);
|
||
|
|
static int polling_thread_running = 0;
|
||
|
|
static pthread_t polling_thread = {0};
|
||
|
|
static pthread_attr_t polling_thread_attr = {{0}};
|
||
|
|
static unsigned short polling_thread_stop = 0;
|
||
|
|
|
||
|
|
#ifdef CIFX_DRV_HWIF
|
||
|
|
void* HWIFDPMRead ( uint32_t ulOpt, void* pvDevInstance, void* pvDpmAddr, void* pvDst, uint32_t ulLen);
|
||
|
|
void* HWIFDPMWrite( uint32_t ulOpt, void* pvDevInstance, void* pvDpmAddr, void* pvSrc, uint32_t ulLen);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Initialization function called on load of libcifx_tk.so */
|
||
|
|
/*****************************************************************************/
|
||
|
|
static void __init()
|
||
|
|
{
|
||
|
|
//cifXTKitInit();
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! De-Initialization function called on unload of libcifx_tk.so */
|
||
|
|
/*****************************************************************************/
|
||
|
|
static void __deinit()
|
||
|
|
{
|
||
|
|
cifXDriverDeinit();
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Helper function to open a uio device
|
||
|
|
* \param uio_num Number of uio device
|
||
|
|
* \param fCheckAccess If != 0 the driver denies access if card is already
|
||
|
|
* accesed
|
||
|
|
* \return fd of uio, -1 on error */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int cifx_uio_open(int uio_num, int fCheckAccess)
|
||
|
|
{
|
||
|
|
char dev_name[16];
|
||
|
|
int fd;
|
||
|
|
int iRet;
|
||
|
|
|
||
|
|
sprintf(dev_name, "/dev/uio%d", uio_num);
|
||
|
|
fd = open(dev_name,O_RDWR);
|
||
|
|
|
||
|
|
/* if fCheckAccess is true lock access to the device */
|
||
|
|
if (1 == fCheckAccess)
|
||
|
|
{
|
||
|
|
/* lock file access (non blocking) */
|
||
|
|
if (0 != (iRet = flock( fd, LOCK_EX | LOCK_NB)))
|
||
|
|
{
|
||
|
|
if (errno == EWOULDBLOCK)
|
||
|
|
{
|
||
|
|
fprintf( stderr, "cifX%d may be opened by another process!\n", uio_num);
|
||
|
|
}
|
||
|
|
close(fd);
|
||
|
|
fd = -1;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return fd;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Helper function to open a ISA device
|
||
|
|
* \return fd -1 on error */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int cifx_ISA_open(void)
|
||
|
|
{
|
||
|
|
char dev_name[16];
|
||
|
|
int fd;
|
||
|
|
|
||
|
|
sprintf(dev_name, "/dev/mem");
|
||
|
|
fd = open(dev_name,O_RDWR, O_SYNC);
|
||
|
|
|
||
|
|
return fd;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Helper function to close a ISA device */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void cifx_ISA_close(int isa_fd)
|
||
|
|
{
|
||
|
|
close( isa_fd);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Checks if mapping matches specific type (dpm, extmem, dma)
|
||
|
|
* \param uio_num number of the uio device
|
||
|
|
* \param mapno Mapping number to validate
|
||
|
|
* \param tMemtype Memory type to be checked
|
||
|
|
* \return CIFX_NO_ERROR if memtype matches */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int32_t validate_memtype( int uio_num, int mapno, CIFX_MEM_TYPE_E tMemtype)
|
||
|
|
{
|
||
|
|
int32_t ret = CIFX_DEV_FUNCTION_FAILED;
|
||
|
|
FILE* file;
|
||
|
|
char memtype[64];
|
||
|
|
char filename[64];
|
||
|
|
|
||
|
|
sprintf(filename, "/sys/class/uio/uio%d/maps/map%d/name", uio_num, mapno);
|
||
|
|
|
||
|
|
if ((file = fopen(filename,"r")) && (1==fscanf(file,"%s",memtype)))
|
||
|
|
{
|
||
|
|
switch (tMemtype)
|
||
|
|
{
|
||
|
|
case eMEM_DPM:
|
||
|
|
ret = ( 0 == strncmp("dpm", memtype, strlen("dpm")))? CIFX_NO_ERROR: CIFX_DEV_FUNCTION_FAILED;
|
||
|
|
break;
|
||
|
|
case eMEM_EXTMEM:
|
||
|
|
ret = ( 0 == strncmp("extmem", memtype, strlen("extmem")))? CIFX_NO_ERROR: CIFX_DEV_FUNCTION_FAILED;
|
||
|
|
break;
|
||
|
|
case eMEM_DMA:
|
||
|
|
ret = ( 0 == strncmp("dma", memtype, strlen("dma")))? CIFX_NO_ERROR: CIFX_DEV_FUNCTION_FAILED;
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
ret = CIFX_INVALID_PARAMETER;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
/* no name specified -> old uio_netx driver */
|
||
|
|
/* name file does not exist -> old uio driver */
|
||
|
|
if ((NULL != file) || (errno == ENOENT))
|
||
|
|
{
|
||
|
|
/* memory type validation via requested mapno (to be downwards compatible) */
|
||
|
|
switch (tMemtype)
|
||
|
|
{
|
||
|
|
case eMEM_DPM: /* first mapno is DPM */
|
||
|
|
ret = (0 == mapno) ? CIFX_NO_ERROR : CIFX_DEV_FUNCTION_FAILED;
|
||
|
|
break;
|
||
|
|
case eMEM_EXTMEM:/* second mapno is ext mem */
|
||
|
|
ret = (1 == mapno) ? CIFX_NO_ERROR : CIFX_DEV_FUNCTION_FAILED;
|
||
|
|
break;
|
||
|
|
case eMEM_DMA:/* dma was not supported */
|
||
|
|
default:
|
||
|
|
ret = CIFX_INVALID_PARAMETER;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (NULL != file)
|
||
|
|
fclose(file);
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Iterates over mapping dir, searching for a specific memtype
|
||
|
|
* \param uio_num number of the uio device
|
||
|
|
* \param memtype to search for
|
||
|
|
* \param bar BAR to mapping file
|
||
|
|
* \return CIFX_NO_ERROR if memtype is found */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int32_t find_memtype( int uio_num, CIFX_MEM_TYPE_E tMemtype, int *bar)
|
||
|
|
{
|
||
|
|
char addr_file[64];
|
||
|
|
struct dirent** namelist;
|
||
|
|
int32_t ret = CIFX_NO_MORE_ENTRIES;
|
||
|
|
int num_map;
|
||
|
|
int found = 0;
|
||
|
|
|
||
|
|
if (!bar)
|
||
|
|
return CIFX_INVALID_PARAMETER;
|
||
|
|
|
||
|
|
sprintf(addr_file, "/sys/class/uio/uio%d/maps/", uio_num);
|
||
|
|
num_map = scandir(addr_file, &namelist, 0, alphasort);
|
||
|
|
if(num_map > 0)
|
||
|
|
{
|
||
|
|
int currfile = 0;
|
||
|
|
for(;currfile < num_map; ++currfile)
|
||
|
|
{
|
||
|
|
if ((0 == found) && (CIFX_NO_ERROR == validate_memtype( uio_num, currfile, tMemtype)))
|
||
|
|
{
|
||
|
|
*bar = currfile;
|
||
|
|
found = 1;
|
||
|
|
}
|
||
|
|
free(namelist[currfile]);
|
||
|
|
}
|
||
|
|
free(namelist);
|
||
|
|
if (found)
|
||
|
|
ret = CIFX_NO_ERROR;
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Returns the memory size of a uio memory bar
|
||
|
|
* \param uio_num Number of uio device
|
||
|
|
* \param bar BAR to read memory size from
|
||
|
|
* \return size of the bar in bytes */
|
||
|
|
/*****************************************************************************/
|
||
|
|
unsigned long cifx_uio_get_mem_size(int uio_num, int bar)
|
||
|
|
{
|
||
|
|
unsigned long ret = ~0;
|
||
|
|
char filename[64];
|
||
|
|
FILE* file;
|
||
|
|
|
||
|
|
sprintf(filename, "/sys/class/uio/uio%d/maps/map%d/size",
|
||
|
|
uio_num, bar);
|
||
|
|
|
||
|
|
file = fopen(filename,"r");
|
||
|
|
if(file)
|
||
|
|
{
|
||
|
|
if (1!=fscanf(file, "0x%lx", &ret))
|
||
|
|
ret = ~0;
|
||
|
|
fclose(file);
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Returns the physical address uio memory bar
|
||
|
|
* \param uio_num Number of uio device
|
||
|
|
* \param bar BAR to read memory size from
|
||
|
|
* \return physical address of bar */
|
||
|
|
/*****************************************************************************/
|
||
|
|
unsigned long cifx_uio_get_mem_addr(int uio_num, int bar)
|
||
|
|
{
|
||
|
|
unsigned long ret = ~0;
|
||
|
|
char filename[64];
|
||
|
|
FILE* file;
|
||
|
|
|
||
|
|
sprintf(filename, "/sys/class/uio/uio%d/maps/map%d/addr",
|
||
|
|
uio_num, bar);
|
||
|
|
|
||
|
|
file = fopen(filename,"r");
|
||
|
|
if(file)
|
||
|
|
{
|
||
|
|
if (1!=fscanf(file,"0x%lx",&ret))
|
||
|
|
ret = ~0;
|
||
|
|
fclose(file);
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Returns the alias given via device-tree
|
||
|
|
* \param uio_num Number of uio device
|
||
|
|
* \return pointer to buffer - needs to be freed after usage */
|
||
|
|
/*****************************************************************************/
|
||
|
|
char* cifx_uio_get_device_alias(int uio_num)
|
||
|
|
{
|
||
|
|
char filename[64];
|
||
|
|
char ret[64];
|
||
|
|
char* alias = NULL;
|
||
|
|
FILE* file;
|
||
|
|
|
||
|
|
sprintf(filename, "/sys/class/uio/uio%d/name",uio_num);
|
||
|
|
|
||
|
|
file = fopen(filename,"r");
|
||
|
|
if(file)
|
||
|
|
{
|
||
|
|
if (1==fscanf(file,"%s",ret)) {
|
||
|
|
char* buf = strstr(ret, ",");
|
||
|
|
if ((buf != NULL) && ((buf+1-ret)<strlen(ret))) {
|
||
|
|
buf = strstr(buf+1, ",");
|
||
|
|
if ((buf != NULL) && ((buf+1-ret)<strlen(ret))) {
|
||
|
|
if (strcmp((buf+1),"-") != 0) {
|
||
|
|
alias = (char*)malloc(CIFx_MAX_INFO_NAME_LENTH);
|
||
|
|
sprintf(alias,"%s",buf+1);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
fclose(file);
|
||
|
|
}
|
||
|
|
return alias;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Returns the startuptype of the device given via device-tree
|
||
|
|
* \param uio_num Number of uio device
|
||
|
|
* \return device type (ram,flash,auto,dont touch) */
|
||
|
|
/*****************************************************************************/
|
||
|
|
CIFX_TOOLKIT_DEVICETYPE_E cifx_uio_get_device_startuptype(int uio_num)
|
||
|
|
{
|
||
|
|
char buf[64];
|
||
|
|
char filename[64];
|
||
|
|
char* next = NULL;
|
||
|
|
CIFX_TOOLKIT_DEVICETYPE_E ret = eCIFX_DEVICE_AUTODETECT;
|
||
|
|
FILE* file;
|
||
|
|
|
||
|
|
sprintf(filename, "/sys/class/uio/uio%d/name",uio_num);
|
||
|
|
|
||
|
|
file = fopen(filename,"r");
|
||
|
|
if(file)
|
||
|
|
{
|
||
|
|
if (1==fscanf(file,"%s",buf)) {
|
||
|
|
next = strstr(buf, ",");
|
||
|
|
if ((next != NULL) && ((next+1-buf)<strlen(buf))) {
|
||
|
|
char* end = strstr(next+1, ",");
|
||
|
|
next+=1;
|
||
|
|
if (end != NULL) {
|
||
|
|
*end = 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
fclose(file);
|
||
|
|
}
|
||
|
|
if (next != NULL) {
|
||
|
|
if (strncmp(next, UIO_NETX_START_TYPE_AUTO, CIFx_MAX_INFO_NAME_LENTH) == 0) {
|
||
|
|
ret = eCIFX_DEVICE_AUTODETECT;
|
||
|
|
} else if (strncmp(next, UIO_NETX_START_TYPE_RAM, CIFx_MAX_INFO_NAME_LENTH) == 0) {
|
||
|
|
ret = eCIFX_DEVICE_RAM_BASED;
|
||
|
|
} else if (strncmp(next, UIO_NETX_START_TYPE_FLASH, CIFx_MAX_INFO_NAME_LENTH) == 0) {
|
||
|
|
ret = eCIFX_DEVICE_FLASH_BASED;
|
||
|
|
} else if (strncmp(next, UIO_NETX_START_TYPE_DONTTOUCH, CIFx_MAX_INFO_NAME_LENTH) == 0) {
|
||
|
|
ret = eCIFX_DEVICE_DONT_TOUCH;
|
||
|
|
} else {
|
||
|
|
/* default to auto-detect */
|
||
|
|
ret = eCIFX_DEVICE_AUTODETECT;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Check if the name of the uio matches the given name
|
||
|
|
* \param uio_num Number of uio device
|
||
|
|
* \param name Expected name of device
|
||
|
|
* \return !=0 if name matches */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int cifx_uio_validate_name(int uio_num, const char* name)
|
||
|
|
{
|
||
|
|
char filename[64];
|
||
|
|
char uio_name[64];
|
||
|
|
FILE* file;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
sprintf(filename, "/sys/class/uio/uio%d/name", uio_num);
|
||
|
|
|
||
|
|
if(NULL == (file = fopen(filename,"r")))
|
||
|
|
{
|
||
|
|
perror("Error opening file.");
|
||
|
|
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
if(NULL == fgets(uio_name, sizeof(uio_name), file))
|
||
|
|
{
|
||
|
|
perror("Error querying name from uio");
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
char* end = uio_name + strlen(uio_name) - 1;
|
||
|
|
while( (*end == '\n') || (*end == '\r') )
|
||
|
|
{
|
||
|
|
*end-- = '\0';
|
||
|
|
}
|
||
|
|
|
||
|
|
if(0 == strncmp(uio_name, name, strlen(name)))
|
||
|
|
ret = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
fclose(file);
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Map the memory of a uio device
|
||
|
|
* \param fd fd returned by uio_open
|
||
|
|
* \param uio_num number of uio-device
|
||
|
|
* \param bar number of mapping
|
||
|
|
* \param dpmbase Pointer to returned virtual base address of memory area
|
||
|
|
* \param dpmaddr Pointer to returned physical address of memory area
|
||
|
|
* \param dpmlen Pointer to returned length of memory area
|
||
|
|
* \return !=0 if mapping succeeded */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int cifx_uio_map_mem(int uio_fd, int uio_num,
|
||
|
|
int map_num, void** membase,
|
||
|
|
unsigned long* memaddr,
|
||
|
|
unsigned long* memlen,
|
||
|
|
unsigned long flags)
|
||
|
|
{
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
if( (~0 != (*memaddr = cifx_uio_get_mem_addr(uio_num, map_num))) &&
|
||
|
|
(~0 != (*memlen = cifx_uio_get_mem_size(uio_num, map_num))) )
|
||
|
|
{
|
||
|
|
*membase = mmap(NULL, *memlen,
|
||
|
|
PROT_READ|PROT_WRITE,
|
||
|
|
MAP_SHARED|MAP_LOCKED|MAP_POPULATE|flags,
|
||
|
|
uio_fd, map_num * getpagesize());
|
||
|
|
|
||
|
|
if(*membase != (void*)-1)
|
||
|
|
ret =1;
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Map the memory (DPM) of a uio_netx device
|
||
|
|
* \param fd fd returned by uio_open
|
||
|
|
* \param dpmbase Pointer to returned virtual base address of memory area
|
||
|
|
* \param dpmaddr Pointer to returned physical address of memory area
|
||
|
|
* \param dpmlen Pointer to returned length of memory area
|
||
|
|
* \return !=0 if mapping succeeded */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int cifx_uio_map_dpm(int uio_fd, int uio_num,
|
||
|
|
void** dpmbase,
|
||
|
|
unsigned long* dpmaddr,
|
||
|
|
unsigned long* dpmlen)
|
||
|
|
{
|
||
|
|
int bar = 0;
|
||
|
|
|
||
|
|
if (CIFX_NO_ERROR == find_memtype( uio_num, eMEM_DPM, &bar))
|
||
|
|
{
|
||
|
|
return cifx_uio_map_mem( uio_fd, uio_num, bar, dpmbase, dpmaddr, dpmlen, 0);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Map the extended memory of a uio_netx device
|
||
|
|
* \param fd fd returned by uio_open
|
||
|
|
* \param dpmbase Pointer to returned virtual base address of memory area
|
||
|
|
* \param dpmaddr Pointer to returned physical address of memory area
|
||
|
|
* \param dpmlen Pointer to returned length of memory area
|
||
|
|
* \return !=0 if mapping succeeded */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int cifx_uio_map_ext_mem(int uio_fd, int uio_num,
|
||
|
|
void** dpmbase,
|
||
|
|
unsigned long* dpmaddr,
|
||
|
|
unsigned long* dpmlen)
|
||
|
|
{
|
||
|
|
int bar = 0;
|
||
|
|
|
||
|
|
if (CIFX_NO_ERROR == find_memtype( uio_num, eMEM_EXTMEM, &bar))
|
||
|
|
{
|
||
|
|
return cifx_uio_map_mem( uio_fd, uio_num, bar, dpmbase, dpmaddr, dpmlen, 0);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
#ifdef CIFX_TOOLKIT_DMA
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Map the DMA memory of a uio device
|
||
|
|
* The function examines the ../uio[x]/maps/ directory searching for dynamic
|
||
|
|
* mappable resources (dyn_map[x]) for dma support (->name=dma)
|
||
|
|
* \param device uio device
|
||
|
|
* \return !=0 if mapping succeeded */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void cifx_uio_map_dma_buffer(struct CIFX_DEVICE_T *device)
|
||
|
|
{
|
||
|
|
char addr_file[64];
|
||
|
|
struct dirent **namelist;
|
||
|
|
int num_map;
|
||
|
|
|
||
|
|
sprintf(addr_file, "/sys/class/uio/uio%d/maps/", device->uio_num);
|
||
|
|
num_map = scandir(addr_file, &namelist, 0, alphasort);
|
||
|
|
if(num_map > 0)
|
||
|
|
{
|
||
|
|
int currfile = 0;
|
||
|
|
device->dma_buffer_cnt = 0;
|
||
|
|
|
||
|
|
for(;(device->dma_buffer_cnt < CIFX_DMA_BUFFER_COUNT) && (currfile < num_map); ++currfile)
|
||
|
|
{
|
||
|
|
if (CIFX_NO_ERROR == validate_memtype( device->uio_num, currfile, eMEM_DMA))
|
||
|
|
{
|
||
|
|
void *membase = NULL;
|
||
|
|
unsigned long memaddr;
|
||
|
|
unsigned long memlen;
|
||
|
|
if (cifx_uio_map_mem(device->uio_fd, device->uio_num,
|
||
|
|
currfile, &membase,
|
||
|
|
&memaddr,
|
||
|
|
&memlen,
|
||
|
|
0))
|
||
|
|
{
|
||
|
|
int DMACounter = 0;
|
||
|
|
if ((DMACounter = memlen/(CIFX_DEFAULT_DMA_BUFFER_SIZE)))
|
||
|
|
{
|
||
|
|
while(DMACounter)
|
||
|
|
{
|
||
|
|
device->dma_buffer[device->dma_buffer_cnt].ulSize = CIFX_DEFAULT_DMA_BUFFER_SIZE;
|
||
|
|
device->dma_buffer[device->dma_buffer_cnt].ulPhysicalAddress = memaddr;
|
||
|
|
device->dma_buffer[device->dma_buffer_cnt].pvBuffer = membase;
|
||
|
|
device->dma_buffer_cnt++;
|
||
|
|
memaddr += CIFX_DEFAULT_DMA_BUFFER_SIZE;
|
||
|
|
membase += CIFX_DEFAULT_DMA_BUFFER_SIZE;
|
||
|
|
#ifdef VERBOSE
|
||
|
|
printf("DMA buffer %d found at 0x%p / size=%d\n", device->dma_buffer_cnt, membase, ulSize);
|
||
|
|
#endif
|
||
|
|
DMACounter--;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
perror("Error mapping DMA buffer!\n");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
while(num_map-->0) {
|
||
|
|
free(namelist[num_map]);
|
||
|
|
}
|
||
|
|
free(namelist);
|
||
|
|
#ifdef VERBOSE
|
||
|
|
if (device->dma_buffer_cnt == 0) {
|
||
|
|
printf("\nThe uio_netx driver does not provide memory for DMA support!\n");
|
||
|
|
printf("If DMA is required, the uio_netx driver needs to be build with DMA support!\n\n");
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Unmap the DMA memory of a uio device
|
||
|
|
* \param device uio device */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void cifx_uio_unmap_dma_buffer(struct CIFX_DEVICE_T *device) {
|
||
|
|
char addr_file[64];
|
||
|
|
struct dirent **namelist;
|
||
|
|
int num_map;
|
||
|
|
|
||
|
|
sprintf(addr_file, "/sys/class/uio/uio%d/maps/", device->uio_num);
|
||
|
|
num_map = scandir(addr_file, &namelist, 0, alphasort);
|
||
|
|
if(num_map > 0) {
|
||
|
|
int currfile = 0;
|
||
|
|
for(;(device->dma_buffer_cnt > 0) && (currfile < num_map); ++currfile) {
|
||
|
|
if (CIFX_NO_ERROR == validate_memtype( device->uio_num, currfile, eMEM_DMA)) {
|
||
|
|
uint32_t no_of_buffers = cifx_uio_get_mem_size(device->uio_num, currfile) / (CIFX_DEFAULT_DMA_BUFFER_SIZE);
|
||
|
|
|
||
|
|
if ((no_of_buffers > 0) && (device->dma_buffer[CIFX_DMA_BUFFER_COUNT - device->dma_buffer_cnt].pvBuffer != NULL)) {
|
||
|
|
munmap( device->dma_buffer[CIFX_DMA_BUFFER_COUNT - device->dma_buffer_cnt].pvBuffer, cifx_uio_get_mem_size(device->uio_num, currfile));
|
||
|
|
}
|
||
|
|
|
||
|
|
if (no_of_buffers >= device->dma_buffer_cnt)
|
||
|
|
device->dma_buffer_cnt = 0;
|
||
|
|
else
|
||
|
|
device->dma_buffer_cnt -= no_of_buffers;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
while(num_map-->0) {
|
||
|
|
free(namelist[num_map]);
|
||
|
|
}
|
||
|
|
free(namelist);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Map the memory (DPM) of a ISA device
|
||
|
|
* \param uio_fd fd returned by cifX_ISA_open -> open /dev/mem
|
||
|
|
* \param dpmbase Pointer to returned virtual base address of memory area
|
||
|
|
* \param dpmaddr physical address of memory area
|
||
|
|
* \param dpmlen length of memory area
|
||
|
|
* \return !=0 if mapping succeeded */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int cifx_ISA_map_dpm(int fd,
|
||
|
|
void** dpmbase,
|
||
|
|
int dpmaddr,
|
||
|
|
int dpmlen)
|
||
|
|
{
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
*dpmbase = mmap(NULL, dpmlen,
|
||
|
|
PROT_READ|PROT_WRITE,
|
||
|
|
MAP_SHARED|MAP_LOCKED|MAP_POPULATE,
|
||
|
|
fd, dpmaddr);
|
||
|
|
|
||
|
|
if(*dpmbase != (void*)-1)
|
||
|
|
ret =1;
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Unmap the memory (DPM) of a ISA device
|
||
|
|
* \param dpmbase Pointer to returned virtual base address of memory area
|
||
|
|
* \param dpmlen length of memory area */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void cifx_ISA_unmap_dpm( void* dpmaddr, int dpmlen)
|
||
|
|
{
|
||
|
|
munmap( dpmaddr, dpmlen);
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifndef CIFX_TOOLKIT_DISABLEPCI
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Try to find a matching PCI card by verifying the physical BAR addresses
|
||
|
|
* \param dev_instance Device to search for. PCI data will be inserted into
|
||
|
|
O/S dependent part
|
||
|
|
* \return !=0 if a matching PCI card was found */
|
||
|
|
/*****************************************************************************/
|
||
|
|
static int match_pci_card(PDEVICEINSTANCE dev_instance, unsigned long ulPys_Addr)
|
||
|
|
{
|
||
|
|
struct pci_device_iterator *pci_dev_it;
|
||
|
|
struct pci_device *dev;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
static const struct pci_id_match id_match =
|
||
|
|
{
|
||
|
|
.vendor_id = PCI_MATCH_ANY,
|
||
|
|
.device_id = PCI_MATCH_ANY,
|
||
|
|
.subvendor_id = PCI_MATCH_ANY,
|
||
|
|
.subdevice_id = PCI_MATCH_ANY,
|
||
|
|
};
|
||
|
|
|
||
|
|
pci_dev_it = pci_id_match_iterator_create(&id_match);
|
||
|
|
|
||
|
|
while( NULL != (dev = pci_device_next(pci_dev_it)) )
|
||
|
|
{
|
||
|
|
int bar;
|
||
|
|
|
||
|
|
pci_device_probe(dev);
|
||
|
|
|
||
|
|
for(bar = 0; bar < sizeof(dev->regions) / sizeof(dev->regions[0]); ++bar)
|
||
|
|
{
|
||
|
|
if(dev->regions[bar].base_addr == (pciaddr_t)ulPys_Addr)
|
||
|
|
{
|
||
|
|
PCIFX_DEVICE_INTERNAL_T internal = (PCIFX_DEVICE_INTERNAL_T)dev_instance->pvOSDependent;
|
||
|
|
#ifdef VERBOSE
|
||
|
|
printf("matched pci card @ bus=%d,dev=%d,func=%d,vendor=0x%x,device=0x%x,subvendor=0x%x,subdevice=0x%x \n",
|
||
|
|
dev->bus, dev->dev, dev->func,
|
||
|
|
dev->vendor_id, dev->device_id, dev->subvendor_id, dev->subdevice_id);
|
||
|
|
#endif
|
||
|
|
/* detect flash based card by device- and sub_device id */
|
||
|
|
if ( (dev->vendor_id == HILSCHER_PCI_VENDOR_ID) &&
|
||
|
|
(
|
||
|
|
((dev->device_id == NETPLC100C_PCI_DEVICE_ID) && (dev->subdevice_id == NETPLC100C_PCI_SUBYSTEM_ID_FLASH)) ||
|
||
|
|
((dev->device_id == NETJACK100_PCI_DEVICE_ID) && (dev->subdevice_id == NETJACK100_PCI_SUBYSTEM_ID_FLASH)) ||
|
||
|
|
(dev->device_id == CIFX4000_PCI_DEVICE_ID)
|
||
|
|
)
|
||
|
|
)
|
||
|
|
{
|
||
|
|
dev_instance->eDeviceType = eCIFX_DEVICE_FLASH_BASED;
|
||
|
|
}
|
||
|
|
|
||
|
|
internal->pci = *dev;
|
||
|
|
ret = 1;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pci_iterator_destroy(pci_dev_it);
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
#endif /* CIFX_TOOLKIT_DISABLEPCI */
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Thread for cyclic Toolkit timer, which handles polling of COS bits on
|
||
|
|
* non-irq cards
|
||
|
|
* \param arg Pollinterval in ms
|
||
|
|
* \return NULL on termination */
|
||
|
|
/*****************************************************************************/
|
||
|
|
static void* cifXPollingThread(void *arg)
|
||
|
|
{
|
||
|
|
unsigned long pollinterval = (unsigned long)arg;
|
||
|
|
struct timespec polling_sleep;
|
||
|
|
|
||
|
|
polling_sleep.tv_sec = 0;
|
||
|
|
polling_sleep.tv_nsec = pollinterval * 1000 * 1000;
|
||
|
|
|
||
|
|
while( 0 == polling_thread_stop )
|
||
|
|
{
|
||
|
|
cifXTKitCyclicTimer();
|
||
|
|
nanosleep(&polling_sleep, NULL);
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Wraps the cifX Toolkit callback to the user's known parameters
|
||
|
|
* The user does not need to know about our device instance, as he only
|
||
|
|
* provided a CIFX_DEVICE_T structure
|
||
|
|
* \param pvDeviceInstance Device the callback was made for
|
||
|
|
* \param eEvent Signalled event */
|
||
|
|
/*****************************************************************************/
|
||
|
|
static void cifXWrapEvent(void* pvDeviceInstance, CIFX_TOOLKIT_NOTIFY_E eEvent)
|
||
|
|
{
|
||
|
|
PDEVICEINSTANCE ptDevInstance = (PDEVICEINSTANCE)pvDeviceInstance;
|
||
|
|
PCIFX_DEVICE_INTERNAL_T ptInternal = (PCIFX_DEVICE_INTERNAL_T)ptDevInstance->pvOSDependent;
|
||
|
|
struct CIFX_DEVICE_T* ptDevice = ptInternal->userdevice;
|
||
|
|
|
||
|
|
ptDevice->notify(ptDevice, eEvent);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Internal function for adding device to toolkit control
|
||
|
|
* \param ptDevice Device to add
|
||
|
|
* \param num Number to use for identifier ("cifX<num>")
|
||
|
|
* \param user_card !=0 if card was given through user parameter
|
||
|
|
* \return CIFX_NO_ERROR on success */
|
||
|
|
/*****************************************************************************/
|
||
|
|
static int32_t cifXDriverAddDevice(struct CIFX_DEVICE_T* ptDevice, unsigned int num, int user_card)
|
||
|
|
{
|
||
|
|
PDEVICEINSTANCE ptDevInstance = NULL;
|
||
|
|
PCIFX_DEVICE_INTERNAL_T ptInternalDev = NULL;
|
||
|
|
int32_t ret = CIFX_FUNCTION_FAILED;
|
||
|
|
|
||
|
|
#ifdef CIFX_DRV_HWIF
|
||
|
|
if ( ((ptDevice->hwif_read) && (NULL == ptDevice->hwif_write)) ||
|
||
|
|
((ptDevice->hwif_write) && (NULL == ptDevice->hwif_read))) {
|
||
|
|
fprintf(stderr, "Error initializing device! Misconfigured HW-Function Interface (read- or write-function is not defined)!");
|
||
|
|
return CIFX_INVALID_PARAMETER;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
if(NULL == (ptInternalDev = (PCIFX_DEVICE_INTERNAL_T)malloc(sizeof(*ptInternalDev))))
|
||
|
|
{
|
||
|
|
fprintf(stderr,"Error allocating internal device structures");
|
||
|
|
} else if(NULL == (ptDevInstance = (PDEVICEINSTANCE)malloc(sizeof(*ptDevInstance))))
|
||
|
|
{
|
||
|
|
fprintf(stderr, "Error allocating internal device structures");
|
||
|
|
free(ptInternalDev);
|
||
|
|
ptInternalDev = NULL;
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
memset(ptDevInstance, 0, sizeof(*ptDevInstance));
|
||
|
|
memset(ptInternalDev, 0, sizeof(*ptInternalDev));
|
||
|
|
|
||
|
|
ptInternalDev->userdevice = ptDevice;
|
||
|
|
ptInternalDev->devinstance = ptDevInstance;
|
||
|
|
ptInternalDev->user_card = user_card;
|
||
|
|
|
||
|
|
ptDevInstance->pvOSDependent = (void*)ptInternalDev;
|
||
|
|
ptDevInstance->pbDPM = (unsigned char*)ptDevice->dpm;
|
||
|
|
ptDevInstance->ulDPMSize = ptDevice->dpmlen;
|
||
|
|
ptDevInstance->ulPhysicalAddress = ptDevice->dpmaddr;
|
||
|
|
|
||
|
|
ptDevInstance->pbExtendedMemory = (uint8_t*)ptDevice->extmem;
|
||
|
|
ptDevInstance->ulExtendedMemorySize = ptDevice->extmemlen;
|
||
|
|
|
||
|
|
#ifdef CIFX_DRV_HWIF
|
||
|
|
/* set to the linux default read/write function, to be able to handle all devices (also memory mapped) */
|
||
|
|
ptDevInstance->pfnHwIfRead = HWIFDPMRead;
|
||
|
|
ptDevInstance->pfnHwIfWrite = HWIFDPMWrite;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef CIFX_TOOLKIT_DMA
|
||
|
|
if (ptDevice->dma_buffer_cnt)
|
||
|
|
{
|
||
|
|
int i = 0;
|
||
|
|
ptDevInstance->ulDMABufferCount = ptDevice->dma_buffer_cnt;
|
||
|
|
for (i=0;i<ptDevice->dma_buffer_cnt;i++)
|
||
|
|
{
|
||
|
|
ptDevInstance->atDmaBuffers[i].ulSize = ptDevice->dma_buffer[i].ulSize;
|
||
|
|
ptDevInstance->atDmaBuffers[i].ulPhysicalAddress = ptDevice->dma_buffer[i].ulPhysicalAddress;
|
||
|
|
ptDevInstance->atDmaBuffers[i].pvBuffer = ptDevice->dma_buffer[i].pvBuffer;
|
||
|
|
ptDevInstance->atDmaBuffers[i].pvUser = NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
if(ptDevice->notify)
|
||
|
|
{
|
||
|
|
ptDevInstance->pfnNotify = cifXWrapEvent;
|
||
|
|
}
|
||
|
|
|
||
|
|
snprintf(ptDevInstance->szName,
|
||
|
|
sizeof(ptDevInstance->szName),
|
||
|
|
"cifX%u",
|
||
|
|
num);
|
||
|
|
|
||
|
|
if (ptDevice->uio_num>=0) {
|
||
|
|
/* extract alias from uio device name (can be used via device-tree) */
|
||
|
|
char* szAlias = cifx_uio_get_device_alias(ptDevice->uio_num);
|
||
|
|
if (szAlias != NULL) {
|
||
|
|
snprintf(ptDevInstance->szAlias,
|
||
|
|
sizeof(ptDevInstance->szName),
|
||
|
|
"%s",
|
||
|
|
szAlias);
|
||
|
|
free(szAlias);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Default to no logfile */
|
||
|
|
ptInternalDev->log_file = NULL;
|
||
|
|
|
||
|
|
/* Create log file if neccessary */
|
||
|
|
if(g_ulTraceLevel > 0)
|
||
|
|
{
|
||
|
|
size_t pathlen = strlen(g_szDriverBaseDir) + sizeof(ptDevInstance->szName) + 2 + 4; /* +2 for 1x NUL and 1 additional '/'
|
||
|
|
+4 for extension ".log" */
|
||
|
|
char* logfilepath = malloc(pathlen);
|
||
|
|
|
||
|
|
snprintf(logfilepath, pathlen, "%s/%s.log", g_szDriverBaseDir, ptDevInstance->szName);
|
||
|
|
|
||
|
|
if (g_logfd == 0) {
|
||
|
|
ptInternalDev->log_file = fopen(logfilepath, "w+");
|
||
|
|
} else {
|
||
|
|
ptInternalDev->log_file = g_logfd;
|
||
|
|
}
|
||
|
|
if( NULL == ptInternalDev->log_file)
|
||
|
|
{
|
||
|
|
perror("Error opening logfile. Traces will be printed to console!");
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
DRIVER_INFORMATION tDriverInfo;
|
||
|
|
CIFXHANDLE hDrv;
|
||
|
|
|
||
|
|
/* Insert header into log file */
|
||
|
|
USER_Trace(ptDevInstance, 0, "----- cifX Driver Log started ---------------------");
|
||
|
|
if (xDriverOpen(&hDrv)) {
|
||
|
|
USER_Trace(ptDevInstance, 0, " %s / Error retrieving Toolkit version", LINUXCIFXDRV_VERSION);
|
||
|
|
} else {
|
||
|
|
xDriverGetInformation( hDrv, sizeof(tDriverInfo), &tDriverInfo);
|
||
|
|
xDriverClose(hDrv);
|
||
|
|
USER_Trace(ptDevInstance, 0, " %s / Toolkit %s", LINUXCIFXDRV_VERSION, tDriverInfo.abDriverVersion);
|
||
|
|
}
|
||
|
|
USER_Trace(ptDevInstance, 0, " Name : %s", ptDevInstance->szName);
|
||
|
|
USER_Trace(ptDevInstance, 0, " DPM : 0x%lx, len=%lu", ptDevInstance->ulPhysicalAddress, ptDevInstance->ulDPMSize);
|
||
|
|
USER_Trace(ptDevInstance, 0, "---------------------------------------------------");
|
||
|
|
}
|
||
|
|
|
||
|
|
free(logfilepath);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(ptDevice->force_ram)
|
||
|
|
{
|
||
|
|
ptDevInstance->eDeviceType = eCIFX_DEVICE_RAM_BASED;
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
if (ptDevice->uio_num>=0) {
|
||
|
|
/* in case of uio device device-type can be given (device-tree) */
|
||
|
|
ptDevInstance->eDeviceType = cifx_uio_get_device_startuptype(ptDevice->uio_num);
|
||
|
|
} else {
|
||
|
|
ptDevInstance->eDeviceType = eCIFX_DEVICE_AUTODETECT;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(ptDevice->pci_card != 0)
|
||
|
|
{
|
||
|
|
#ifndef CIFX_TOOLKIT_DISABLEPCI
|
||
|
|
/* Try to find the card on the PCI bus. If it is not found, deny to work with this card */
|
||
|
|
if(!match_pci_card(ptDevInstance, ptDevice->dpmaddr))
|
||
|
|
{
|
||
|
|
/* Don't add this device */
|
||
|
|
if (g_ulTraceLevel & TRACE_LEVEL_ERROR)
|
||
|
|
{
|
||
|
|
USER_Trace(ptDevInstance,
|
||
|
|
TRACE_LEVEL_ERROR,
|
||
|
|
"Error finding pci device (Phys. Addr 0x%lx) on PCI bus",
|
||
|
|
ptDevice->dpmaddr);
|
||
|
|
}
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
ptDevInstance->fPCICard = 1;
|
||
|
|
ret = CIFX_NO_ERROR;
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
if (g_ulTraceLevel & TRACE_LEVEL_ERROR)
|
||
|
|
{
|
||
|
|
USER_Trace(ptDevInstance,
|
||
|
|
TRACE_LEVEL_ERROR,
|
||
|
|
"cifX Driver was compiled without PCI support. Unable to handle requested PCI card @0x%lx!",
|
||
|
|
ptDevice->dpmaddr);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
ptDevInstance->fPCICard = 0;
|
||
|
|
ret = CIFX_NO_ERROR;
|
||
|
|
}
|
||
|
|
#ifdef CIFX_DRV_HWIF
|
||
|
|
/* initialize the hardware function interface */
|
||
|
|
if (ptDevice->hwif_init) {
|
||
|
|
if (CIFX_NO_ERROR != (ret = ptDevice->hwif_init( ptDevice))) {
|
||
|
|
if (g_ulTraceLevel & TRACE_LEVEL_ERROR)
|
||
|
|
{
|
||
|
|
char szError[1024] ={0};
|
||
|
|
USER_Trace(ptDevInstance,
|
||
|
|
TRACE_LEVEL_ERROR,
|
||
|
|
"Failed to initialize custom hardware interface. 'hwif_init' returns 0x%lx - %s! Skip adding custom device to toolkit!",
|
||
|
|
(unsigned int)ret,
|
||
|
|
((CIFX_NO_ERROR == xDriverGetErrorDescription( ret, szError, sizeof(szError))) ? szError : "Unknown error"));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
/* Add the device to the toolkits handled device list */
|
||
|
|
if(CIFX_NO_ERROR == ret) {
|
||
|
|
if ((ret = cifXTKitAddDevice(ptDevInstance))) {
|
||
|
|
if (g_ulTraceLevel & TRACE_LEVEL_ERROR)
|
||
|
|
{
|
||
|
|
char szError[1024] ={0};
|
||
|
|
xDriverGetErrorDescription( ret, szError, sizeof(szError));
|
||
|
|
USER_Trace(ptDevInstance, 0, "Error: 0x%X, <%s>\n", (unsigned int)ret, szError);
|
||
|
|
}
|
||
|
|
#ifdef CIFX_DRV_HWIF
|
||
|
|
/* de-initialize the hardware function interface */
|
||
|
|
if (ptDevice->hwif_deinit)
|
||
|
|
ptDevice->hwif_deinit( ptDevice);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(CIFX_NO_ERROR != ret)
|
||
|
|
{
|
||
|
|
free(ptDevInstance);
|
||
|
|
free(ptInternalDev);
|
||
|
|
#ifdef CIFXETHERNET
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
CIFX_DEVICE_INFORMATION tDevInfo;
|
||
|
|
|
||
|
|
OS_Memset(&tDevInfo, 0, sizeof(tDevInfo));
|
||
|
|
|
||
|
|
/* Initalize file information structure */
|
||
|
|
tDevInfo.ulDeviceNumber = ptDevInstance->ulDeviceNumber;
|
||
|
|
tDevInfo.ulSerialNumber = ptDevInstance->ulSerialNumber;
|
||
|
|
tDevInfo.ulChannel = CIFX_SYSTEM_DEVICE;
|
||
|
|
tDevInfo.ptDeviceInstance = ptDevInstance;
|
||
|
|
|
||
|
|
if (0 != USER_GetEthernet( &tDevInfo))
|
||
|
|
{
|
||
|
|
NETX_ETH_DEV_CFG_T config;
|
||
|
|
|
||
|
|
sprintf( config.cifx_name, "%s", ptDevInstance->szName);
|
||
|
|
if (NULL != cifxeth_create_device( &config))
|
||
|
|
{
|
||
|
|
ptInternalDev->eth_support = 1;
|
||
|
|
if (g_ulTraceLevel & TRACE_LEVEL_INFO)
|
||
|
|
{
|
||
|
|
USER_Trace(ptDevInstance, 0, "Successfully created ethernet interface on %s", ptDevInstance->szName);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Linux driver initialization function
|
||
|
|
* \param init_params Initialization parameters
|
||
|
|
* \return CIFX_NO_ERROR on success */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int32_t cifXDriverInit(const struct CIFX_LINUX_INIT* init_params)
|
||
|
|
{
|
||
|
|
int32_t lRet = cifXTKitInit();
|
||
|
|
unsigned int num = 0;
|
||
|
|
unsigned int temp;
|
||
|
|
|
||
|
|
#ifdef CIFXETHERNET
|
||
|
|
/* in case of unordinary shutdown of the application the devices may still */
|
||
|
|
/* exist (since we create the net devices persistent) so we clean up here */
|
||
|
|
cifxeth_sys_cleanup();
|
||
|
|
|
||
|
|
g_eth_list_lock = OS_CreateLock();
|
||
|
|
#endif
|
||
|
|
if (init_params == NULL)
|
||
|
|
return CIFX_INVALID_PARAMETER;
|
||
|
|
|
||
|
|
g_ulTraceLevel = init_params->trace_level;
|
||
|
|
|
||
|
|
if(CIFX_NO_ERROR == lRet)
|
||
|
|
{
|
||
|
|
unsigned long poll_interval = init_params->poll_interval;
|
||
|
|
size_t tStackSize = init_params->poll_StackSize;
|
||
|
|
|
||
|
|
polling_thread_running = 0;
|
||
|
|
|
||
|
|
if(poll_interval != CIFX_POLLINTERVAL_DISABLETHREAD)
|
||
|
|
{
|
||
|
|
struct sched_param sched_param = {0};
|
||
|
|
sched_param.sched_priority = init_params->poll_priority;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
/* Default to 500ms poll interval */
|
||
|
|
if(poll_interval == 0)
|
||
|
|
poll_interval = 500;
|
||
|
|
|
||
|
|
if ( tStackSize == 0)
|
||
|
|
tStackSize = COS_THREAD_STACK_MIN;
|
||
|
|
|
||
|
|
/* Create COS flag polling thread for non-irq devices */
|
||
|
|
polling_thread_stop = 0;
|
||
|
|
|
||
|
|
if( (ret = pthread_attr_init(&polling_thread_attr)) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "cifXDriverInit: Failed to initialize attributes for polling thread (pthread_attr_init=%d)", ret);
|
||
|
|
lRet = CIFX_DRV_INIT_STATE_ERROR;
|
||
|
|
|
||
|
|
} else if (init_params->poll_priority && ( (ret = pthread_attr_setinheritsched( &polling_thread_attr, PTHREAD_EXPLICIT_SCHED)) != 0))
|
||
|
|
{
|
||
|
|
fprintf( stderr, "cifXDriverInit: Failed to set the polling thread attributes (pthread_attr_setinheritsched=%d)", ret);
|
||
|
|
lRet = CIFX_DRV_INIT_STATE_ERROR;
|
||
|
|
|
||
|
|
} else if (init_params->poll_priority && ( (ret = pthread_attr_setschedpolicy(&polling_thread_attr, init_params->poll_schedpolicy)) != 0))
|
||
|
|
{
|
||
|
|
fprintf( stderr, "cifXDriverInit: Failed to set scheduler policy of polling thread (pthread_attr_setschedpolicy=%d)", ret);
|
||
|
|
lRet = CIFX_DRV_INIT_STATE_ERROR;
|
||
|
|
|
||
|
|
/* Setup Stack size to minimum */
|
||
|
|
} else if( (ret = pthread_attr_setstacksize(&polling_thread_attr, PTHREAD_STACK_MIN + tStackSize)) != 0)
|
||
|
|
{
|
||
|
|
fprintf( stderr, "cifXDriverInit: Failed to set stack size of polling thread (pthread_attr_setstacksize=%d)", ret);
|
||
|
|
lRet = CIFX_DRV_INIT_STATE_ERROR;
|
||
|
|
|
||
|
|
/* Set polling thread priority */
|
||
|
|
} else if(init_params->poll_priority && ((ret = pthread_attr_setschedparam(&polling_thread_attr, &sched_param) != 0)))
|
||
|
|
{
|
||
|
|
fprintf( stderr, "cifXDriverInit: Failed to set priority of polling thread (pthread_attr_setschedparam=%d)", ret);
|
||
|
|
lRet = CIFX_DRV_INIT_STATE_ERROR;
|
||
|
|
} else if( (ret = pthread_create(&polling_thread, &polling_thread_attr, cifXPollingThread, (void*)poll_interval)) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "cifXDriverInit: Could not create polling thread (pthread_create=%d)", ret);
|
||
|
|
lRet = CIFX_DRV_INIT_STATE_ERROR;
|
||
|
|
}
|
||
|
|
polling_thread_running = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(CIFX_NO_ERROR == lRet)
|
||
|
|
{
|
||
|
|
if (init_params->logfd != 0) {
|
||
|
|
g_logfd = init_params->logfd;
|
||
|
|
}
|
||
|
|
/* Set driver base directory */
|
||
|
|
if(NULL == init_params->base_dir)
|
||
|
|
{
|
||
|
|
g_szDriverBaseDir = strdup("/opt/cifx");
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
g_szDriverBaseDir = strdup(init_params->base_dir);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(CIFX_DRIVER_INIT_CARDNUMBER == init_params->init_options)
|
||
|
|
{
|
||
|
|
struct CIFX_DEVICE_T* ptDevice;
|
||
|
|
int iDevice = init_params->iCardNumber;
|
||
|
|
|
||
|
|
if(NULL == (ptDevice = cifXFindDevice( iDevice, init_params->fEnableCardLocking)))
|
||
|
|
{
|
||
|
|
fprintf(stderr, "Error opening device with number %u\n", iDevice);
|
||
|
|
lRet = CIFX_INVALID_BOARD;
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
lRet = cifXDriverAddDevice(ptDevice, 0, 0);
|
||
|
|
if(CIFX_NO_ERROR != lRet)
|
||
|
|
{
|
||
|
|
fprintf(stderr, "Error adding automatically found cifX device @ Phys. Addr 0x%lX. (Status=0x%08X)\n", ptDevice->dpmaddr, lRet);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
/* Automatically scan for uio devices */
|
||
|
|
} else if(CIFX_DRIVER_INIT_AUTOSCAN == init_params->init_options)
|
||
|
|
{
|
||
|
|
int iDevice;
|
||
|
|
struct CIFX_DEVICE_T* ptDevice;
|
||
|
|
int iCardCount = cifXGetDeviceCount();
|
||
|
|
|
||
|
|
for(iDevice = 0; iDevice < iCardCount; ++iDevice)
|
||
|
|
{
|
||
|
|
if(NULL == (ptDevice = cifXFindDevice( iDevice, init_params->fEnableCardLocking)))
|
||
|
|
{
|
||
|
|
fprintf(stderr, "Error opening device with number %u\n", iDevice);
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
uint32_t lTemp = cifXDriverAddDevice(ptDevice, num, 0);
|
||
|
|
if(CIFX_NO_ERROR != lTemp)
|
||
|
|
{
|
||
|
|
fprintf(stderr, "Error adding automatically found cifX device @ Phys. Addr 0x%lX. (Status=0x%08X)\n", ptDevice->dpmaddr, lTemp);
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
num++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#ifdef CIFX_PLUGIN_SUPPORT
|
||
|
|
char szPath[CIFX_MAX_FILE_NAME_LENGTH+5];
|
||
|
|
DIR* dir;
|
||
|
|
|
||
|
|
snprintf(szPath, CIFX_MAX_FILE_NAME_LENGTH,
|
||
|
|
"%s/plugins/",
|
||
|
|
g_szDriverBaseDir);
|
||
|
|
|
||
|
|
/* Iterate over plugins in ${basedir}/plugins folder */
|
||
|
|
if(NULL != (dir = opendir(szPath)))
|
||
|
|
{
|
||
|
|
struct dirent* dirent;
|
||
|
|
|
||
|
|
while(NULL != (dirent = readdir(dir)))
|
||
|
|
{
|
||
|
|
char* szExt = strstr(dirent->d_name, ".");
|
||
|
|
if(NULL != szExt)
|
||
|
|
{
|
||
|
|
if(0 == strncasecmp(szExt, ".so", 3))
|
||
|
|
{
|
||
|
|
snprintf(szPath, sizeof(szPath),
|
||
|
|
"%s/plugins/%s",
|
||
|
|
g_szDriverBaseDir, dirent->d_name);
|
||
|
|
|
||
|
|
void* hFile = dlopen(szPath, RTLD_NOW | RTLD_LOCAL);
|
||
|
|
if(NULL == hFile)
|
||
|
|
{
|
||
|
|
fprintf(stderr, "Error loading plugin library %s with error=%s)\n", dirent->d_name, dlerror());
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
PFN_CIFX_PLUGIN_GET_DEVICE_COUNT pfnCount;
|
||
|
|
PFN_CIFX_PLUGIN_ALLOC_DEVICE pfnAlloc;
|
||
|
|
|
||
|
|
if( (NULL == (pfnCount = dlsym(hFile, CIFX_PLUGIN_GET_DEVICE_COUNT))) ||
|
||
|
|
(NULL == (pfnAlloc = dlsym(hFile, CIFX_PLUGIN_ALLOC_DEVICE))) ||
|
||
|
|
(NULL == dlsym(hFile, CIFX_PLUGIN_FREE_DEVICE)) )
|
||
|
|
{
|
||
|
|
fprintf(stderr, "Error loading plugin library %s, as it does not contain required exports\n", dirent->d_name);
|
||
|
|
dlclose(hFile);
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
struct CIFX_PLUGIN_T* plugin = calloc(1, sizeof(*plugin));
|
||
|
|
uint32_t i;
|
||
|
|
|
||
|
|
plugin->hPluginFile = hFile;
|
||
|
|
plugin->ulDeviceCount = pfnCount();
|
||
|
|
plugin->aptDevices = calloc(plugin->ulDeviceCount, sizeof(*plugin->aptDevices));
|
||
|
|
|
||
|
|
SLIST_INSERT_HEAD(&s_tPluginList, plugin, tList);
|
||
|
|
|
||
|
|
for(i = 0; i < plugin->ulDeviceCount; i++)
|
||
|
|
{
|
||
|
|
uint32_t lTemp;
|
||
|
|
|
||
|
|
plugin->aptDevices[i] = pfnAlloc(i);
|
||
|
|
|
||
|
|
if(NULL == plugin->aptDevices[i])
|
||
|
|
{
|
||
|
|
fprintf(stderr, "Error: Plugin (%s) return no device for idx=%i\n",
|
||
|
|
dirent->d_name, i);
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
lTemp = cifXDriverAddDevice(plugin->aptDevices[i], num, 1);
|
||
|
|
if(CIFX_NO_ERROR != lTemp)
|
||
|
|
{
|
||
|
|
fprintf(stderr, "Error adding plugin (%s) device %u@0x%lX. (Status=0x%08X)\n",
|
||
|
|
dirent->d_name, i, plugin->aptDevices[i]->dpmaddr, lTemp);
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
num++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
closedir(dir);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
if (CIFX_NO_ERROR == lRet)
|
||
|
|
{
|
||
|
|
/* Add all user specified cards */
|
||
|
|
for(temp = 0; temp < init_params->user_card_cnt; ++temp)
|
||
|
|
{
|
||
|
|
if(cifXDriverAddDevice(&init_params->user_cards[temp], num, 1) != CIFX_NO_ERROR )
|
||
|
|
{
|
||
|
|
fprintf(stderr, "Adding user device #%d failed \n", temp);
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
++num;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return lRet;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! cifX driver restart function
|
||
|
|
* \param hDriver Handle to the driver
|
||
|
|
* \param szBoardName Identifier for the Board
|
||
|
|
* \param pvData For further extensions can be NULL
|
||
|
|
* \return CIFX_NO_ERROR on success */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int32_t xDriverRestartDevice ( CIFXHANDLE hDriver, char* szBoardName, void* pvData)
|
||
|
|
{
|
||
|
|
int32_t lRet = CIFX_INVALID_BOARD;
|
||
|
|
uint32_t ulIdx = 0;
|
||
|
|
|
||
|
|
UNREFERENCED_PARAMETER(pvData);
|
||
|
|
|
||
|
|
OS_EnterLock(g_pvTkitLock);
|
||
|
|
|
||
|
|
/* Seach the device with the given name */
|
||
|
|
for (ulIdx = 0; ulIdx < g_ulDeviceCount; ulIdx++)
|
||
|
|
{
|
||
|
|
/* Compare the device name */
|
||
|
|
PDEVICEINSTANCE ptDev = g_pptDevices[ulIdx];
|
||
|
|
|
||
|
|
if( (OS_Strcmp( ptDev->szName, szBoardName) == 0) ||
|
||
|
|
(OS_Strcmp( ptDev->szAlias, szBoardName) == 0) )
|
||
|
|
{
|
||
|
|
#if CIFXETHERNET || CIFX_DRV_HWIF
|
||
|
|
PCIFX_DEVICE_INTERNAL_T dev_intern = (PCIFX_DEVICE_INTERNAL_T)ptDev->pvOSDependent;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if (g_ulTraceLevel & TRACE_LEVEL_DEBUG)
|
||
|
|
{
|
||
|
|
USER_Trace( ptDev,
|
||
|
|
TRACE_LEVEL_DEBUG,
|
||
|
|
"RESTART DEVICE requested for device: %s",
|
||
|
|
szBoardName);
|
||
|
|
}
|
||
|
|
/* Remove a device */
|
||
|
|
#ifdef CIFXETHERNET
|
||
|
|
if (1 == dev_intern->eth_support)
|
||
|
|
{
|
||
|
|
NETX_ETH_DEV_CFG_T config;
|
||
|
|
|
||
|
|
sprintf( config.cifx_name, "%s", ptDev->szName);
|
||
|
|
cifxeth_remove_device( NULL, &config);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
if ( CIFX_NO_ERROR == (lRet = cifXTKitRemoveDevice(ptDev->szName, 1)))
|
||
|
|
{
|
||
|
|
#ifdef CIFX_DRV_HWIF
|
||
|
|
/* de-initialize hardware interface */
|
||
|
|
if (dev_intern->userdevice->hwif_deinit)
|
||
|
|
dev_intern->userdevice->hwif_deinit( dev_intern->userdevice);
|
||
|
|
|
||
|
|
/* re-initialize hardware interface */
|
||
|
|
if (dev_intern->userdevice->hwif_init) {
|
||
|
|
lRet = dev_intern->userdevice->hwif_init( dev_intern->userdevice);
|
||
|
|
if (CIFX_NO_ERROR != lRet) {
|
||
|
|
if (g_ulTraceLevel & TRACE_LEVEL_ERROR)
|
||
|
|
{
|
||
|
|
char szError[1024] ={0};
|
||
|
|
USER_Trace(ptDev,
|
||
|
|
TRACE_LEVEL_ERROR,
|
||
|
|
"Failed to initialize custom hardware interface. 'hwif_init' returns 0x%lx - %s! Skip adding custom device to toolkit!",
|
||
|
|
(unsigned int)lRet,
|
||
|
|
((CIFX_NO_ERROR == xDriverGetErrorDescription( lRet, szError, sizeof(szError))) ? szError : "Unknown error"));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
/* Re-insert a device */
|
||
|
|
if ((lRet == CIFX_NO_ERROR) && (CIFX_NO_ERROR == (lRet = cifXTKitAddDevice( ptDev))))
|
||
|
|
{
|
||
|
|
#ifdef CIFXETHERNET
|
||
|
|
if (1 == dev_intern->eth_support)
|
||
|
|
{
|
||
|
|
NETX_ETH_DEV_CFG_T config;
|
||
|
|
|
||
|
|
sprintf( config.cifx_name, "%s", ptDev->szName);
|
||
|
|
cifxeth_create_device( &config);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
#ifdef CIFX_DRV_HWIF
|
||
|
|
/* de-initialize hardware interface */
|
||
|
|
if (dev_intern->userdevice->hwif_deinit)
|
||
|
|
dev_intern->userdevice->hwif_deinit( dev_intern->userdevice);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (g_ulTraceLevel & TRACE_LEVEL_DEBUG)
|
||
|
|
{
|
||
|
|
USER_Trace(ptDev,
|
||
|
|
TRACE_LEVEL_DEBUG,
|
||
|
|
"RESTART DEVICE done, (Status: 0x%08X)\n",
|
||
|
|
lRet);
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
OS_LeaveLock(g_pvTkitLock);
|
||
|
|
|
||
|
|
return lRet;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Linux driver de-initialization */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void cifXDriverDeinit()
|
||
|
|
{
|
||
|
|
/* Stop polling thread if it was enabled */
|
||
|
|
if(polling_thread_running)
|
||
|
|
{
|
||
|
|
polling_thread_stop = 1;
|
||
|
|
pthread_join(polling_thread, NULL);
|
||
|
|
pthread_attr_destroy(&polling_thread_attr);
|
||
|
|
polling_thread_running = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (NULL == g_pvTkitLock) /* toolkit is already de-initialized */
|
||
|
|
return;
|
||
|
|
|
||
|
|
OS_EnterLock(g_pvTkitLock);
|
||
|
|
|
||
|
|
/* Remove all internal device structures */
|
||
|
|
while(g_ulDeviceCount > 0)
|
||
|
|
{
|
||
|
|
PDEVICEINSTANCE devinstance = g_pptDevices[0];
|
||
|
|
PCIFX_DEVICE_INTERNAL_T dev_intern = (PCIFX_DEVICE_INTERNAL_T)devinstance->pvOSDependent;
|
||
|
|
#ifdef CIFXETHERNET
|
||
|
|
if (1 == dev_intern->eth_support)
|
||
|
|
{
|
||
|
|
NETX_ETH_DEV_CFG_T config;
|
||
|
|
|
||
|
|
sprintf( config.cifx_name, "%s", devinstance->szName);
|
||
|
|
cifxeth_remove_device( NULL, &config);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
cifXTKitRemoveDevice(devinstance->szName , 1);
|
||
|
|
|
||
|
|
if( NULL != dev_intern->log_file)
|
||
|
|
{
|
||
|
|
USER_Trace(devinstance, 0, "----- cifX Driver Log stopped ---------------------");
|
||
|
|
|
||
|
|
if (g_logfd == 0) {
|
||
|
|
/* log file is under our control so close it */
|
||
|
|
fclose(dev_intern->log_file);
|
||
|
|
}
|
||
|
|
dev_intern->log_file = NULL;
|
||
|
|
}
|
||
|
|
#ifdef CIFX_DRV_HWIF
|
||
|
|
/* de-initialize hardware interface */
|
||
|
|
if (dev_intern->userdevice->hwif_deinit)
|
||
|
|
dev_intern->userdevice->hwif_deinit( dev_intern->userdevice);
|
||
|
|
#endif
|
||
|
|
/* Only process non-user card device structures */
|
||
|
|
if(!dev_intern->user_card)
|
||
|
|
{
|
||
|
|
cifXDeleteDevice(dev_intern->userdevice);
|
||
|
|
dev_intern->userdevice = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
free(dev_intern);
|
||
|
|
free(devinstance);
|
||
|
|
}
|
||
|
|
|
||
|
|
OS_LeaveLock(g_pvTkitLock);
|
||
|
|
|
||
|
|
#ifdef CIFX_PLUGIN_SUPPORT
|
||
|
|
struct CIFX_PLUGIN_T* plugin;
|
||
|
|
|
||
|
|
while(NULL != (plugin = SLIST_FIRST(&s_tPluginList)))
|
||
|
|
{
|
||
|
|
uint32_t i;
|
||
|
|
|
||
|
|
for(i = 0; i < plugin->ulDeviceCount; i++)
|
||
|
|
{
|
||
|
|
PFN_CIFX_PLUGIN_FREE_DEVICE pfnFree = dlsym(plugin->hPluginFile, CIFX_PLUGIN_FREE_DEVICE);
|
||
|
|
|
||
|
|
if( (NULL != pfnFree) &&
|
||
|
|
(NULL != plugin->aptDevices[i]) )
|
||
|
|
{
|
||
|
|
pfnFree(plugin->aptDevices[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
free(plugin->aptDevices);
|
||
|
|
dlclose(plugin->hPluginFile);
|
||
|
|
SLIST_REMOVE(&s_tPluginList, plugin, CIFX_PLUGIN_T, tList);
|
||
|
|
free(plugin);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef CIFXETHERNET
|
||
|
|
if (NULL != g_eth_list_lock) {
|
||
|
|
OS_DeleteLock( g_eth_list_lock);
|
||
|
|
g_eth_list_lock = NULL;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if (NULL != g_szDriverBaseDir) {
|
||
|
|
free(g_szDriverBaseDir);
|
||
|
|
g_szDriverBaseDir = NULL;
|
||
|
|
}
|
||
|
|
cifXTKitDeinit();
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Query Driver Version
|
||
|
|
* \param ulSize Size of the passed string
|
||
|
|
* \param szVersion Pointer to returned data (string)
|
||
|
|
* \return CIFX_NO_ERROR on success */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int32_t cifXGetDriverVersion(uint32_t ulSize, char* szVersion)
|
||
|
|
{
|
||
|
|
if(ulSize < OS_Strlen(LINUXCIFXDRV_VERSION))
|
||
|
|
return CIFX_INVALID_BUFFERSIZE;
|
||
|
|
|
||
|
|
OS_Strncpy(szVersion, LINUXCIFXDRV_VERSION, OS_Strlen(LINUXCIFXDRV_VERSION));
|
||
|
|
|
||
|
|
return CIFX_NO_ERROR;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Retrieve the number of automatically detectable cifX Devices.
|
||
|
|
* \return Number found netX/cifX uio devices */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int cifXGetDeviceCount(void)
|
||
|
|
{
|
||
|
|
struct dirent** namelist;
|
||
|
|
int num_uios;
|
||
|
|
int ret = 0;
|
||
|
|
|
||
|
|
num_uios = scandir("/sys/class/uio", &namelist, 0, alphasort);
|
||
|
|
if(num_uios > 0)
|
||
|
|
{
|
||
|
|
int currentuio;
|
||
|
|
|
||
|
|
for(currentuio = 0; currentuio < num_uios; ++currentuio)
|
||
|
|
{
|
||
|
|
int uio_num;
|
||
|
|
|
||
|
|
if(0 == sscanf(namelist[currentuio]->d_name,
|
||
|
|
"uio%u",
|
||
|
|
&uio_num))
|
||
|
|
{
|
||
|
|
/* Error extracting uio number */
|
||
|
|
|
||
|
|
} else if( cifx_uio_validate_name(uio_num, CIFX_UIO_CARD_NAME) ||
|
||
|
|
cifx_uio_validate_name(uio_num, CIFX_UIO_PLX_CARD_NAME) ||
|
||
|
|
cifx_uio_validate_name(uio_num, CIFX_UIO_NETPLC_CARD_NAME) ||
|
||
|
|
cifx_uio_validate_name(uio_num, CIFX_UIO_NETJACK_CARD_NAME)||
|
||
|
|
cifx_uio_validate_name(uio_num, CIFX_UIO_CUSTOM_CARD_NAME) )
|
||
|
|
{
|
||
|
|
/* device is not a netX device */
|
||
|
|
++ret;
|
||
|
|
}
|
||
|
|
free(namelist[currentuio]);
|
||
|
|
}
|
||
|
|
free(namelist);
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Scan for cifX Devices via uio driver
|
||
|
|
* \param iNum Number of card to detect (0..num_of_cards)
|
||
|
|
* \param fCheckAccess If !=0, function denies access if device is
|
||
|
|
* already used by another application
|
||
|
|
* \return NULL if no device with this number was found */
|
||
|
|
/*****************************************************************************/
|
||
|
|
struct CIFX_DEVICE_T* cifXFindDevice(int iNum, int fCheckAccess)
|
||
|
|
{
|
||
|
|
struct dirent** namelist;
|
||
|
|
int num_uios;
|
||
|
|
struct CIFX_DEVICE_T* device = NULL;
|
||
|
|
|
||
|
|
num_uios = scandir("/sys/class/uio", &namelist, 0, alphasort);
|
||
|
|
if(num_uios > 0)
|
||
|
|
{
|
||
|
|
int netx_uios = 0;
|
||
|
|
int currentuio;
|
||
|
|
int founddevice = 0;
|
||
|
|
|
||
|
|
for(currentuio = 0; currentuio < num_uios; ++currentuio)
|
||
|
|
{
|
||
|
|
int uio_num;
|
||
|
|
|
||
|
|
if(founddevice)
|
||
|
|
{
|
||
|
|
/* we already found the device, so skip it.
|
||
|
|
we need to handle all data from name list, so we need to
|
||
|
|
cycle through whole list */
|
||
|
|
} else if(0 == sscanf(namelist[currentuio]->d_name,
|
||
|
|
"uio%u",
|
||
|
|
&uio_num))
|
||
|
|
{
|
||
|
|
/* Error extracting uio number */
|
||
|
|
|
||
|
|
} else if( !cifx_uio_validate_name(uio_num, CIFX_UIO_CARD_NAME) &&
|
||
|
|
!cifx_uio_validate_name(uio_num, CIFX_UIO_PLX_CARD_NAME) &&
|
||
|
|
!cifx_uio_validate_name(uio_num, CIFX_UIO_NETPLC_CARD_NAME) &&
|
||
|
|
!cifx_uio_validate_name(uio_num, CIFX_UIO_NETJACK_CARD_NAME) &&
|
||
|
|
!cifx_uio_validate_name(uio_num, CIFX_UIO_CUSTOM_CARD_NAME) )
|
||
|
|
{
|
||
|
|
/* device is not a netX device */
|
||
|
|
|
||
|
|
} else if(netx_uios++ != iNum)
|
||
|
|
{
|
||
|
|
/* not the device we are looking for, so skip it */
|
||
|
|
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
void* dpmbase = NULL;
|
||
|
|
void* extmembase = NULL;
|
||
|
|
unsigned long dpmaddr, dpmlen, extmemaddr, extmemlen;;
|
||
|
|
int uio_fd;
|
||
|
|
|
||
|
|
if(-1 == (uio_fd = cifx_uio_open( uio_num, fCheckAccess)))
|
||
|
|
{
|
||
|
|
perror("Error opening uio");
|
||
|
|
} else if(!cifx_uio_map_dpm(uio_fd, uio_num, &dpmbase, &dpmaddr, &dpmlen))
|
||
|
|
{
|
||
|
|
perror("Error mapping dpm");
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
/* try to map extended memory */
|
||
|
|
if (cifx_uio_map_ext_mem(uio_fd, uio_num, &extmembase, &extmemaddr, &extmemlen))
|
||
|
|
{
|
||
|
|
#ifdef VERBOSE
|
||
|
|
printf("Extended memory found at (0x%X - 0x%X)\n", (unsigned int)extmemaddr, (unsigned int)(extmemaddr + extmemlen));
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Build device structure */
|
||
|
|
device = malloc(sizeof(*device));
|
||
|
|
memset(device, 0, sizeof(*device));
|
||
|
|
device->uio_num = uio_num;
|
||
|
|
device->uio_fd = uio_fd;
|
||
|
|
|
||
|
|
if( cifx_uio_validate_name(uio_num, CIFX_UIO_PLX_CARD_NAME) )
|
||
|
|
device->pci_card = 0;
|
||
|
|
else if ( cifx_uio_validate_name(uio_num, CIFX_UIO_CUSTOM_CARD_NAME) )
|
||
|
|
device->pci_card = 0;
|
||
|
|
else
|
||
|
|
device->pci_card = 1;
|
||
|
|
|
||
|
|
device->dpm = dpmbase;
|
||
|
|
device->dpmaddr = dpmaddr;
|
||
|
|
device->dpmlen = dpmlen;
|
||
|
|
/* optional extended memory */
|
||
|
|
device->extmem = extmembase;
|
||
|
|
device->extmemaddr = extmemaddr;
|
||
|
|
device->extmemlen = extmemlen;
|
||
|
|
#ifdef CIFX_TOOLKIT_DMA
|
||
|
|
cifx_uio_map_dma_buffer( device);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
founddevice = 1;
|
||
|
|
}
|
||
|
|
free(namelist[currentuio]);
|
||
|
|
}
|
||
|
|
free(namelist);
|
||
|
|
}
|
||
|
|
|
||
|
|
return device;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Delete a previously via cifXFindDevice found device. Unmaps DPM and closes
|
||
|
|
* all open file handles to the uio driver. Also frees the pointer.
|
||
|
|
* \param device Device to delete */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void cifXDeleteDevice(struct CIFX_DEVICE_T* device)
|
||
|
|
{
|
||
|
|
if(device->uio_fd != -1)
|
||
|
|
{
|
||
|
|
#ifdef CIFX_TOOLKIT_DMA
|
||
|
|
if (device->dma_buffer_cnt)
|
||
|
|
cifx_uio_unmap_dma_buffer(device);
|
||
|
|
#endif
|
||
|
|
/* Unmap DPM */
|
||
|
|
munmap(device->dpm, device->dpmlen);
|
||
|
|
if (device->extmem)
|
||
|
|
munmap(device->extmem, device->extmemlen);
|
||
|
|
/* close uio_fd */
|
||
|
|
flock( device->uio_fd, LOCK_UN);
|
||
|
|
close(device->uio_fd);
|
||
|
|
}
|
||
|
|
free(device);
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef CIFX_DRV_HWIF
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Read a number of bytes from hardware interface
|
||
|
|
* If no hw-functions are defined DPM is accessed via simple memcpy
|
||
|
|
* \param ulDpmAddr Address offset in DPM to read data from
|
||
|
|
* \param pvDst Buffer to store read data
|
||
|
|
* \param pvDst Number of bytes to read */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void* HWIFDPMRead( uint32_t ulOpt, void* pvDevInstance, void* pvDpmAddr, void* pvDst, uint32_t ulLen)
|
||
|
|
{
|
||
|
|
PDEVICEINSTANCE pDev = (PDEVICEINSTANCE)pvDevInstance;
|
||
|
|
PCIFX_DEVICE_INTERNAL_T ptInternalDev = (PCIFX_DEVICE_INTERNAL_T)pDev->pvOSDependent;
|
||
|
|
struct CIFX_DEVICE_T* ptDevice = ptInternalDev->userdevice;
|
||
|
|
(void) ulOpt;
|
||
|
|
|
||
|
|
if (ptDevice->hwif_read)/* call the custom defined hw-read function */
|
||
|
|
pvDst = ptDevice->hwif_read( ptDevice, pvDpmAddr, pvDst, ulLen);
|
||
|
|
else /* if function is not defined, its a memory mapped DPM */
|
||
|
|
OS_Memcpy( pvDst, pvDpmAddr, ulLen);
|
||
|
|
|
||
|
|
return pvDst;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Write a number of bytes to hardware interface
|
||
|
|
* If no hw-functions are defined DPM is accessed via simple memcpy
|
||
|
|
* \param ulDpmAddr Address offset in DPM to read data from
|
||
|
|
* \param pvDst Buffer to store read data
|
||
|
|
* \param pvDst Number of bytes to read */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void* HWIFDPMWrite( uint32_t ulOpt, void* pvDevInstance, void* pvDpmAddr, void* pvSrc, uint32_t ulLen)
|
||
|
|
{
|
||
|
|
PDEVICEINSTANCE pDev = (PDEVICEINSTANCE)pvDevInstance;
|
||
|
|
PCIFX_DEVICE_INTERNAL_T ptInternalDev = (PCIFX_DEVICE_INTERNAL_T)pDev->pvOSDependent;
|
||
|
|
struct CIFX_DEVICE_T* ptDevice = ptInternalDev->userdevice;
|
||
|
|
(void) ulOpt;
|
||
|
|
|
||
|
|
if (ptDevice->hwif_write)/* call the custom defined hw-write function */
|
||
|
|
pvDpmAddr = ptDevice->hwif_write( ptDevice, pvDpmAddr, pvSrc, ulLen);
|
||
|
|
else /* if function is not defined, its a memory mapped DPM */
|
||
|
|
OS_Memcpy( pvDpmAddr, pvSrc, ulLen);
|
||
|
|
|
||
|
|
return pvDpmAddr;
|
||
|
|
}
|
||
|
|
#endif
|