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