1 /* hfp_hf.c - Hands free Profile - Handsfree side handling */
2 
3 /*
4  * Copyright (c) 2015-2016 Intel Corporation
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 #include <ble_os.h>
9 #include <bt_errno.h>
10 #include <atomic.h>
11 #include <misc/byteorder.h>
12 #include <misc/util.h>
13 #include <misc/printk.h>
14 #ifdef CONFIG_BT_HFP_HF
15 #include <bluetooth/conn.h>
16 
17 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HFP_HF)
18 #define LOG_MODULE_NAME bt_hfp_hf
19 /* FIXME: #include "common/log.h" */
20 #include <bluetooth/rfcomm.h>
21 #include <bluetooth/hfp_hf.h>
22 
23 #include "hci_core.h"
24 #include "conn_internal.h"
25 #include "l2cap_internal.h"
26 #include "rfcomm_internal.h"
27 #include "at.h"
28 #include "hfp_internal.h"
29 
30 #define MAX_IND_STR_LEN 17
31 
32 struct bt_hfp_hf_cb *bt_hf;
33 
34 NET_BUF_POOL_FIXED_DEFINE(hf_pool, CONFIG_BT_MAX_CONN + 1,
35 			  BT_RFCOMM_BUF_SIZE(BT_HF_CLIENT_MAX_PDU), NULL);
36 
37 static struct bt_hfp_hf bt_hfp_hf_pool[CONFIG_BT_MAX_CONN];
38 
39 /* The order should follow the enum hfp_hf_ag_indicators */
40 static const struct {
41 	char *name;
42 	bt_u32_t min;
43 	bt_u32_t max;
44 } ag_ind[] = {
45 	{"service", 0, 1}, /* HF_SERVICE_IND */
46 	{"call", 0, 1}, /* HF_CALL_IND */
47 	{"callsetup", 0, 3}, /* HF_CALL_SETUP_IND */
48 	{"callheld", 0, 2}, /* HF_CALL_HELD_IND */
49 	{"signal", 0, 5}, /* HF_SINGNAL_IND */
50 	{"roam", 0, 1}, /* HF_ROAM_IND */
51 	{"battchg", 0, 5} /* HF_BATTERY_IND */
52 };
53 
hf_slc_error(struct at_client * hf_at)54 void hf_slc_error(struct at_client *hf_at)
55 {
56 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
57 	int err;
58 
59 	BT_ERR("SLC error: disconnecting");
60 	err = bt_rfcomm_dlc_disconnect(&hf->rfcomm_dlc);
61 	if (err) {
62 		BT_ERR("Rfcomm: Unable to disconnect :%d", -err);
63 	}
64 }
65 
hfp_hf_send_cmd(struct bt_hfp_hf * hf,at_resp_cb_t resp,at_finish_cb_t finish,const char * format,...)66 int hfp_hf_send_cmd(struct bt_hfp_hf *hf, at_resp_cb_t resp,
67 		    at_finish_cb_t finish, const char *format, ...)
68 {
69 	struct net_buf *buf;
70 	va_list vargs;
71 	int ret;
72 
73 	/* register the callbacks */
74 	at_register(&hf->at, resp, finish);
75 
76 	buf = bt_rfcomm_create_pdu(&hf_pool);
77 	if (!buf) {
78 		BT_ERR("No Buffers!");
79 		return -ENOMEM;
80 	}
81 
82 	va_start(vargs, format);
83 	ret = vsnprintk(buf->data, (net_buf_tailroom(buf) - 1), format, vargs);
84 	if (ret < 0) {
85 		BT_ERR("Unable to format variable arguments");
86 		return ret;
87 	}
88 	va_end(vargs);
89 
90 	net_buf_add(buf, ret);
91 	net_buf_add_u8(buf, '\r');
92 
93 	ret = bt_rfcomm_dlc_send(&hf->rfcomm_dlc, buf);
94 	if (ret < 0) {
95 		BT_ERR("Rfcomm send error :(%d)", ret);
96 		return ret;
97 	}
98 
99 	return 0;
100 }
101 
brsf_handle(struct at_client * hf_at)102 int brsf_handle(struct at_client *hf_at)
103 {
104 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
105 	bt_u32_t val;
106 	int ret;
107 
108 	ret = at_get_number(hf_at, &val);
109 	if (ret < 0) {
110 		BT_ERR("Error getting value");
111 		return ret;
112 	}
113 
114 	hf->ag_features = val;
115 
116 	return 0;
117 }
118 
brsf_resp(struct at_client * hf_at,struct net_buf * buf)119 int brsf_resp(struct at_client *hf_at, struct net_buf *buf)
120 {
121 	int err;
122 
123 	BT_DBG("");
124 
125 	err = at_parse_cmd_input(hf_at, buf, "BRSF", brsf_handle,
126 				 AT_CMD_TYPE_NORMAL);
127 	if (err < 0) {
128 		/* Returning negative value is avoided before SLC connection
129 		 * established.
130 		 */
131 		BT_ERR("Error parsing CMD input");
132 		hf_slc_error(hf_at);
133 	}
134 
135 	return 0;
136 }
137 
cind_handle_values(struct at_client * hf_at,bt_u32_t index,char * name,bt_u32_t min,bt_u32_t max)138 static void cind_handle_values(struct at_client *hf_at, bt_u32_t index,
139 			       char *name, bt_u32_t min, bt_u32_t max)
140 {
141 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
142 	int i;
143 
144 	BT_DBG("index: %u, name: %s, min: %u, max:%u", index, name, min, max);
145 
146 	for (i = 0; i < ARRAY_SIZE(ag_ind); i++) {
147 		if (strcmp(name, ag_ind[i].name) != 0) {
148 			continue;
149 		}
150 		if (min != ag_ind[i].min || max != ag_ind[i].max) {
151 			BT_ERR("%s indicator min/max value not matching", name);
152 		}
153 
154 		hf->ind_table[index] = i;
155 		break;
156 	}
157 }
158 
cind_handle(struct at_client * hf_at)159 int cind_handle(struct at_client *hf_at)
160 {
161 	bt_u32_t index = 0U;
162 
163 	/* Parsing Example: CIND: ("call",(0,1)) etc.. */
164 	while (at_has_next_list(hf_at)) {
165 		char name[MAX_IND_STR_LEN];
166 		bt_u32_t min, max;
167 
168 		if (at_open_list(hf_at) < 0) {
169 			BT_ERR("Could not get open list");
170 			goto error;
171 		}
172 
173 		if (at_list_get_string(hf_at, name, sizeof(name)) < 0) {
174 			BT_ERR("Could not get string");
175 			goto error;
176 		}
177 
178 		if (at_open_list(hf_at) < 0) {
179 			BT_ERR("Could not get open list");
180 			goto error;
181 		}
182 
183 		if (at_list_get_range(hf_at, &min, &max) < 0) {
184 			BT_ERR("Could not get range");
185 			goto error;
186 		}
187 
188 		if (at_close_list(hf_at) < 0) {
189 			BT_ERR("Could not get close list");
190 			goto error;
191 		}
192 
193 		if (at_close_list(hf_at) < 0) {
194 			BT_ERR("Could not get close list");
195 			goto error;
196 		}
197 
198 		cind_handle_values(hf_at, index, name, min, max);
199 		index++;
200 	}
201 
202 	return 0;
203 error:
204 	BT_ERR("Error on CIND response");
205 	hf_slc_error(hf_at);
206 	return -EINVAL;
207 }
208 
cind_resp(struct at_client * hf_at,struct net_buf * buf)209 int cind_resp(struct at_client *hf_at, struct net_buf *buf)
210 {
211 	int err;
212 
213 	err = at_parse_cmd_input(hf_at, buf, "CIND", cind_handle,
214 				 AT_CMD_TYPE_NORMAL);
215 	if (err < 0) {
216 		BT_ERR("Error parsing CMD input");
217 		hf_slc_error(hf_at);
218 	}
219 
220 	return 0;
221 }
222 
ag_indicator_handle_values(struct at_client * hf_at,bt_u32_t index,bt_u32_t value)223 void ag_indicator_handle_values(struct at_client *hf_at, bt_u32_t index,
224 				bt_u32_t value)
225 {
226 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
227 	struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
228 
229 	BT_DBG("Index :%u, Value :%u", index, value);
230 
231 	if (index >= ARRAY_SIZE(ag_ind)) {
232 		BT_ERR("Max only %lu indicators are supported",
233 		       ARRAY_SIZE(ag_ind));
234 		return;
235 	}
236 
237 	if (value > ag_ind[hf->ind_table[index]].max ||
238 	    value < ag_ind[hf->ind_table[index]].min) {
239 		BT_ERR("Indicators out of range - value: %u", value);
240 		return;
241 	}
242 
243 	switch (hf->ind_table[index]) {
244 	case HF_SERVICE_IND:
245 		if (bt_hf->service) {
246 			bt_hf->service(conn, value);
247 		}
248 		break;
249 	case HF_CALL_IND:
250 		if (bt_hf->call) {
251 			bt_hf->call(conn, value);
252 		}
253 		break;
254 	case HF_CALL_SETUP_IND:
255 		if (bt_hf->call_setup) {
256 			bt_hf->call_setup(conn, value);
257 		}
258 		break;
259 	case HF_CALL_HELD_IND:
260 		if (bt_hf->call_held) {
261 			bt_hf->call_held(conn, value);
262 		}
263 		break;
264 	case HF_SINGNAL_IND:
265 		if (bt_hf->signal) {
266 			bt_hf->signal(conn, value);
267 		}
268 		break;
269 	case HF_ROAM_IND:
270 		if (bt_hf->roam) {
271 			bt_hf->roam(conn, value);
272 		}
273 		break;
274 	case HF_BATTERY_IND:
275 		if (bt_hf->battery) {
276 			bt_hf->battery(conn, value);
277 		}
278 		break;
279 	default:
280 		BT_ERR("Unknown AG indicator");
281 		break;
282 	}
283 }
284 
cind_status_handle(struct at_client * hf_at)285 int cind_status_handle(struct at_client *hf_at)
286 {
287 	bt_u32_t index = 0U;
288 
289 	while (at_has_next_list(hf_at)) {
290 		bt_u32_t value;
291 		int ret;
292 
293 		ret = at_get_number(hf_at, &value);
294 		if (ret < 0) {
295 			BT_ERR("could not get the value");
296 			return ret;
297 		}
298 
299 		ag_indicator_handle_values(hf_at, index, value);
300 
301 		index++;
302 	}
303 
304 	return 0;
305 }
306 
cind_status_resp(struct at_client * hf_at,struct net_buf * buf)307 int cind_status_resp(struct at_client *hf_at, struct net_buf *buf)
308 {
309 	int err;
310 
311 	err = at_parse_cmd_input(hf_at, buf, "CIND", cind_status_handle,
312 				 AT_CMD_TYPE_NORMAL);
313 	if (err < 0) {
314 		BT_ERR("Error parsing CMD input");
315 		hf_slc_error(hf_at);
316 	}
317 
318 	return 0;
319 }
320 
ciev_handle(struct at_client * hf_at)321 int ciev_handle(struct at_client *hf_at)
322 {
323 	bt_u32_t index, value;
324 	int ret;
325 
326 	ret = at_get_number(hf_at, &index);
327 	if (ret < 0) {
328 		BT_ERR("could not get the Index");
329 		return ret;
330 	}
331 	/* The first element of the list shall have 1 */
332 	if (!index) {
333 		BT_ERR("Invalid index value '0'");
334 		return 0;
335 	}
336 
337 	ret = at_get_number(hf_at, &value);
338 	if (ret < 0) {
339 		BT_ERR("could not get the value");
340 		return ret;
341 	}
342 
343 	ag_indicator_handle_values(hf_at, (index - 1), value);
344 
345 	return 0;
346 }
347 
ring_handle(struct at_client * hf_at)348 int ring_handle(struct at_client *hf_at)
349 {
350 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
351 	struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
352 
353 	if (bt_hf->ring_indication) {
354 		bt_hf->ring_indication(conn);
355 	}
356 
357 	return 0;
358 }
359 
360 static const struct unsolicited {
361 	const char *cmd;
362 	enum at_cmd_type type;
363 	int (*func)(struct at_client *hf_at);
364 } handlers[] = {
365 	{ "CIEV", AT_CMD_TYPE_UNSOLICITED, ciev_handle },
366 	{ "RING", AT_CMD_TYPE_OTHER, ring_handle }
367 };
368 
hfp_hf_unsol_lookup(struct at_client * hf_at)369 static const struct unsolicited *hfp_hf_unsol_lookup(struct at_client *hf_at)
370 {
371 	int i;
372 
373 	for (i = 0; i < ARRAY_SIZE(handlers); i++) {
374 		if (!strncmp(hf_at->buf, handlers[i].cmd,
375 			     strlen(handlers[i].cmd))) {
376 			return &handlers[i];
377 		}
378 	}
379 
380 	return NULL;
381 }
382 
unsolicited_cb(struct at_client * hf_at,struct net_buf * buf)383 int unsolicited_cb(struct at_client *hf_at, struct net_buf *buf)
384 {
385 	const struct unsolicited *handler;
386 
387 	handler = hfp_hf_unsol_lookup(hf_at);
388 	if (!handler) {
389 		BT_ERR("Unhandled unsolicited response");
390 		return -ENOMSG;
391 	}
392 
393 	if (!at_parse_cmd_input(hf_at, buf, handler->cmd, handler->func,
394 				handler->type)) {
395 		return 0;
396 	}
397 
398 	return -ENOMSG;
399 }
400 
cmd_complete(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)401 int cmd_complete(struct at_client *hf_at, enum at_result result,
402 	       enum at_cme cme_err)
403 {
404 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
405 	struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
406 	struct bt_hfp_hf_cmd_complete cmd = { 0 };
407 
408 	BT_DBG("");
409 
410 	switch (result) {
411 	case AT_RESULT_OK:
412 		cmd.type = HFP_HF_CMD_OK;
413 		break;
414 	case AT_RESULT_ERROR:
415 		cmd.type = HFP_HF_CMD_ERROR;
416 		break;
417 	case AT_RESULT_CME_ERROR:
418 		cmd.type = HFP_HF_CMD_CME_ERROR;
419 		cmd.cme = cme_err;
420 		break;
421 	default:
422 		BT_ERR("Unknown error code");
423 		cmd.type = HFP_HF_CMD_UNKNOWN_ERROR;
424 		break;
425 	}
426 
427 	if (bt_hf->cmd_complete_cb) {
428 		bt_hf->cmd_complete_cb(conn, &cmd);
429 	}
430 
431 	return 0;
432 }
433 
cmee_finish(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)434 int cmee_finish(struct at_client *hf_at, enum at_result result,
435 		enum at_cme cme_err)
436 {
437 	if (result != AT_RESULT_OK) {
438 		BT_ERR("SLC Connection ERROR in response");
439 		return -EINVAL;
440 	}
441 
442 	return 0;
443 }
444 
slc_completed(struct at_client * hf_at)445 static void slc_completed(struct at_client *hf_at)
446 {
447 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
448 	struct bt_conn *conn = hf->rfcomm_dlc.session->br_chan.chan.conn;
449 
450 	if (bt_hf->connected) {
451 		bt_hf->connected(conn);
452 	}
453 
454 	if (hfp_hf_send_cmd(hf, NULL, cmee_finish, "AT+CMEE=1") < 0) {
455 		BT_ERR("Error Sending AT+CMEE");
456 	}
457 }
458 
cmer_finish(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)459 int cmer_finish(struct at_client *hf_at, enum at_result result,
460 		enum at_cme cme_err)
461 {
462 	if (result != AT_RESULT_OK) {
463 		BT_ERR("SLC Connection ERROR in response");
464 		hf_slc_error(hf_at);
465 		return -EINVAL;
466 	}
467 
468 	slc_completed(hf_at);
469 
470 	return 0;
471 }
472 
cind_status_finish(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)473 int cind_status_finish(struct at_client *hf_at, enum at_result result,
474 		       enum at_cme cme_err)
475 {
476 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
477 	int err;
478 
479 	if (result != AT_RESULT_OK) {
480 		BT_ERR("SLC Connection ERROR in response");
481 		hf_slc_error(hf_at);
482 		return -EINVAL;
483 	}
484 
485 	at_register_unsolicited(hf_at, unsolicited_cb);
486 	err = hfp_hf_send_cmd(hf, NULL, cmer_finish, "AT+CMER=3,0,0,1");
487 	if (err < 0) {
488 		hf_slc_error(hf_at);
489 		return err;
490 	}
491 
492 	return 0;
493 }
494 
cind_finish(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)495 int cind_finish(struct at_client *hf_at, enum at_result result,
496 		enum at_cme cme_err)
497 {
498 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
499 	int err;
500 
501 	if (result != AT_RESULT_OK) {
502 		BT_ERR("SLC Connection ERROR in response");
503 		hf_slc_error(hf_at);
504 		return -EINVAL;
505 	}
506 
507 	err = hfp_hf_send_cmd(hf, cind_status_resp, cind_status_finish,
508 			      "AT+CIND?");
509 	if (err < 0) {
510 		hf_slc_error(hf_at);
511 		return err;
512 	}
513 
514 	return 0;
515 }
516 
brsf_finish(struct at_client * hf_at,enum at_result result,enum at_cme cme_err)517 int brsf_finish(struct at_client *hf_at, enum at_result result,
518 		enum at_cme cme_err)
519 {
520 	struct bt_hfp_hf *hf = CONTAINER_OF(hf_at, struct bt_hfp_hf, at);
521 	int err;
522 
523 	if (result != AT_RESULT_OK) {
524 		BT_ERR("SLC Connection ERROR in response");
525 		hf_slc_error(hf_at);
526 		return -EINVAL;
527 	}
528 
529 	err = hfp_hf_send_cmd(hf, cind_resp, cind_finish, "AT+CIND=?");
530 	if (err < 0) {
531 		hf_slc_error(hf_at);
532 		return err;
533 	}
534 
535 	return 0;
536 }
537 
hf_slc_establish(struct bt_hfp_hf * hf)538 int hf_slc_establish(struct bt_hfp_hf *hf)
539 {
540 	int err;
541 
542 	BT_DBG("");
543 
544 	err = hfp_hf_send_cmd(hf, brsf_resp, brsf_finish, "AT+BRSF=%u",
545 			      hf->hf_features);
546 	if (err < 0) {
547 		hf_slc_error(&hf->at);
548 		return err;
549 	}
550 
551 	return 0;
552 }
553 
bt_hfp_hf_lookup_bt_conn(struct bt_conn * conn)554 static struct bt_hfp_hf *bt_hfp_hf_lookup_bt_conn(struct bt_conn *conn)
555 {
556 	int i;
557 
558 	for (i = 0; i < ARRAY_SIZE(bt_hfp_hf_pool); i++) {
559 		struct bt_hfp_hf *hf = &bt_hfp_hf_pool[i];
560 
561 		if (hf->rfcomm_dlc.session->br_chan.chan.conn == conn) {
562 			return hf;
563 		}
564 	}
565 
566 	return NULL;
567 }
568 
bt_hfp_hf_send_cmd(struct bt_conn * conn,enum bt_hfp_hf_at_cmd cmd)569 int bt_hfp_hf_send_cmd(struct bt_conn *conn, enum bt_hfp_hf_at_cmd cmd)
570 {
571 	struct bt_hfp_hf *hf;
572 	int err;
573 
574 	BT_DBG("");
575 
576 	if (!conn) {
577 		BT_ERR("Invalid connection");
578 		return -ENOTCONN;
579 	}
580 
581 	hf = bt_hfp_hf_lookup_bt_conn(conn);
582 	if (!hf) {
583 		BT_ERR("No HF connection found");
584 		return -ENOTCONN;
585 	}
586 
587 	switch (cmd) {
588 	case BT_HFP_HF_ATA:
589 		err = hfp_hf_send_cmd(hf, NULL, cmd_complete, "ATA");
590 		if (err < 0) {
591 			BT_ERR("Failed ATA");
592 			return err;
593 		}
594 		break;
595 	case BT_HFP_HF_AT_CHUP:
596 		err = hfp_hf_send_cmd(hf, NULL, cmd_complete, "AT+CHUP");
597 		if (err < 0) {
598 			BT_ERR("Failed AT+CHUP");
599 			return err;
600 		}
601 		break;
602 	default:
603 		BT_ERR("Invalid AT Command");
604 		return -EINVAL;
605 	}
606 
607 	return 0;
608 }
609 
hfp_hf_connected(struct bt_rfcomm_dlc * dlc)610 static void hfp_hf_connected(struct bt_rfcomm_dlc *dlc)
611 {
612 	struct bt_hfp_hf *hf = CONTAINER_OF(dlc, struct bt_hfp_hf, rfcomm_dlc);
613 
614 	BT_DBG("hf connected");
615 
616 	BT_ASSERT(hf);
617 	hf_slc_establish(hf);
618 }
619 
hfp_hf_disconnected(struct bt_rfcomm_dlc * dlc)620 static void hfp_hf_disconnected(struct bt_rfcomm_dlc *dlc)
621 {
622 	struct bt_conn *conn = dlc->session->br_chan.chan.conn;
623 
624 	BT_DBG("hf disconnected!");
625 	if (bt_hf->disconnected) {
626 		bt_hf->disconnected(conn);
627 	}
628 }
629 
hfp_hf_recv(struct bt_rfcomm_dlc * dlc,struct net_buf * buf)630 static void hfp_hf_recv(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
631 {
632 	struct bt_hfp_hf *hf = CONTAINER_OF(dlc, struct bt_hfp_hf, rfcomm_dlc);
633 
634 	if (at_parse_input(&hf->at, buf) < 0) {
635 		BT_ERR("Parsing failed");
636 	}
637 }
638 
bt_hfp_hf_accept(struct bt_conn * conn,struct bt_rfcomm_dlc ** dlc)639 static int bt_hfp_hf_accept(struct bt_conn *conn, struct bt_rfcomm_dlc **dlc)
640 {
641 	int i;
642 	static struct bt_rfcomm_dlc_ops ops = {
643 		.connected = hfp_hf_connected,
644 		.disconnected = hfp_hf_disconnected,
645 		.recv = hfp_hf_recv,
646 	};
647 
648 	BT_DBG("conn %p", conn);
649 
650 	for (i = 0; i < ARRAY_SIZE(bt_hfp_hf_pool); i++) {
651 		struct bt_hfp_hf *hf = &bt_hfp_hf_pool[i];
652 		int j;
653 
654 		if (hf->rfcomm_dlc.session) {
655 			continue;
656 		}
657 
658 		hf->at.buf = hf->hf_buffer;
659 		hf->at.buf_max_len = HF_MAX_BUF_LEN;
660 
661 		hf->rfcomm_dlc.ops = &ops;
662 		hf->rfcomm_dlc.mtu = BT_HFP_MAX_MTU;
663 
664 		*dlc = &hf->rfcomm_dlc;
665 
666 		/* Set the supported features*/
667 		hf->hf_features = BT_HFP_HF_SUPPORTED_FEATURES;
668 
669 		for (j = 0; j < HF_MAX_AG_INDICATORS; j++) {
670 			hf->ind_table[j] = -1;
671 		}
672 
673 		return 0;
674 	}
675 
676 	BT_ERR("Unable to establish HF connection (%p)", conn);
677 
678 	return -ENOMEM;
679 }
680 
hfp_hf_init(void)681 static void hfp_hf_init(void)
682 {
683 	static struct bt_rfcomm_server chan = {
684 		.channel = BT_RFCOMM_CHAN_HFP_HF,
685 		.accept = bt_hfp_hf_accept,
686 	};
687 
688     NET_BUF_POOL_INIT(hf_pool);
689 
690 	bt_rfcomm_server_register(&chan);
691 }
692 
bt_hfp_hf_register(struct bt_hfp_hf_cb * cb)693 int bt_hfp_hf_register(struct bt_hfp_hf_cb *cb)
694 {
695 	if (!cb) {
696 		return -EINVAL;
697 	}
698 
699 	if (bt_hf) {
700 		return -EALREADY;
701 	}
702 
703 	bt_hf = cb;
704 
705 	hfp_hf_init();
706 
707 	return 0;
708 }
709 #endif
710