Ganesh Ganapathi Batta | ead3cde | 2013-02-05 15:22:31 -0800 | [diff] [blame] | 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" |
Mike J. Chen | 5cd8bff | 2014-01-31 18:16:59 -0800 | [diff] [blame] | 21 | #include "bt_utils.h" |
Ganesh Ganapathi Batta | ead3cde | 2013-02-05 15:22:31 -0800 | [diff] [blame] | 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 |
| 28 | tGAP_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 | ******************************************************************************/ |
| 40 | static 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_EVENT2(" 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_EVENT1(" GAP Discovery Complete Event(SDP Result: 0x%04x)", *((UINT16 *) p_data)); |
| 69 | } |
| 70 | else |
| 71 | { |
| 72 | GAP_TRACE_EVENT0(" 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_EVENT1(" 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 ***/ |
| 97 | void gap_btm_cback0(void *p1) |
| 98 | { |
| 99 | btm_cback(0, p1); |
| 100 | } |
| 101 | |
| 102 | #if GAP_MAX_BLOCKS > 1 |
| 103 | void gap_btm_cback1(void *p1) |
| 104 | { |
| 105 | btm_cback(1, p1); |
| 106 | } |
| 107 | #endif |
| 108 | #if GAP_MAX_BLOCKS > 2 |
| 109 | void 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 */ |
| 116 | void gap_inq_results_cb(tBTM_INQ_RESULTS *p_results, UINT8 *p_eir) |
| 117 | { |
| 118 | tGAP_INFO *p_cb; |
| 119 | UINT8 index; |
Mike J. Chen | 5cd8bff | 2014-01-31 18:16:59 -0800 | [diff] [blame] | 120 | UNUSED(p_eir); |
Ganesh Ganapathi Batta | ead3cde | 2013-02-05 15:22:31 -0800 | [diff] [blame] | 121 | |
| 122 | GAP_TRACE_EVENT6 ("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_EVENT4 (" (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 | *******************************************************************************/ |
| 161 | void 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_EVENT2(" 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, |
Ganesh Ganapathi Batta | 8fe5887 | 2014-04-16 16:50:09 -0700 | [diff] [blame] | 186 | (tBTM_CMPL_CB *) gap_find_addr_name_cb, BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED) |
Ganesh Ganapathi Batta | ead3cde | 2013-02-05 15:22:31 -0800 | [diff] [blame] | 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_EVENT1(" 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 | *******************************************************************************/ |
| 227 | void 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_EVENT2(" 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, |
Ganesh Ganapathi Batta | 8fe5887 | 2014-04-16 16:50:09 -0700 | [diff] [blame] | 249 | (tBTM_CMPL_CB *) gap_find_addr_name_cb, BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED) |
Ganesh Ganapathi Batta | ead3cde | 2013-02-05 15:22:31 -0800 | [diff] [blame] | 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 | *******************************************************************************/ |
| 287 | UINT16 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 |
Mike J. Chen | 5cd8bff | 2014-01-31 18:16:59 -0800 | [diff] [blame] | 310 | UNUSED(devname); |
| 311 | UNUSED(bd_addr); |
Ganesh Ganapathi Batta | ead3cde | 2013-02-05 15:22:31 -0800 | [diff] [blame] | 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 | *******************************************************************************/ |
| 327 | tGAP_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 | *******************************************************************************/ |
| 359 | void 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 | *******************************************************************************/ |
| 381 | BOOLEAN 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 | *******************************************************************************/ |
| 407 | UINT16 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 | } |