1 /****************************************************************************** 2 * 3 * Copyright (C) 2009-2013 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 #include <string.h> 20 #include "bt_target.h" 21 #include "gap_int.h" 22 23 /*****************************************************************************/ 24 /* G L O B A L GAP D A T A */ 25 /*****************************************************************************/ 26 #if GAP_DYNAMIC_MEMORY == FALSE 27 tGAP_CB gap_cb; 28 #endif 29 30 /***************************************************************************** 31 ** Callbacks passed to BTM - 32 ** There are different callbacks based on the control block index so that 33 ** more than one command can be pending at a time. 34 ** NOTE: There must be 1 callback for each control block defined 35 ** GAP_MAX_BLOCKS 36 ** 37 ** Also, the inquiry results event has its own callback; Not handled here! 38 ******************************************************************************/ 39 static void btm_cback(UINT16 index, void *p_data) 40 { 41 tGAP_INFO *p_cb; 42 tGAP_INQ_CMPL inq_cmpl; 43 44 /* Make sure that the index is valid AND it is in use */ 45 if (index < GAP_MAX_BLOCKS && gap_cb.blk[index].in_use) 46 { 47 p_cb = &gap_cb.blk[index]; 48 49 /* If the callback is non-NULL, call it with the specified event */ 50 switch (p_cb->event) 51 { 52 case GAP_EVT_INQUIRY_COMPLETE: 53 /* pass the number of results to caller */ 54 inq_cmpl.num_results = ((tBTM_INQUIRY_CMPL *)p_data)->num_resp; 55 56 inq_cmpl.status = (((tBTM_INQUIRY_CMPL *)p_data)->status == BTM_SUCCESS) ? BT_PASS : GAP_ERR_PROCESSING; 57 58 p_data = &inq_cmpl; 59 60 GAP_TRACE_EVENT2(" GAP Inquiry Complete Event (Status 0x%04x, Result(s) %d)", 61 inq_cmpl.status, inq_cmpl.num_results); 62 break; 63 64 case GAP_EVT_DISCOVERY_COMPLETE: 65 if (*((UINT16 *) p_data)) 66 { 67 GAP_TRACE_EVENT1(" GAP Discovery Complete Event(SDP Result: 0x%04x)", *((UINT16 *) p_data)); 68 } 69 else 70 { 71 GAP_TRACE_EVENT0(" GAP Discovery Successfully Completed"); 72 } 73 74 break; 75 76 case GAP_EVT_REM_NAME_COMPLETE: 77 /* override the BTM error code with a GAP error code */ 78 ((tGAP_REMOTE_DEV_NAME *)p_data)->status = 79 gap_convert_btm_status ((tBTM_STATUS)((tBTM_REMOTE_DEV_NAME *)p_data)->status); 80 81 GAP_TRACE_EVENT1(" GAP Remote Name Complete Event (status 0x%04x)", ((tGAP_REMOTE_DEV_NAME *)p_data)->status); 82 83 break; 84 }; 85 86 if (p_cb->gap_cback) 87 p_cb->gap_cback(p_cb->event, p_data); 88 89 /* Deallocate the control block */ 90 gap_free_cb(p_cb); 91 } 92 } 93 94 95 /*** Callback functions for BTM_CMPL_CB ***/ 96 void gap_btm_cback0(void *p1) 97 { 98 btm_cback(0, p1); 99 } 100 101 #if GAP_MAX_BLOCKS > 1 102 void gap_btm_cback1(void *p1) 103 { 104 btm_cback(1, p1); 105 } 106 #endif 107 #if GAP_MAX_BLOCKS > 2 108 void gap_btm_cback2(void *p1) 109 { 110 btm_cback(2, p1); 111 } 112 #endif 113 114 /* There is only one instance of this because only 1 inquiry can be active at a time */ 115 void gap_inq_results_cb(tBTM_INQ_RESULTS *p_results, UINT8 *p_eir) 116 { 117 tGAP_INFO *p_cb; 118 UINT8 index; 119 120 GAP_TRACE_EVENT6 ("GAP Inquiry Results Callback (bdaddr [%02x%02x%02x%02x%02x%02x])", 121 p_results->remote_bd_addr[0], p_results->remote_bd_addr[1], 122 p_results->remote_bd_addr[2], p_results->remote_bd_addr[3], 123 p_results->remote_bd_addr[4], p_results->remote_bd_addr[5]); 124 GAP_TRACE_EVENT4 (" (COD [%02x%02x%02x], clkoff 0x%04x)", 125 p_results->dev_class[0], p_results->dev_class[1], p_results->dev_class[2], 126 p_results->clock_offset); 127 128 /* Find the control block which has an Inquiry Active and call its results callback */ 129 for (index = 0, p_cb = &gap_cb.blk[0]; index < GAP_MAX_BLOCKS; index++, p_cb++) 130 { 131 /* Look for the control block that is using inquiry */ 132 if (p_cb->in_use && (p_cb->event == GAP_EVT_INQUIRY_COMPLETE)) 133 { 134 /* Notify the higher layer if they care */ 135 if (p_cb->gap_inq_rslt_cback) 136 p_cb->gap_inq_rslt_cback (GAP_EVT_INQUIRY_RESULTS, (tGAP_INQ_RESULTS *)p_results); 137 } 138 } 139 } 140 141 142 /******************************************************************************* 143 ** 144 ** Function gap_find_addr_name_cb 145 ** 146 ** Description Processes the remote name request event when the Find Addr by Name 147 ** request is active. The following procedure takes place: 148 ** 1. Check the resulting name (If return status is ok) 149 ** 2. If name matches requested name, we're done, call the appl's callback 150 ** with the BD ADDR. 151 ** 3. Otherwise get the next BD ADDR out of the inquiry database and intiate 152 ** another remote name request. 153 ** 4. If there are no more BD ADDRs, then call the appl's callback with a FAIL 154 ** status. 155 ** 156 ** Returns void 157 ** 158 *******************************************************************************/ 159 void gap_find_addr_name_cb (tBTM_REMOTE_DEV_NAME *p) 160 { 161 tGAP_FINDADDR_CB *p_cb = &gap_cb.findaddr_cb; 162 tGAP_FINDADDR_RESULTS *p_result = &p_cb->results; 163 164 if (p_cb->in_use) 165 { 166 if (p->status == BTM_SUCCESS) 167 { 168 GAP_TRACE_EVENT2(" GAP: FindAddrByName Rem Name Cmpl Evt (Status 0x%04x, Name [%s])", 169 p->status, p->remote_bd_name); 170 171 /* See if the returned name matches the desired name; if not initiate another search */ 172 if (!strncmp ((char *)p_result->devname, (char *) p->remote_bd_name, strlen ((char *) p_result->devname))) 173 { 174 /* We found the device! Copy it into the return structure */ 175 memcpy (p_result->bd_addr, p_cb->p_cur_inq->results.remote_bd_addr, BD_ADDR_LEN); 176 p_result->status = BT_PASS; 177 } 178 else /* The name doesn't match so initiate another search */ 179 { 180 /* Get the device address of the next database entry */ 181 if ((p_cb->p_cur_inq = BTM_InqDbNext(p_cb->p_cur_inq)) != NULL) 182 { 183 if ((BTM_ReadRemoteDeviceName (p_cb->p_cur_inq->results.remote_bd_addr, 184 (tBTM_CMPL_CB *) gap_find_addr_name_cb)) == BTM_CMD_STARTED) 185 return; /* This routine will get called again with the next results */ 186 else 187 p_result->status = gap_convert_btm_status ((tBTM_STATUS) p->status); 188 } 189 else 190 p_result->status = GAP_EOINQDB; /* No inquiry results; we're done! */ 191 } 192 } 193 else 194 { 195 GAP_TRACE_EVENT1(" GAP: FindAddrByName Rem Name Cmpl Evt (Status 0x%04x)", p->status); 196 p_result->status = gap_convert_btm_status ((tBTM_STATUS) p->status); 197 } 198 199 /* If this code is reached, the process has completed so call the appl's callback with results */ 200 if (p_cb->p_cback) 201 p_cb->p_cback (GAP_EVT_FIND_ADDR_COMPLETE, (tGAP_FINDADDR_RESULTS *) p_result); 202 203 /* Clear out the control block */ 204 p_cb->in_use = FALSE; 205 p_cb->p_cback = (tGAP_CALLBACK *) NULL; 206 } 207 } 208 209 /******************************************************************************* 210 ** 211 ** Function gap_find_addr_inq_cb 212 ** 213 ** Description Processes the inquiry complete event when the Find Addr by Name 214 ** request is active. This callback performs one of the two following 215 ** steps: 216 ** 1. If the remote name is retrieved automatically, the DB is searched 217 ** immediately, and the results are returned in the appls callback. 218 ** 219 ** 2. If remote name is not automatic, retrieve the first BTM INQ 220 ** database entry and initiate a remote name request. 221 ** 222 ** Returns void 223 ** 224 *******************************************************************************/ 225 void gap_find_addr_inq_cb (tBTM_INQUIRY_CMPL *p) 226 { 227 tGAP_FINDADDR_CB *p_cb = &gap_cb.findaddr_cb; 228 tGAP_FINDADDR_RESULTS *p_result = &p_cb->results; 229 230 if (p_cb->in_use) 231 { 232 233 GAP_TRACE_EVENT2(" GAP: FindAddrByName Inq Cmpl Evt (Status 0x%04x, Result(s) %d)", 234 p->status, p->num_resp); 235 236 if (p->status == BTM_SUCCESS) 237 { 238 /* Step 1: If automatically retrieving remote names then search the local database */ 239 if ((p_result->status = gap_find_local_addr_by_name (p_result->devname, p_result->bd_addr)) == GAP_NO_DATA_AVAIL) 240 { 241 /* Step 2: The name is not stored automatically, so a search of all devices needs to 242 * be initiated. 243 */ 244 if ((p_cb->p_cur_inq = BTM_InqDbFirst()) != NULL) 245 { 246 if ((BTM_ReadRemoteDeviceName (p_cb->p_cur_inq->results.remote_bd_addr, 247 (tBTM_CMPL_CB *) gap_find_addr_name_cb)) == BTM_CMD_STARTED) 248 return; /* Wait for the response in gap_find_addr_name_cb() */ 249 else 250 p_result->status = gap_convert_btm_status (p->status); 251 } 252 else 253 p_result->status = GAP_EOINQDB; /* No inquiry results; we're done! */ 254 } 255 } 256 else 257 p_result->status = gap_convert_btm_status (p->status); 258 259 /* If this code is reached, the process has completed so call the appl's callback with results */ 260 if (p_cb->p_cback) 261 p_cb->p_cback (GAP_EVT_FIND_ADDR_COMPLETE, (tGAP_FINDADDR_RESULTS *) p_result); 262 263 /* Clear out the control block */ 264 p_cb->in_use = FALSE; 265 p_cb->p_cback = (tGAP_CALLBACK *) NULL; 266 } 267 } 268 269 /******************************************************************************* 270 ** 271 ** Function gap_find_local_addr_by_name 272 ** 273 ** Description Searches through the internal inquiry database for a device 274 ** that has the same name as the one passed in. If found, the 275 ** device address is filled in. 276 ** 277 ** NOTE: It only searches up to the first BTM_MAX_REM_BD_NAME_LEN 278 ** bytes because the inquiry database uses tBTM_BD_NAME. 279 ** 280 ** Returns BT_PASS if the name was found and the device address is filled in 281 ** GAP_EOINQDB if the name was not found in the database 282 ** GAP_NO_DATA_AVAIL if the name is not saved with the inquiry 283 ** 284 *******************************************************************************/ 285 UINT16 gap_find_local_addr_by_name (const tBTM_BD_NAME devname, BD_ADDR bd_addr) 286 { 287 288 /* If the remote name is retrieved automatically during an inquiry search the local db */ 289 #if (BTM_INQ_GET_REMOTE_NAME == TRUE) 290 tBTM_INQ_INFO *p_result; 291 292 p_result = BTM_InqDbFirst(); 293 294 while (p_result) 295 { 296 /* Check the entry for a device name match */ 297 if (!strncmp ((char *)devname, (char *)p_result->remote_name, BTM_MAX_REM_BD_NAME_LEN)) 298 { 299 memcpy (bd_addr, p_result->results.remote_bd_addr, BD_ADDR_LEN); 300 return (BT_PASS); 301 } 302 else 303 p_result = BTM_InqDbNext(p_result); 304 }; 305 306 return (GAP_EOINQDB); 307 #else 308 /* No data available because we are not automatically saving the data */ 309 return (GAP_NO_DATA_AVAIL); 310 #endif 311 } 312 313 314 /******************************************************************************* 315 ** 316 ** Function gap_allocate_cb 317 ** 318 ** Description Look through the GAP Control Blocks for a free one. 319 ** 320 ** Returns Pointer to the control block or NULL if not found 321 ** 322 *******************************************************************************/ 323 tGAP_INFO *gap_allocate_cb (void) 324 { 325 tGAP_INFO *p_cb = &gap_cb.blk[0]; 326 UINT8 x; 327 328 for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) 329 { 330 if (!p_cb->in_use) 331 { 332 memset (p_cb, 0, sizeof (tGAP_INFO)); 333 334 p_cb->in_use = TRUE; 335 p_cb->index = x; 336 p_cb->p_data = (void *)NULL; 337 return (p_cb); 338 } 339 } 340 341 /* If here, no free control blocks found */ 342 return (NULL); 343 } 344 345 346 /******************************************************************************* 347 ** 348 ** Function gap_free_cb 349 ** 350 ** Description Release GAP control block. 351 ** 352 ** Returns Pointer to the control block or NULL if not found 353 ** 354 *******************************************************************************/ 355 void gap_free_cb (tGAP_INFO *p_cb) 356 { 357 if (p_cb) 358 { 359 p_cb->gap_cback = NULL; 360 p_cb->in_use = FALSE; 361 } 362 } 363 364 365 /******************************************************************************* 366 ** 367 ** Function gap_is_service_busy 368 ** 369 ** Description Look through the GAP Control Blocks that are in use 370 ** and check to see if the event waiting for is the command 371 ** requested. 372 ** 373 ** Returns TRUE if already in use 374 ** FALSE if not busy 375 ** 376 *******************************************************************************/ 377 BOOLEAN gap_is_service_busy (UINT16 request) 378 { 379 tGAP_INFO *p_cb = &gap_cb.blk[0]; 380 UINT8 x; 381 382 for (x = 0; x < GAP_MAX_BLOCKS; x++, p_cb++) 383 { 384 if (p_cb->in_use && p_cb->event == request) 385 return (TRUE); 386 } 387 388 /* If here, service is not busy */ 389 return (FALSE); 390 } 391 392 393 /******************************************************************************* 394 ** 395 ** Function gap_convert_btm_status 396 ** 397 ** Description Converts a BTM error status into a GAP error status 398 ** 399 ** 400 ** Returns GAP_UNKNOWN_BTM_STATUS is returned if not recognized 401 ** 402 *******************************************************************************/ 403 UINT16 gap_convert_btm_status (tBTM_STATUS btm_status) 404 { 405 switch (btm_status) 406 { 407 case BTM_SUCCESS: 408 return (BT_PASS); 409 410 case BTM_CMD_STARTED: 411 return (GAP_CMD_INITIATED); 412 413 case BTM_BUSY: 414 return (GAP_ERR_BUSY); 415 416 case BTM_MODE_UNSUPPORTED: 417 case BTM_ILLEGAL_VALUE: 418 return (GAP_ERR_ILL_PARM); 419 420 case BTM_WRONG_MODE: 421 return (GAP_DEVICE_NOT_UP); 422 423 case BTM_UNKNOWN_ADDR: 424 return (GAP_BAD_BD_ADDR); 425 426 case BTM_DEVICE_TIMEOUT: 427 return (GAP_ERR_TIMEOUT); 428 429 default: 430 return (GAP_ERR_PROCESSING); 431 } 432 } 433