rfs: Consistent coding style, cleanup and fresh new implementation
[libsamsung-ipc.git] / samsung-ipc / devices / xmm6260 / xmm6260_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 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 "xmm6260.h"
34 #include "xmm6260_hsic.h"
35
36 int xmm6260_hsic_ack_read(int device_fd, unsigned short ack)
37 {
38     struct timeval timeout;
39     fd_set fds;
40
41     unsigned short value;
42     int rc;
43     int i;
44
45     timeout.tv_sec = 1;
46     timeout.tv_usec = 0;
47
48     FD_ZERO(&fds);
49     FD_SET(device_fd, &fds);
50
51     for (i = 0; i < 50; i++) {
52         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
53         if (rc <= 0)
54             return -1;
55
56         value = 0;
57         rc = read(device_fd, &value, sizeof(value));
58         if (rc < (int) sizeof(value))
59             continue;
60
61         if (value == ack)
62             return 0;
63     }
64
65     return -1;
66 }
67
68 int xmm6260_hsic_psi_send(struct ipc_client *client, int device_fd,
69     void *psi_data, unsigned short psi_size)
70 {
71     struct xmm6260_hsic_psi_header psi_header;
72     char at[] = XMM6260_AT;
73     unsigned char psi_ack;
74     unsigned char chip_id;
75     unsigned char psi_crc;
76
77     struct timeval timeout;
78     fd_set fds;
79     int wc;
80
81     unsigned char *p;
82     int length;
83     int rc;
84     int i;
85
86     if (client == NULL || device_fd < 0 || psi_data == NULL || psi_size == 0)
87         return -1;
88
89     FD_ZERO(&fds);
90
91     i = 0;
92     length = strlen(at);
93
94     do {
95         FD_SET(device_fd, &fds);
96
97         timeout.tv_sec = 0;
98         timeout.tv_usec = 100000;
99
100         rc = write(device_fd, at, length);
101         if (rc < length) {
102             ipc_client_log(client, "Writing ATAT in ASCII failed");
103             goto error;
104         }
105         ipc_client_log(client, "Wrote ATAT in ASCII");
106
107         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
108         if (rc < 0) {
109             ipc_client_log(client, "Waiting for bootup failed");
110             goto error;
111         }
112
113         if (i++ > 50) {
114             ipc_client_log(client, "Waiting for bootup failed");
115             goto error;
116         }
117     } while(rc == 0);
118
119     FD_SET(device_fd, &fds);
120
121     timeout.tv_sec = 0;
122     timeout.tv_usec = 100000;
123
124     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
125     if (rc <= 0) {
126         ipc_client_log(client, "Reading chip id failed");
127         goto error;
128     }
129
130     psi_ack = 0;
131     rc = read(device_fd, &psi_ack, sizeof(psi_ack));
132     if (rc < 0 || psi_ack != XMM6260_HSIC_BOOT0_ACK) {
133         ipc_client_log(client, "Reading boot ACK failed");
134         goto error;
135     }
136
137     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
138     if (rc <= 0) {
139         ipc_client_log(client, "Reading chip id failed");
140         goto error;
141     }
142
143     chip_id = 0;
144     rc = read(device_fd, &chip_id, sizeof(chip_id));
145     if (rc < 0) {
146         ipc_client_log(client, "Reading chip id failed");
147         goto error;
148     }
149     ipc_client_log(client, "Read chip id (0x%x)", chip_id);
150
151     psi_header.magic = XMM6260_PSI_MAGIC;
152     psi_header.length = psi_size;
153     psi_header.padding = XMM6260_PSI_PADDING;
154
155     rc = write(device_fd, &psi_header, sizeof(psi_header));
156     if (rc < (int) sizeof(psi_header)) {
157         ipc_client_log(client, "Writing PSI header failed");
158         goto error;
159     }
160     ipc_client_log(client, "Wrote PSI header");
161
162     p = (unsigned char *) psi_data;
163
164     wc = 0;
165     while (wc < psi_size) {
166         rc = write(device_fd, (void *) p, psi_size - wc);
167         if (rc < 0) {
168             ipc_client_log(client, "Writing PSI failed");
169             goto error;
170         }
171
172         p += rc;
173         wc += rc;
174     }
175
176     psi_crc = xmm6260_crc_calculate(psi_data, psi_size);
177
178     ipc_client_log(client, "Wrote PSI, CRC is 0x%x", psi_crc);
179
180     rc = write(device_fd, &psi_crc, sizeof(psi_crc));
181     if (rc < (int) sizeof(psi_crc)) {
182         ipc_client_log(client, "Writing PSI CRC failed");
183         goto error;
184     }
185     ipc_client_log(client, "Wrote PSI CRC (0x%x)", psi_crc);
186
187     timeout.tv_sec = 0;
188     timeout.tv_usec = 100000;
189
190     for (i = 0; i < XMM6260_HSIC_PSI_UNKNOWN_COUNT; i++) {
191         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
192         if (rc <= 0) {
193             ipc_client_log(client, "Reading PSI unknown failed");
194             goto error;
195         }
196
197         rc = read(device_fd, &psi_ack, sizeof(psi_ack));
198         if (rc < (int) sizeof(psi_ack)) {
199             ipc_client_log(client, "Reading PSI unknown failed");
200             goto error;
201         }
202     }
203
204     for (i = 0; i < XMM6260_HSIC_PSI_CRC_ACK_COUNT ; i++) {
205         rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
206         if (rc <= 0) {
207             ipc_client_log(client, "Reading PSI CRC ACK failed");
208             goto error;
209         }
210
211         rc = read(device_fd, &psi_ack, sizeof(psi_ack));
212         if (rc < (int) sizeof(psi_ack) || psi_ack != XMM6260_HSIC_PSI_CRC_ACK) {
213             ipc_client_log(client, "Reading PSI CRC ACK failed");
214             goto error;
215         }
216     }
217     ipc_client_log(client, "Read PSI CRC ACK");
218
219     rc = xmm6260_hsic_ack_read(device_fd, XMM6260_HSIC_PSI_ACK);
220     if (rc < 0) {
221         ipc_client_log(client, "Reading PSI ACK failed");
222         goto error;
223     }
224     ipc_client_log(client, "Read PSI ACK");
225
226     rc = 0;
227     goto complete;
228
229 error:
230     rc = -1;
231
232 complete:
233     return rc;
234 }
235
236 int xmm6260_hsic_ebl_send(struct ipc_client *client, int device_fd,
237     void *ebl_data, int ebl_size)
238 {
239     unsigned char ebl_crc;
240
241     int chunk;
242     int count;
243     int wc;
244
245     unsigned char *p;
246     int length;
247     int rc;
248
249     if (client == NULL || device_fd < 0 || ebl_data == NULL || ebl_size <= 0)
250         return -1;
251
252     length = sizeof(ebl_size);
253
254     rc = write(device_fd, &ebl_size, length);
255     if (rc < length) {
256         ipc_client_log(client, "Writing EBL size failed");
257         goto error;
258     }
259     ipc_client_log(client, "Wrote EBL size");
260
261     rc = xmm6260_hsic_ack_read(device_fd, XMM6260_HSIC_EBL_SIZE_ACK);
262     if (rc < 0) {
263         ipc_client_log(client, "Reading EBL size ACK failed");
264         goto error;
265     }
266
267     p = (unsigned char *) ebl_data;
268
269     chunk = XMM6260_HSIC_EBL_CHUNK;
270     wc = 0;
271     while (wc < ebl_size) {
272         count = chunk < ebl_size - wc ? chunk : ebl_size - wc;
273
274         rc = write(device_fd, (void *) p, count);
275         if (rc < 0) {
276             ipc_client_log(client, "Writing EBL failed");
277             goto error;
278         }
279
280         p += rc;
281         wc += rc;
282     }
283
284     ebl_crc = xmm6260_crc_calculate(ebl_data, ebl_size);
285
286     ipc_client_log(client, "Wrote EBL, CRC is 0x%x", ebl_crc);
287
288     rc = write(device_fd, &ebl_crc, sizeof(ebl_crc));
289     if (rc < (int) sizeof(ebl_crc)) {
290         ipc_client_log(client, "Writing EBL CRC failed");
291         goto error;
292     }
293     ipc_client_log(client, "Wrote EBL CRC (0x%x)", ebl_crc);
294
295     rc = xmm6260_hsic_ack_read(device_fd, XMM6260_HSIC_EBL_ACK);
296     if (rc < 0) {
297         ipc_client_log(client, "Reading EBL ACK failed");
298         goto error;
299     }
300
301     rc = 0;
302     goto complete;
303
304 error:
305     rc = -1;
306
307 complete:
308     return rc;
309 }
310
311 int xmm6260_hsic_command_send(int device_fd, unsigned short code,
312     void *data, int size, int command_data_size, int ack)
313 {
314     struct xmm6260_hsic_command_header header;
315     void *buffer = NULL;
316     int length;
317
318     struct timeval timeout;
319     fd_set fds;
320
321     unsigned char *p;
322     int rc;
323     int i;
324
325     if (device_fd < 0 || data == NULL || size <= 0 || command_data_size < size)
326         return -1;
327
328     header.checksum = (size & 0xffff) + code;
329     header.code = code;
330     header.data_size = size;
331
332     p = (unsigned char *) data;
333
334     for (i = 0; i < size; i++)
335         header.checksum += *p++;
336
337     length = command_data_size + sizeof(header);
338     buffer = malloc(length);
339
340     memset(buffer, 0, length);
341     p = (unsigned char *) buffer;
342     memcpy(p, &header, sizeof(header));
343     p += sizeof(header);
344     memcpy(p, data, size);
345
346     rc = write(device_fd, buffer, length);
347     if (rc < length)
348         goto error;
349
350     if (!ack) {
351         rc = 0;
352         goto complete;
353     }
354
355     memset(buffer, 0, length);
356
357     FD_ZERO(&fds);
358     FD_SET(device_fd, &fds);
359
360     timeout.tv_sec = 1;
361     timeout.tv_usec = 0;
362
363     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
364     if (rc <= 0)
365         goto error;
366
367     rc = read(device_fd, &header, sizeof(header));
368     if (rc < (int) sizeof(header))
369         goto error;
370
371     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
372     if (rc <= 0)
373         goto error;
374
375     rc = read(device_fd, buffer, command_data_size);
376     if (rc < command_data_size)
377         goto error;
378
379     if (header.code != code)
380         goto error;
381
382     rc = 0;
383     goto complete;
384
385 error:
386     rc = -1;
387
388 complete:
389     if (buffer != NULL)
390         free(buffer);
391
392     return rc;
393 }
394
395 int xmm6260_hsic_modem_data_send(int device_fd, void *data, int size, int address)
396 {
397     int chunk;
398     int count;
399     int c;
400
401     unsigned char *p;
402     int rc;
403
404     if (device_fd < 0 || data == NULL || size <= 0)
405         return -1;
406
407     rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_FLASH_SET_ADDRESS, &address, sizeof(address), XMM6260_HSIC_FLASH_SET_ADDRESS_SIZE, 1);
408     if (rc < 0)
409         goto error;
410
411     p = (unsigned char *) data;
412
413     chunk = XMM6260_HSIC_MODEM_DATA_CHUNK;
414     c = 0;
415     while (c < size) {
416         count = chunk < size - c ? chunk : size - c;
417
418         rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_FLASH_WRITE_BLOCK, p, count, XMM6260_HSIC_FLASH_WRITE_BLOCK_SIZE, 0);
419         if (rc < 0)
420             goto error;
421
422         p += count;
423         c += count;
424     }
425
426     rc = 0;
427     goto complete;
428
429 error:
430     rc = -1;
431
432 complete:
433     return rc;
434 }
435
436 int xmm6260_hsic_port_config_send(struct ipc_client *client, int device_fd)
437 {
438     void *buffer = NULL;
439     int length;
440
441     struct timeval timeout;
442     fd_set fds;
443
444     int rc;
445
446     if (client == NULL || device_fd < 0)
447         return -1;
448
449     FD_ZERO(&fds);
450     FD_SET(device_fd, &fds);
451
452     timeout.tv_sec = 2;
453     timeout.tv_usec = 0;
454
455     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
456     if (rc <= 0)
457         goto error;
458
459     length = XMM6260_HSIC_PORT_CONFIG_SIZE;
460     buffer = malloc(length);
461
462     rc = select(device_fd + 1, &fds, NULL, NULL, &timeout);
463     if (rc <= 0)
464         goto error;
465
466     rc = read(device_fd, buffer, length);
467     if (rc < length) {
468         ipc_client_log(client, "Reading port config failed");
469         goto error;
470     }
471     ipc_client_log(client, "Read port config");
472
473     rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_SET_PORT_CONFIG, buffer, length, XMM6260_HSIC_SET_PORT_CONFIG_SIZE, 1);
474     if (rc < 0) {
475         ipc_client_log(client, "Sending port config command failed");
476         goto error;
477     }
478
479     rc = 0;
480     goto complete;
481
482 error:
483     rc = -1;
484
485 complete:
486     if (buffer != NULL)
487         free(buffer);
488
489     return rc;
490 }
491
492 int xmm6260_hsic_sec_start_send(struct ipc_client *client, int device_fd,
493     void *sec_data, int sec_size)
494 {
495     int rc;
496
497     if (client == NULL || device_fd < 0 || sec_data == NULL || sec_size <= 0)
498         return -1;
499
500     rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_SEC_START, sec_data, sec_size, XMM6260_HSIC_SEC_START_SIZE, 1);
501     if (rc < 0)
502         return -1;
503
504     return 0;
505 }
506
507 int xmm6260_hsic_sec_end_send(struct ipc_client *client, int device_fd)
508 {
509     unsigned short sec_data;
510     int sec_size;
511     int rc;
512
513     if (client == NULL || device_fd < 0)
514         return -1;
515
516     sec_data = XMM6260_SEC_END_MAGIC;
517     sec_size = sizeof(sec_data);
518
519     rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_SEC_END, &sec_data, sec_size, XMM6260_HSIC_SEC_END_SIZE, 1);
520     if (rc < 0)
521         return -1;
522
523     return 0;
524 }
525
526 int xmm6260_hsic_firmware_send(struct ipc_client *client, int device_fd,
527     void *firmware_data, int firmware_size)
528 {
529     int rc;
530
531     if (client == NULL || device_fd < 0 || firmware_data == NULL || firmware_size <= 0)
532         return -1;
533
534     rc = xmm6260_hsic_modem_data_send(device_fd, firmware_data, firmware_size, XMM6260_FIRMWARE_ADDRESS);
535     if (rc < 0)
536         return -1;
537
538     return 0;
539 }
540
541 int xmm6260_hsic_nv_data_send(struct ipc_client *client, int device_fd)
542 {
543     void *nv_data = NULL;
544     int nv_size;
545     int rc;
546
547     if (client == NULL || device_fd < 0)
548         return -1;
549
550     nv_size = ipc_client_nv_data_size(client);
551
552     nv_data = ipc_nv_data_load(client);
553     if (nv_data == NULL) {
554         ipc_client_log(client, "Loading nv_data failed");
555         goto error;
556     }
557     ipc_client_log(client, "Loaded nv_data");
558
559     rc = xmm6260_hsic_modem_data_send(device_fd, nv_data, nv_size, XMM6260_NV_DATA_ADDRESS);
560     if (rc < 0)
561         goto error;
562
563     rc = 0;
564     goto complete;
565
566 error:
567     rc = -1;
568
569 complete:
570     if (nv_data != NULL)
571         free(nv_data);
572
573     return rc;
574 }
575
576 int xmm6260_hsic_hw_reset_send(struct ipc_client *client, int device_fd)
577 {
578     unsigned int hw_reset_data;
579     int hw_reset_size;
580     int rc;
581
582     if (client == NULL || device_fd < 0)
583         return -1;
584
585     hw_reset_data = XMM6260_HW_RESET_MAGIC;
586     hw_reset_size = sizeof(hw_reset_data);
587
588     rc = xmm6260_hsic_command_send(device_fd, XMM6260_COMMAND_HW_RESET, &hw_reset_data, hw_reset_size, XMM6260_HSIC_HW_RESET_SIZE, 0);
589     if (rc < 0)
590         return -1;
591
592     return 0;
593 }
594
595 // vim:ts=4:sw=4:expandtab