diff --git a/temp/ofono/0007-qmimodem-implement-dtmf.patch b/temp/ofono/0007-qmimodem-implement-dtmf.patch new file mode 100644 index 000000000..2a439a4fc --- /dev/null +++ b/temp/ofono/0007-qmimodem-implement-dtmf.patch @@ -0,0 +1,247 @@ +From 306a3a6f19546b7b9b6b8df973d75710ce21bc3c Mon Sep 17 00:00:00 2001 +From: Joey Hewitt +Date: Mon, 4 Sep 2017 23:51:07 -0700 +Subject: [PATCH] qmimodem: implement DTMF + +The TLVs are documented in GobiAPI. I pass 0xff for the call ID, as the +stock RIL appears to always do. I would guess it means "current foreground +call." + +The call ID is returned in TLV 0x10, but I didn't implement parsing of +that. + +Acked-by: Alexey Andreyev + +diff --git a/drivers/qmimodem/voice_generated.c b/drivers/qmimodem/voice_generated.c +index aef79c4..b579043 100644 +--- a/drivers/qmimodem/voice_generated.c ++++ b/drivers/qmimodem/voice_generated.c +@@ -216,3 +216,72 @@ enum parse_error qmi_voice_call_status( + + return err; + } ++ ++int qmi_voice_start_cont_dtmf( ++ struct qmi_voice_start_cont_dtmf_arg *arg, ++ struct qmi_service *service, ++ qmi_result_func_t func, ++ void *user_data, ++ qmi_destroy_func_t destroy) ++{ ++ struct qmi_param *param = NULL; ++ uint8_t param_body[2]; ++ ++ param = qmi_param_new(); ++ if (!param) ++ goto error; ++ ++ param_body[0] = arg->call_id; ++ param_body[1] = arg->dtmf_char; ++ ++ if (!qmi_param_append( ++ param, ++ 0x1, ++ sizeof(param_body), ++ param_body)) ++ goto error; ++ ++ if (qmi_service_send(service, ++ 0x29, ++ param, ++ func, ++ user_data, ++ destroy) > 0) ++ return 0; ++ ++error: ++ g_free(param); ++ return 1; ++} ++ ++int qmi_voice_stop_cont_dtmf( ++ struct qmi_voice_stop_cont_dtmf_arg *arg, ++ struct qmi_service *service, ++ qmi_result_func_t func, ++ void *user_data, ++ qmi_destroy_func_t destroy) ++{ ++ struct qmi_param *param = NULL; ++ ++ param = qmi_param_new(); ++ if (!param) ++ goto error; ++ ++ if (!qmi_param_append_uint8( ++ param, ++ 0x1, ++ arg->call_id)) ++ goto error; ++ ++ if (qmi_service_send(service, ++ 0x2a, ++ param, ++ func, ++ user_data, ++ destroy) > 0) ++ return 0; ++ ++error: ++ g_free(param); ++ return 1; ++} +\ No newline at end of file +diff --git a/drivers/qmimodem/voice_generated.h b/drivers/qmimodem/voice_generated.h +index dc238ef..c627fe1 100644 +--- a/drivers/qmimodem/voice_generated.h ++++ b/drivers/qmimodem/voice_generated.h +@@ -110,4 +110,27 @@ enum parse_error qmi_voice_call_status( + struct qmi_result *qmi_result, + struct qmi_voice_all_call_status_ind *result); + ++struct qmi_voice_start_cont_dtmf_arg { ++ uint8_t call_id; ++ uint8_t dtmf_char; ++}; ++ ++int qmi_voice_start_cont_dtmf( ++ struct qmi_voice_start_cont_dtmf_arg *arg, ++ struct qmi_service *service, ++ qmi_result_func_t func, ++ void *user_data, ++ qmi_destroy_func_t destroy); ++ ++struct qmi_voice_stop_cont_dtmf_arg { ++ uint8_t call_id; ++}; ++ ++int qmi_voice_stop_cont_dtmf( ++ struct qmi_voice_stop_cont_dtmf_arg *arg, ++ struct qmi_service *service, ++ qmi_result_func_t func, ++ void *user_data, ++ qmi_destroy_func_t destroy); ++ + #endif /* __OFONO_QMI_VOICE_GENERATED_H */ +diff --git a/drivers/qmimodem/voicecall.c b/drivers/qmimodem/voicecall.c +index bc8ac2b..5d8d35f 100644 +--- a/drivers/qmimodem/voicecall.c ++++ b/drivers/qmimodem/voicecall.c +@@ -413,6 +413,110 @@ static void hangup_active(struct ofono_voicecall *vc, + release_specific(vc, call->id, cb, data); + } + ++static void stop_cont_dtmf_cb(struct qmi_result *result, void *user_data) ++{ ++ struct cb_data *cbd = user_data; ++ ofono_voicecall_cb_t cb = cbd->cb; ++ ++ uint16_t error; ++ ++ if (qmi_result_set_error(result, &error)) { ++ DBG("QMI Error %d", error); ++ CALLBACK_WITH_FAILURE(cb, cbd->data); ++ return; ++ } ++ ++ CALLBACK_WITH_SUCCESS(cb, cbd->data); ++} ++ ++static void start_cont_dtmf_cb(struct qmi_result *result, void *user_data) ++{ ++ struct cb_data *cbd = user_data; ++ ofono_voicecall_cb_t cb = cbd->cb; ++ struct ofono_voicecall *vc = cbd->user; ++ struct voicecall_data *vd = ofono_voicecall_get_data(vc); ++ struct qmi_voice_stop_cont_dtmf_arg arg; ++ uint16_t error; ++ ++ if (qmi_result_set_error(result, &error)) { ++ DBG("QMI Error %d", error); ++ CALLBACK_WITH_FAILURE(cb, cbd->data); ++ return; ++ } ++ ++ arg.call_id = 0xff; ++ ++ if (!qmi_voice_stop_cont_dtmf(&arg, ++ vd->voice, ++ stop_cont_dtmf_cb, ++ cbd, ++ g_free)) ++ return; ++ ++ CALLBACK_WITH_FAILURE(cb, cbd->data); ++} ++ ++static void send_one_dtmf(struct ofono_voicecall *vc, const char dtmf, ++ ofono_voicecall_cb_t cb, void *data) { ++ struct qmi_voice_start_cont_dtmf_arg arg; ++ struct voicecall_data *vd = ofono_voicecall_get_data(vc); ++ ++ arg.call_id = 0xff; ++ arg.dtmf_char = (uint8_t) dtmf; ++ ++ struct cb_data *cbd = cb_data_new(cb, data); ++ cbd->user = vc; ++ ++ if (!qmi_voice_start_cont_dtmf(&arg, ++ vd->voice, ++ start_cont_dtmf_cb, ++ cbd, ++ NULL)) ++ return; ++ ++ CALLBACK_WITH_FAILURE(cb, data); ++ g_free(cbd); ++} ++ ++struct send_one_dtmf_cb_data { ++ const char *full_dtmf; ++ const char *next_dtmf; ++ struct ofono_voicecall *vc; ++}; ++ ++static void send_one_dtmf_cb(const struct ofono_error *error, void *data) { ++ struct cb_data *cbd = data; ++ ofono_voicecall_cb_t cb = cbd->cb; ++ struct send_one_dtmf_cb_data *send_one_dtmf_cb_data = cbd->user; ++ ++ if (error->type != OFONO_ERROR_TYPE_NO_ERROR || *send_one_dtmf_cb_data->next_dtmf == 0) { ++ if (error->type == OFONO_ERROR_TYPE_NO_ERROR) { ++ CALLBACK_WITH_SUCCESS(cb, cbd->data); ++ } else { ++ CALLBACK_WITH_FAILURE(cb, cbd->data); ++ } ++ g_free((gpointer)send_one_dtmf_cb_data->full_dtmf); ++ g_free(send_one_dtmf_cb_data); ++ g_free(cbd); ++ } else { ++ send_one_dtmf(send_one_dtmf_cb_data->vc, *(send_one_dtmf_cb_data->next_dtmf++), send_one_dtmf_cb, data); ++ } ++} ++ ++static void send_dtmf(struct ofono_voicecall *vc, const char *dtmf, ++ ofono_voicecall_cb_t cb, void *data) ++{ ++ struct cb_data *cbd = cb_data_new(cb, data); ++ struct send_one_dtmf_cb_data *send_one_dtmf_cb_data = g_new(struct send_one_dtmf_cb_data, 1); ++ ++ send_one_dtmf_cb_data->full_dtmf = g_strdup(dtmf); ++ send_one_dtmf_cb_data->next_dtmf = &send_one_dtmf_cb_data->full_dtmf[1]; ++ send_one_dtmf_cb_data->vc = vc; ++ cbd->user = send_one_dtmf_cb_data; ++ ++ send_one_dtmf(vc, *dtmf, send_one_dtmf_cb, cbd); ++} ++ + static const struct ofono_voicecall_driver driver = { + .name = "qmimodem", + .probe = qmi_voicecall_probe, +@@ -421,6 +525,7 @@ static const struct ofono_voicecall_driver driver = { + .answer = answer, + .hangup_active = hangup_active, + .release_specific = release_specific, ++ .send_tones = send_dtmf, + }; + + void qmi_voicecall_init(void) diff --git a/temp/ofono/APKBUILD b/temp/ofono/APKBUILD index 349967f9c..9f79563fe 100644 --- a/temp/ofono/APKBUILD +++ b/temp/ofono/APKBUILD @@ -3,7 +3,7 @@ pkgname=ofono pkgver=9999 _pkgver=1.31 -pkgrel=7 +pkgrel=8 pkgdesc="Infrastructure for building mobile telephony (GSM/UMTS) applications [$_pkgver]" url="https://01.org/ofono" arch="armhf armv7 aarch64" @@ -24,6 +24,7 @@ source="https://www.kernel.org/pub/linux/network/ofono/ofono-$_pkgver.tar.xz 0004-add-call-list-helper-to-manage-voice-call-lists.patch 0005-qmimodem-implement-voice-calls.patch 0006-qmimodem-Fix-dialing-to-an-international-number.patch + 0007-qmimodem-implement-dtmf.patch $pkgname.initd $pkgname-auto-enable.initd udev.rules @@ -83,6 +84,7 @@ ad25dcc34bf710287c9a03fdcd61f2f2fd675691f55be30dbe7c8421753aa857906dd23b2d4f7f75 3e0dce12bcb65d3c6db15cfd50058e793bf1f1ae6e330bf804565afde54614227746a8d4316ccd36093f22e2cc4f62e3a32e46276ab81a7b1f3a61f56984ed78 0004-add-call-list-helper-to-manage-voice-call-lists.patch 72d0f63c091d4b1fc5b405ec67e73f377887ee3dffd4791272122462bf4feaeec207de9b177632756e1f973a7bf7bde119c6ec6556568a6307287ba43998b7a0 0005-qmimodem-implement-voice-calls.patch 6dd4d5f829d66b5b9a13aed6d5a991a2cd3dee6db04a122bcc1d87d0eddc37637468bec58f9fe6027c89eac3b14411201d324150e6be4b103622340da6a599fe 0006-qmimodem-Fix-dialing-to-an-international-number.patch +7d28bcec2dc8b13003c05d74202aced9c86efe35447fbcb0f444fb04447fab8e80a47fa20a662aa0148d42c25333b3261e3cd570991deee9cdfd76effd24af7e 0007-qmimodem-implement-dtmf.patch bc76c404a7de626210dbd78f659444567a95b6e6d8db0661d5d67ea361e2941ad55242d43a5957995817145d4d5323476fbc42d1830b20608a5e90a7a4ba1194 ofono.initd 54a2cb55547e77c22a98c4260f2e94d9327d5d98e1b604f9413a7380ae4489247a97561cc2ab39476bc6e6fb5e673dca8053218b18ac4626addb51ecb29f0167 ofono-auto-enable.initd 28ba914e171ba7f0dcc4be24f2bd078a8db6b2c0fdbb29845b2702f00f9cf64d0e9ecb277e5d7f8113ef450eb9044e542e7093129ecd67bef1c9e9328756391c udev.rules