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 37 static 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 *******************************************************************************/ 52 void 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 *******************************************************************************/ 66 void 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 *******************************************************************************/ 80 void 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 *******************************************************************************/ 95 void 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 *******************************************************************************/ 129 void *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 *******************************************************************************/ 146 void *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 *******************************************************************************/ 183 void *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 *******************************************************************************/ 204 void *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 *******************************************************************************/ 220 void *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 *******************************************************************************/ 266 void 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 *******************************************************************************/ 290 void 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 *******************************************************************************/ 305 void utils_unlock (void) 306 { 307 pthread_mutex_unlock(&utils_mutex); 308 } 309 310