1135 lines
37 KiB
C
1135 lines
37 KiB
C
|
|
// SPDX-License-Identifier: MIT
|
||
|
|
/**************************************************************************************
|
||
|
|
*
|
||
|
|
* Copyright (c) 2024, Hilscher Gesellschaft fuer Systemautomation mbH. All Rights Reserved.
|
||
|
|
*
|
||
|
|
* Description: Linux specific abstraction of the toolkit.
|
||
|
|
*
|
||
|
|
* Changes:
|
||
|
|
*
|
||
|
|
* Version Date Author Description
|
||
|
|
* ----------------------------------------------------------------------------------
|
||
|
|
* 1 02.01.24 SD changed licensing terms
|
||
|
|
*
|
||
|
|
**************************************************************************************/
|
||
|
|
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <time.h>
|
||
|
|
#include <pthread.h>
|
||
|
|
#include <limits.h> /* for PTHREAD_STACK_MIN */
|
||
|
|
#include <stdint.h>
|
||
|
|
#include <sys/types.h>
|
||
|
|
#include <sys/stat.h>
|
||
|
|
#include <sys/time.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
#include <fcntl.h>
|
||
|
|
#include <semaphore.h>
|
||
|
|
#include <errno.h>
|
||
|
|
|
||
|
|
#ifndef CIFX_TOOLKIT_DISABLEPCI
|
||
|
|
#include <pciaccess.h>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#include "cifXErrors.h"
|
||
|
|
#include "OS_Dependent.h"
|
||
|
|
|
||
|
|
#include "cifxlinux.h"
|
||
|
|
#include "cifxlinux_internal.h"
|
||
|
|
#include "cifXEndianess.h"
|
||
|
|
|
||
|
|
#define IRQ_CFG_REG_OFFSET 0xfff0
|
||
|
|
#define IRQ_ENABLE_MASK 0x80000000
|
||
|
|
|
||
|
|
#define IRQ_STACK_MIN_SIZE 0x1000 /* Stack size needed by IRQ Thread
|
||
|
|
calling Toolkit's ISR/DSR Handler*/
|
||
|
|
|
||
|
|
#define BLOCK64 sizeof(uint64_t)
|
||
|
|
#define BLOCK32 sizeof(uint32_t)
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! O/S Specific initialization (initializes libpciaccess)
|
||
|
|
* \return CIFX_NO_ERROR on success */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int32_t OS_Init(void)
|
||
|
|
{
|
||
|
|
int32_t ret = CIFX_NO_ERROR;
|
||
|
|
int err = 0;
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifndef CIFX_TOOLKIT_DISABLEPCI
|
||
|
|
if(0 != (err = pci_system_init()))
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Error initializing PCI access subsystem (pci_system_init=%d)", err);
|
||
|
|
ret = CIFX_FUNCTION_FAILED;
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! O/S Specific de-initialization (de-initializes libpciaccess) */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_Deinit(void)
|
||
|
|
{
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifndef CIFX_TOOLKIT_DISABLEPCI
|
||
|
|
pci_system_cleanup();
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Memory allocation wrapper (standard malloc)
|
||
|
|
* \param ulSize Size of block to allocate
|
||
|
|
* \return NULL on failure */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void* OS_Memalloc(uint32_t ulSize) {
|
||
|
|
void *mem_ptr;
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
mem_ptr = malloc(ulSize);
|
||
|
|
|
||
|
|
if( mem_ptr == NULL )
|
||
|
|
perror("Memalloc failed");
|
||
|
|
|
||
|
|
return mem_ptr;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Memory de-allocation wrapper (standard free)
|
||
|
|
* \param pvMem Block to free */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_Memfree(void* pvMem) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
free(pvMem);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Memory resize wrapper (standard realloc)
|
||
|
|
* \param pvMem Block to resize
|
||
|
|
* \param ulNewSize New size of the block
|
||
|
|
* \return NULL on error */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void* OS_Memrealloc(void* pvMem, uint32_t ulNewSize) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
pvMem = realloc(pvMem, ulNewSize);
|
||
|
|
|
||
|
|
if( (pvMem == NULL) && (ulNewSize != 0) )
|
||
|
|
perror("Memrealloc failed");
|
||
|
|
|
||
|
|
return pvMem;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Memset wrapper
|
||
|
|
* \param pvMem Memory to set
|
||
|
|
* \param bFill Fill byte
|
||
|
|
* \param ulSize Size of the fill block */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_Memset(void* pvMem, unsigned char bFill, uint32_t ulSize) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
memset(pvMem, bFill, ulSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Memcopy wrapper
|
||
|
|
* \param pvDest Destination pointer
|
||
|
|
* \param pvSrc Source pointer
|
||
|
|
* \param ulSize Size to copy */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_Memcpy(void* pvDest, void* pvSrc, uint32_t ulSize) {
|
||
|
|
uint32_t ulDestAlignment = (uint32_t)(unsigned long)pvDest & 0x03;
|
||
|
|
uint32_t ulSrcAlignment = (uint32_t)(unsigned long)pvSrc & 0x03;
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
/* printf("%s() called\n", __FUNCTION__); */
|
||
|
|
#endif
|
||
|
|
uint8_t *pDest8 = (uint8_t*)pvDest;
|
||
|
|
uint8_t *pSrc8 = (uint8_t*)pvSrc;
|
||
|
|
if ( (ulDestAlignment == 0) &&
|
||
|
|
(ulSrcAlignment == 0) )
|
||
|
|
{
|
||
|
|
uint32_t *pDest32 = (uint32_t*)pvDest;
|
||
|
|
uint32_t *pSrc32 = (uint32_t*)pvSrc;
|
||
|
|
|
||
|
|
while(ulSize>=BLOCK64) {
|
||
|
|
*(pDest32)++ = *(pSrc32)++;
|
||
|
|
*(pDest32)++ = *(pSrc32)++;
|
||
|
|
ulSize-=BLOCK64;
|
||
|
|
}
|
||
|
|
while(ulSize>=BLOCK32) {
|
||
|
|
*(pDest32)++ = *(pSrc32)++;
|
||
|
|
ulSize-=BLOCK32;
|
||
|
|
}
|
||
|
|
pDest8 = (uint8_t*)pDest32;
|
||
|
|
pSrc8 = (uint8_t*)pSrc32;
|
||
|
|
}
|
||
|
|
while(ulSize--)
|
||
|
|
*(pDest8++) = *(pSrc8++);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Memcompare wrapper
|
||
|
|
* \param pvBuf1 First compare buffer
|
||
|
|
* \param pvBuf2 Second compare buffer
|
||
|
|
* \param ulSize Size to compare
|
||
|
|
* \return 0 if blocks are equal */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int OS_Memcmp(void* pvBuf1, void* pvBuf2, uint32_t ulSize) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
return memcmp(pvBuf1, pvBuf2, ulSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Memmove wrapper (Overlapping memory copy)
|
||
|
|
* \param pvDest Destination buffer
|
||
|
|
* \param pvSrc Source buffer
|
||
|
|
* \param ulSize Size to move */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_Memmove(void* pvDest, void* pvSrc, uint32_t ulSize) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
pvDest = memmove(pvDest, pvSrc, ulSize);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Read PCI configuration area of specified card
|
||
|
|
* \param pvOSDependent OS Dependent parameter to identify card
|
||
|
|
* \return Pointer to configuration data (passed to WritePCIConfig) */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void* OS_ReadPCIConfig(void* pvOSDependent) {
|
||
|
|
#ifndef CIFX_TOOLKIT_DISABLEPCI
|
||
|
|
PCIFX_DEVICE_INTERNAL_T info = (PCIFX_DEVICE_INTERNAL_T)pvOSDependent;
|
||
|
|
|
||
|
|
int pci_ret;
|
||
|
|
void *pci_buf;
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
if(!pvOSDependent)
|
||
|
|
return NULL;
|
||
|
|
|
||
|
|
pci_buf = malloc(256);
|
||
|
|
if(!pci_buf)
|
||
|
|
{
|
||
|
|
perror("pci_buf malloc failed");
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ((pci_ret = pci_device_cfg_read(&info->pci, pci_buf, 0, 256, NULL)) )
|
||
|
|
{
|
||
|
|
#ifdef VERBOSE
|
||
|
|
printf("libnetx: pci_read_block() returns %d\n", pci_ret);
|
||
|
|
#endif
|
||
|
|
free( pci_buf);
|
||
|
|
pci_buf = NULL;
|
||
|
|
}
|
||
|
|
return pci_buf;
|
||
|
|
#else
|
||
|
|
return NULL;
|
||
|
|
#endif /* CIFX_TOOLKIT_DISABLEPCI */
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Restore PCI configuration
|
||
|
|
* \param pvOSDependent OS Dependent parameter to identify card
|
||
|
|
* \param pvPCIConfig Pointer returned from ReadPCIConfig */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_WritePCIConfig(void* pvOSDependent, void* pvPCIConfig) {
|
||
|
|
|
||
|
|
#ifndef CIFX_TOOLKIT_DISABLEPCI
|
||
|
|
int pci_ret;
|
||
|
|
PCIFX_DEVICE_INTERNAL_T info = (PCIFX_DEVICE_INTERNAL_T)pvOSDependent;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if ((pci_ret = pci_device_cfg_write(&info->pci, pvPCIConfig, 0, 256, NULL)) )
|
||
|
|
{
|
||
|
|
#ifdef VERBOSE
|
||
|
|
printf("libnetx: pci_write_block() returns %d\n", pci_ret);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
free(pvPCIConfig);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Checks if irq occurred for an uio device
|
||
|
|
* \param info Pointer to internal device structure
|
||
|
|
* \param timeout timeout in ms to wait
|
||
|
|
* \return 1 if irq occurred / 0 if not / < 0 in case of an error */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int check_uio_irq( PCIFX_DEVICE_INTERNAL_T info, int32_t timeout) {
|
||
|
|
int ret = 0;
|
||
|
|
int nfds = info->userdevice->uio_fd + 1;
|
||
|
|
struct timeval sel_timeout;
|
||
|
|
fd_set readfd;
|
||
|
|
|
||
|
|
FD_ZERO(&readfd);
|
||
|
|
FD_SET(info->userdevice->uio_fd, &readfd);
|
||
|
|
|
||
|
|
sel_timeout.tv_sec = 0;
|
||
|
|
sel_timeout.tv_usec = timeout * 1000; /* Default wait timeout = 500ms */
|
||
|
|
|
||
|
|
if ( ((ret = select(nfds, &readfd, NULL, NULL, &sel_timeout))>0) && FD_ISSET( info->userdevice->uio_fd, &readfd)) {
|
||
|
|
uint32_t buf;
|
||
|
|
if ((ret = read( info->userdevice->uio_fd, &buf, sizeof(buf)))>0)
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Checks if irq occurred for a gpio
|
||
|
|
* \param info Pointer to internal device structure
|
||
|
|
* \param timeout timeout in ms to wait
|
||
|
|
* \return 1 if irq occurred / 0 if not / < 0 in case of an error */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int check_gpio_irq( PCIFX_DEVICE_INTERNAL_T info, uint32_t timeout) {
|
||
|
|
int ret = 0;
|
||
|
|
uint8_t bVal = 0;
|
||
|
|
int nfds = info->userdevice->uio_fd + 1;
|
||
|
|
struct timeval sel_timeout;
|
||
|
|
fd_set exceptfd;
|
||
|
|
|
||
|
|
FD_ZERO(&exceptfd);
|
||
|
|
FD_SET(info->userdevice->uio_fd, &exceptfd);
|
||
|
|
|
||
|
|
sel_timeout.tv_sec = 0;
|
||
|
|
sel_timeout.tv_usec = timeout * 1000; /* Default wait timeout = 500ms */
|
||
|
|
|
||
|
|
/* set to beginning to be able to read first, see NOTE */
|
||
|
|
lseek( info->userdevice->uio_fd, 0, SEEK_SET);
|
||
|
|
/* NOTE: Since netx does level sensitive irqs and linux gpio only recongnize edge */
|
||
|
|
/* we always need to check current level to make sure not to miss an irq. */
|
||
|
|
if ( !( ((ret = read( info->userdevice->uio_fd, &bVal, sizeof(bVal))) > 0) && (bVal == '1') ) ) {
|
||
|
|
/* wait for irq */
|
||
|
|
ret = select(nfds, NULL, NULL, &exceptfd, &sel_timeout);
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Interrupt Service Thread
|
||
|
|
* \param ptr Pointer to internal device structure
|
||
|
|
* \return NULL */
|
||
|
|
/*****************************************************************************/
|
||
|
|
static void *netx_irq_thread(void *ptr) {
|
||
|
|
PCIFX_DEVICE_INTERNAL_T info = (PCIFX_DEVICE_INTERNAL_T)ptr;
|
||
|
|
int ret = 0;
|
||
|
|
int uio_irq = 1;
|
||
|
|
uint32_t timeout = 500;
|
||
|
|
|
||
|
|
if(!info)
|
||
|
|
return (void *) -1;
|
||
|
|
|
||
|
|
/* check if it's an uio device or a custom */
|
||
|
|
if ((info->userdevice != NULL) && (info->userdevice->uio_num < 0))
|
||
|
|
uio_irq = 0;
|
||
|
|
|
||
|
|
while( info->irq_stop == 0 )
|
||
|
|
{
|
||
|
|
if (uio_irq) {
|
||
|
|
ret = check_uio_irq( info, timeout);
|
||
|
|
} else {
|
||
|
|
ret = check_gpio_irq( info, timeout);
|
||
|
|
}
|
||
|
|
if (ret == 1) {
|
||
|
|
uint32_t ulVal = 0;
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("IRQ @status_thread\n");
|
||
|
|
#endif
|
||
|
|
ret = cifXTKitISRHandler(info->devinstance, 1);
|
||
|
|
|
||
|
|
switch(ret)
|
||
|
|
{
|
||
|
|
case CIFX_TKIT_IRQ_DSR_REQUESTED:
|
||
|
|
cifXTKitDSRHandler(info->devinstance);
|
||
|
|
break;
|
||
|
|
|
||
|
|
case CIFX_TKIT_IRQ_HANDLED:
|
||
|
|
/* Everything was done by ISR, no need to call DSR */
|
||
|
|
break;
|
||
|
|
|
||
|
|
case CIFX_TKIT_IRQ_OTHERDEVICE:
|
||
|
|
default:
|
||
|
|
/* This should never happen, as the uio driver already filters our IRQs */
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (uio_irq) {
|
||
|
|
if(info->devinstance->ulDPMSize >= NETX_DPM_MEMORY_SIZE) {
|
||
|
|
/* if it's open for writing enable irq again (currently function not implemented in uio_netx) */
|
||
|
|
//write(info->userdevice->uio_fd, &bVal, 1);
|
||
|
|
HWIF_READN(info->devinstance, &ulVal, info->devinstance->pbDPM+IRQ_CFG_REG_OFFSET, sizeof(ulVal));
|
||
|
|
ulVal |= HOST_TO_LE32(IRQ_ENABLE_MASK);
|
||
|
|
HWIF_WRITEN(info->devinstance, info->devinstance->pbDPM+IRQ_CFG_REG_OFFSET, (void*)&ulVal, sizeof(ulVal));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Enable interrupts on the given device
|
||
|
|
* \param pvOSDependent Pointer to internal device structure */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_EnableInterrupts(void* pvOSDependent) {
|
||
|
|
PCIFX_DEVICE_INTERNAL_T info = (PCIFX_DEVICE_INTERNAL_T)pvOSDependent;
|
||
|
|
int ret = 0;
|
||
|
|
uint32_t ulVal;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
pthread_attr_init(&info->irq_thread_attr);
|
||
|
|
pthread_attr_setstacksize(&info->irq_thread_attr, PTHREAD_STACK_MIN + IRQ_STACK_MIN_SIZE);
|
||
|
|
|
||
|
|
if(info->set_irq_scheduler_algo)
|
||
|
|
{
|
||
|
|
pthread_attr_setinheritsched( &info->irq_thread_attr, PTHREAD_EXPLICIT_SCHED);
|
||
|
|
if( (ret = pthread_attr_setschedpolicy(&info->irq_thread_attr, info->irq_scheduler_algo)) != 0)
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Error setting custom thread scheduling algorithm for IRQ thread (pthread_attr_setschedpolicy=%d)", ret);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if(info->set_irq_prio)
|
||
|
|
{
|
||
|
|
struct sched_param sched_param = {0};
|
||
|
|
sched_param.sched_priority = info->irq_prio;
|
||
|
|
|
||
|
|
pthread_attr_setinheritsched( &info->irq_thread_attr, PTHREAD_EXPLICIT_SCHED);
|
||
|
|
if( (ret = pthread_attr_setschedparam(&info->irq_thread_attr, &sched_param)) != 0)
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Error setting custom thread priority in IRQ thread (pthread_attr_setschedparam=%d)", ret);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if( (ret = pthread_create( &info->irq_thread, &info->irq_thread_attr, netx_irq_thread,
|
||
|
|
(void*)info )) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Enabling Interrupts (pthread_create=%d)", ret);
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
info->irq_stop = 0;
|
||
|
|
if(info->devinstance->ulDPMSize >= NETX_DPM_MEMORY_SIZE) {
|
||
|
|
HWIF_READN(info->devinstance, &ulVal, info->devinstance->pbDPM+IRQ_CFG_REG_OFFSET, sizeof(ulVal));
|
||
|
|
ulVal |= HOST_TO_LE32(IRQ_ENABLE_MASK);
|
||
|
|
HWIF_WRITEN(info->devinstance, info->devinstance->pbDPM+IRQ_CFG_REG_OFFSET, (void*)&ulVal, sizeof(ulVal));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Disable interrupts on the given device
|
||
|
|
* \param pvOSDependent Pointer to internal device structure */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_DisableInterrupts(void* pvOSDependent) {
|
||
|
|
PCIFX_DEVICE_INTERNAL_T info = (PCIFX_DEVICE_INTERNAL_T)pvOSDependent;
|
||
|
|
uint32_t ulVal;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
info->irq_stop = 1;
|
||
|
|
pthread_join(info->irq_thread, NULL);
|
||
|
|
|
||
|
|
if(info->devinstance->ulDPMSize >= NETX_DPM_MEMORY_SIZE) {
|
||
|
|
HWIF_READN(info->devinstance, &ulVal, info->devinstance->pbDPM+IRQ_CFG_REG_OFFSET, sizeof(ulVal));
|
||
|
|
ulVal &= HOST_TO_LE32(~IRQ_ENABLE_MASK);
|
||
|
|
HWIF_WRITEN(info->devinstance, info->devinstance->pbDPM+IRQ_CFG_REG_OFFSET, (void*)&ulVal, sizeof(ulVal));
|
||
|
|
}
|
||
|
|
|
||
|
|
pthread_attr_destroy(&info->irq_thread_attr);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Open file for reading
|
||
|
|
* \param szFilename File to open (including path)
|
||
|
|
* \param pulFileSize Returned size of the file in bytes
|
||
|
|
* \return Handle to the file, NULL on failure */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void* OS_FileOpen(char* szFilename, uint32_t * pulFileSize) {
|
||
|
|
int fd;
|
||
|
|
struct stat buf;
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s(%s) called\n", __FUNCTION__, szFilename);
|
||
|
|
#endif
|
||
|
|
fd = open(szFilename, O_RDONLY);
|
||
|
|
if( fd == -1 )
|
||
|
|
{
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( fstat(fd, &buf) != 0 )
|
||
|
|
{
|
||
|
|
perror("fstat failed");
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
*pulFileSize = buf.st_size;
|
||
|
|
#ifdef VERBOSE
|
||
|
|
printf("opened: %s (%u bytes)\n", szFilename, *pulFileSize);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
return fdopen(fd, "r");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Read data from file
|
||
|
|
* \param pvFile Handle to the file (acquired by OS_FileOpen)
|
||
|
|
* \param ulOffset Offset to read from
|
||
|
|
* \param ulSize Size to read
|
||
|
|
* \param pvBuffer Buffer to read data into
|
||
|
|
* \return number of bytes read */
|
||
|
|
/*****************************************************************************/
|
||
|
|
uint32_t OS_FileRead(void* pvFile, uint32_t ulOffset,
|
||
|
|
uint32_t ulSize, void* pvBuffer) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
return fread(pvBuffer, 1, ulSize, pvFile);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Close open file
|
||
|
|
* \param pvFile Handle to the file (acquired by OS_FileOpen) */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_FileClose(void* pvFile) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
if( fclose(pvFile) != 0 )
|
||
|
|
perror("FileClose failed");
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Get Millisecond counter value (used for timeout handling)
|
||
|
|
* \return Counter value with a resolution of 1ms */
|
||
|
|
/*****************************************************************************/
|
||
|
|
uint32_t OS_GetMilliSecCounter(void) {
|
||
|
|
struct timespec ts_get_milli;
|
||
|
|
unsigned int msec_count;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
if( clock_gettime( CLOCK_MONOTONIC, &ts_get_milli ) != 0 )
|
||
|
|
{
|
||
|
|
perror("gettime failed");
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
msec_count = ts_get_milli.tv_sec * 1000;
|
||
|
|
msec_count += ts_get_milli.tv_nsec / 1000 / 1000;
|
||
|
|
|
||
|
|
return msec_count;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Sleep for the given time
|
||
|
|
* \param ulSleepTimeMs Time in ms to sleep (0 will sleep for 50us) */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_Sleep(uint32_t ulSleepTimeMs) {
|
||
|
|
struct timespec sleeptime;
|
||
|
|
struct timespec RemainingTime;
|
||
|
|
struct timespec *pRemainingTime = &RemainingTime;
|
||
|
|
int iRet;
|
||
|
|
int iTmpErrno;
|
||
|
|
|
||
|
|
if(ulSleepTimeMs == 0)
|
||
|
|
{
|
||
|
|
#ifdef NO_MIN_SLEEP
|
||
|
|
/* do not sleep and return immediately */
|
||
|
|
return;
|
||
|
|
#else
|
||
|
|
sleeptime.tv_sec = 0;
|
||
|
|
sleeptime.tv_nsec = 50000; // 50 usecs
|
||
|
|
#endif
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
sleeptime.tv_sec = ulSleepTimeMs / 1000;
|
||
|
|
ulSleepTimeMs -= sleeptime.tv_sec * 1000;
|
||
|
|
sleeptime.tv_nsec = ulSleepTimeMs * 1000 * 1000;
|
||
|
|
}
|
||
|
|
|
||
|
|
iTmpErrno = errno;
|
||
|
|
errno = 0;
|
||
|
|
while((iRet = nanosleep(&sleeptime, pRemainingTime)))
|
||
|
|
{
|
||
|
|
if ((errno == EINTR) && (pRemainingTime != NULL) )
|
||
|
|
{
|
||
|
|
sleeptime.tv_sec = RemainingTime.tv_sec;
|
||
|
|
sleeptime.tv_nsec = RemainingTime.tv_nsec;
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
perror("OS_Sleep failed");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
errno = iTmpErrno;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Create mutex
|
||
|
|
* \return Handle to new created mutex */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void* OS_CreateMutex(void) {
|
||
|
|
pthread_mutex_t *mut = malloc(sizeof(pthread_mutex_t));
|
||
|
|
pthread_mutexattr_t attr;
|
||
|
|
int iRet;
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if( mut == NULL )
|
||
|
|
{
|
||
|
|
perror("allocating memory for mutex failed");
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
if( (iRet = pthread_mutexattr_init(&attr)) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Mutex init attr: %s\n", strerror(iRet));
|
||
|
|
goto err_out;
|
||
|
|
}
|
||
|
|
if( (iRet = pthread_mutex_init(mut, &attr)) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Mutex init: %s\n", strerror(iRet));
|
||
|
|
goto err_out;
|
||
|
|
}
|
||
|
|
return (void*) mut;
|
||
|
|
|
||
|
|
err_out:
|
||
|
|
free(mut);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Add timeout (given in ms) to timespec struct. On success the new value is
|
||
|
|
* returned in time_val.
|
||
|
|
* \param time_val (in/out) time on which msec should be added
|
||
|
|
* \param msec time to add (ms)
|
||
|
|
* \return 0 on success */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int add_msec_to_timespec( struct timespec* time_val, uint32_t msec)
|
||
|
|
{
|
||
|
|
if (time_val == NULL)
|
||
|
|
return -1;
|
||
|
|
|
||
|
|
time_val->tv_sec += msec / 1000; /* integer part in seconds */
|
||
|
|
msec = (msec % 1000) * 1000 * 1000; /* reminder in nano seconds */
|
||
|
|
|
||
|
|
time_val->tv_nsec += msec; /* add nano seconds */
|
||
|
|
if (time_val->tv_nsec >= 1000000000)
|
||
|
|
{
|
||
|
|
time_val->tv_sec++;
|
||
|
|
time_val->tv_nsec = time_val->tv_nsec - 1000000000;
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Try to acquire mutex with timeout
|
||
|
|
* \param pvMutex Handle to mutex
|
||
|
|
* \param ulTimeout Timeout in ms to wait for mutex
|
||
|
|
* \return !=0 if mutex was acquired */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int OS_WaitMutex(void* pvMutex, uint32_t ulTimeout) {
|
||
|
|
struct timespec lock_ts;
|
||
|
|
pthread_mutex_t *mut = (pthread_mutex_t*) pvMutex;
|
||
|
|
int iRet;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
clock_gettime( CLOCK_REALTIME, &lock_ts );
|
||
|
|
|
||
|
|
if (add_msec_to_timespec( &lock_ts, ulTimeout))
|
||
|
|
{
|
||
|
|
fprintf( stderr, "OS_WaitMutex(): Faild to calculate time to block\n");
|
||
|
|
return 0;
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
if( (iRet = pthread_mutex_timedlock(mut, &lock_ts)) != 0 )
|
||
|
|
{
|
||
|
|
if (iRet != ETIMEDOUT)
|
||
|
|
fprintf( stderr, "Mutex wait: %s\n", strerror(iRet));
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Release previously acquired mutex
|
||
|
|
* \param pvMutex Handle to mutex */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_ReleaseMutex(void* pvMutex) {
|
||
|
|
pthread_mutex_t *mut = (pthread_mutex_t*) pvMutex;
|
||
|
|
int iRet;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if( (iRet = pthread_mutex_unlock(mut)) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Mutex unlock: %s\n", strerror(iRet));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Delete mutex
|
||
|
|
* \param pvMutex Handle to mutex */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_DeleteMutex(void* pvMutex) {
|
||
|
|
pthread_mutex_t *mut = (pthread_mutex_t*) pvMutex;
|
||
|
|
int iRet;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if( (iRet = pthread_mutex_destroy(mut)) != 0 )
|
||
|
|
fprintf( stderr, "Delete mutex: %s\n", strerror(iRet));
|
||
|
|
|
||
|
|
free(mut);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Create Lock (Usually same as mutex, but does not support timed waiting)
|
||
|
|
* \return Handle to created lock */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void* OS_CreateLock(void) {
|
||
|
|
pthread_mutexattr_t mta;
|
||
|
|
pthread_mutex_t *mutex;
|
||
|
|
int iRet;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
pthread_mutexattr_init(&mta);
|
||
|
|
if( (iRet = pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE)) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Mutex set attr: %s\n", strerror(iRet));
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
mutex = malloc( sizeof(pthread_mutex_t) );
|
||
|
|
if( mutex == NULL )
|
||
|
|
{
|
||
|
|
perror("allocating memory for mutex");
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
if( (iRet = pthread_mutex_init(mutex, &mta)) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Mutex init: %s\n", strerror(iRet));
|
||
|
|
goto err_out;
|
||
|
|
}
|
||
|
|
return mutex;
|
||
|
|
|
||
|
|
err_out:
|
||
|
|
free(mutex);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Acquire a lock
|
||
|
|
* \param pvLock Handle to lock */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_EnterLock(void* pvLock) {
|
||
|
|
pthread_mutex_t *mutex = (pthread_mutex_t *) pvLock;
|
||
|
|
int iRet;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if( (iRet = pthread_mutex_lock(mutex)) != 0)
|
||
|
|
{
|
||
|
|
fprintf( stderr, "EnterLock failed: %s\n", strerror(iRet));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Release a lock
|
||
|
|
* \param pvLock Handle to lock */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_LeaveLock(void* pvLock) {
|
||
|
|
pthread_mutex_t *mutex = (pthread_mutex_t *) pvLock;
|
||
|
|
int iRet;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if( (iRet = pthread_mutex_unlock(mutex)) != 0)
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Mutex unlock: %s\n", strerror(iRet));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Delete a lock
|
||
|
|
* \param pvLock Handle to lock */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_DeleteLock(void* pvLock) {
|
||
|
|
pthread_mutex_t *mutex = (pthread_mutex_t *) pvLock;
|
||
|
|
int iRet;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if( (iRet = pthread_mutex_destroy(mutex)) != 0 )
|
||
|
|
fprintf( stderr, "Delete lock: %s\n", strerror(iRet));
|
||
|
|
|
||
|
|
free(mutex);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Compare strings
|
||
|
|
* \param pszBuf1 String buffer 1
|
||
|
|
* \param pszBuf2 String buffer 2
|
||
|
|
* \return 0 if strings are equal */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int OS_Strcmp(const char* pszBuf1, const char* pszBuf2) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
return strcmp(pszBuf1, pszBuf2);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Compare strings case insensitive
|
||
|
|
* \param pszBuf1 String buffer 1
|
||
|
|
* \param pszBuf2 String buffer 2
|
||
|
|
* \param ulLen Maximum length to compare
|
||
|
|
* \return 0 if strings are equal */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int OS_Strnicmp(const char* pszBuf1, const char* pszBuf2, uint32_t ulLen) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
return strncasecmp(pszBuf1, pszBuf2, ulLen);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Get length of string
|
||
|
|
* \param szText Text buffer
|
||
|
|
* \return Length of given string */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int OS_Strlen(const char* szText) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
return strlen(szText);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Copy string to destination buffer
|
||
|
|
* \param szText Destination string
|
||
|
|
* \param szSource Source string
|
||
|
|
* \param ulLen Maximum length to copy
|
||
|
|
* \return Pointer to szDest */
|
||
|
|
/*****************************************************************************/
|
||
|
|
char* OS_Strncpy(char* szDest, const char* szSource, uint32_t ulLen) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
return strncpy(szDest, szSource, ulLen);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Map driver pointer to user space
|
||
|
|
* \param pvDriverMem Pointer to driver memory
|
||
|
|
* \param ulMemSize Size of the memory to map
|
||
|
|
* \param ppvMappedMem Returned mapped pointer
|
||
|
|
* \param os_dependent OS Dependent parameter in DEVICEINSTANCE
|
||
|
|
* \param fCached Caching option (0=do not use) -> currently ignored
|
||
|
|
* \return Handle to mapping, NULL on error */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void* OS_MapUserPointer(void* pvDriverMem, uint32_t ulMemSize,
|
||
|
|
void** ppvMappedMem, void *os_dependent, unsigned char fCached) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
/* We don't need to do any mapping, as we are already in user space */
|
||
|
|
*ppvMappedMem = pvDriverMem;
|
||
|
|
|
||
|
|
return pvDriverMem;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Unmap previously mapped user space pointer
|
||
|
|
* \param phMapping Handle returned from OS_MapUserPointer
|
||
|
|
* \param os_dependent OS Dependent parameter in DEVICEINSTANCE
|
||
|
|
* \return 0 on error */
|
||
|
|
/*****************************************************************************/
|
||
|
|
int OS_UnmapUserPointer(void* phMapping, void *os_dependent) {
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! This function invalidates a cache buffer to be refreshed by
|
||
|
|
* the physical memory.
|
||
|
|
* \param pvMem Pointer to the cached memory
|
||
|
|
* \param ulMemSize Length of the cached memory area */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_InvalidateCacheMemory_FromDevice(void* pvCachedMemPtr, unsigned long ulMemSize) {
|
||
|
|
/* not implemented yet */
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! This function flushes a cached memory area to the device buffer
|
||
|
|
* \param pvMem Pointer to the cached memory
|
||
|
|
* \param ulMemSize Length of the cached memory area */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_FlushCacheMemory_ToDevice(void* pvMem, unsigned long ulMemSize)
|
||
|
|
{
|
||
|
|
/* not implemented yet */
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Structure for event handling */
|
||
|
|
/*****************************************************************************/
|
||
|
|
struct os_event {
|
||
|
|
pthread_mutex_t mutex; /*!< Mutex to lock access to set, waiting_threads
|
||
|
|
and cond */
|
||
|
|
int set; /*!< Protected by mutex. !=0 if event is set */
|
||
|
|
int waiting_threads; /*!< Number of waiting threads on this event */
|
||
|
|
pthread_cond_t cond; /*!< Condition to signal, if event state has changed,
|
||
|
|
and a thread is waiting */
|
||
|
|
};
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Create event
|
||
|
|
* \return Handle to created event */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void* OS_CreateEvent(void) {
|
||
|
|
struct os_event *ev = malloc( sizeof(*ev) );
|
||
|
|
pthread_condattr_t ev_attr;
|
||
|
|
pthread_mutexattr_t ev_mutattr;
|
||
|
|
int iRet;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if( ev == NULL )
|
||
|
|
{
|
||
|
|
perror("allocating memory for OS_Event");
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if( (iRet = pthread_condattr_init( &ev_attr )) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Cond init attr: %s\n", strerror(iRet));
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
pthread_condattr_setclock(&ev_attr, CLOCK_MONOTONIC);
|
||
|
|
|
||
|
|
if( (iRet = pthread_cond_init( &(ev->cond), &ev_attr )) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Cond init: %s\n", strerror(iRet));
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
if( (iRet = pthread_mutexattr_init(&ev_mutattr)) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Mutex init attr: %s\n", strerror(iRet));
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
if( (iRet = pthread_mutexattr_setprotocol(&ev_mutattr, PTHREAD_PRIO_INHERIT)) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Mutex set attr: %s\n", strerror(iRet));
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
if( (iRet = pthread_mutex_init(&(ev->mutex), &ev_mutattr)) != 0 )
|
||
|
|
{
|
||
|
|
fprintf( stderr, "Mutex init: %s\n", strerror(iRet));
|
||
|
|
goto free_out;
|
||
|
|
}
|
||
|
|
|
||
|
|
ev->set = 0;
|
||
|
|
ev->waiting_threads = 0;
|
||
|
|
|
||
|
|
return ev;
|
||
|
|
|
||
|
|
free_out:
|
||
|
|
free(ev);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Signal event
|
||
|
|
* \param pvEvent Handle to event */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_SetEvent(void* pvEvent) {
|
||
|
|
struct os_event *ev = (struct os_event *) pvEvent;
|
||
|
|
int iRet;
|
||
|
|
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if( ev == NULL )
|
||
|
|
{
|
||
|
|
fprintf(stderr, "SetEvent, no event given\n");
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
pthread_mutex_lock(&ev->mutex);
|
||
|
|
|
||
|
|
if (!ev->set)
|
||
|
|
{
|
||
|
|
ev->set = 1;
|
||
|
|
|
||
|
|
/* Check if there are any waiters, and release them appropriately */
|
||
|
|
if(ev->waiting_threads > 0)
|
||
|
|
{
|
||
|
|
if( (iRet = pthread_cond_signal(&(ev->cond))) != 0 )
|
||
|
|
fprintf( stderr, "SetEvent: %s\n", strerror(iRet));
|
||
|
|
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pthread_mutex_unlock(&ev->mutex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Reset event
|
||
|
|
* \param pvEvent Handle to event */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_ResetEvent(void* pvEvent) {
|
||
|
|
struct os_event *ev = (struct os_event *) pvEvent;
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
if( ev == NULL )
|
||
|
|
{
|
||
|
|
fprintf(stderr, "ResetEvent, no event given\n");
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
pthread_mutex_lock(&ev->mutex);
|
||
|
|
|
||
|
|
ev->set = 0;
|
||
|
|
|
||
|
|
pthread_mutex_unlock(&ev->mutex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Delete event
|
||
|
|
* \param pvEvent Handle to event */
|
||
|
|
/*****************************************************************************/
|
||
|
|
void OS_DeleteEvent(void* pvEvent) {
|
||
|
|
struct os_event *ev = (struct os_event *) pvEvent;
|
||
|
|
int iRet;
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if( (iRet = pthread_cond_destroy(&(ev->cond)) ) != 0 )
|
||
|
|
fprintf( stderr, "Delete event cond: %s\n", strerror(iRet));
|
||
|
|
|
||
|
|
if( (iRet = pthread_mutex_destroy(&(ev->mutex)) ) != 0 )
|
||
|
|
fprintf( stderr, "Delete mutex: %s\n", strerror(iRet));
|
||
|
|
|
||
|
|
free(ev);
|
||
|
|
}
|
||
|
|
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Wait for event
|
||
|
|
* \param pvEvent Handle to event
|
||
|
|
* \param ulTimeout Timeout in ms to wait for event
|
||
|
|
* \return CIFX_EVENT_SIGNALLED if event was set, CIFX_EVENT_TIMEOUT otherwise */
|
||
|
|
/*****************************************************************************/
|
||
|
|
uint32_t OS_WaitEvent(void* pvEvent, uint32_t ulTimeout) {
|
||
|
|
struct os_event *ev = (struct os_event *) pvEvent;
|
||
|
|
struct timespec timeout;
|
||
|
|
unsigned long ret = CIFX_EVENT_TIMEOUT;
|
||
|
|
#ifdef VERBOSE_1
|
||
|
|
printf("%s() called\n", __FUNCTION__);
|
||
|
|
#endif
|
||
|
|
|
||
|
|
if( clock_gettime(CLOCK_MONOTONIC, &timeout) != 0 )
|
||
|
|
{
|
||
|
|
perror("WaitEvent gettime failed");
|
||
|
|
} else
|
||
|
|
{
|
||
|
|
if (add_msec_to_timespec( &timeout, ulTimeout))
|
||
|
|
{
|
||
|
|
fprintf( stderr, "OS_WaitEvent(): Faild to calculate time to block\n");
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
pthread_mutex_lock(&ev->mutex);
|
||
|
|
|
||
|
|
if(!ev->set)
|
||
|
|
{
|
||
|
|
/* We need to wait for event */
|
||
|
|
++ev->waiting_threads;
|
||
|
|
|
||
|
|
pthread_cond_timedwait(&ev->cond, &ev->mutex, &timeout);
|
||
|
|
|
||
|
|
--ev->waiting_threads;
|
||
|
|
}
|
||
|
|
|
||
|
|
if(ev->set)
|
||
|
|
{
|
||
|
|
/* We got the event, now reset it */
|
||
|
|
ev->set = 0;
|
||
|
|
ret = CIFX_EVENT_SIGNALLED;
|
||
|
|
}
|
||
|
|
|
||
|
|
pthread_mutex_unlock(&ev->mutex);
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
#ifdef CIFX_TOOLKIT_TIME
|
||
|
|
/*****************************************************************************/
|
||
|
|
/*! Get the system time since 1970/01/01
|
||
|
|
* \param ptTime Pointer to store the time value
|
||
|
|
* \return actual time vlaue */
|
||
|
|
/*****************************************************************************/
|
||
|
|
uint32_t OS_Time( uint32_t *ptTime)
|
||
|
|
{
|
||
|
|
struct timeval tCurrentTime = {0};
|
||
|
|
time_t tSecSince1970 = 0;
|
||
|
|
|
||
|
|
/* get local time */
|
||
|
|
if (0 == gettimeofday( &tCurrentTime, NULL))
|
||
|
|
tSecSince1970 = tCurrentTime.tv_sec;
|
||
|
|
|
||
|
|
if (ptTime)
|
||
|
|
*ptTime = (uint32_t)tSecSince1970;
|
||
|
|
|
||
|
|
return (uint32_t)tSecSince1970;
|
||
|
|
}
|
||
|
|
#endif
|