IMC plugin update
[platform/core/telephony/tel-plugin-imc.git] / src / nvm / nvm.c
1 /*
2  * tel-plugin-imc
3  *
4  * Copyright (c) 2013 Samsung Electronics Co. Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <glib.h>
24
25 #include <sys/stat.h>
26 #include <tcore.h>
27 #include "nvm/nvm.h"
28
29 /* NVM file type */
30 #define NVM_TYPE_CALIB                          0
31 #define NVM_TYPE_STATIC                 1
32 #define NVM_TYPE_DYNAMIC                        2
33 #define NVM_FILE_TYPE_POS                       36
34
35 /* NVM Payload information */
36 #define NVM_PAYLOAD_OFFSET_0            48
37 #define NVM_PAYLOAD_LENGTH_0            52
38 #define NVM_PAYLOAD_OFFSET_1            64
39 #define NVM_PAYLOAD_LENGTH_1            68
40 #define NVM_DATA_LEN_POS                        80
41
42 /* Image Path information */
43 #define MODEM_IMAGE_PATH                                "/boot/modem.bin"
44 #define NVM_DIR_PATH                                    "/csa/nv"
45 #define NV_FILE_PATH NVM_DIR_PATH               "/nvdata.bin"
46
47 /* NV offsets and size */
48 #define MODEM_NV_OFFSET                                 0xA00000
49 #define MAX_NVDATA_SIZE                                 0x200000
50 #define NVM_CALIB_OFFSET                                0x80000
51 #define NVM_STATIC_OFFSET                               0x100000
52
53 struct nvm_payload_info {
54         unsigned long m_offset_0;
55         unsigned long m_length_0;
56         unsigned long m_offset_1;
57         unsigned long m_length_1;
58 };
59
60 static nvm_error __nvm_file_write(int nvm_type, const char *update_buf, int update_len, int offset)
61 {
62         int nv_fd;
63         nvm_error ret_val = NVM_NO_ERR;
64         int ret;
65
66         char err_str[256] = {0, };
67         errno = 0;
68         dbg("Entered");
69
70         if (NULL == update_buf) {
71                 err("Buffer is invalid!!!");
72                 return NVM_WRITE_ERR;
73         }
74
75         switch (nvm_type) {
76         case NVM_TYPE_CALIB:
77                 msg("           [NVM File] calib.nvm");
78                 offset = offset + NVM_CALIB_OFFSET;
79                 break;
80
81         case NVM_TYPE_STATIC:
82                 msg("           [NVM File] static.nvm");
83                 offset = offset + NVM_STATIC_OFFSET;
84                 break;
85
86         case NVM_TYPE_DYNAMIC:
87                 msg("           [NVM File] dynamic.nvm");
88                 break;
89
90         default:
91                 err("[NVM File] Wrong NVM file type: [%d]", nvm_type);
92                 return NVM_FILE_ERR;
93         }
94
95         /* Open NVM file for Write operation */
96         nv_fd = open(NV_FILE_PATH, O_RDWR);
97         if (nv_fd < 0) {
98                 strerror_r(errno, err_str, 255);
99                 err("[OPEN] Failed: [%s]", err_str);
100                 return NVM_READ_ERR;
101         }
102
103         /* Seek the offset */
104         ret = lseek(nv_fd, (long)offset, SEEK_SET);
105         if (ret < 0) {
106                 strerror_r(errno, err_str, 255);
107                 err("[SEEK] Failed: [%s]", err_str);
108                 ret_val = NVM_RES_LEN_ERR;
109         } else {
110                 dbg("Buffer: [0x%x] length: [%d]", update_buf, update_len);
111
112                 /* Write the buffer to file */
113                 ret = write(nv_fd, update_buf, update_len);
114                 if (ret > 0) {
115                         dbg("[WRITE] Successfully updated NVM data");
116                 } else if (ret == 0) {
117                         strerror_r(errno, err_str, 255);
118                         dbg("[WRITE] Nothing is written: [%s]", err_str);
119                 } else {
120                         strerror_r(errno, err_str, 255);
121                         err("[WRITE] Failed: [%s]", err_str);
122                         ret_val = NVM_MEM_FULL_ERR;
123                 }
124         }
125
126         /* Close 'fd' */
127         close(nv_fd);
128
129         return ret_val;
130 }
131
132 static nvm_error __nvm_write_payload_1(int nvm_type,
133                                                 const char *p_bin_buff, struct nvm_payload_info *nvm1)
134 {
135         const char *p_buf_ptr = p_bin_buff;
136
137         /* Write to file */
138         return __nvm_file_write(nvm_type,
139                                         (p_buf_ptr + NVM_DATA_LEN_POS + nvm1->m_length_0),
140                                         nvm1->m_length_1,
141                                         nvm1->m_offset_1);
142 }
143
144 static nvm_error __nvm_write_payload_0(int nvm_type,
145                                                 const char *p_bin_buff, struct nvm_payload_info *nvm)
146 {
147         nvm_error ret_val;
148
149         /* Write to file */
150         ret_val = __nvm_file_write(nvm_type,
151                                         (p_bin_buff + NVM_DATA_LEN_POS),
152                                         nvm->m_length_0,
153                                         nvm->m_offset_0);
154         if (NVM_NO_ERR == ret_val) {
155                 /* The payload_0 has been done, so calls this method to write payload_1 to file */
156                 ret_val = __nvm_write_payload_1(nvm_type, p_bin_buff, nvm);
157         } else {
158                 err("Failed to write to NV data file!!!");
159         }
160
161         return ret_val;
162 }
163
164 int nvm_sum_4_bytes(const char *pos)
165 {
166         int sum = 0;
167         sum = sum | (*(pos+3)) << 24;
168         sum = sum | (*(pos+2)) << 16;
169         sum = sum | (*(pos+1)) << 8;
170         sum = sum | *pos;
171         return sum;
172 }
173
174 nvm_error nvm_process_nv_update(const char *data)
175 {
176         struct nvm_payload_info nvm_info;
177         int nvm_type;
178         nvm_error ret_val;
179         dbg("Entered");
180
181         memset(&nvm_info, 0x0, sizeof(struct nvm_payload_info));
182
183         /* Determine lengths from the little-endian 4 bytes */
184         nvm_info.m_length_0 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_LENGTH_0]);
185         nvm_info.m_offset_0 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_OFFSET_0]);
186         nvm_info.m_length_1 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_LENGTH_1]);
187         nvm_info.m_offset_1 = nvm_sum_4_bytes(&data[NVM_PAYLOAD_OFFSET_1]);
188         dbg("Offsets - 0th: [%d] 1st: [%d]", nvm_info.m_offset_0, nvm_info.m_offset_1);
189
190         nvm_type = *(data + NVM_FILE_TYPE_POS);
191         if ((NVM_TYPE_CALIB <= nvm_type)
192                         && (NVM_TYPE_DYNAMIC >= nvm_type)) {
193                 dbg("NVM type: [%d]", nvm_type);
194
195                 /* Write NVM data to file */
196                 ret_val = __nvm_write_payload_0(nvm_type, data, &nvm_info);
197         } else {
198                 err("Wrong NVM file type: [%d]", nvm_type);
199                 ret_val = NVM_RES_ERR;
200         }
201
202         return ret_val;
203 }
204
205 gboolean nvm_create_nvm_data()
206 {
207         int modem_fd;
208         int nv_fd;
209         char *buffer = NULL;
210         char err_str[256] = {0, };
211
212         gboolean ret_val = FALSE;
213         dbg("Entered");
214
215         /* Open modem binary */
216         modem_fd = open(MODEM_IMAGE_PATH, O_RDONLY | O_NDELAY);
217         if (modem_fd < 0) {
218                 strerror_r(errno, err_str, 255);
219                 err("[OPEN] Failed for (%s): [%s]", MODEM_IMAGE_PATH, err_str);
220                 return ret_val;
221         }
222
223         /* Create NV data folder if it doesn't exist */
224         if (mkdir(NVM_DIR_PATH, 0755) < 0) {
225                 if (errno != EEXIST) {
226                         strerror_r(errno, err_str, 255);
227                         err("mkdir() failed: [%s]", err_str);
228
229                         /* Close 'modem_fd' */
230                         close(modem_fd);
231                         return ret_val;
232                 } else {
233                         gint fd = open(NV_FILE_PATH, O_EXCL);
234                         if (fd < 0) {
235                                 dbg("File does't exsits... need to create!!!");
236                         } else {
237                                 /* NV data file already exists */
238                                 dbg("File exists: [%s]", NV_FILE_PATH);
239
240                                 /* Close 'fds' */
241                                 close(fd);
242                                 close(modem_fd);
243
244                                 return TRUE;
245                         }
246                 }
247         }
248
249         /* Change directory permissions */
250         if (chmod(NVM_DIR_PATH, 0755) < 0) {
251                 strerror_r(errno, err_str, 255);
252                 err("chmod() failed: [%s]", err_str);
253
254                 /* Close 'modem_fd' */
255                 close(modem_fd);
256                 return ret_val;
257         }
258
259         /* Open NV data file for different file operations */
260         nv_fd = open(NV_FILE_PATH, O_RDWR | O_CREAT | O_SYNC, S_IRWXU);
261         if (nv_fd < 0) {
262                 strerror_r(errno, err_str, 255);
263                 err("[OPEN] Failed for (%s): %s", NV_FILE_PATH, err_str);
264
265                 /* Close 'modem_fd' */
266                 close(modem_fd);
267                 return ret_val;
268         }
269
270         dbg("Setting the file descriptor offset to NV data in modem.bin");
271         do {
272                 /* Seek pre-defined offset in modem binary */
273                 if (lseek(modem_fd, MODEM_NV_OFFSET, SEEK_SET) < 0) {
274                         strerror_r(errno, err_str, 255);
275                         err("[SEEK] Failed: [%s]", err_str);
276                         break;
277                 }
278
279                 /* Allocate memory */
280                 buffer = g_try_malloc0(MAX_NVDATA_SIZE);
281                 if (NULL == buffer) {
282                         err("Failed to allocate memory");
283                         break;
284                 }
285
286                 /* Read NV data from modem binary */
287                 if (read(modem_fd, buffer, MAX_NVDATA_SIZE) < 0) {
288                         strerror_r(errno, err_str, 255);
289                         err("[READ] Failed: [%s]", err_str);
290                         break;
291                 }
292
293                 /* Write the data read from modem binary to nvdata */
294                 if (write(nv_fd, buffer, MAX_NVDATA_SIZE) < 0) {
295                         strerror_r(errno, err_str, 255);
296                         err("[WRITE} Failed: [%s]", err_str);
297                         break;
298                 }
299
300                 ret_val = TRUE;
301         } while (0);
302
303         if (ret_val == FALSE) {
304                 err("nvdata (%s) creation Failed!!!", NV_FILE_PATH);
305         } else {
306                 dbg("nvdata (%s) created Success", NV_FILE_PATH);
307         }
308
309         /* Close 'fds' */
310         close(modem_fd);
311         close(nv_fd);
312
313         /* Free 'buffer' */
314         g_free(buffer);
315
316         return ret_val;
317 }