| /****************************************************************************** |
| |
| 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; |
| } |