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