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 27tGAP_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******************************************************************************/ 39static 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 ***/ 96void gap_btm_cback0(void *p1) 97{ 98 btm_cback(0, p1); 99} 100 101#if GAP_MAX_BLOCKS > 1 102void gap_btm_cback1(void *p1) 103{ 104 btm_cback(1, p1); 105} 106#endif 107#if GAP_MAX_BLOCKS > 2 108void 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 */ 115void 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*******************************************************************************/ 159void 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*******************************************************************************/ 225void 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*******************************************************************************/ 285UINT16 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*******************************************************************************/ 323tGAP_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*******************************************************************************/ 355void 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*******************************************************************************/ 377BOOLEAN 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*******************************************************************************/ 403UINT16 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