Home | History | Annotate | Download | only in server
      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 */
     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. */
    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. */
    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. */
    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. */
    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  */
    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  */
    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. */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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 
    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  */
    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 
    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 
    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 
    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 
    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 
    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  */
    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 
    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 
    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 
    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 
    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 
    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 
    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