1 /* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 */
5
6 #include <sys/socket.h>
7 #include <syslog.h>
8
9 #include "cras_bt_device.h"
10 #include "cras_telephony.h"
11 #include "cras_hfp_ag_profile.h"
12 #include "cras_hfp_slc.h"
13 #include "cras_system_state.h"
14
15 #define SLC_BUF_SIZE_BYTES 256
16
17 /* Indicator update command response and indicator indices.
18 * Note that indicator index starts from '1'.
19 */
20 #define BATTERY_IND_INDEX 1
21 #define SIGNAL_IND_INDEX 2
22 #define SERVICE_IND_INDEX 3
23 #define CALL_IND_INDEX 4
24 #define CALLSETUP_IND_INDEX 5
25 #define CALLHELD_IND_INDEX 6
26 #define INDICATOR_UPDATE_RSP \
27 "+CIND: " \
28 "(\"battchg\",(0-5))," \
29 "(\"signal\",(0-5))," \
30 "(\"service\",(0,1))," \
31 "(\"call\",(0,1))," \
32 "(\"callsetup\",(0-3))," \
33 "(\"callheld\",(0-2))," \
34 "(\"roam\",(0,1))" \
35 ""
36 /* Mode values for standard event reporting activation/deactivation AT
37 * command AT+CMER. Used for indicator events reporting in HFP. */
38 #define FORWARD_UNSOLICIT_RESULT_CODE 3
39
40 /* Handle object to hold required info to initialize and maintain
41 * an HFP service level connection.
42 * Args:
43 * buf - Buffer hold received commands.
44 * buf_read_idx - Read index for buf.
45 * buf_write_idx - Write index for buf.
46 * rfcomm_fd - File descriptor for the established RFCOMM connection.
47 * init_cb - Callback to be triggered when an SLC is initialized.
48 * initialized - The service level connection is fully initilized of not.
49 * cli_active - Calling line identification notification is enabled or not.
50 * battery - Current battery level of AG stored in SLC.
51 * signal - Current signal strength of AG stored in SLC.
52 * service - Current service availability of AG stored in SLC.
53 * callheld - Current callheld status of AG stored in SLC.
54 * ind_event_report - Activate status of indicator events reporting.
55 * telephony - A reference of current telephony handle.
56 * device - The associated bt device.
57 */
58 struct hfp_slc_handle {
59 char buf[SLC_BUF_SIZE_BYTES];
60 int buf_read_idx;
61 int buf_write_idx;
62
63 int is_hsp;
64 int rfcomm_fd;
65 hfp_slc_init_cb init_cb;
66 hfp_slc_disconnect_cb disconnect_cb;
67 int initialized;
68 int cli_active;
69 int battery;
70 int signal;
71 int service;
72 int callheld;
73 int ind_event_report;
74 struct cras_bt_device *device;
75
76 struct cras_telephony_handle *telephony;
77 };
78
79 /* AT command exchanges between AG(Audio gateway) and HF(Hands-free device) */
80 struct at_command {
81 const char *cmd;
82 int (*callback) (struct hfp_slc_handle *handle, const char *cmd);
83 };
84
85 /* Sends a response or command to HF */
hfp_send(struct hfp_slc_handle * handle,const char * buf)86 static int hfp_send(struct hfp_slc_handle *handle, const char *buf)
87 {
88 int written, err, len;
89
90 if (handle->rfcomm_fd < 0)
91 return -EIO;
92
93 /* Message start and end with "\r\n". refer to spec 4.33. */
94 err = write(handle->rfcomm_fd, "\r\n", 2);
95 if (err < 0)
96 return -errno;
97
98 len = strlen(buf);
99 written = 0;
100 while (written < len) {
101 err = write(handle->rfcomm_fd,
102 buf + written, len - written);
103 if (err < 0)
104 return -errno;
105 written += err;
106 }
107
108 err = write(handle->rfcomm_fd, "\r\n", 2);
109 if (err < 0)
110 return -errno;
111
112 return 0;
113 }
114
115 /* Sends a response for indicator event reporting. */
hfp_send_ind_event_report(struct hfp_slc_handle * handle,int ind_index,int value)116 static int hfp_send_ind_event_report(struct hfp_slc_handle *handle,
117 int ind_index,
118 int value)
119 {
120 char cmd[64];
121
122 if (handle->is_hsp || !handle->ind_event_report)
123 return 0;
124
125 snprintf(cmd, 64, "+CIEV: %d,%d", ind_index, value);
126 return hfp_send(handle, cmd);
127 }
128
129 /* Sends calling line identification unsolicited result code and
130 * standard call waiting notification. */
hfp_send_calling_line_identification(struct hfp_slc_handle * handle,const char * number,int type)131 static int hfp_send_calling_line_identification(struct hfp_slc_handle *handle,
132 const char *number,
133 int type)
134 {
135 char cmd[64];
136
137 if (handle->is_hsp)
138 return 0;
139
140 if (handle->telephony->call) {
141 snprintf(cmd, 64, "+CCWA: \"%s\",%d", number, type);
142 } else {
143 snprintf(cmd, 64, "+CLIP: \"%s\",%d", number, type);
144 }
145 return hfp_send(handle, cmd);
146 }
147
148 /* ATA command to accept an incoming call. Mandatory support per spec 4.13. */
answer_call(struct hfp_slc_handle * handle,const char * cmd)149 static int answer_call(struct hfp_slc_handle *handle, const char *cmd)
150 {
151 int rc;
152 rc = hfp_send(handle, "OK");
153 if (rc)
154 return rc;
155
156 return cras_telephony_event_answer_call();
157 }
158
159 /* AT+CCWA command to enable the "Call Waiting notification" function.
160 * Mandatory support per spec 4.21. */
call_waiting_notify(struct hfp_slc_handle * handle,const char * buf)161 static int call_waiting_notify(struct hfp_slc_handle *handle, const char *buf)
162 {
163 return hfp_send(handle, "OK");
164 }
165
166 /* AT+CLIP command to enable the "Calling Line Identification notification"
167 * function. Mandatory per spec 4.23.
168 */
cli_notification(struct hfp_slc_handle * handle,const char * cmd)169 static int cli_notification(struct hfp_slc_handle *handle, const char *cmd)
170 {
171 handle->cli_active = (cmd[8] == '1');
172 return hfp_send(handle, "OK");
173 }
174
175 /* ATDdd...dd command to place call with supplied number, or ATD>nnn...
176 * command to dial the number stored at memory location. Mandatory per
177 * spec 4.18 and 4.19.
178 */
dial_number(struct hfp_slc_handle * handle,const char * cmd)179 static int dial_number(struct hfp_slc_handle *handle, const char *cmd)
180 {
181 int rc, cmd_len;
182
183 cmd_len = strlen(cmd);
184
185 if (cmd[3] == '>') {
186 /* Handle memory dial. Extract memory location from command
187 * ATD>nnn...; and lookup. */
188 int memory_location;
189 memory_location = strtol(cmd + 4, NULL, 0);
190 if (handle->telephony->dial_number == NULL || memory_location != 1)
191 return hfp_send(handle, "ERROR");
192 }
193 else {
194 /* ATDddddd; Store dial number to the only memory slot. */
195 cras_telephony_store_dial_number(cmd_len - 3 - 1, cmd + 3);
196 }
197
198 rc = hfp_send(handle, "OK");
199 if (rc)
200 return rc;
201
202 handle->telephony->callsetup = 2;
203 return hfp_send_ind_event_report(handle, CALLSETUP_IND_INDEX, 2);
204 }
205
206 /* AT+VTS command to generate a DTMF code. Mandatory per spec 4.27. */
dtmf_tone(struct hfp_slc_handle * handle,const char * buf)207 static int dtmf_tone(struct hfp_slc_handle *handle, const char *buf)
208 {
209 return hfp_send(handle, "OK");
210 }
211
212 /* AT+CMER command enables the registration status update function in AG.
213 * The service level connection is consider initialized when successfully
214 * responded OK to the AT+CMER command. Mandatory support per spec 4.4.
215 */
event_reporting(struct hfp_slc_handle * handle,const char * cmd)216 static int event_reporting(struct hfp_slc_handle *handle, const char *cmd)
217 {
218 char *tokens, *mode, *tmp;
219 int err = 0;
220
221 /* AT+CMER=[<mode>[,<keyp>[,<disp>[,<ind> [,<bfr>]]]]]
222 * Parse <ind>, the only token we care about.
223 */
224 tokens = strdup(cmd);
225 strtok(tokens, "=");
226
227 mode = strtok(NULL, ",");
228 tmp = strtok(NULL, ",");
229 tmp = strtok(NULL, ",");
230 tmp = strtok(NULL, ",");
231
232 /* mode = 3 for forward unsolicited result codes.
233 * AT+CMER=3,0,0,1 activates “indicator events reporting”.
234 * The service level connection is considered established after
235 * successfully responded with OK, regardless of the indicator
236 * events reporting status.
237 */
238 if (!mode || !tmp) {
239 syslog(LOG_ERR, "Invalid event reporting” cmd %s", cmd);
240 err = -EINVAL;
241 goto event_reporting_err;
242 }
243 if (atoi(mode) == FORWARD_UNSOLICIT_RESULT_CODE)
244 handle->ind_event_report = atoi(tmp);
245
246 err = hfp_send(handle, "OK");
247 if (err) {
248 syslog(LOG_ERR, "Error sending response for command %s", cmd);
249 goto event_reporting_err;
250 }
251
252 /* Consider the Service Level Connection to be fully initialized,
253 * and thereby established, after successfully responded with OK.
254 */
255 if (!handle->initialized) {
256 handle->initialized = 1;
257 if (handle->init_cb)
258 handle->init_cb(handle);
259 }
260
261 event_reporting_err:
262 free(tokens);
263 return err;
264 }
265
266 /* AT+CMEE command to set the "Extended Audio Gateway Error Result Code".
267 * Mandatory per spec 4.9.
268 */
extended_errors(struct hfp_slc_handle * handle,const char * buf)269 static int extended_errors(struct hfp_slc_handle *handle, const char *buf)
270 {
271 return hfp_send(handle, "OK");
272 }
273
274 /* AT+CKPD command to handle the user initiated action from headset profile
275 * device.
276 */
key_press(struct hfp_slc_handle * handle,const char * buf)277 static int key_press(struct hfp_slc_handle *handle, const char *buf)
278 {
279 hfp_send(handle, "OK");
280
281 /* Release the call and connection. */
282 if (handle->telephony->call || handle->telephony->callsetup) {
283 cras_telephony_event_terminate_call();
284 handle->disconnect_cb(handle);
285 return -EIO;
286 }
287 return 0;
288 }
289
290 /* AT+BLDN command to re-dial the last number. Mandatory support
291 * per spec 4.20.
292 */
last_dialed_number(struct hfp_slc_handle * handle,const char * buf)293 static int last_dialed_number(struct hfp_slc_handle *handle, const char *buf)
294 {
295 int rc;
296
297 if (!handle->telephony->dial_number)
298 return hfp_send(handle, "ERROR");
299
300 rc = hfp_send(handle, "OK");
301 if (rc)
302 return rc;
303
304 handle->telephony->callsetup = 2;
305 return hfp_send_ind_event_report(handle, CALLSETUP_IND_INDEX, 2);
306 }
307
308 /* AT+CLCC command to query list of current calls. Mandatory support
309 * per spec 4.31.
310 *
311 * +CLCC: <idx>,<direction>,<status>,<mode>,<multiparty>
312 */
list_current_calls(struct hfp_slc_handle * handle,const char * cmd)313 static int list_current_calls(struct hfp_slc_handle *handle, const char *cmd)
314 {
315 char buf[64];
316
317 int idx = 1;
318 int rc;
319 /* Fake the call list base on callheld and call status
320 * since we have no API exposed to manage call list.
321 * This is a hack to pass qualification test which ask us to
322 * handle the basic case that one call is active and
323 * the other is on hold. */
324 if (handle->telephony->callheld)
325 {
326 snprintf(buf, 64, "+CLCC: %d,1,1,0,0", idx++);
327 rc = hfp_send(handle, buf);
328 if (rc)
329 return rc;
330 }
331
332 if (handle->telephony->call)
333 {
334 snprintf(buf, 64, "+CLCC: %d,1,0,0,0", idx++);
335 rc = hfp_send(handle, buf);
336 if (rc)
337 return rc;
338 }
339
340 return hfp_send(handle, "OK");
341 }
342
343 /* AT+COPS command to query currently selected operator or set name format.
344 * Mandatory support per spec 4.8.
345 */
operator_selection(struct hfp_slc_handle * handle,const char * buf)346 static int operator_selection(struct hfp_slc_handle *handle, const char *buf)
347 {
348 int rc;
349 if (buf[7] == '?')
350 {
351 /* HF sends AT+COPS? command to find current network operator.
352 * AG responds with +COPS:<mode>,<format>,<operator>, where
353 * the mode=0 means automatic for network selection. If no
354 * operator is selected, <format> and <operator> are omitted.
355 */
356 rc = hfp_send(handle, "+COPS: 0");
357 if (rc)
358 return rc;
359 }
360 return hfp_send(handle, "OK");
361 }
362
363 /* AT+CIND command retrieves the supported indicator and its corresponding
364 * range and order index or read current status of indicators. Mandatory
365 * support per spec 4.2.
366 */
report_indicators(struct hfp_slc_handle * handle,const char * cmd)367 static int report_indicators(struct hfp_slc_handle *handle, const char *cmd)
368 {
369 int err;
370 char buf[64];
371
372 if (cmd[7] == '=') {
373 /* Indicator update test command "AT+CIND=?" */
374 err = hfp_send(handle, INDICATOR_UPDATE_RSP);
375 } else {
376 /* Indicator update read command "AT+CIND?".
377 * Respond with current status of AG indicators,
378 * the values must be listed in the indicator order declared
379 * in INDICATOR_UPDATE_RSP.
380 * +CIND: <signal>,<service>,<call>,
381 * <callsetup>,<callheld>,<roam>
382 */
383 snprintf(buf, 64, "+CIND: %d,%d,%d,%d,%d,%d,0",
384 handle->battery,
385 handle->signal,
386 handle->service,
387 handle->telephony->call,
388 handle->telephony->callsetup,
389 handle->telephony->callheld
390 );
391 err = hfp_send(handle, buf);
392 }
393
394 if (err < 0)
395 return err;
396
397 return hfp_send(handle, "OK");
398 }
399
400 /* AT+BIA command to change the subset of indicators that shall be
401 * sent by the AG. It is okay to ignore this command here since we
402 * don't do event reporting(CMER).
403 */
indicator_activation(struct hfp_slc_handle * handle,const char * cmd)404 static int indicator_activation(struct hfp_slc_handle *handle, const char *cmd)
405 {
406 /* AT+BIA=[[<indrep 1>][,[<indrep 2>][,...[,[<indrep n>]]]]] */
407 syslog(LOG_ERR, "Bluetooth indicator activation command %s", cmd);
408 return hfp_send(handle, "OK");
409 }
410
411 /* AT+VGM and AT+VGS command reports the current mic and speaker gain
412 * level respectively. Optional support per spec 4.28.
413 */
signal_gain_setting(struct hfp_slc_handle * handle,const char * cmd)414 static int signal_gain_setting(struct hfp_slc_handle *handle,
415 const char *cmd)
416 {
417 int gain;
418
419 if (strlen(cmd) < 8) {
420 syslog(LOG_ERR, "Invalid gain setting command %s", cmd);
421 return -EINVAL;
422 }
423
424 /* Map 0 to the smallest non-zero scale 6/100, and 15 to
425 * 100/100 full. */
426 if (cmd[5] == 'S') {
427 gain = atoi(&cmd[7]);
428 cras_bt_device_update_hardware_volume(handle->device,
429 (gain + 1) * 100 / 16);
430 }
431
432 return hfp_send(handle, "OK");
433 }
434
435 /* AT+CNUM command to query the subscriber number. Mandatory support
436 * per spec 4.30.
437 */
subscriber_number(struct hfp_slc_handle * handle,const char * buf)438 static int subscriber_number(struct hfp_slc_handle *handle, const char *buf)
439 {
440 return hfp_send(handle, "OK");
441 }
442
443 /* AT+BRSF command notifies the HF(Hands-free device) supported features
444 * and retrieves the AG(Audio gateway) supported features. Mandatory
445 * support per spec 4.2.
446 */
supported_features(struct hfp_slc_handle * handle,const char * cmd)447 static int supported_features(struct hfp_slc_handle *handle, const char *cmd)
448 {
449 int err;
450 char response[128];
451 if (strlen(cmd) < 9)
452 return -EINVAL;
453
454 /* AT+BRSF=<feature> command received, ignore the HF supported feature
455 * for now. Respond with +BRSF:<feature> to notify mandatory supported
456 * features in AG(audio gateway).
457 */
458 snprintf(response, 128, "+BRSF: %u", HFP_SUPPORTED_FEATURE);
459 err = hfp_send(handle, response);
460 if (err < 0)
461 return err;
462
463 return hfp_send(handle, "OK");
464 }
465
hfp_event_speaker_gain(struct hfp_slc_handle * handle,int gain)466 int hfp_event_speaker_gain(struct hfp_slc_handle *handle, int gain)
467 {
468 char command[128];
469
470 /* Normailize gain value to 0-15 */
471 gain = gain * 15 / 100;
472 snprintf(command, 128, "+VGS=%d", gain);
473
474 return hfp_send(handle, command);
475 }
476
477 /* AT+CHUP command to terminate current call. Mandatory support
478 * per spec 4.15.
479 */
terminate_call(struct hfp_slc_handle * handle,const char * cmd)480 static int terminate_call(struct hfp_slc_handle *handle, const char *cmd)
481 {
482 int rc;
483 rc = hfp_send(handle, "OK");
484 if (rc)
485 return rc;
486
487 return cras_telephony_event_terminate_call();
488 }
489
490 /* AT commands to support in order to conform HFP specification.
491 *
492 * An initialized service level connection is the pre-condition for all
493 * call related procedures. Note that for the call related commands,
494 * we are good to just respond with a dummy "OK".
495 *
496 * The procedure to establish a service level connection is described below:
497 *
498 * 1. HF notifies AG about its own supported features and AG responds
499 * with its supported feature.
500 *
501 * HF(hands-free) AG(audio gateway)
502 * AT+BRSF=<HF supported feature> -->
503 * <-- +BRSF:<AG supported feature>
504 * <-- OK
505 *
506 * 2. HF retrieves the information about the indicators supported in AG.
507 *
508 * HF(hands-free) AG(audio gateway)
509 * AT+CIND=? -->
510 * <-- +CIND:...
511 * <-- OK
512 *
513 * 3. The HF requests the current status of the indicators in AG.
514 *
515 * HF(hands-free) AG(audio gateway)
516 * AT+CIND -->
517 * <-- +CIND:...
518 * <-- OK
519 *
520 * 4. HF requests enabling indicator status update in the AG.
521 *
522 * HF(hands-free) AG(audio gateway)
523 * AT+CMER= -->
524 * <-- OK
525 */
526 static struct at_command at_commands[] = {
527 { "ATA", answer_call },
528 { "ATD", dial_number },
529 { "AT+BIA", indicator_activation },
530 { "AT+BLDN", last_dialed_number },
531 { "AT+BRSF", supported_features },
532 { "AT+CCWA", call_waiting_notify },
533 { "AT+CHUP", terminate_call },
534 { "AT+CIND", report_indicators },
535 { "AT+CKPD", key_press },
536 { "AT+CLCC", list_current_calls },
537 { "AT+CLIP", cli_notification },
538 { "AT+CMEE", extended_errors },
539 { "AT+CMER", event_reporting },
540 { "AT+CNUM", subscriber_number },
541 { "AT+COPS", operator_selection },
542 { "AT+VG", signal_gain_setting },
543 { "AT+VTS", dtmf_tone },
544 { 0 }
545 };
546
handle_at_command(struct hfp_slc_handle * slc_handle,const char * cmd)547 static int handle_at_command(struct hfp_slc_handle *slc_handle,
548 const char *cmd) {
549 struct at_command *atc;
550
551 for (atc = at_commands; atc->cmd; atc++)
552 if (!strncmp(cmd, atc->cmd, strlen(atc->cmd)))
553 return atc->callback(slc_handle, cmd);
554
555 syslog(LOG_ERR, "AT command %s not supported", cmd);
556 return hfp_send(slc_handle, "ERROR");
557 }
558
slc_watch_callback(void * arg)559 static void slc_watch_callback(void *arg)
560 {
561 struct hfp_slc_handle *handle = (struct hfp_slc_handle *)arg;
562 ssize_t bytes_read;
563 int err;
564
565 bytes_read = read(handle->rfcomm_fd,
566 &handle->buf[handle->buf_write_idx],
567 SLC_BUF_SIZE_BYTES - handle->buf_write_idx - 1);
568 if (bytes_read < 0) {
569 syslog(LOG_ERR, "Error reading slc command %s",
570 strerror(errno));
571 handle->disconnect_cb(handle);
572 return;
573 }
574 handle->buf_write_idx += bytes_read;
575 handle->buf[handle->buf_write_idx] = '\0';
576
577 while (handle->buf_read_idx != handle->buf_write_idx) {
578 char *end_char;
579 end_char = strchr(&handle->buf[handle->buf_read_idx], '\r');
580 if (end_char == NULL)
581 break;
582
583 *end_char = '\0';
584 err = handle_at_command(handle,
585 &handle->buf[handle->buf_read_idx]);
586 if (err < 0)
587 return;
588
589 /* Shift the read index */
590 handle->buf_read_idx = 1 + end_char - handle->buf;
591 if (handle->buf_read_idx == handle->buf_write_idx) {
592 handle->buf_read_idx = 0;
593 handle->buf_write_idx = 0;
594 }
595 }
596
597 /* Handle the case when buffer is full and no command found. */
598 if (handle->buf_write_idx == SLC_BUF_SIZE_BYTES - 1) {
599 if (handle->buf_read_idx) {
600 memmove(handle->buf,
601 &handle->buf[handle->buf_read_idx],
602 handle->buf_write_idx - handle->buf_read_idx);
603 handle->buf_write_idx -= handle->buf_read_idx;
604 handle->buf_read_idx = 0;
605 } else {
606 syslog(LOG_ERR,
607 "Parse SLC command error, clean up buffer");
608 handle->buf_write_idx = 0;
609 }
610 }
611
612 return;
613 }
614
615 /* Exported interfaces */
616
hfp_slc_create(int fd,int is_hsp,struct cras_bt_device * device,hfp_slc_init_cb init_cb,hfp_slc_disconnect_cb disconnect_cb)617 struct hfp_slc_handle *hfp_slc_create(int fd,
618 int is_hsp,
619 struct cras_bt_device *device,
620 hfp_slc_init_cb init_cb,
621 hfp_slc_disconnect_cb disconnect_cb)
622 {
623 struct hfp_slc_handle *handle;
624
625 handle = (struct hfp_slc_handle*) calloc(1, sizeof(*handle));
626 if (!handle)
627 return NULL;
628
629 handle->rfcomm_fd = fd;
630 handle->is_hsp = is_hsp;
631 handle->device = device;
632 handle->init_cb = init_cb;
633 handle->disconnect_cb = disconnect_cb;
634 handle->cli_active = 0;
635 handle->battery = 5;
636 handle->signal = 5;
637 handle->service = 1;
638 handle->ind_event_report = 0;
639 handle->telephony = cras_telephony_get();
640
641 cras_system_add_select_fd(handle->rfcomm_fd,
642 slc_watch_callback, handle);
643
644 return handle;
645 }
646
hfp_slc_destroy(struct hfp_slc_handle * slc_handle)647 void hfp_slc_destroy(struct hfp_slc_handle *slc_handle)
648 {
649 cras_system_rm_select_fd(slc_handle->rfcomm_fd);
650 close(slc_handle->rfcomm_fd);
651 free(slc_handle);
652 }
653
hfp_set_call_status(struct hfp_slc_handle * handle,int call)654 int hfp_set_call_status(struct hfp_slc_handle *handle, int call)
655 {
656 int old_call = handle->telephony->call;
657
658 if (old_call == call)
659 return 0;
660
661 handle->telephony->call = call;
662 return hfp_event_update_call(handle);
663 }
664
665 /* Procedure to setup a call when AG sees incoming call.
666 *
667 * HF(hands-free) AG(audio gateway)
668 * <-- Incoming call
669 * <-- +CIEV: (callsetup = 1)
670 * <-- RING (ALERT)
671 */
hfp_event_incoming_call(struct hfp_slc_handle * handle,const char * number,int type)672 int hfp_event_incoming_call(struct hfp_slc_handle *handle,
673 const char *number,
674 int type)
675 {
676 int rc;
677
678 if (handle->is_hsp)
679 return 0;
680
681 if (handle->cli_active) {
682 rc = hfp_send_calling_line_identification(handle, number, type);
683 if (rc)
684 return rc;
685 }
686
687 if (handle->telephony->call)
688 return 0;
689 else
690 return hfp_send(handle, "RING");
691 }
692
hfp_event_update_call(struct hfp_slc_handle * handle)693 int hfp_event_update_call(struct hfp_slc_handle *handle)
694 {
695 return hfp_send_ind_event_report(handle, CALL_IND_INDEX,
696 handle->telephony->call);
697 }
698
hfp_event_update_callsetup(struct hfp_slc_handle * handle)699 int hfp_event_update_callsetup(struct hfp_slc_handle *handle)
700 {
701 return hfp_send_ind_event_report(handle, CALLSETUP_IND_INDEX,
702 handle->telephony->callsetup);
703 }
704
hfp_event_update_callheld(struct hfp_slc_handle * handle)705 int hfp_event_update_callheld(struct hfp_slc_handle *handle)
706 {
707 return hfp_send_ind_event_report(handle, CALLHELD_IND_INDEX,
708 handle->telephony->callheld);
709 }
710
hfp_event_set_battery(struct hfp_slc_handle * handle,int level)711 int hfp_event_set_battery(struct hfp_slc_handle *handle, int level)
712 {
713 handle->battery = level;
714 return hfp_send_ind_event_report(handle, BATTERY_IND_INDEX, level);
715 }
716
hfp_event_set_signal(struct hfp_slc_handle * handle,int level)717 int hfp_event_set_signal(struct hfp_slc_handle *handle, int level)
718 {
719 handle->signal = level;
720 return hfp_send_ind_event_report(handle, SIGNAL_IND_INDEX, level);
721 }
722
hfp_event_set_service(struct hfp_slc_handle * handle,int avail)723 int hfp_event_set_service(struct hfp_slc_handle *handle, int avail)
724 {
725 /* Convert to 0 or 1.
726 * Since the value must be either 1 or 0. (service presence or not) */
727 handle->service = !!avail;
728 return hfp_send_ind_event_report(handle, SERVICE_IND_INDEX, avail);
729 }
730