• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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