rfs: Consistent coding style, cleanup and fresh new implementation
[libsamsung-ipc.git] / samsung-ipc / devices / 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 #include <stdlib.h>
21 #include <stdio.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <termios.h>
25 #include <sys/select.h>
26
27 #include <samsung-ipc.h>
28 #include <utils.h>
29
30 #include "xmm6160.h"
31
32 int xmm6160_psi_send(struct ipc_client *client, int serial_fd,
33     void *psi_data, unsigned short psi_size)
34 {
35     char at[] = XMM6160_AT;
36     unsigned char version;
37     unsigned char info;
38     unsigned char psi_magic;
39     unsigned char psi_crc;
40     unsigned char psi_ack;
41
42     struct termios termios;
43     struct timeval timeout;
44     fd_set fds;
45
46     unsigned char *p;
47     int length;
48     int rc;
49     int i;
50
51     if (client == NULL || serial_fd < 0 || psi_data == NULL || psi_size <= 0)
52         return -1;
53
54     tcgetattr(serial_fd, &termios);
55
56     cfmakeraw(&termios);
57     cfsetispeed(&termios, B115200);
58     cfsetospeed(&termios, B115200);
59
60     tcsetattr(serial_fd, TCSANOW, &termios);
61
62     length = strlen(at);
63     for (i = 0; i < XMM6160_AT_COUNT; i++) {
64         rc = write(serial_fd, at, length);
65         if (rc < length) {
66             ipc_client_log(client, "Writing AT in ASCII failed");
67             goto error;
68         }
69
70         usleep(50000);
71     }
72     ipc_client_log(client, "Wrote AT in ASCII");
73
74     usleep(50000);
75
76     version = 0;
77
78     rc = read(serial_fd, &version, sizeof(version));
79     if (rc < (int) sizeof(version)) {
80         ipc_client_log(client, "Reading bootcore version failed");
81         goto error;
82     }
83
84     if (version != XMM6160_BOOTCORE_VERSION) {
85         ipc_client_log(client, "Read wrong bootcore version (0x%x)", version);
86         goto error;
87     }
88
89     ipc_client_log(client, "Read bootcore version (0x%x)", version);
90
91     rc = read(serial_fd, &info, sizeof(info));
92     if (rc < (int) sizeof(info)) {
93         ipc_client_log(client, "Reading info size failed");
94         goto error;
95     }
96     ipc_client_log(client, "Read info size (0x%x)", info);
97
98     psi_magic = XMM6160_PSI_MAGIC;
99
100     rc = write(serial_fd, &psi_magic, sizeof(psi_magic));
101     if (rc < (int) sizeof(psi_magic)) {
102         ipc_client_log(client, "Writing PSI magic failed");
103         goto error;
104     }
105     ipc_client_log(client, "Wrote PSI magic (0x%x)", psi_magic);
106
107     rc = write(serial_fd, &psi_size, sizeof(psi_size));
108     if (rc < (int) sizeof(psi_size)) {
109         ipc_client_log(client, "Writing PSI size failed");
110         goto error;
111     }
112     ipc_client_log(client, "Wrote PSI size (0x%x)", psi_size);
113
114     FD_ZERO(&fds);
115     FD_SET(serial_fd, &fds);
116
117     timeout.tv_sec = 4;
118     timeout.tv_usec = 0;
119
120     p = (unsigned char *) psi_data;
121     psi_crc = 0;
122
123     for (i = 0; i < psi_size; i++) {
124         rc = select(serial_fd + 1, NULL, &fds, NULL, &timeout);
125         if (rc <= 0) {
126             ipc_client_log(client, "Writing PSI failed");
127             goto error;
128         }
129
130         rc = write(serial_fd, p, 1);
131         if (rc < 1) {
132             ipc_client_log(client, "Writing PSI failed");
133             goto error;
134         }
135
136         psi_crc ^= *p++;
137     }
138     ipc_client_log(client, "Wrote PSI, CRC is 0x%x", psi_crc);
139
140     rc = select(serial_fd + 1, NULL, &fds, NULL, &timeout);
141     if (rc <= 0) {
142         ipc_client_log(client, "Writing PSI crc failed");
143         goto error;
144     }
145
146     rc = write(serial_fd, &psi_crc, sizeof(psi_crc));
147     if (rc < (int) sizeof(psi_crc)) {
148         ipc_client_log(client, "Writing PSI crc failed");
149         goto error;
150     }
151     ipc_client_log(client, "Wrote PSI CRC (0x%x)", psi_crc);
152
153     timeout.tv_sec = 4;
154     timeout.tv_usec = 0;
155
156     i = 0;
157     do {
158         rc = select(serial_fd + 1, &fds, NULL, NULL, &timeout);
159         if (rc <= 0) {
160             ipc_client_log(client, "Reading PSI ACK failed");
161             goto error;
162         }
163
164         rc = read(serial_fd, &psi_ack, sizeof(psi_ack));
165         if (rc < (int) sizeof(psi_ack)) {
166             ipc_client_log(client, "Reading PSI ACK failed");
167             goto error;
168         }
169
170         if (i++ > 50) {
171             ipc_client_log(client, "Reading PSI ACK failed");
172             goto error;
173         }
174     } while (psi_ack != XMM6160_PSI_ACK);
175     ipc_client_log(client, "Read PSI ACK (0x%x)", psi_ack);
176
177     rc = 0;
178     goto complete;
179
180 error:
181     rc = -1;
182
183 complete:
184     return rc;
185 }
186
187 int xmm6160_firmware_send(struct ipc_client *client, int device_fd,
188     void *device_address, void *firmware_data, int firmware_size)
189 {
190     int wc;
191
192     unsigned char *p;
193     int rc;
194     int i;
195
196     if (client == NULL || (device_fd < 0 && device_address == NULL) || firmware_data == NULL || firmware_size <= 0)
197         return -1;
198
199     p = (unsigned char *) firmware_data;
200
201     if (device_address != NULL) {
202         memcpy(device_address, (void *) p, firmware_size);
203     } else {
204         wc = 0;
205         while (wc < firmware_size) {
206             rc = write(device_fd, (void *) p, firmware_size - wc);
207             if (rc < 0) {
208                 ipc_client_log(client, "Writing firmware failed");
209                 goto error;
210             }
211
212             p += rc;
213             wc += rc;
214         }
215     }
216     ipc_client_log(client, "Wrote firmware");
217
218     rc = 0;
219     goto complete;
220
221 error:
222     rc = -1;
223
224 complete:
225     return rc;
226 }
227
228 int xmm6160_nv_data_send(struct ipc_client *client, int device_fd,
229     void *device_address)
230 {
231     void *nv_data = NULL;
232     int nv_size;
233     int wc;
234
235     unsigned char *p;
236     int rc;
237
238     if (client == NULL || (device_fd < 0 && device_address == NULL))
239         return -1;
240
241     nv_size = ipc_client_nv_data_size(client);
242
243     nv_data = ipc_nv_data_load(client);
244     if (nv_data == NULL) {
245         ipc_client_log(client, "Loading nv_data failed");
246         goto error;
247     }
248     ipc_client_log(client, "Loaded nv_data");
249
250     p = (unsigned char *) nv_data;
251
252     if (device_address != NULL) {
253         memcpy(device_address, p, nv_size);
254     } else {
255         wc = 0;
256         while (wc < nv_size) {
257             rc = write(device_fd, p, nv_size - wc);
258             if (rc < 0) {
259                 ipc_client_log(client, "Writing modem image failed");
260                 goto error;
261             }
262
263             p += rc;
264             wc += rc;
265         }
266     }
267
268     rc = 0;
269     goto complete;
270
271 error:
272     rc = -1;
273
274 complete:
275     if (nv_data != NULL)
276         free(nv_data);
277
278     return rc;
279 }
280
281 // vim:ts=4:sw=4:expandtab