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