xmm6160: Use device-specific sizes and offsets
[libsamsung-ipc.git] / samsung-ipc / device / xmm6160 / xmm6160.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr>
5  *
6  * libsamsung-ipc is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * libsamsung-ipc 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 libsamsung-ipc.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <string.h>
25 #include <termios.h>
26 #include <sys/select.h>
27
28 #include <samsung-ipc.h>
29 #include <util.h>
30
31 #include "xmm6160.h"
32
33 int xmm6160_psi_send(struct ipc_client *client, int serial_fd,
34     void *modem_image_data, unsigned short psi_size)
35 {
36     char at[] = XMM6160_AT;
37     unsigned char version;
38     unsigned char info;
39     unsigned char psi_magic;
40     unsigned char psi_crc;
41     unsigned char psi_ack;
42
43     struct termios termios;
44     struct timeval timeout;
45     fd_set fds;
46
47     unsigned char *p;
48     int length;
49     int rc;
50     int i;
51
52     if (client == NULL || serial_fd < 0 || modem_image_data == NULL || psi_size <= 0)
53         return -1;
54
55     tcgetattr(serial_fd, &termios);
56
57     cfmakeraw(&termios);
58     cfsetispeed(&termios, B115200);
59     cfsetospeed(&termios, B115200);
60
61     tcsetattr(serial_fd, TCSANOW, &termios);
62
63     length = strlen(at);
64     for (i=0; i < XMM6160_AT_COUNT; i++) {
65         rc = write(serial_fd, at, length);
66         if (rc < length) {
67             ipc_client_log(client, "Writing AT in ASCII failed");
68             goto error;
69         }
70
71         usleep(50000);
72     }
73     ipc_client_log(client, "Wrote AT in ASCII");
74
75     usleep(50000);
76
77     version = 0;
78
79     rc = read(serial_fd, &version, sizeof(version));
80     if (rc < (int) sizeof(version)) {
81         ipc_client_log(client, "Reading bootcore version failed");
82         goto error;
83     }
84
85     if (version != XMM6160_BOOTCORE_VERSION) {
86         ipc_client_log(client, "Read wrong bootcore version (0x%x)", version);
87         goto error;
88     }
89
90     ipc_client_log(client, "Read bootcore version (0x%x)", version);
91
92     rc = read(serial_fd, &info, sizeof(info));
93     if (rc < (int) sizeof(info)) {
94         ipc_client_log(client, "Reading info size failed");
95         goto error;
96     }
97     ipc_client_log(client, "Read info size (0x%x)", info);
98
99     psi_magic = XMM6160_PSI_MAGIC;
100
101     rc = write(serial_fd, &psi_magic, sizeof(psi_magic));
102     if (rc < (int) sizeof(psi_magic)) {
103         ipc_client_log(client, "Writing PSI magic failed");
104         goto error;
105     }
106     ipc_client_log(client, "Wrote PSI magic (0x%x)", psi_magic);
107
108     rc = write(serial_fd, &psi_size, sizeof(psi_size));
109     if (rc < (int) sizeof(psi_size)) {
110         ipc_client_log(client, "Writing PSI size failed");
111         goto error;
112     }
113     ipc_client_log(client, "Wrote PSI size (0x%x)", psi_size);
114
115     FD_ZERO(&fds);
116     FD_SET(serial_fd, &fds);
117
118     timeout.tv_sec = 4;
119     timeout.tv_usec = 0;
120
121     p = (unsigned char *) modem_image_data;
122     psi_crc = 0;
123
124     for (i=0; i < psi_size; i++) {
125         rc = select(serial_fd + 1, NULL, &fds, NULL, &timeout);
126         if (rc <= 0) {
127             ipc_client_log(client, "Writing PSI failed");
128             goto error;
129         }
130
131         rc = write(serial_fd, p, 1);
132         if (rc < 1) {
133             ipc_client_log(client, "Writing PSI failed");
134             goto error;
135         }
136
137         psi_crc ^= *p++;
138     }
139     ipc_client_log(client, "Wrote PSI, CRC is 0x%x", psi_crc);
140
141     rc = select(serial_fd + 1, NULL, &fds, NULL, &timeout);
142     if (rc <= 0) {
143         ipc_client_log(client, "Writing PSI crc failed");
144         goto error;
145     }
146
147     rc = write(serial_fd, &psi_crc, sizeof(psi_crc));
148     if (rc < (int) sizeof(psi_crc)) {
149         ipc_client_log(client, "Writing PSI crc failed");
150         goto error;
151     }
152     ipc_client_log(client, "Wrote PSI CRC (0x%x)", psi_crc);
153
154     timeout.tv_sec = 4;
155     timeout.tv_usec = 0;
156
157     i = 0;
158     do {
159         rc = select(serial_fd + 1, &fds, NULL, NULL, &timeout);
160         if (rc <= 0) {
161             ipc_client_log(client, "Reading PSI ACK failed");
162             goto error;
163         }
164
165         rc = read(serial_fd, &psi_ack, sizeof(psi_ack));
166         if (rc < (int) sizeof(psi_ack)) {
167             ipc_client_log(client, "Reading PSI ACK failed");
168             goto error;
169         }
170
171         if (i++ > 50) {
172             ipc_client_log(client, "Reading PSI ACK failed");
173             goto error;
174         }
175     } while (psi_ack != XMM6160_PSI_ACK);
176     ipc_client_log(client, "Read PSI ACK (0x%x)", psi_ack);
177
178     rc = 0;
179     goto complete;
180
181 error:
182     rc = -1;
183
184 complete:
185     return rc;
186 }
187
188 int xmm6160_modem_image_send(struct ipc_client *client, int device_fd,
189     void *device_address, void *modem_image_data, int modem_image_size)
190 {
191     int wc;
192
193     unsigned char *p;
194     int rc;
195     int i;
196
197     if (client == NULL || (device_fd < 0 && device_address == NULL) || modem_image_data == NULL || modem_image_size <= 0)
198         return -1;
199
200     p = (unsigned char *) modem_image_data;
201
202     if (device_address != NULL) {
203         memcpy(device_address, (void *) p, modem_image_size);
204     } else {
205         wc = 0;
206         while (wc < modem_image_size) {
207             rc = write(device_fd, (void *) p, modem_image_size - wc);
208             if (rc < 0) {
209                 ipc_client_log(client, "Writing modem image failed");
210                 goto error;
211             }
212
213             p += rc;
214             wc += rc;
215         }
216     }
217     ipc_client_log(client, "Wrote modem image");
218
219     rc = 0;
220     goto complete;
221
222 error:
223     rc = -1;
224
225 complete:
226     return rc;
227 }
228
229 int xmm6160_nv_data_send(struct ipc_client *client, int device_fd,
230     void *device_address)
231 {
232     void *nv_data = NULL;
233     int wc;
234
235     unsigned char *p;
236     int length;
237     int rc;
238
239     if (client == NULL || (device_fd < 0 && device_address == NULL))
240         return -1;
241
242     rc = nv_data_check(client);
243     if (rc < 0) {
244         ipc_client_log(client, "Checking nv_data failed");
245         goto error;
246     }
247     ipc_client_log(client, "Checked nv_data");
248
249     rc = nv_data_md5_check(client);
250     if (rc < 0) {
251         ipc_client_log(client, "Checking nv_data md5 failed");
252         goto error;
253     }
254     ipc_client_log(client, "Checked nv_data md5");
255
256     nv_data = file_data_read(nv_data_path(client), nv_data_size(client), nv_data_chunk_size(client));
257     if (nv_data == NULL) {
258         ipc_client_log(client, "Reading nv_data failed");
259         goto error;
260     }
261     ipc_client_log(client, "Read nv_data");
262
263     p = (unsigned char *) nv_data;
264     length = nv_data_size(client);
265
266     if (device_address != NULL) {
267         memcpy(device_address, p, length);
268     } else {
269         wc = 0;
270         while (wc < length) {
271             rc = write(device_fd, p, length - wc);
272             if (rc < 0) {
273                 ipc_client_log(client, "Writing modem image failed");
274                 goto error;
275             }
276
277             p += rc;
278             wc += rc;
279         }
280     }
281
282     rc = 0;
283     goto complete;
284
285 error:
286     rc = -1;
287
288 complete:
289     if (nv_data != NULL)
290         free(nv_data);
291
292     return rc;
293 }
294
295 // vim:ts=4:sw=4:expandtab