blob: bfcf72481e18a579cb0a91df0350ae6686af00cf [file] [log] [blame]
/******************************************************************************
*
* Copyright (C) 2009-2012 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/******************************************************************************
*
* Filename: utils.c
*
* Description: Contains helper functions
*
******************************************************************************/
#include <errno.h>
#include <pthread.h>
#include <time.h>
#include "bt_hci_bdroid.h"
#include "utils.h"
/******************************************************************************
** Static variables
******************************************************************************/
static pthread_mutex_t utils_mutex;
/*****************************************************************************
** UTILS INTERFACE FUNCTIONS
*****************************************************************************/
/*******************************************************************************
**
** Function utils_init
**
** Description Utils initialization
**
** Returns None
**
*******************************************************************************/
void utils_init (void)
{
pthread_mutex_init(&utils_mutex, NULL);
}
/*******************************************************************************
**
** Function utils_cleanup
**
** Description Utils cleanup
**
** Returns None
**
*******************************************************************************/
void utils_cleanup (void)
{
}
/*******************************************************************************
**
** Function utils_queue_init
**
** Description Initialize the given buffer queue
**
** Returns None
**
*******************************************************************************/
void utils_queue_init (BUFFER_Q *p_q)
{
p_q->p_first = p_q->p_last = NULL;
p_q->count = 0;
}
/*******************************************************************************
**
** Function utils_enqueue
**
** Description Enqueue a buffer at the tail of the given queue
**
** Returns None
**
*******************************************************************************/
void utils_enqueue (BUFFER_Q *p_q, void *p_buf)
{
HC_BUFFER_HDR_T *p_hdr;
p_hdr = (HC_BUFFER_HDR_T *) ((uint8_t *) p_buf - BT_HC_BUFFER_HDR_SIZE);
pthread_mutex_lock(&utils_mutex);
if (p_q->p_last)
{
HC_BUFFER_HDR_T *p_last_hdr = \
(HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_last - BT_HC_BUFFER_HDR_SIZE);
p_last_hdr->p_next = p_hdr;
}
else
p_q->p_first = p_buf;
p_q->p_last = p_buf;
p_q->count++;
p_hdr->p_next = NULL;
pthread_mutex_unlock(&utils_mutex);
}
/*******************************************************************************
**
** Function utils_dequeue
**
** Description Dequeues a buffer from the head of the given queue
**
** Returns NULL if queue is empty, else buffer
**
*******************************************************************************/
void *utils_dequeue (BUFFER_Q *p_q)
{
pthread_mutex_lock(&utils_mutex);
void* p_buf = utils_dequeue_unlocked(p_q);
pthread_mutex_unlock(&utils_mutex);
return p_buf;
}
/*******************************************************************************
**
** Function utils_dequeue_unlocked
**
** Description Dequeues a buffer from the head of the given queue without lock
**
** Returns NULL if queue is empty, else buffer
**
*******************************************************************************/
void *utils_dequeue_unlocked (BUFFER_Q *p_q)
{
HC_BUFFER_HDR_T *p_hdr;
if (!p_q || !p_q->count)
{
return (NULL);
}
p_hdr=(HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_first-BT_HC_BUFFER_HDR_SIZE);
if (p_hdr->p_next)
p_q->p_first = ((uint8_t *)p_hdr->p_next + BT_HC_BUFFER_HDR_SIZE);
else
{
p_q->p_first = NULL;
p_q->p_last = NULL;
}
p_q->count--;
p_hdr->p_next = NULL;
return ((uint8_t *)p_hdr + BT_HC_BUFFER_HDR_SIZE);
}
/*******************************************************************************
**
** Function utils_getnext
**
** Description Return a pointer to the next buffer linked to the given
** buffer
**
** Returns NULL if the given buffer does not point to any next buffer,
** else next buffer address
**
*******************************************************************************/
void *utils_getnext (void *p_buf)
{
HC_BUFFER_HDR_T *p_hdr;
p_hdr = (HC_BUFFER_HDR_T *) ((uint8_t *) p_buf - BT_HC_BUFFER_HDR_SIZE);
if (p_hdr->p_next)
return ((uint8_t *)p_hdr->p_next + BT_HC_BUFFER_HDR_SIZE);
else
return (NULL);
}
/*******************************************************************************
**
** Function utils_remove_from_queue
**
** Description Dequeue the given buffer from the middle of the given queue
**
** Returns NULL if the given queue is empty, else the given buffer
**
*******************************************************************************/
void *utils_remove_from_queue (BUFFER_Q *p_q, void *p_buf)
{
pthread_mutex_lock(&utils_mutex);
p_buf = utils_remove_from_queue_unlocked(p_q, p_buf);
pthread_mutex_unlock(&utils_mutex);
return p_buf;
}
/*******************************************************************************
**
** Function utils_remove_from_queue_unlocked
**
** Description Dequeue the given buffer from the middle of the given queue
**
** Returns NULL if the given queue is empty, else the given buffer
**
*******************************************************************************/
void *utils_remove_from_queue_unlocked (BUFFER_Q *p_q, void *p_buf)
{
HC_BUFFER_HDR_T *p_prev;
HC_BUFFER_HDR_T *p_buf_hdr;
if (p_buf == p_q->p_first)
{
return (utils_dequeue_unlocked (p_q));
}
p_buf_hdr = (HC_BUFFER_HDR_T *)((uint8_t *)p_buf - BT_HC_BUFFER_HDR_SIZE);
p_prev=(HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_first-BT_HC_BUFFER_HDR_SIZE);
for ( ; p_prev; p_prev = p_prev->p_next)
{
/* If the previous points to this one, move the pointers around */
if (p_prev->p_next == p_buf_hdr)
{
p_prev->p_next = p_buf_hdr->p_next;
/* If we are removing the last guy in the queue, update p_last */
if (p_buf == p_q->p_last)
p_q->p_last = p_prev + 1;
/* One less in the queue */
p_q->count--;
/* The buffer is now unlinked */
p_buf_hdr->p_next = NULL;
return (p_buf);
}
}
return (NULL);
}
/*******************************************************************************
**
** Function utils_delay
**
** Description sleep unconditionally for timeout milliseconds
**
** Returns None
**
*******************************************************************************/
void utils_delay (uint32_t timeout)
{
struct timespec delay;
int err;
delay.tv_sec = timeout / 1000;
delay.tv_nsec = 1000 * 1000 * (timeout%1000);
/* [u]sleep can't be used because it uses SIGALRM */
do {
err = nanosleep(&delay, &delay);
} while (err < 0 && errno ==EINTR);
}
/*******************************************************************************
**
** Function utils_lock
**
** Description application calls this function before entering critical
** section
**
** Returns None
**
*******************************************************************************/
void utils_lock (void)
{
pthread_mutex_lock(&utils_mutex);
}
/*******************************************************************************
**
** Function utils_unlock
**
** Description application calls this function when leaving critical
** section
**
** Returns None
**
*******************************************************************************/
void utils_unlock (void)
{
pthread_mutex_unlock(&utils_mutex);
}