blob: e852d20d24b46ad452b81d87ba246a4644691a3c [file] [log] [blame]
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -08001/******************************************************************************
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. Chen5cd8bff2014-01-31 18:16:59 -080021#include "bt_utils.h"
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -080022#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_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 ***/
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;
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800120 UNUSED(p_eir);
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800121
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*******************************************************************************/
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_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 Batta8fe58872014-04-16 16:50:09 -0700186 (tBTM_CMPL_CB *) gap_find_addr_name_cb, BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800187 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*******************************************************************************/
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_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 Batta8fe58872014-04-16 16:50:09 -0700249 (tBTM_CMPL_CB *) gap_find_addr_name_cb, BT_TRANSPORT_BR_EDR)) == BTM_CMD_STARTED)
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800250 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
Mike J. Chen5cd8bff2014-01-31 18:16:59 -0800310 UNUSED(devname);
311 UNUSED(bd_addr);
Ganesh Ganapathi Battaead3cde2013-02-05 15:22:31 -0800312 /* 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}