diff options
Diffstat (limited to 'call.c')
-rw-r--r-- | call.c | 683 |
1 files changed, 499 insertions, 184 deletions
@@ -2,7 +2,7 @@ * This file is part of Samsung-RIL. * * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com> - * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr> + * Copyright (C) 2011-2014 Paul Kocialkowski <contact@paulk.fr> * * Samsung-RIL is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,10 +18,12 @@ * along with Samsung-RIL. If not, see <http://www.gnu.org/licenses/>. */ -#define LOG_TAG "RIL-CALL" +#include <stdlib.h> + +#define LOG_TAG "RIL" #include <utils/Log.h> -#include "samsung-ril.h" +#include <samsung-ril.h> unsigned char ril2ipc_call_identity(int clir) { @@ -33,28 +35,26 @@ unsigned char ril2ipc_call_identity(int clir) case 2: return IPC_CALL_IDENTITY_HIDE; default: - RIL_LOGE("Unknown call identity: 0x%x", clir); return IPC_CALL_IDENTITY_DEFAULT; } } -unsigned char ipc2ril_call_list_entry_state(unsigned char call_state) +unsigned char ipc2ril_call_list_entry_state(unsigned char status) { - switch (call_state) { - case IPC_CALL_LIST_ENTRY_STATE_ACTIVE: + switch (status) { + case IPC_CALL_LIST_ENTRY_STATUS_ACTIVE: return RIL_CALL_ACTIVE; - case IPC_CALL_LIST_ENTRY_STATE_HOLDING: + case IPC_CALL_LIST_ENTRY_STATUS_HOLDING: return RIL_CALL_HOLDING; - case IPC_CALL_LIST_ENTRY_STATE_DIALING: + case IPC_CALL_LIST_ENTRY_STATUS_DIALING: return RIL_CALL_DIALING; - case IPC_CALL_LIST_ENTRY_STATE_ALERTING: + case IPC_CALL_LIST_ENTRY_STATUS_ALERTING: return RIL_CALL_ALERTING; - case IPC_CALL_LIST_ENTRY_STATE_INCOMING: + case IPC_CALL_LIST_ENTRY_STATUS_INCOMING: return RIL_CALL_INCOMING; - case IPC_CALL_LIST_ENTRY_STATE_WAITING: + case IPC_CALL_LIST_ENTRY_STATUS_WAITING: return RIL_CALL_WAITING; default: - RIL_LOGE("Unknown call list entry state: 0x%x", call_state); return -1; } } @@ -67,303 +67,618 @@ RIL_LastCallFailCause ipc2ril_call_fail_cause(unsigned char end_cause) return CALL_FAIL_NORMAL; case IPC_CALL_END_CAUSE_UNSPECIFIED: default: - RIL_LOGE("Unknown call fail cause: 0x%x", end_cause); return CALL_FAIL_ERROR_UNSPECIFIED; } } -void ipc_call_incoming(struct ipc_message_info *info) +int ril_request_dial(void *data, size_t size, RIL_Token token) +{ + struct ipc_call_outgoing_data request_data; + RIL_Dial *dial = NULL; + unsigned char identity; + unsigned char prefix; + int rc; + + if (data == NULL || size < sizeof(RIL_Dial)) + goto error; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + dial = (RIL_Dial *) data; + + if (dial->address == NULL) + goto error; + + identity = ril2ipc_call_identity(dial->clir); + prefix = dial->address[0] == '+' ? IPC_CALL_PREFIX_INTL : IPC_CALL_PREFIX_NONE; + + rc = ipc_call_outgoing_setup(&request_data, IPC_CALL_TYPE_VOICE, identity, prefix, dial->address); + if (rc < 0) + goto error; + + free(dial->address); + dial = NULL; + + rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_CALL_OUTGOING); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_OUTGOING, IPC_TYPE_EXEC, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + goto error; + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + if (dial != NULL && dial->address != NULL) + free(dial->address); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ipc_call_incoming(struct ipc_message *message) { ril_request_unsolicited(RIL_UNSOL_CALL_RING, NULL, 0); ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); + + return 0; } -void ipc_call_status(struct ipc_message_info *info) +int ril_request_hangup(void *data, size_t size, RIL_Token token) { - struct ipc_call_status *call_status; + int hangup; + int rc; - if (info->data == NULL || info->length < sizeof(struct ipc_call_status)) - return; + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - call_status = (struct ipc_call_status *) info->data; + hangup = 1; + ril_request_data_set_uniq(RIL_REQUEST_HANGUP, &hangup, sizeof(hangup)); - RIL_LOGD("Updating call status data"); - memcpy(&(ril_data.state.call_status), call_status, sizeof(struct ipc_call_status)); + rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_CALL_RELEASE); + if (rc < 0) + goto error; + + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_RELEASE, IPC_TYPE_EXEC, NULL, 0); + if (rc < 0) + goto error; ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); + + rc = RIL_REQUEST_HANDLED; + goto complete; + +error: + ril_request_data_free(RIL_REQUEST_HANGUP); + + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; } -void ril_request_dial(RIL_Token t, void *data, size_t length) +int ril_request_answer(void *data, size_t size, RIL_Token token) { - RIL_Dial *dial; - struct ipc_call_outgoing call; - int clir; + int rc; - if (data == NULL || length < sizeof(RIL_Dial)) - goto error; + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - dial = (RIL_Dial *) data; + rc = ipc_gen_phone_res_expect_complete(ipc_fmt_request_seq(token), IPC_CALL_ANSWER); + if (rc < 0) + goto error; - if (strlen(dial->address) > sizeof(call.number)) { - printf("Outgoing call number too long\n"); + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_ANSWER, IPC_TYPE_EXEC, NULL, 0); + if (rc < 0) goto error; - } - memset(&call, 0, sizeof(call)); - call.type = IPC_CALL_TYPE_VOICE; - call.identity = ril2ipc_call_identity(dial->clir); - call.prefix = dial->address[0] == '+' ? IPC_CALL_PREFIX_INTL : IPC_CALL_PREFIX_NONE; - call.length = strlen(dial->address); - memcpy(call.number, dial->address, strlen(dial->address)); + ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_CALL_OUTGOING); + rc = RIL_REQUEST_HANDLED; + goto complete; - ipc_fmt_send(IPC_CALL_OUTGOING, IPC_TYPE_EXEC, (unsigned char *) &call, sizeof(call), ril_request_get_id(t)); +error: + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); - return; + rc = RIL_REQUEST_COMPLETED; -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); +complete: + return rc; +} + +int ipc_call_status(struct ipc_message *message) +{ + struct ipc_call_status_data *data; + int fail_cause; + void *hangup_data; + size_t hangup_size; + + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_call_status_data)) + return -1; + + data = (struct ipc_call_status_data *) message->data; + + // Nobody will ask for a call fail cause when we hangup ourselves + hangup_size = ril_request_data_size_get(RIL_REQUEST_HANGUP); + hangup_data = ril_request_data_get(RIL_REQUEST_HANGUP); + + if (data->status == IPC_CALL_STATUS_RELEASED && (hangup_data == NULL || hangup_size == 0)) { + fail_cause = ipc2ril_call_fail_cause(data->end_cause); + + ril_request_data_set_uniq(RIL_REQUEST_LAST_CALL_FAIL_CAUSE, &fail_cause, sizeof(fail_cause)); + } else if (hangup_data != NULL && hangup_size > 0) { + free(hangup_data); + } + + ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); + + return 0; } -void ril_request_get_current_calls(RIL_Token t) +int ril_request_last_call_fail_cause(void *data, size_t size, RIL_Token token) { - ipc_fmt_send_get(IPC_CALL_LIST, ril_request_get_id(t)); + void *fail_cause_data; + size_t fail_cause_size; + int fail_cause; + int rc; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; + + fail_cause_size = ril_request_data_size_get(RIL_REQUEST_LAST_CALL_FAIL_CAUSE); + fail_cause_data = ril_request_data_get(RIL_REQUEST_LAST_CALL_FAIL_CAUSE); + + if (fail_cause_data == NULL || fail_cause_size < sizeof(fail_cause)) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } + + fail_cause = *((int *) fail_cause_data); + + ril_request_complete(token, RIL_E_SUCCESS, &fail_cause, sizeof(fail_cause)); + + free(fail_cause_data); + + return RIL_REQUEST_COMPLETED; } -void ipc_call_list(struct ipc_message_info *info) +int ipc_call_list(struct ipc_message *message) { struct ipc_call_list_entry *entry; + RIL_Call **calls = NULL; + size_t calls_size; + unsigned int calls_count = 0; unsigned char count; + unsigned char index; char *number; - RIL_Call **current_calls = NULL; - int i; + int rc; - if (info->data == NULL || info->length < sizeof(unsigned char)) - goto error; + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_call_list_header)) + return -1; - if (info->type != IPC_TYPE_RESP) - return; + if (message->type != IPC_TYPE_RESP || !ipc_seq_valid(message->aseq)) + return 0; - count = *((unsigned char *) info->data); + count = ipc_call_list_count_extract(message->data, message->size); if (count == 0) { - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, NULL, 0); - return; + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, NULL, 0); + return 0; } - current_calls = (RIL_Call **) calloc(1, count * sizeof(RIL_Call *)); - entry = (struct ipc_call_list_entry *) ((char *) info->data + sizeof(unsigned char)); + calls_size = count * sizeof(RIL_Call *); + calls = (RIL_Call **) calloc(1, calls_size); + + for (index = 0; index < count; index++) { + entry = ipc_call_list_entry_extract(message->data, message->size, index); + if (entry == NULL) + goto error; - for (i = 0 ; i < count ; i++) { - if (((int) entry - (int) info->data) >= (int) info->length) + number = ipc_call_list_entry_number_extract(entry); + if (number == NULL) goto error; - number = ((char *) entry) + sizeof(struct ipc_call_list_entry); - - current_calls[i] = (RIL_Call *) calloc(1, sizeof(RIL_Call)); - - current_calls[i]->state = ipc2ril_call_list_entry_state(entry->state); - current_calls[i]->index = entry->idx; - current_calls[i]->toa = (entry->number_len > 0 && number[0] == '+') ? 145 : 129; - current_calls[i]->isMpty = entry->mpty; - current_calls[i]->isMT = (entry->term == IPC_CALL_TERM_MT); - current_calls[i]->als = 0; - current_calls[i]->isVoice = (entry->type == IPC_CALL_TYPE_VOICE); - current_calls[i]->isVoicePrivacy = 0; - current_calls[i]->number = strdup(number); - current_calls[i]->numberPresentation = (entry->number_len > 0) ? 0 : 2; - current_calls[i]->name = NULL; - current_calls[i]->namePresentation = 2; - current_calls[i]->uusInfo = NULL; - - entry = (struct ipc_call_list_entry *) (number + entry->number_len); + calls[index] = (RIL_Call *) calloc(1, sizeof(RIL_Call)); + calls[index]->state = ipc2ril_call_list_entry_state(entry->status); + calls[index]->index = entry->id; + calls[index]->isMpty = entry->mpty; + calls[index]->isMT = entry->term == IPC_CALL_TERM_MT; + calls[index]->als = 0; + calls[index]->isVoice = entry->type == IPC_CALL_TYPE_VOICE; + calls[index]->isVoicePrivacy = 0; + calls[index]->number = strdup(number); + calls[index]->numberPresentation = (entry->number_length > 0) ? 0 : 2; + calls[index]->name = NULL; + calls[index]->namePresentation = 2; + calls[index]->uusInfo = NULL; + + if (entry->number_length > 0 && number != NULL && number[0] == '+') + calls[index]->toa = 145; + else + calls[index]->toa = 129; + + calls_count++; } - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, current_calls, (count * sizeof(RIL_Call *))); + calls_size = calls_count * sizeof(RIL_Call *); - for (i = 0 ; i < count ; i++) { - if (current_calls[i]->number != NULL) - free(current_calls[i]->number); + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, (void *) calls, calls_size); - free(current_calls[i]); - } + goto complete; - free(current_calls); +error: + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); - return; +complete: + if (calls != NULL && calls_size > 0) { + for (index = 0; index < calls_count; index++) { + if (calls[index] == NULL) + continue; -error: - if (current_calls != NULL) { - for (i = 0 ; i < count ; i++) { - if (current_calls[i]->number != NULL) - free(current_calls[i]->number); + if (calls[index]->number != NULL) + free(calls[index]->number); - free(current_calls[i]); + free(calls[index]); } - free(current_calls); + free(calls); } - if (info->type == IPC_TYPE_RESP) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + return 0; } -void ril_request_hangup(RIL_Token t) +int ril_request_get_current_calls(void *data, size_t size, RIL_Token token) { - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_CALL_RELEASE); + int rc; + + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) { + ril_request_complete(token, RIL_E_SUCCESS, NULL, 0); + return RIL_REQUEST_COMPLETED; + } - ipc_fmt_send_exec(IPC_CALL_RELEASE, ril_request_get_id(t)); + rc = ipc_fmt_send(ipc_fmt_request_seq(token), IPC_CALL_LIST, IPC_TYPE_GET, NULL, 0); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } - ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); + return RIL_REQUEST_HANDLED; } - -void ril_request_answer(RIL_Token t) +int ipc_call_cont_dtmf_callback(struct ipc_message *message) { - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_CALL_ANSWER); + struct ipc_gen_phone_res_data *data; + void *dtmf_data; + size_t dtmf_size; + char tone; + int rc; - ipc_fmt_send_exec(IPC_CALL_ANSWER, ril_request_get_id(t)); + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_gen_phone_res_data)) + return -1; - ril_request_unsolicited(RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0); + data = (struct ipc_gen_phone_res_data *) message->data; + + rc = ipc_gen_phone_res_check(data); + if (rc < 0) + goto error; + + dtmf_size = ril_request_data_size_get(RIL_REQUEST_DTMF_START); + dtmf_data = ril_request_data_get(RIL_REQUEST_DTMF_START); + + if (dtmf_data != NULL && dtmf_size >= sizeof(tone)) { + tone = *((char *) dtmf_data); + + // Register a new DTMF tone + ril_request_data_set(RIL_REQUEST_DTMF_START, dtmf_data, dtmf_size); + + free(dtmf_data); + + rc = ril_request_dtmf_start_complete(message->aseq, tone); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_DTMF_START); + goto error; + } + } + + dtmf_size = ril_request_data_size_get(RIL_REQUEST_DTMF); + dtmf_data = ril_request_data_get(RIL_REQUEST_DTMF); + + if (dtmf_data != NULL && dtmf_size >= sizeof(tone)) { + tone = *((char *) dtmf_data); + + free(dtmf_data); + + rc = ril_request_dtmf_complete(message->aseq, tone); + if (rc < 0) + goto error; + } + + goto complete; + +error: + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + +complete: + return 0; } -void ril_request_last_call_fail_cause(RIL_Token t) +int ipc_call_burst_dtmf(struct ipc_message *message) { - RIL_LastCallFailCause fail_cause; - struct ipc_call_status *call_status = &(ril_data.state.call_status); + if (message == NULL || message->data == NULL || message->size < sizeof(struct ipc_call_burst_dtmf_response_data)) + return -1; - fail_cause = ipc2ril_call_fail_cause(call_status->end_cause); + if (!ipc_seq_valid(message->aseq)) + return 0; - // Empty global call_status - memset(call_status, 0, sizeof(struct ipc_call_status)); + ril_request_complete(ipc_fmt_request_token(message->aseq), RIL_E_SUCCESS, NULL, 0); - ril_request_complete(t, RIL_E_SUCCESS, &fail_cause, sizeof(RIL_LastCallFailCause)); + return 0; } -void ril_request_dtmf(RIL_Token t, void *data, int length) +int ril_request_dtmf_complete(unsigned char aseq, char tone) { - struct ipc_call_cont_dtmf cont_dtmf; - unsigned char tone; - unsigned char count; + struct ipc_call_burst_dtmf_request_entry entry; + void *request_data = NULL; + size_t request_size = 0; + int rc; - unsigned char *burst; - int burst_length; + memset(&entry, 0, sizeof(entry)); + entry.status = IPC_CALL_DTMF_STATUS_START; + entry.tone = tone; - int i; + request_size = ipc_call_burst_dtmf_size_setup(&entry, 1); + if (request_size == 0) + goto error; - if (data == NULL || length < (int) sizeof(unsigned char)) + request_data = ipc_call_burst_dtmf_setup(&entry, 1); + if (request_data == NULL) goto error; - tone = *((unsigned char *) data); - count = 1; + rc = ipc_gen_phone_res_expect_abort(aseq, IPC_CALL_BURST_DTMF); + if (rc < 0) + goto error; - if (ril_data.state.dtmf_tone != 0) { - RIL_LOGD("Another tone wasn't stopped, stopping it before anything"); + rc = ipc_fmt_send(aseq, IPC_CALL_BURST_DTMF, IPC_TYPE_EXEC, request_data, request_size); + if (rc < 0) + goto error; - cont_dtmf.state = IPC_CALL_DTMF_STATE_STOP; - cont_dtmf.tone = 0; + rc = 0; + goto complete; - ipc_fmt_send(IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (void *) &cont_dtmf, sizeof(cont_dtmf), ril_request_get_id(t)); +error: + rc = -1; - usleep(300); - } +complete: + if (request_data != NULL && request_size > 0) + free(request_data); - burst_length = sizeof(struct ipc_call_cont_dtmf) * count + 1; - burst = calloc(1, burst_length); + return rc; +} - burst[0] = count; +int ril_request_dtmf(void *data, size_t size, RIL_Token token) +{ + struct ril_request *request; + void *dtmf_data; + size_t dtmf_size; + char tone; + int rc; - // Apparently, it's possible to set multiple DTMF tones on this message - for (i = 0 ; i < count ; i++) { - cont_dtmf.state = IPC_CALL_DTMF_STATE_START; - cont_dtmf.tone = tone; + if (data == NULL || size < sizeof(char)) + goto error; - memcpy(burst + 1 + sizeof(struct ipc_call_cont_dtmf) * i, &cont_dtmf, sizeof(cont_dtmf)); - } + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - ipc_gen_phone_res_expect_to_abort(ril_request_get_id(t), IPC_CALL_BURST_DTMF); + request = ril_request_find_request_status(RIL_REQUEST_DTMF, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - ipc_fmt_send(IPC_CALL_BURST_DTMF, IPC_TYPE_EXEC, burst, burst_length, ril_request_get_id(t)); + request = ril_request_find_request_status(RIL_REQUEST_DTMF_START, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - free(burst); + request = ril_request_find_request_status(RIL_REQUEST_DTMF_STOP, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - return; + tone = *((char *) data); -error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); -} + // A previous DTMF tone was started + dtmf_size = ril_request_data_size_get(RIL_REQUEST_DTMF_START); + dtmf_data = ril_request_data_get(RIL_REQUEST_DTMF_START); -void ipc_call_burst_dtmf(struct ipc_message_info *info) -{ - unsigned char code; + if (dtmf_data != NULL && dtmf_size >= sizeof(tone)) { + free(dtmf_data); - if (info->data == NULL || info->length < sizeof(unsigned char)) - goto error; + // Let the callback know what to do after completing the previous DTMF tone + ril_request_data_set(RIL_REQUEST_DTMF, data, size); - code = *((unsigned char *) info->data); + rc = ril_request_dtmf_stop_complete(ipc_fmt_request_seq(token), 1); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_DTMF); + goto error; + } - // This apparently should return 1, or perhaps that is the DTMF tones count - if (code == 0) { - RIL_LOGD("Apparently, something went wrong with DTMF burst (code=0x%x)", code); - goto error; + rc = RIL_REQUEST_HANDLED; + goto complete; } - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_SUCCESS, NULL, 0); + rc = ril_request_dtmf_complete(ipc_fmt_request_seq(token), tone); + if (rc < 0) + goto error; - return; + rc = RIL_REQUEST_HANDLED; + goto complete; error: - if (info != NULL) - ril_request_complete(ril_request_get_token(info->aseq), RIL_E_GENERIC_FAILURE, NULL, 0); + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; +} + +int ril_request_dtmf_start_complete(unsigned char aseq, char tone) +{ + struct ipc_call_cont_dtmf_data request_data; + int rc; + + memset(&request_data, 0, sizeof(request_data)); + request_data.status = IPC_CALL_DTMF_STATUS_START; + request_data.tone = tone; + + rc = ipc_gen_phone_res_expect_complete(aseq, IPC_CALL_CONT_DTMF); + if (rc < 0) + return -1; + + rc = ipc_fmt_send(aseq, IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + return -1; + + return 0; } -void ril_request_dtmf_start(RIL_Token t, void *data, int length) +int ril_request_dtmf_start(void *data, size_t size, RIL_Token token) { - struct ipc_call_cont_dtmf cont_dtmf; - unsigned char tone; + struct ril_request *request; + void *dtmf_data; + size_t dtmf_size; + char tone; + int rc; - if (data == NULL || length < (int) sizeof(unsigned char)) + if (data == NULL || size < sizeof(char)) goto error; - tone = *((unsigned char *) data); + rc = ril_radio_state_check(RADIO_STATE_SIM_NOT_READY); + if (rc < 0) + return RIL_REQUEST_UNHANDLED; - if (ril_data.state.dtmf_tone != 0) { - RIL_LOGD("Another tone wasn't stopped, stopping it before anything"); + request = ril_request_find_request_status(RIL_REQUEST_DTMF, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - cont_dtmf.state = IPC_CALL_DTMF_STATE_STOP; - cont_dtmf.tone = 0; + request = ril_request_find_request_status(RIL_REQUEST_DTMF_START, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - ipc_fmt_send(IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (unsigned char *) &cont_dtmf, sizeof(cont_dtmf), ril_request_get_id(t)); + request = ril_request_find_request_status(RIL_REQUEST_DTMF_STOP, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; - usleep(300); - } + tone = *((char *) data); - ril_data.state.dtmf_tone = cont_dtmf.tone; + // A previous DTMF tone was started + dtmf_size = ril_request_data_size_get(RIL_REQUEST_DTMF_START); + dtmf_data = ril_request_data_get(RIL_REQUEST_DTMF_START); - cont_dtmf.state = IPC_CALL_DTMF_STATE_START; - cont_dtmf.tone = tone; + if (dtmf_data != NULL && dtmf_size >= sizeof(tone)) { + free(dtmf_data); - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_CALL_CONT_DTMF); + // Let the callback know what to do after completing the previous DTMF tone + ril_request_data_set(RIL_REQUEST_DTMF_START, data, size); - ipc_fmt_send(IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (unsigned char *) &cont_dtmf, sizeof(cont_dtmf), ril_request_get_id(t)); + rc = ril_request_dtmf_stop_complete(ipc_fmt_request_seq(token), 1); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_DTMF_START); + goto error; + } + + rc = RIL_REQUEST_HANDLED; + goto complete; + } + + // Register a new DTMF tone + ril_request_data_set(RIL_REQUEST_DTMF_START, data, size); + + rc = ril_request_dtmf_start_complete(ipc_fmt_request_seq(token), tone); + if (rc < 0) { + ril_request_data_free(RIL_REQUEST_DTMF_START); + goto error; + } - return; + rc = RIL_REQUEST_HANDLED; + goto complete; error: - ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0); + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + + rc = RIL_REQUEST_COMPLETED; + +complete: + return rc; } -void ril_request_dtmf_stop(RIL_Token t) +int ril_request_dtmf_stop_complete(unsigned char aseq, int callback) { - struct ipc_call_cont_dtmf cont_dtmf; + struct ipc_call_cont_dtmf_data request_data; + int rc; + + memset(&request_data, 0, sizeof(request_data)); + request_data.status = IPC_CALL_DTMF_STATUS_STOP; + request_data.tone = 0; + + if (callback) + rc = ipc_gen_phone_res_expect_callback(aseq, IPC_CALL_CONT_DTMF, ipc_call_cont_dtmf_callback); + else + rc = ipc_gen_phone_res_expect_complete(aseq, IPC_CALL_CONT_DTMF); - ril_data.state.dtmf_tone = 0; + if (rc < 0) + return -1; - cont_dtmf.state = IPC_CALL_DTMF_STATE_STOP; - cont_dtmf.tone = 0; + rc = ipc_fmt_send(aseq, IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (void *) &request_data, sizeof(request_data)); + if (rc < 0) + return -1; - ipc_gen_phone_res_expect_to_complete(ril_request_get_id(t), IPC_CALL_CONT_DTMF); + return 0; +} + +int ril_request_dtmf_stop(void *data, size_t size, RIL_Token token) +{ + struct ril_request *request; + void *dtmf_data; + size_t dtmf_size; + int rc; + + request = ril_request_find_request_status(RIL_REQUEST_DTMF, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_DTMF_START, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + request = ril_request_find_request_status(RIL_REQUEST_DTMF_STOP, RIL_REQUEST_HANDLED); + if (request != NULL) + return RIL_REQUEST_UNHANDLED; + + // Clear the DTMF tone + dtmf_size = ril_request_data_size_get(RIL_REQUEST_DTMF_START); + dtmf_data = ril_request_data_get(RIL_REQUEST_DTMF_START); + + if (dtmf_data != NULL && dtmf_size >= sizeof(char)) + free(dtmf_data); + + rc = ril_request_dtmf_stop_complete(ipc_fmt_request_seq(token), 0); + if (rc < 0) { + ril_request_complete(token, RIL_E_GENERIC_FAILURE, NULL, 0); + return RIL_REQUEST_COMPLETED; + } - ipc_fmt_send(IPC_CALL_CONT_DTMF, IPC_TYPE_SET, (unsigned char *) &cont_dtmf, sizeof(cont_dtmf), ril_request_get_id(t)); + return RIL_REQUEST_HANDLED; } |