xmm626: HSIC ACKs are not reliable
[libsamsung-ipc.git] / samsung-ipc / devices / xmm626 / xmm626_hsic.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2012 Alexander Tarasikov <alexander.tarasikov@gmail.com>
5  * Copyright (C) 2013-2014 Paul Kocialkowski <contact@paulk.fr>
6  *
7  * Based on the incomplete C++ implementation which is:
8  * Copyright (C) 2012 Sergey Gridasov <grindars@gmail.com>
9  *
10  * libsamsung-ipc is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * libsamsung-ipc is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with libsamsung-ipc.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <sys/select.h>
29
30 #include <samsung-ipc.h>
31 #include <utils.h>
32
33 #include "xmm626.h"
34 #include "xmm626_hsic.h"
35
36 int xmm626_hsic_ack_read(int device_fd, unsigned short ack)
37 {
38     struct timeval timeout;
39     fd_set fds;
40     unsigned short value;
41     int rc;
42     int i;
43
44     timeout.tv_sec = 1;
45     timeout.tv_usec = 0;
46
47     FD_ZERO(&fds);
48     FD_SET(device_fd, &fds);
49
50     for (i = 0; i < 50; i++) {
51         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
52         if (rc <= 0)
53             return -1;
54
55         value = 0;
56         rc = read(device_fd, &value, sizeof(value));
57         if (rc < (int) sizeof(value))
58             continue;
59
60         if (value == ack)
61             return 0;
62     }
63
64     return -1;
65 }
66
67 int xmm626_hsic_psi_send(struct ipc_client *client, int device_fd,
68     const void *psi_data, unsigned short psi_size)
69 {
70     struct xmm626_hsic_psi_header psi_header;
71     char at[] = XMM626_AT;
72     unsigned char psi_ack;
73     unsigned char chip_id;
74     unsigned char psi_crc;
75     struct timeval timeout;
76     fd_set fds;
77     size_t wc;
78     size_t length;
79     unsigned char *p;
80     int rc;
81     int i;
82
83     if (client == NULL || device_fd < 0 || psi_data == NULL || psi_size == 0)
84         return -1;
85
86     FD_ZERO(&fds);
87
88     i = 0;
89     length = strlen(at);
90
91     do {
92         FD_SET(device_fd, &fds);
93
94         timeout.tv_sec = 0;
95         timeout.tv_usec = 100000;
96
97         rc = write(device_fd, at, length);
98         if (rc < (int) length) {
99             ipc_client_log(client, "Writing ATAT in ASCII failed");
100             goto error;
101         }
102         ipc_client_log(client, "Wrote ATAT in ASCII");
103
104         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
105         if (rc < 0) {
106             ipc_client_log(client, "Waiting for bootup failed");
107             goto error;
108         }
109
110         if (i++ > 50) {
111             ipc_client_log(client, "Waiting for bootup failed");
112             goto error;
113         }
114     } while(rc == 0);
115
116     FD_SET(device_fd, &fds);
117
118     timeout.tv_sec = 0;
119     timeout.tv_usec = 100000;
120
121     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
122     if (rc <= 0) {
123         ipc_client_log(client, "Reading boot ACK failed");
124         goto error;
125     }
126
127     psi_ack = 0;
128     rc = read(device_fd, &psi_ack, sizeof(psi_ack));
129     if (rc < (int) sizeof(psi_ack)) {
130         ipc_client_log(client, "Reading boot ACK failed");
131         goto error;
132     }
133
134     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
135     if (rc <= 0) {
136         ipc_client_log(client, "Reading chip id failed");
137         goto error;
138     }
139
140     chip_id = 0;
141     rc = read(device_fd, &chip_id, sizeof(chip_id));
142     if (rc < (int) sizeof(chip_id)) {
143         ipc_client_log(client, "Reading chip id failed");
144         goto error;
145     }
146     ipc_client_log(client, "Read chip id (0x%x)", chip_id);
147
148     psi_header.magic = XMM626_PSI_MAGIC;
149     psi_header.length = psi_size;
150     psi_header.padding = XMM626_PSI_PADDING;
151
152     rc = write(device_fd, &psi_header, sizeof(psi_header));
153     if (rc < (int) sizeof(psi_header)) {
154         ipc_client_log(client, "Writing PSI header failed");
155         goto error;
156     }
157     ipc_client_log(client, "Wrote PSI header");
158
159     p = (unsigned char *) psi_data;
160
161     wc = 0;
162     while (wc < psi_size) {
163         rc = write(device_fd, (void *) p, psi_size - wc);
164         if (rc <= 0) {
165             ipc_client_log(client, "Writing PSI failed");
166             goto error;
167         }
168
169         p += rc;
170         wc += rc;
171     }
172
173     psi_crc = xmm626_crc_calculate(psi_data, psi_size);
174
175     ipc_client_log(client, "Wrote PSI, CRC is 0x%x", psi_crc);
176
177     rc = write(device_fd, &psi_crc, sizeof(psi_crc));
178     if (rc < (int) sizeof(psi_crc)) {
179         ipc_client_log(client, "Writing PSI CRC failed");
180         goto error;
181     }
182     ipc_client_log(client, "Wrote PSI CRC (0x%x)", psi_crc);
183
184     timeout.tv_sec = 0;
185     timeout.tv_usec = 100000;
186
187     for (i = 0; i < XMM626_HSIC_PSI_UNKNOWN_COUNT; i++) {
188         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
189         if (rc <= 0) {
190             ipc_client_log(client, "Reading PSI unknown failed");
191             goto error;
192         }
193
194         rc = read(device_fd, &psi_ack, sizeof(psi_ack));
195         if (rc < (int) sizeof(psi_ack)) {
196             ipc_client_log(client, "Reading PSI unknown failed");
197             goto error;
198         }
199     }
200
201     for (i = 0; i < XMM626_HSIC_PSI_CRC_ACK_COUNT ; i++) {
202         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
203         if (rc <= 0) {
204             ipc_client_log(client, "Reading PSI CRC ACK failed");
205             goto error;
206         }
207
208         rc = read(device_fd, &psi_ack, sizeof(psi_ack));
209         if (rc < (int) sizeof(psi_ack)) {
210             ipc_client_log(client, "Reading PSI CRC ACK failed");
211             goto error;
212         }
213     }
214     ipc_client_log(client, "Read PSI CRC ACK");
215
216     rc = xmm626_hsic_ack_read(device_fd, XMM626_HSIC_PSI_ACK);
217     if (rc < 0) {
218         ipc_client_log(client, "Reading PSI ACK failed");
219         goto error;
220     }
221     ipc_client_log(client, "Read PSI ACK");
222
223     rc = 0;
224     goto complete;
225
226 error:
227     rc = -1;
228
229 complete:
230     return rc;
231 }
232
233 int xmm626_hsic_ebl_send(struct ipc_client *client, int device_fd,
234     const void *ebl_data, size_t ebl_size)
235 {
236     unsigned char ebl_crc;
237     size_t chunk;
238     size_t count;
239     size_t wc;
240     size_t size;
241     unsigned char *p;
242     int rc;
243
244     if (client == NULL || device_fd < 0 || ebl_data == NULL || ebl_size == 0)
245         return -1;
246
247     size = sizeof(ebl_size);
248
249     rc = write(device_fd, &ebl_size, size);
250     if (rc < (int) size) {
251         ipc_client_log(client, "Writing EBL size failed");
252         goto error;
253     }
254     ipc_client_log(client, "Wrote EBL size");
255
256     rc = xmm626_hsic_ack_read(device_fd, XMM626_HSIC_EBL_SIZE_ACK);
257     if (rc < 0) {
258         ipc_client_log(client, "Reading EBL size ACK failed");
259         goto error;
260     }
261
262     p = (unsigned char *) ebl_data;
263
264     chunk = XMM626_HSIC_EBL_CHUNK;
265     wc = 0;
266     while (wc < ebl_size) {
267         count = chunk < ebl_size - wc ? chunk : ebl_size - wc;
268
269         rc = write(device_fd, (void *) p, count);
270         if (rc <= 0) {
271             ipc_client_log(client, "Writing EBL failed");
272             goto error;
273         }
274
275         p += rc;
276         wc += rc;
277     }
278
279     ebl_crc = xmm626_crc_calculate(ebl_data, ebl_size);
280
281     ipc_client_log(client, "Wrote EBL, CRC is 0x%x", ebl_crc);
282
283     rc = write(device_fd, &ebl_crc, sizeof(ebl_crc));
284     if (rc < (int) sizeof(ebl_crc)) {
285         ipc_client_log(client, "Writing EBL CRC failed");
286         goto error;
287     }
288     ipc_client_log(client, "Wrote EBL CRC (0x%x)", ebl_crc);
289
290     rc = xmm626_hsic_ack_read(device_fd, XMM626_HSIC_EBL_ACK);
291     if (rc < 0) {
292         ipc_client_log(client, "Reading EBL ACK failed");
293         goto error;
294     }
295
296     rc = 0;
297     goto complete;
298
299 error:
300     rc = -1;
301
302 complete:
303     return rc;
304 }
305
306 int xmm626_hsic_command_send(int device_fd, unsigned short code,
307     const void *data, size_t size, size_t command_data_size, int ack)
308 {
309     struct xmm626_hsic_command_header header;
310     void *buffer = NULL;
311     size_t length;
312     struct timeval timeout;
313     fd_set fds;
314     unsigned char *p;
315     int rc;
316     int i;
317
318     if (device_fd < 0 || data == NULL || size == 0 || command_data_size == 0 || command_data_size < size)
319         return -1;
320
321     header.checksum = (size & 0xffff) + code;
322     header.code = code;
323     header.data_size = size;
324
325     p = (unsigned char *) data;
326
327     for (i = 0; i < (int) size; i++)
328         header.checksum += *p++;
329
330     length = command_data_size + sizeof(header);
331     buffer = calloc(1, length);
332
333     memset(buffer, 0, length);
334     p = (unsigned char *) buffer;
335     memcpy(p, &header, sizeof(header));
336     p += sizeof(header);
337     memcpy(p, data, size);
338
339     rc = write(device_fd, buffer, length);
340     if (rc < (int) length)
341         goto error;
342
343     if (!ack) {
344         rc = 0;
345         goto complete;
346     }
347
348     memset(buffer, 0, length);
349
350     FD_ZERO(&fds);
351     FD_SET(device_fd, &fds);
352
353     timeout.tv_sec = 1;
354     timeout.tv_usec = 0;
355
356     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
357     if (rc <= 0)
358         goto error;
359
360     rc = read(device_fd, &header, sizeof(header));
361     if (rc < (int) sizeof(header))
362         goto error;
363
364     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
365     if (rc <= 0)
366         goto error;
367
368     rc = read(device_fd, buffer, command_data_size);
369     if (rc < (int) command_data_size)
370         goto error;
371
372     if (header.code != code)
373         goto error;
374
375     rc = 0;
376     goto complete;
377
378 error:
379     rc = -1;
380
381 complete:
382     if (buffer != NULL)
383         free(buffer);
384
385     return rc;
386 }
387
388 int xmm626_hsic_modem_data_send(int device_fd, const void *data, size_t size,
389     int address)
390 {
391     size_t chunk;
392     size_t count;
393     size_t c;
394     unsigned char *p;
395     int rc;
396
397     if (device_fd < 0 || data == NULL || size == 0)
398         return -1;
399
400     rc = xmm626_hsic_command_send(device_fd, XMM626_COMMAND_FLASH_SET_ADDRESS, &address, sizeof(address), XMM626_HSIC_FLASH_SET_ADDRESS_SIZE, 1);
401     if (rc < 0)
402         goto error;
403
404     p = (unsigned char *) data;
405
406     chunk = XMM626_HSIC_MODEM_DATA_CHUNK;
407     c = 0;
408     while (c < size) {
409         count = chunk < size - c ? chunk : size - c;
410
411         rc = xmm626_hsic_command_send(device_fd, XMM626_COMMAND_FLASH_WRITE_BLOCK, p, count, XMM626_HSIC_FLASH_WRITE_BLOCK_SIZE, 0);
412         if (rc < 0)
413             goto error;
414
415         p += count;
416         c += count;
417     }
418
419     rc = 0;
420     goto complete;
421
422 error:
423     rc = -1;
424
425 complete:
426     return rc;
427 }
428
429 int xmm626_hsic_port_config_send(struct ipc_client *client, int device_fd)
430 {
431     void *buffer = NULL;
432     size_t length;
433     struct timeval timeout;
434     fd_set fds;
435     int rc;
436
437     if (client == NULL || device_fd < 0)
438         return -1;
439
440     FD_ZERO(&fds);
441     FD_SET(device_fd, &fds);
442
443     timeout.tv_sec = 2;
444     timeout.tv_usec = 0;
445
446     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
447     if (rc <= 0)
448         goto error;
449
450     length = XMM626_HSIC_PORT_CONFIG_SIZE;
451     buffer = calloc(1, length);
452
453     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
454     if (rc <= 0)
455         goto error;
456
457     rc = read(device_fd, buffer, length);
458     if (rc < (int) length) {
459         ipc_client_log(client, "Reading port config failed");
460         goto error;
461     }
462     ipc_client_log(client, "Read port config");
463
464     rc = xmm626_hsic_command_send(device_fd, XMM626_COMMAND_SET_PORT_CONFIG, buffer, length, XMM626_HSIC_SET_PORT_CONFIG_SIZE, 1);
465     if (rc < 0) {
466         ipc_client_log(client, "Sending port config command failed");
467         goto error;
468     }
469
470     rc = 0;
471     goto complete;
472
473 error:
474     rc = -1;
475
476 complete:
477     if (buffer != NULL)
478         free(buffer);
479
480     return rc;
481 }
482
483 int xmm626_hsic_sec_start_send(struct ipc_client *client, int device_fd,
484     const void *sec_data, size_t sec_size)
485 {
486     int rc;
487
488     if (client == NULL || device_fd < 0 || sec_data == NULL || sec_size == 0)
489         return -1;
490
491     rc = xmm626_hsic_command_send(device_fd, XMM626_COMMAND_SEC_START, sec_data, sec_size, XMM626_HSIC_SEC_START_SIZE, 1);
492     if (rc < 0)
493         return -1;
494
495     return 0;
496 }
497
498 int xmm626_hsic_sec_end_send(struct ipc_client *client, int device_fd)
499 {
500     unsigned short sec_data;
501     size_t sec_size;
502     int rc;
503
504     if (client == NULL || device_fd < 0)
505         return -1;
506
507     sec_data = XMM626_SEC_END_MAGIC;
508     sec_size = sizeof(sec_data);
509
510     rc = xmm626_hsic_command_send(device_fd, XMM626_COMMAND_SEC_END, &sec_data, sec_size, XMM626_HSIC_SEC_END_SIZE, 1);
511     if (rc < 0)
512         return -1;
513
514     return 0;
515 }
516
517 int xmm626_hsic_firmware_send(struct ipc_client *client, int device_fd,
518     const void *firmware_data, size_t firmware_size)
519 {
520     int rc;
521
522     if (client == NULL || device_fd < 0 || firmware_data == NULL || firmware_size == 0)
523         return -1;
524
525     rc = xmm626_hsic_modem_data_send(device_fd, firmware_data, firmware_size, XMM626_FIRMWARE_ADDRESS);
526     if (rc < 0)
527         return -1;
528
529     return 0;
530 }
531
532 int xmm626_hsic_nv_data_send(struct ipc_client *client, int device_fd)
533 {
534     void *nv_data = NULL;
535     size_t nv_size;
536     int rc;
537
538     if (client == NULL || device_fd < 0)
539         return -1;
540
541     nv_size = ipc_client_nv_data_size(client);
542     if (nv_size == 0)
543         return -1;
544
545     nv_data = ipc_nv_data_load(client);
546     if (nv_data == NULL) {
547         ipc_client_log(client, "Loading nv_data failed");
548         goto error;
549     }
550     ipc_client_log(client, "Loaded nv_data");
551
552     rc = xmm626_hsic_modem_data_send(device_fd, nv_data, nv_size, XMM626_NV_DATA_ADDRESS);
553     if (rc < 0)
554         goto error;
555
556     rc = 0;
557     goto complete;
558
559 error:
560     rc = -1;
561
562 complete:
563     if (nv_data != NULL)
564         free(nv_data);
565
566     return rc;
567 }
568
569 int xmm626_hsic_hw_reset_send(struct ipc_client *client, int device_fd)
570 {
571     unsigned int hw_reset_data;
572     int hw_reset_size;
573     int rc;
574
575     if (client == NULL || device_fd < 0)
576         return -1;
577
578     hw_reset_data = XMM626_HW_RESET_MAGIC;
579     hw_reset_size = sizeof(hw_reset_data);
580
581     rc = xmm626_hsic_command_send(device_fd, XMM626_COMMAND_HW_RESET, &hw_reset_data, hw_reset_size, XMM626_HSIC_HW_RESET_SIZE, 0);
582     if (rc < 0)
583         return -1;
584
585     return 0;
586 }
587
588 // vim:ts=4:sw=4:expandtab