080f7ee6fb987a2c56794b60a22947dfa9e76c9c
[platform/upstream/ofono.git] / drivers / ifxmodem / radio-settings.c
1 /*
2  *
3  *  oFono - Open Source Telephony
4  *
5  *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #define _GNU_SOURCE
27 #include <string.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <errno.h>
31
32 #include <glib.h>
33
34 #include <ofono/log.h>
35 #include <ofono/modem.h>
36 #include <ofono/radio-settings.h>
37
38 #include "gatchat.h"
39 #include "gatresult.h"
40
41 #include "ifxmodem.h"
42
43 static const char *none_prefix[] = { NULL };
44 static const char *xrat_prefix[] = { "+XRAT:", NULL };
45
46 struct radio_settings_data {
47         GAtChat *chat;
48 };
49
50 static void xrat_query_cb(gboolean ok, GAtResult *result, gpointer user_data)
51 {
52         struct cb_data *cbd = user_data;
53         ofono_radio_settings_rat_mode_query_cb_t cb = cbd->cb;
54         enum ofono_radio_access_mode mode;
55         struct ofono_error error;
56         GAtResultIter iter;
57         int value, preferred;
58
59         decode_at_error(&error, g_at_result_final_response(result));
60
61         if (!ok) {
62                 cb(&error, -1, cbd->data);
63                 return;
64         }
65
66         g_at_result_iter_init(&iter, result);
67
68         if (g_at_result_iter_next(&iter, "+XRAT:") == FALSE)
69                 goto error;
70
71         if (g_at_result_iter_next_number(&iter, &value) == FALSE)
72                 goto error;
73
74         if (g_at_result_iter_next_number(&iter, &preferred) == FALSE)
75                 goto error;
76
77         switch (value) {
78         case 0:
79                 mode = OFONO_RADIO_ACCESS_MODE_GSM;
80                 break;
81         case 1:
82                 mode = OFONO_RADIO_ACCESS_MODE_ANY;
83                 break;
84         case 2:
85                 mode = OFONO_RADIO_ACCESS_MODE_UMTS;
86                 break;
87         default:
88                 CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
89                 return;
90         }
91
92         cb(&error, mode, cbd->data);
93
94         return;
95
96 error:
97         CALLBACK_WITH_FAILURE(cb, -1, cbd->data);
98 }
99
100 static void ifx_query_rat_mode(struct ofono_radio_settings *rs,
101                                 ofono_radio_settings_rat_mode_query_cb_t cb,
102                                 void *data)
103 {
104         struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
105         struct cb_data *cbd = cb_data_new(cb, data);
106
107         if (g_at_chat_send(rsd->chat, "AT+XRAT?", xrat_prefix,
108                                         xrat_query_cb, cbd, g_free) == 0) {
109                 CALLBACK_WITH_FAILURE(cb, -1, data);
110                 g_free(cbd);
111         }
112 }
113
114 static void xrat_modify_cb(gboolean ok, GAtResult *result, gpointer user_data)
115 {
116         struct cb_data *cbd = user_data;
117         ofono_radio_settings_rat_mode_set_cb_t cb = cbd->cb;
118         struct ofono_error error;
119
120         decode_at_error(&error, g_at_result_final_response(result));
121         cb(&error, cbd->data);
122 }
123
124 static void ifx_set_rat_mode(struct ofono_radio_settings *rs,
125                                 enum ofono_radio_access_mode mode,
126                                 ofono_radio_settings_rat_mode_set_cb_t cb,
127                                 void *data)
128 {
129         struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
130         struct cb_data *cbd = cb_data_new(cb, data);
131         char buf[20];
132         int value = 1, preferred = 2;
133
134         switch (mode) {
135         case OFONO_RADIO_ACCESS_MODE_ANY:
136                 value = 1;
137                 break;
138         case OFONO_RADIO_ACCESS_MODE_GSM:
139                 value = 0;
140                 break;
141         case OFONO_RADIO_ACCESS_MODE_UMTS:
142                 value = 2;
143                 break;
144         case OFONO_RADIO_ACCESS_MODE_LTE:
145                 goto error;
146         }
147
148         if (value == 1)
149                 snprintf(buf, sizeof(buf), "AT+XRAT=%u,%u", value, preferred);
150         else
151                 snprintf(buf, sizeof(buf), "AT+XRAT=%u", value);
152
153         if (g_at_chat_send(rsd->chat, buf, none_prefix,
154                                         xrat_modify_cb, cbd, g_free) > 0)
155                 return;
156
157 error:
158         CALLBACK_WITH_FAILURE(cb, data);
159         g_free(cbd);
160 }
161
162 static void xrat_support_cb(gboolean ok, GAtResult *result, gpointer user_data)
163 {
164         struct ofono_radio_settings *rs = user_data;
165
166         if (!ok)
167                 return;
168
169         ofono_radio_settings_register(rs);
170 }
171
172 static int ifx_radio_settings_probe(struct ofono_radio_settings *rs,
173                                         unsigned int vendor, void *data)
174 {
175         GAtChat *chat = data;
176         struct radio_settings_data *rsd;
177
178         rsd = g_try_new0(struct radio_settings_data, 1);
179         if (rsd == NULL)
180                 return -ENOMEM;
181
182         rsd->chat = g_at_chat_clone(chat);
183
184         ofono_radio_settings_set_data(rs, rsd);
185
186         g_at_chat_send(rsd->chat, "AT+XRAT=?", xrat_prefix,
187                                         xrat_support_cb, rs, NULL);
188
189         return 0;
190 }
191
192 static void ifx_radio_settings_remove(struct ofono_radio_settings *rs)
193 {
194         struct radio_settings_data *rsd = ofono_radio_settings_get_data(rs);
195
196         ofono_radio_settings_set_data(rs, NULL);
197
198         g_at_chat_unref(rsd->chat);
199         g_free(rsd);
200 }
201
202 static struct ofono_radio_settings_driver driver = {
203         .name                   = "ifxmodem",
204         .probe                  = ifx_radio_settings_probe,
205         .remove                 = ifx_radio_settings_remove,
206         .query_rat_mode         = ifx_query_rat_mode,
207         .set_rat_mode           = ifx_set_rat_mode
208 };
209
210 void ifx_radio_settings_init(void)
211 {
212         ofono_radio_settings_driver_register(&driver);
213 }
214
215 void ifx_radio_settings_exit(void)
216 {
217         ofono_radio_settings_driver_unregister(&driver);
218 }