3 * oFono - Open Source Telephony
5 * Copyright (C) 2008-2012 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31 #include <ofono/log.h>
32 #include <ofono/modem.h>
33 #include <ofono/ussd.h>
38 #include "speedupmodem.h"
40 static const char *cusd_prefix[] = { "+CUSD:", NULL };
41 static const char *none_prefix[] = { NULL };
47 static void cusd_parse(GAtResult *result, struct ofono_ussd *ussd)
52 unsigned char msg[160];
53 const unsigned char *msg_ptr = NULL;
56 g_at_result_iter_init(&iter, result);
58 if (!g_at_result_iter_next(&iter, "+CUSD:"))
61 if (!g_at_result_iter_next_number(&iter, &status))
64 if (!g_at_result_iter_next_string(&iter, &content))
67 if (!g_at_result_iter_next_number(&iter, &dcs))
70 msg_ptr = decode_hex_own_buf(content, -1, &msg_len, 0, msg);
73 ofono_ussd_notify(ussd, status, dcs, msg_ptr, msg_ptr ? msg_len : 0);
76 static void cusd_request_cb(gboolean ok, GAtResult *result, gpointer user_data)
78 struct cb_data *cbd = user_data;
79 ofono_ussd_cb_t cb = cbd->cb;
80 struct ofono_ussd *ussd = cbd->user;
81 struct ofono_error error;
83 decode_at_error(&error, g_at_result_final_response(result));
85 cb(&error, cbd->data);
87 cusd_parse(result, ussd);
90 static void speedup_ussd_request(struct ofono_ussd *ussd, int dcs,
91 const unsigned char *pdu, int len,
92 ofono_ussd_cb_t cb, void *user_data)
94 struct ussd_data *data = ofono_ussd_get_data(ussd);
95 struct cb_data *cbd = cb_data_new(cb, user_data);
96 char buf[512], coded_buf[182];
101 unpack_7bit_own_buf(pdu, len, 0, TRUE, sizeof(coded_buf),
102 &written, 0, (unsigned char *)coded_buf);
106 snprintf(buf, sizeof(buf), "AT+CUSD=1,\"%.*s\",%d", (int) written,
109 if (g_at_chat_send(data->chat, buf, cusd_prefix,
110 cusd_request_cb, cbd, g_free) > 0)
116 CALLBACK_WITH_FAILURE(cb, user_data);
119 static void cusd_cancel_cb(gboolean ok, GAtResult *result, gpointer user_data)
121 struct cb_data *cbd = user_data;
122 ofono_ussd_cb_t cb = cbd->cb;
123 struct ofono_error error;
125 decode_at_error(&error, g_at_result_final_response(result));
128 * All errors and notifications arrive unexpected and
129 * thus just reset the state here. This is safer than
130 * getting stuck in a dead-lock.
132 error.type = OFONO_ERROR_TYPE_NO_ERROR;
135 cb(&error, cbd->data);
138 static void speedup_ussd_cancel(struct ofono_ussd *ussd,
139 ofono_ussd_cb_t cb, void *user_data)
141 struct ussd_data *data = ofono_ussd_get_data(ussd);
142 struct cb_data *cbd = cb_data_new(cb, user_data);
146 if (g_at_chat_send(data->chat, "AT+CUSD=2", none_prefix,
147 cusd_cancel_cb, cbd, g_free) > 0)
152 CALLBACK_WITH_FAILURE(cb, user_data);
155 static void cusd_notify(GAtResult *result, gpointer user_data)
157 struct ofono_ussd *ussd = user_data;
159 cusd_parse(result, ussd);
162 static void cusd_register(gboolean ok, GAtResult *result, gpointer user_data)
164 struct ofono_ussd *ussd = user_data;
165 struct ussd_data *data = ofono_ussd_get_data(ussd);
168 ofono_error("Could not enable CUSD notifications");
169 ofono_ussd_remove(ussd);
173 g_at_chat_register(data->chat, "+CUSD:", cusd_notify,
176 ofono_ussd_register(ussd);
179 static int speedup_ussd_probe(struct ofono_ussd *ussd,
180 unsigned int vendor, void *user)
182 GAtChat *chat = user;
183 struct ussd_data *data;
185 data = g_try_new0(struct ussd_data, 1);
189 data->chat = g_at_chat_clone(chat);
191 ofono_ussd_set_data(ussd, data);
193 g_at_chat_send(data->chat, "AT+CUSD=1", none_prefix,
194 cusd_register, ussd, NULL);
199 static void speedup_ussd_remove(struct ofono_ussd *ussd)
201 struct ussd_data *data = ofono_ussd_get_data(ussd);
203 ofono_ussd_set_data(ussd, NULL);
205 g_at_chat_unref(data->chat);
209 static struct ofono_ussd_driver driver = {
210 .name = "speedupmodem",
211 .probe = speedup_ussd_probe,
212 .remove = speedup_ussd_remove,
213 .request = speedup_ussd_request,
214 .cancel = speedup_ussd_cancel,
217 void speedup_ussd_init(void)
219 ofono_ussd_driver_register(&driver);
222 void speedup_ussd_exit(void)
224 ofono_ussd_driver_unregister(&driver);