MISC: Timezone can be negative: handle that case as well
[samsung-ril.git] / misc.c
1 /**
2  * This file is part of samsung-ril.
3  *
4  * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com>
5  * Copyright (C) 2011-2012 Paul Kocialkowski <contact@paulk.fr>
6  *
7  * samsung-ril is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * samsung-ril is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with samsung-ril.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21
22 #define LOG_TAG "RIL-MISC"
23 #include <utils/Log.h>
24
25 #include "samsung-ril.h"
26 #include "util.h"
27
28 void ril_request_get_imei_send(RIL_Token t)
29 {
30         unsigned char data;
31
32         data = IPC_MISC_ME_SN_SERIAL_NUM;
33         ipc_fmt_send(IPC_MISC_ME_SN, IPC_TYPE_GET,
34                 (unsigned char *) &data, sizeof(data), ril_request_get_id(t));
35 }
36
37 void ril_request_get_imei(RIL_Token t)
38 {
39         if(ril_data.tokens.get_imei) {
40                 LOGD("Another IMEI request is waiting, aborting");
41                 ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
42                 return;
43         }
44
45         ril_data.tokens.get_imei = t;
46
47         if(ril_data.tokens.get_imeisv) {
48                 LOGD("IMEISV token found: %p", ril_data.tokens.get_imeisv);
49
50                 if(ril_data.state.radio_state != RADIO_STATE_OFF) {
51                         ril_request_get_imei_send(ril_data.tokens.get_imei);
52                 } else {
53                         LOGD("Radio is off, waiting");
54                 }
55         } else {
56                 LOGD("Waiting for IMEISV token");
57         }
58 }
59
60 void ril_request_get_imeisv(RIL_Token t)
61 {
62         if(ril_data.tokens.get_imeisv) {
63                 LOGD("Another IMEISV request is waiting, aborting");
64                 ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
65                 return;
66         }
67
68         ril_data.tokens.get_imeisv = t;
69
70         if(ril_data.tokens.get_imei) {
71                 LOGD("IMEI token found: %p", ril_data.tokens.get_imei);
72
73                 if(ril_data.state.radio_state != RADIO_STATE_OFF) {
74                         ril_request_get_imei_send(ril_data.tokens.get_imei);
75                 } else {
76                         LOGD("Radio is off, waiting");
77                 }
78         } else {
79                 LOGD("Waiting for IMEI token");
80         }
81 }
82
83 void ipc_misc_me_sn_imei(RIL_Token t, void *data, int length)
84 {
85         struct ipc_misc_me_sn *imei_info;
86         char imei[33];
87         char imeisv[3];
88
89         imei_info = (struct ipc_misc_me_sn *) data;
90
91         if(ril_data.tokens.get_imei != t) 
92                 LOGE("IMEI tokens mismatch (%p and %p)",
93                         ril_data.tokens.get_imei, t);
94
95         if(imei_info->length > 32)
96                 return;
97
98         memset(imei, 0, sizeof(imei));
99         memset(imeisv, 0, sizeof(imeisv));
100
101         memcpy(imei, imei_info->data, imei_info->length);
102
103         // Last two bytes of IMEI in imei_info are the SV bytes
104         memcpy(imeisv, (imei_info->data + imei_info->length - 2), 2);
105
106         // In case of token mismatch, complete both requests
107         if(t && ril_data.tokens.get_imei != t) {
108                 ril_request_complete(t, RIL_E_SUCCESS, imei, sizeof(char *));
109         }
110
111         // IMEI
112         if(ril_data.tokens.get_imei) {
113                 ril_request_complete(ril_data.tokens.get_imei,
114                         RIL_E_SUCCESS, imei, sizeof(char *));
115                 ril_data.tokens.get_imei = 0;
116         }
117
118         // IMEI SV
119         if(ril_data.tokens.get_imeisv) {
120                 ril_request_complete(ril_data.tokens.get_imeisv,
121                         RIL_E_SUCCESS, imeisv, sizeof(char *));
122                 ril_data.tokens.get_imeisv = 0;
123         }
124 }
125
126 void ipc_misc_me_sn(struct ipc_message_info *info)
127 {
128         struct ipc_misc_me_sn *me_sn_info = (struct ipc_misc_me_sn *) info->data;
129
130         switch(me_sn_info->type) {
131                 case IPC_MISC_ME_SN_SERIAL_NUM:
132                         ipc_misc_me_sn_imei(ril_request_get_token(info->aseq), info->data, info->length);
133                         break;
134                 case IPC_MISC_ME_SN_SERIAL_NUM_SERIAL:
135                         LOGD("Got IPC_MISC_ME_SN_SERIAL_NUM_SERIAL: %s\n",
136                                 me_sn_info->data);
137                         break;
138         }
139 }
140
141 void ril_request_baseband_version(RIL_Token t)
142 {
143         unsigned char data;
144         if(ril_data.tokens.baseband_version) {
145                 LOGD("Another Baseband version request is waiting, aborting");
146                 ril_request_complete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
147                 return;
148         }
149
150         ril_data.tokens.baseband_version = t;
151
152         if(ril_data.state.radio_state != RADIO_STATE_OFF) {
153                 data = 0xff;
154
155                 ipc_fmt_send(IPC_MISC_ME_VERSION, IPC_TYPE_GET,
156                         (unsigned char *) &data, sizeof(data), ril_request_get_id(t));
157         }
158 }
159
160 void ipc_misc_me_version(struct ipc_message_info *info)
161 {
162         char sw_version[33];
163         struct ipc_misc_me_version *version =
164                 (struct ipc_misc_me_version *) info->data;
165         RIL_Token t = ril_request_get_token(info->aseq);
166
167         if(ril_data.tokens.baseband_version != t) 
168                 LOGE("Baseband tokens mismatch (%p and %p)",
169                         ril_data.tokens.baseband_version, t);
170
171
172         memcpy(sw_version, version->sw_version, 32);
173         sw_version[32] = '\0';
174
175         ril_request_complete(t, RIL_E_SUCCESS, sw_version, sizeof(sw_version));
176         ril_data.tokens.baseband_version = 0;
177 }
178
179 /**
180  * In: RIL_REQUEST_GET_IMSI
181  *   Get the SIM IMSI
182  *   Only valid when radio state is "RADIO_STATE_SIM_READY"
183  *
184  * Out: IPC_MISC_ME_IMSI
185  *   Requests ME's IMSI
186  */
187 void ril_request_get_imsi(RIL_Token t)
188 {
189         ipc_fmt_send_get(IPC_MISC_ME_IMSI, ril_request_get_id(t));
190 }
191
192 /**
193  * In: IPC_MISC_ME_IMSI
194  *   Provides ME's IMSI
195  *
196  * Out: RIL_REQUEST_GET_IMSI
197  *   Get the SIM IMSI
198  *   Only valid when radio state is "RADIO_STATE_SIM_READY"
199  */
200 void ipc_misc_me_imsi(struct ipc_message_info *info)
201 {
202         unsigned char *imsi_length;
203         char *imsi;
204
205         /* Don't consider this if modem isn't in normal power mode. */
206         if(ril_data.state.power_state != IPC_PWR_PHONE_STATE_NORMAL)
207                 return;
208
209         if(info->length < 1) {
210                 LOGE("%s: zero data length", __FUNCTION__);
211                 ril_request_complete(ril_request_get_token(info->aseq),
212                         RIL_E_GENERIC_FAILURE, NULL, 0);
213                 return;
214         }
215
216         imsi_length = (unsigned char*) info->data;
217
218         if(((int) info->length) < *imsi_length + 1) {
219                 LOGE("%s: missing IMSI data", __FUNCTION__);
220                 ril_request_complete(ril_request_get_token(info->aseq),
221                         RIL_E_GENERIC_FAILURE, NULL, 0);
222                 return;
223         }
224
225         /* Copy IMSI */
226         imsi = (char*) malloc(*imsi_length+1);
227         memcpy(imsi, ((unsigned char*) info->data) + 1, *imsi_length);
228         imsi[*imsi_length] = '\0';
229
230         ril_request_complete(ril_request_get_token(info->aseq),
231                 RIL_E_SUCCESS, imsi, *imsi_length+1);
232 }
233
234 void ipc_misc_time_info(struct ipc_message_info *info)
235 {
236         struct ipc_misc_time_info *nitz = (struct ipc_misc_time_info*) info->data;
237         char str[128];
238
239         sprintf(str, "%02u/%02u/%02u,%02u:%02u:%02u%c%02d,%02d",
240                 nitz->year, nitz->mon, nitz->day, nitz->hour,
241                 nitz->min, nitz->sec, nitz->tz < 0 ? '-' : '+',
242                 nitz->tz < 0 ? -nitz->tz : nitz->tz, 0);
243
244         ril_request_unsolicited(RIL_UNSOL_NITZ_TIME_RECEIVED,
245                 str, strlen(str) + 1);
246 }