1/******************************************************************************
2 *
3 *  Copyright (C) 2009-2012 Broadcom Corporation
4 *
5 *  Licensed under the Apache License, Version 2.0 (the "License");
6 *  you may not use this file except in compliance with the License.
7 *  You may obtain a copy of the License at:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 *
17 ******************************************************************************/
18
19/******************************************************************************
20 *
21 *  Filename:      utils.c
22 *
23 *  Description:   Contains helper functions
24 *
25 ******************************************************************************/
26
27#include <errno.h>
28#include <pthread.h>
29#include <time.h>
30#include "bt_hci_bdroid.h"
31#include "utils.h"
32
33/******************************************************************************
34**  Static variables
35******************************************************************************/
36
37static pthread_mutex_t utils_mutex;
38
39/*****************************************************************************
40**   UTILS INTERFACE FUNCTIONS
41*****************************************************************************/
42
43/*******************************************************************************
44**
45** Function        utils_init
46**
47** Description     Utils initialization
48**
49** Returns         None
50**
51*******************************************************************************/
52void utils_init (void)
53{
54    pthread_mutex_init(&utils_mutex, NULL);
55}
56
57/*******************************************************************************
58**
59** Function        utils_cleanup
60**
61** Description     Utils cleanup
62**
63** Returns         None
64**
65*******************************************************************************/
66void utils_cleanup (void)
67{
68    pthread_mutex_destroy(&utils_mutex);
69}
70
71/*******************************************************************************
72**
73** Function        utils_queue_init
74**
75** Description     Initialize the given buffer queue
76**
77** Returns         None
78**
79*******************************************************************************/
80void utils_queue_init (BUFFER_Q *p_q)
81{
82    p_q->p_first = p_q->p_last = NULL;
83    p_q->count = 0;
84}
85
86/*******************************************************************************
87**
88** Function        utils_enqueue
89**
90** Description     Enqueue a buffer at the tail of the given queue
91**
92** Returns         None
93**
94*******************************************************************************/
95void utils_enqueue (BUFFER_Q *p_q, void *p_buf)
96{
97    HC_BUFFER_HDR_T    *p_hdr;
98
99    p_hdr = (HC_BUFFER_HDR_T *) ((uint8_t *) p_buf - BT_HC_BUFFER_HDR_SIZE);
100
101    pthread_mutex_lock(&utils_mutex);
102
103    if (p_q->p_last)
104    {
105        HC_BUFFER_HDR_T *p_last_hdr = \
106          (HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_last - BT_HC_BUFFER_HDR_SIZE);
107
108        p_last_hdr->p_next = p_hdr;
109    }
110    else
111        p_q->p_first = p_buf;
112
113    p_q->p_last = p_buf;
114    p_q->count++;
115
116    p_hdr->p_next = NULL;
117
118    pthread_mutex_unlock(&utils_mutex);
119}
120/*******************************************************************************
121**
122** Function        utils_dequeue
123**
124** Description     Dequeues a buffer from the head of the given queue
125**
126** Returns         NULL if queue is empty, else buffer
127**
128*******************************************************************************/
129void *utils_dequeue (BUFFER_Q *p_q)
130{
131    pthread_mutex_lock(&utils_mutex);
132    void* p_buf =  utils_dequeue_unlocked(p_q);
133    pthread_mutex_unlock(&utils_mutex);
134    return p_buf;
135}
136
137/*******************************************************************************
138**
139** Function        utils_dequeue_unlocked
140**
141** Description     Dequeues a buffer from the head of the given queue without lock
142**
143** Returns         NULL if queue is empty, else buffer
144**
145*******************************************************************************/
146void *utils_dequeue_unlocked (BUFFER_Q *p_q)
147{
148    HC_BUFFER_HDR_T    *p_hdr;
149
150
151    if (!p_q || !p_q->count)
152    {
153        return (NULL);
154    }
155
156    p_hdr=(HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_first-BT_HC_BUFFER_HDR_SIZE);
157
158    if (p_hdr->p_next)
159        p_q->p_first = ((uint8_t *)p_hdr->p_next + BT_HC_BUFFER_HDR_SIZE);
160    else
161    {
162        p_q->p_first = NULL;
163        p_q->p_last  = NULL;
164    }
165
166    p_q->count--;
167
168    p_hdr->p_next = NULL;
169    return ((uint8_t *)p_hdr + BT_HC_BUFFER_HDR_SIZE);
170}
171
172/*******************************************************************************
173**
174** Function        utils_getnext
175**
176** Description     Return a pointer to the next buffer linked to the given
177**                 buffer
178**
179** Returns         NULL if the given buffer does not point to any next buffer,
180**                 else next buffer address
181**
182*******************************************************************************/
183void *utils_getnext (void *p_buf)
184{
185    HC_BUFFER_HDR_T    *p_hdr;
186
187    p_hdr = (HC_BUFFER_HDR_T *) ((uint8_t *) p_buf - BT_HC_BUFFER_HDR_SIZE);
188
189    if (p_hdr->p_next)
190        return ((uint8_t *)p_hdr->p_next + BT_HC_BUFFER_HDR_SIZE);
191    else
192        return (NULL);
193}
194
195/*******************************************************************************
196**
197** Function        utils_remove_from_queue
198**
199** Description     Dequeue the given buffer from the middle of the given queue
200**
201** Returns         NULL if the given queue is empty, else the given buffer
202**
203*******************************************************************************/
204void *utils_remove_from_queue (BUFFER_Q *p_q, void *p_buf)
205{
206    pthread_mutex_lock(&utils_mutex);
207    p_buf = utils_remove_from_queue_unlocked(p_q, p_buf);
208    pthread_mutex_unlock(&utils_mutex);
209    return p_buf;
210}
211/*******************************************************************************
212**
213** Function        utils_remove_from_queue_unlocked
214**
215** Description     Dequeue the given buffer from the middle of the given queue
216**
217** Returns         NULL if the given queue is empty, else the given buffer
218**
219*******************************************************************************/
220void *utils_remove_from_queue_unlocked (BUFFER_Q *p_q, void *p_buf)
221{
222    HC_BUFFER_HDR_T    *p_prev;
223    HC_BUFFER_HDR_T    *p_buf_hdr;
224
225
226    if (p_buf == p_q->p_first)
227    {
228        return (utils_dequeue_unlocked (p_q));
229    }
230
231    p_buf_hdr = (HC_BUFFER_HDR_T *)((uint8_t *)p_buf - BT_HC_BUFFER_HDR_SIZE);
232    p_prev=(HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_first-BT_HC_BUFFER_HDR_SIZE);
233
234    for ( ; p_prev; p_prev = p_prev->p_next)
235    {
236        /* If the previous points to this one, move the pointers around */
237        if (p_prev->p_next == p_buf_hdr)
238        {
239            p_prev->p_next = p_buf_hdr->p_next;
240
241            /* If we are removing the last guy in the queue, update p_last */
242            if (p_buf == p_q->p_last)
243                p_q->p_last = p_prev + 1;
244
245            /* One less in the queue */
246            p_q->count--;
247
248            /* The buffer is now unlinked */
249            p_buf_hdr->p_next = NULL;
250
251            return (p_buf);
252        }
253    }
254    return (NULL);
255}
256
257/*******************************************************************************
258**
259** Function        utils_delay
260**
261** Description     sleep unconditionally for timeout milliseconds
262**
263** Returns         None
264**
265*******************************************************************************/
266void utils_delay (uint32_t timeout)
267{
268    struct timespec delay;
269    int err;
270
271    delay.tv_sec = timeout / 1000;
272    delay.tv_nsec = 1000 * 1000 * (timeout%1000);
273
274    /* [u]sleep can't be used because it uses SIGALRM */
275    do {
276        err = nanosleep(&delay, &delay);
277    } while (err < 0 && errno ==EINTR);
278}
279
280/*******************************************************************************
281**
282** Function        utils_lock
283**
284** Description     application calls this function before entering critical
285**                 section
286**
287** Returns         None
288**
289*******************************************************************************/
290void utils_lock (void)
291{
292    pthread_mutex_lock(&utils_mutex);
293}
294
295/*******************************************************************************
296**
297** Function        utils_unlock
298**
299** Description     application calls this function when leaving critical
300**                 section
301**
302** Returns         None
303**
304*******************************************************************************/
305void utils_unlock (void)
306{
307    pthread_mutex_unlock(&utils_mutex);
308}
309
310