blob: f42a2158171d2a071c308de72dcf39031f372353 [file] [log] [blame]
/******************************************************************************
Copyright (c) 2014-2015 Lantiq Deutschland GmbH
Copyright (c) 2015-2016 Lantiq Beteiligungs-GmbH & Co.KG
Copyright 2016, Intel Corporation.
For licensing information, see the file 'LICENSE' in the root folder of
this software module.
******************************************************************************/
/**
\file dxs_wait.c
Implementation of WaitList functions.
*/
/* ========================================================================== */
/* Includes */
/* ========================================================================== */
#include "dxs.h"
#include "dxs_lib.h"
#include "dxs_fifo.h"
#include "dxs_errno.h"
#include "dxs_error.h"
/* ========================================================================== */
/* Macro definitions */
/* ========================================================================== */
/* max number of waiting lists */
#define DXS_MAX_WAITLISTS 16
/* max elements in a single waiting list */
#define DXS_MAX_WAITLIST_OBJ 32
/* max total waiting list elements */
#define DXS_MAX_WAITLIST_ELEMENTS (DXS_MAX_WAITLISTS*DXS_MAX_WAITLIST_OBJ)
#define DXS_WAITLIST_MAGIC 0x574C7853
/* ========================================================================== */
/* Type definitions */
/* ========================================================================== */
struct __waitlist
{
uint32_t magic;
uint8_t in_use;
pthread_mutex_t op_mtx;
sem_t wait_sem;
struct __waiting_obj *head;
};
struct __waiting_obj
{
DXS_DEVICE_t *pDev;
struct __waiting_obj *next;
};
/* ========================================================================== */
/* Global variables */
/* ========================================================================== */
static struct __waitlist waitlists[DXS_MAX_WAITLISTS] = {{0},};
static struct __waiting_obj wobjects[DXS_MAX_WAITLIST_ELEMENTS] = {{NULL},};
/* ========================================================================== */
/* Function prototypes */
/* ========================================================================== */
/* ========================================================================== */
/* Function implementation */
/* ========================================================================== */
/*
*
* FIXME: current limitation:
* a device can be a member of the one waiting list
*
*/
/**
Function dxs_wl_init
\return
- waiting list instance or NULL
*/
DXS_WaitList_t dxs_wl_init()
{
int i, err;
struct __waitlist *wl;
/* find the next free list */
for (i=0; i<DXS_MAX_WAITLISTS; i++)
{
wl = &waitlists[i];
if (!wl->in_use)
break;
}
if (i == DXS_MAX_WAITLISTS)
{
/* list not found */
return (DXS_WaitList_t)NULL;
}
pthread_mutex_init(&wl->op_mtx, NULL);
err = pthread_mutex_lock (&wl->op_mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
wl->magic = DXS_WAITLIST_MAGIC;
wl->in_use = 1;
wl->head = NULL;
/* initialize wait sem */
sem_init(&wl->wait_sem, 0, 0);
err = pthread_mutex_unlock (&wl->op_mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
return (DXS_WaitList_t)wl;
}
/**
Function dxs_wl_destroy
\param wlist - WaitList
*/
void dxs_wl_destroy(DXS_WaitList_t wlist)
{
struct __waitlist *wl = (struct __waitlist *)wlist;
int err;
if (wl == NULL || wl->magic != DXS_WAITLIST_MAGIC)
return;
err = pthread_mutex_lock (&wl->op_mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
wl->in_use = 0;
wl->magic = 0;
sem_destroy(&wl->wait_sem);
err = pthread_mutex_unlock (&wl->op_mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
err = pthread_mutex_destroy(&wl->op_mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
}
/**
Function dxs_wl_dev_add
\param pDev - pointer to DXS device structure
\param wlist - WaitList
\return
- DXS_status_t
*/
int32_t dxs_wl_dev_add(DXS_DEVICE_t *pDev, DXS_WaitList_t wlist)
{
struct __waitlist *wl = (struct __waitlist *)wlist;
struct __waiting_obj *wo;
int i, err;
if (wl == NULL || wl->magic != DXS_WAITLIST_MAGIC)
{
DXS_RETURN(DXS_statusWaitListObjInv);
}
if (pDev == NULL)
{
DXS_RETURN(DXS_statusInvalidParam);
}
err = pthread_mutex_lock (&wl->op_mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
/* check if pDev was already added to the list */
if (wl->head != NULL)
{
uint8_t found = 0;
struct __waiting_obj *w = wl->head;
while (w != NULL)
{
if (w->pDev == pDev)
{
found = 1;
break;
}
w = w->next;
}
if (found)
{
/* device was already added - not an error */
err = pthread_mutex_unlock (&wl->op_mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
return DXS_statusOk;
}
}
/* get the next free element */
for (i=0; i<DXS_MAX_WAITLIST_ELEMENTS; i++)
{
wo = &wobjects[i];
if (wo->pDev == NULL)
break;
}
if (i == DXS_MAX_WAITLIST_ELEMENTS)
{
/* cannot add a device into the list */
err = pthread_mutex_unlock (&wl->op_mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
DXS_RETURN(DXS_statusWaitListDevAddErr);
}
wo->pDev = pDev;
wo->next = NULL;
/* add to the tail of the list */
if (wl->head == NULL)
{
wl->head = wo;
}
else
{
struct __waiting_obj *w = wl->head;
while (w->next != NULL)
w = w->next;
w->next = wo;
}
/* link pDev with wl
TODO: introduce a list of wl as a device
might be a member of more than one wl */
pDev->wait_list = wlist;
err = pthread_mutex_unlock (&wl->op_mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
return DXS_statusOk;
}
/**
Function dxs_wl_dev_remove
\param pDev - pointer to DXS device structure
\param wlist - WaitList
\return
- int32_t 0 or -1
*/
int32_t dxs_wl_dev_remove(DXS_DEVICE_t *pDev, DXS_WaitList_t wlist)
{
struct __waitlist *wl = (struct __waitlist *)wlist;
struct __waiting_obj *wo, *prev;
int err;
if (wl == NULL || wl->magic != DXS_WAITLIST_MAGIC)
{
DXS_RETURN(DXS_statusWaitListObjInv);
}
if (pDev == NULL)
{
DXS_RETURN(DXS_statusInvalidParam);
}
err = pthread_mutex_lock (&wl->op_mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
wo = wl->head;
prev = NULL;
while (wo != NULL)
{
if (wo->pDev == pDev)
{
if (prev == NULL)
{
wl->head = wo->next;
}
else
{
prev->next = wo->next;
}
wo->pDev = NULL;
wo->next = NULL;
break;
}
prev = wo;
wo = wo->next;
}
err = pthread_mutex_unlock (&wl->op_mtx);
if (err != 0)
DXS_ERROR_PUSH(err);
DXS_RETURN(DXS_statusOk);
}
/**
Function dxs_wait
\param wlist - WaitList
\return
- device number
*/
int32_t dxs_wait(DXS_WaitList_t wlist)
{
struct __waitlist *wl = (struct __waitlist *)wlist;
struct __waiting_obj *wo;
int32_t ret;
if (wl == NULL || wl->magic != DXS_WAITLIST_MAGIC)
{
return -1;
}
if (wl->head == NULL)
{
return -2;
}
wo = wl->head;
while (wo != NULL)
{
FIFO_t *evq = wo->pDev->event_queue;
if (0 < fifo_count (evq))
{
return wo->pDev->nDevNum;
}
wo = wo->next;
}
ret = sem_wait (&wl->wait_sem);
if (ret)
{
return ret;
}
wo = wl->head;
while (wo != NULL)
{
FIFO_t *evq = wo->pDev->event_queue;
if (0 < fifo_count (evq))
{
return wo->pDev->nDevNum;
}
wo = wo->next;
}
/* unreachable */
return 0;
}
/**
Function dxs_wakeup
\param pDev - pointer to DXS device structure
*/
void dxs_wakeup(DXS_DEVICE_t *pDev)
{
struct __waitlist *wl;
if (pDev != NULL && pDev->wait_list != NULL)
{
wl = (struct __waitlist *)pDev->wait_list;
sem_post (&wl->wait_sem);
}
}