blob: 9697868401fba660068b4c3a0ce4b3a936059d75 [file] [log] [blame]
/******************************************************************************
Copyright (c) 2006-2015 Lantiq Deutschland GmbH
Copyright (c) 2015 Lantiq Beteiligungs-GmbH & Co.KG
Copyright 2018, Intel Corporation.
For licensing information, see the file 'LICENSE' in the root folder of
this software module.
******************************************************************************/
/**
\file dxs_pollint.c
*/
/* ========================================================================== */
/* Includes */
/* ========================================================================== */
#include <stdint.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <pthread.h>
#include <sched.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include "dxs_init.h"
#include "dxs_config.h"
#include "dxs_error.h"
#include "dxs_pollint.h"
#include "irq_handler/dxs_irq.h"
#include "dxs_access.h"
/* ========================================================================== */
/* Macro definitions */
/* ========================================================================== */
#define DXS_SHARED_INTERRUPT
/*#undef DXS_SHARED_INTERRUPT*/
/* ========================================================================== */
/* Type definitions */
/* ========================================================================== */
/* ========================================================================== */
/* Global variables */
/* ========================================================================== */
static timer_t gPollTimerId;
static uint8_t timer_use = 0;
static pthread_t gInterruptThread;
static volatile int gInterruptThreadStop = 0;
static int gInterruptFD = -1;
/* ========================================================================== */
/* Function prototypes */
/* ========================================================================== */
/* ========================================================================== */
/* Function implementation */
/* ========================================================================== */
/**
Function dxs_poll_devices
*/
static void dxs_poll_devices()
{
uint8_t dev;
DXS_DEVICE_t *pDev;
for (dev=0; dev<DXS_MAX_DEVICES; dev++)
{
pDev = dxs_get_dev (dev);
DXS_StatusGet(pDev);
}
}
/**
Function dxs_polling_timer_start
*/
void dxs_polling_timer_start()
{
if (!timer_use)
{
struct itimerspec value;
(void) signal(SIGALRM, dxs_poll_devices);
value.it_value.tv_sec = 0;
value.it_value.tv_nsec = DXS_POLLING_INTERVAL_MS * 1000000;
value.it_interval.tv_sec = 0;
value.it_interval.tv_nsec = DXS_POLLING_INTERVAL_MS * 1000000;
timer_create (CLOCK_REALTIME, NULL, &gPollTimerId);
timer_settime (gPollTimerId, 0, &value, NULL);
}
timer_use++;
}
/**
Function dxs_polling_timer_stop
*/
void dxs_polling_timer_stop()
{
timer_use--;
if (!timer_use)
{
struct itimerspec value;
value.it_value.tv_sec = 0;
value.it_value.tv_nsec = 0;
value.it_interval.tv_sec = 0;
value.it_interval.tv_nsec = 0;
timer_settime (gPollTimerId, 0, &value, NULL);
timer_delete (gPollTimerId);
}
}
/* definition of dxs_int_client() */
/* - open /dev/dxs
* - prepare select
* - while (1) {
* - sleep on select()
* - when woken up, call dxs_poll_devices()
* - }
*/
/**
Function dxs_interrupt_handler
\param arg - unused
*/
static void *dxs_interrupt_handler (void *arg)
{
fd_set readfds;
int ret, dev;
FD_ZERO(&readfds);
while (gInterruptThreadStop == 0)
{
FD_SET(gInterruptFD, &readfds);
ret = select (gInterruptFD + 1, &readfds, NULL, NULL, NULL);
if (ret > 0)
{
#if defined(DXS_SHARED_INTERRUPT)
ret = ioctl(gInterruptFD, DXS_INT_DEV_GET, &dev);
if (ret == 0)
{
dxs_poll_devices();
/* Outbox handling is finished. Release IRQ line. */
ioctl(gInterruptFD, DXS_INT_DEV_REL, &dev);
}
#else
do
{
ret = ioctl(gInterruptFD, DXS_INT_DEV_GET, &dev);
if (ret == 0)
{
DXS_DEVICE_t *pDev = dxs_get_dev(dev);
if (pDev && (pDev->flags & DXS_DEV_OBX_HND_INITIALIZED))
{
DXS_StatusGet(pDev);
/* Outbox handling is finished. Release IRQ line. */
ioctl(gInterruptFD, DXS_INT_DEV_REL, &dev);
}
}
} while (ret == 0 && dev != -1);
#endif /* DXS_SHARED_INTERRUPT */
}
}
return NULL;
}
/**
Initialize interrupt handling code. Start interrupt handling thread,
configure interrupt number.
\param pDev pointer to the device interface
\return
Error code.
*/
int32_t dxs_interrupt_init (DXS_DEVICE_t *pDev)
{
int32_t ret;
DXS_INT_CONF_t int_conf;
pthread_attr_t irq_thread_attr;
if (pDev->irqNumber == -1)
{
DXS_RETURN(DXS_statusInvalidParam);
}
if (gInterruptFD == -1)
{
gInterruptFD = open("/dev/" DXS_IRQ_NAME, O_RDWR);
if (gInterruptFD == -1)
{
DXS_RETURN(DXS_statusFdOpenError);
}
/* Set highest priority for IRQ thread handling */
pthread_attr_init(&irq_thread_attr);
pthread_attr_setschedpolicy(&irq_thread_attr, SCHED_RR);
ret = pthread_create(&gInterruptThread, &irq_thread_attr,
dxs_interrupt_handler, NULL);
if (ret != 0)
{
close(gInterruptFD);
pthread_attr_destroy(&irq_thread_attr);
gInterruptFD = -1;
/* error code */
DXS_RETURN(DXS_statusThreadCreatError);
}
pthread_attr_destroy(&irq_thread_attr);
#if defined(DXS_SHARED_INTERRUPT)
int_conf.dev = pDev->nDevNum;
int_conf.irq = pDev->irqNumber;
ret = ioctl(gInterruptFD, DXS_INT_CONF, &int_conf);
if (ret < 0)
{
DXS_RETURN(DXS_statusIntConfError);
}
#endif
}
#if !defined(DXS_SHARED_INTERRUPT)
int_conf.dev = pDev->nDevNum;
int_conf.irq = pDev->irqNumber;
ret = ioctl(gInterruptFD, DXS_INT_CONF, &int_conf);
if (ret < 0)
{
DXS_RETURN(DXS_statusIntConfError);
}
#endif
return DXS_statusOk;
}
/**
Release interrupt handling code. Stop interrupt handling thread,
close interrupt handler driver file descriptor.
\param none
\return
Error code.
*/
int32_t dxs_interrupt_exit (void)
{
int32_t ret = DXS_statusOk;
void *status;
if (gInterruptFD != -1)
{
gInterruptThreadStop = 1;
/* wait for the thread to exit */
ret = pthread_join(gInterruptThread, &status);
if (ret || status != DXS_statusOk)
{
/* error code */
DXS_RETURN(DXS_statusThreadStopError);
}
close(gInterruptFD);
gInterruptFD = -1;
}
return ret;
}