Rename ipc_header to ipc_fmt_header, add ipc_rfs_header and utility functions
[libsamsung-ipc.git] / samsung-ipc / device / aries / aries_ipc.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2011-2013 Paul Kocialkowski <contact@paulk.fr>
5  * Copyright (C) 2011 Simon Busch <morphis@gravedo.de>
6  * Copyright (C) 2011 Igor Almeida <igor.contato@gmail.com>
7  * Copyright (C) 2011 Joerie de Gram <j.de.gram@gmail.com>
8  *
9  * libsamsung-ipc is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * libsamsung-ipc is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with libsamsung-ipc.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  */
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <stdint.h>
27 #include <stdbool.h>
28 #include <string.h>
29 #include <fcntl.h>
30 #include <sys/ioctl.h>
31 #include <sys/mman.h>
32 #include <net/if.h>
33
34 #include <samsung-ipc.h>
35 #include <ipc.h>
36 #include <util.h>
37
38 #include "onedram.h"
39 #include "phonet.h"
40
41 #include "xmm6160.h"
42 #include "aries_ipc.h"
43
44 int aries_ipc_bootstrap(struct ipc_client *client)
45 {
46     void *modem_image_data = NULL;
47     void *onedram_address = NULL;
48     unsigned int onedram_init;
49     unsigned int onedram_magic;
50     unsigned int onedram_deinit;
51
52     int onedram_fd = -1;
53     int serial_fd = -1;
54
55     struct timeval timeout;
56     fd_set fds;
57
58     unsigned char *p;
59     unsigned char *pp;
60     int rc;
61     int i;
62
63     if (client == NULL || client->handlers == NULL || client->handlers->power_on == NULL || client->handlers->power_off == NULL)
64         return -1;
65
66     ipc_client_log(client, "Starting aries modem bootstrap");
67
68     modem_image_data = file_data_read(ARIES_MODEM_IMAGE_DEVICE, ARIES_MODEM_IMAGE_SIZE, 0x1000);
69     if (modem_image_data == NULL) {
70         ipc_client_log(client, "Reading modem image data failed");
71         goto error;
72     }
73     ipc_client_log(client, "Read modem image data");
74
75     onedram_fd = open(ARIES_ONEDRAM_DEVICE, O_RDWR);
76     if (onedram_fd < 0) {
77         ipc_client_log(client, "Opening onedram failed");
78         goto error;
79     }
80     ipc_client_log(client, "Opened onedram");
81
82     rc = network_iface_down(ARIES_MODEM_IFACE, AF_PHONET, SOCK_DGRAM);
83     if (rc < 0) {
84         ipc_client_log(client, "Turning modem network iface down failed");
85         goto error;
86     }
87     ipc_client_log(client, "Turned modem network iface down");
88
89     rc = client->handlers->power_on(client->handlers->power_data);
90     if (rc < 0) {
91         ipc_client_log(client, "Powering the modem off failed");
92         goto error;
93     }
94     ipc_client_log(client, "Powered the modem off");
95
96     usleep(1000);
97
98     rc = client->handlers->power_off(client->handlers->power_data);
99     if (rc < 0) {
100         ipc_client_log(client, "Powering the modem on failed");
101         goto error;
102     }
103     ipc_client_log(client, "Powered the modem on");
104
105     serial_fd = open(ARIES_MODEM_SERIAL_DEVICE, O_RDWR | O_NDELAY);
106     if (serial_fd < 0) {
107         ipc_client_log(client, "Opening serial failed");
108         goto error;
109     }
110     ipc_client_log(client, "Opened serial");
111
112     usleep(100000);
113
114     p = (unsigned char *) modem_image_data;
115
116     rc = xmm6160_psi_send(client, serial_fd, (void *) p, ARIES_PSI_SIZE);
117     if (rc < 0) {
118         ipc_client_log(client, "Sending XMM6160 PSI failed");
119         goto error;
120     }
121     ipc_client_log(client, "Sent XMM6160 PSI");
122
123     p += ARIES_PSI_SIZE;
124
125     onedram_init = 0;
126
127     FD_ZERO(&fds);
128     FD_SET(onedram_fd, &fds);
129
130     timeout.tv_sec = 4;
131     timeout.tv_usec = 0;
132
133     i = 0;
134     do {
135         rc = select(onedram_fd + 1, &fds, NULL, NULL, &timeout);
136         if (rc <= 0) {
137             ipc_client_log(client, "Reading onedram init failed");
138             goto error;
139         }
140
141         rc = read(onedram_fd, &onedram_init, sizeof(onedram_init));
142         if (rc < (int) sizeof(onedram_init)) {
143             ipc_client_log(client, "Reading onedram init failed");
144             goto error;
145         }
146
147         if (i++ > 50) {
148             ipc_client_log(client, "Reading onedram init failed");
149             goto error;
150         }
151     } while (onedram_init != ARIES_ONEDRAM_INIT);
152     ipc_client_log(client, "Read onedram init (0x%x)", onedram_init);
153
154     onedram_address = mmap(NULL, ARIES_ONEDRAM_MEMORY_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, onedram_fd, 0);
155     if (onedram_address == NULL || onedram_address == (void *) 0xffffffff) {
156             ipc_client_log(client, "Mapping onedram to memory failed");
157             goto error;
158     }
159     ipc_client_log(client, "Mapped onedram to memory");
160
161     pp = (unsigned char *) onedram_address;
162
163     rc = xmm6160_firmware_send(client, -1, (void *) pp, (void *) p, ARIES_MODEM_IMAGE_SIZE - ARIES_PSI_SIZE);
164     if (rc < 0) {
165         ipc_client_log(client, "Sending XMM6160 firmware failed");
166         goto error;
167     }
168     ipc_client_log(client, "Sent XMM6160 firmware");
169
170     pp = (unsigned char *) onedram_address + ARIES_ONEDRAM_NV_DATA_OFFSET;
171
172     rc = xmm6160_nv_data_send(client, -1, pp);
173     if (rc < 0) {
174         ipc_client_log(client, "Sending XMM6160 nv_data failed");
175         goto error;
176     }
177     ipc_client_log(client, "Sent XMM6160 nv_data");
178
179     munmap(onedram_address, ARIES_ONEDRAM_MEMORY_SIZE);
180     onedram_address = NULL;
181
182     rc = ioctl(onedram_fd, ONEDRAM_REL_SEM);
183     if (rc < 0)
184         goto error;
185
186     onedram_magic = ARIES_ONEDRAM_MAGIC;
187     rc = write(onedram_fd, &onedram_magic, sizeof(onedram_magic));
188     if (rc < (int) sizeof(onedram_magic)) {
189         ipc_client_log(client, "Writing onedram magic failed");
190         goto error;
191     }
192     ipc_client_log(client, "Wrote onedram magic");
193
194     FD_ZERO(&fds);
195     FD_SET(onedram_fd, &fds);
196
197     timeout.tv_sec = 4;
198     timeout.tv_usec = 0;
199
200     i = 0;
201     do {
202         rc = select(onedram_fd + 1, &fds, NULL, NULL, &timeout);
203         if (rc <= 0) {
204             ipc_client_log(client, "Reading onedram deinit failed");
205             goto error;
206         }
207
208         rc = read(onedram_fd, &onedram_deinit, sizeof(onedram_deinit));
209         if (rc < (int) sizeof(onedram_deinit)) {
210             ipc_client_log(client, "Reading onedram deinit failed");
211             goto error;
212         }
213
214         if (i++ > 50) {
215             ipc_client_log(client, "Reading onedram deinit failed");
216             goto error;
217         }
218     } while (onedram_deinit != ARIES_ONEDRAM_DEINIT);
219     ipc_client_log(client, "Read onedram deinit (0x%x)", onedram_deinit);
220
221     rc = 0;
222     goto complete;
223
224 error:
225     rc = -1;
226
227 complete:
228     if (modem_image_data != NULL)
229         free(modem_image_data);
230
231     if (serial_fd >= 0)
232         close(serial_fd);
233
234     if (onedram_address != NULL)
235         munmap(onedram_address, ARIES_ONEDRAM_MEMORY_SIZE);
236
237     if (onedram_fd >= 0)
238         close(onedram_fd);
239
240     return rc;
241 }
242
243 int aries_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request)
244 {
245     struct ipc_fmt_header header;
246     void *buffer;
247     int rc;
248
249     if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || request == NULL)
250         return -1;
251
252     ipc_fmt_header_fill(&header, request);
253
254     buffer = malloc(header.length);
255
256     memcpy(buffer, &header, sizeof(struct ipc_fmt_header));
257     if (request->data != NULL && request->length > 0)
258         memcpy((void *) ((unsigned char *) buffer + sizeof(struct ipc_fmt_header)), request->data, request->length);
259
260     ipc_client_log_send(client, request, __func__);
261
262     rc = client->handlers->write(client->handlers->transport_data, buffer, header.length);
263     if (rc < header.length) {
264         ipc_client_log(client, "Writing FMT data to the modem failed");
265         goto error;
266     }
267
268     rc = 0;
269     goto complete;
270
271 error:
272     rc = -1;
273
274 complete:
275     if (buffer != NULL)
276         free(buffer);
277
278     return rc;
279 }
280
281 int aries_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response)
282 {
283     struct ipc_fmt_header *header;
284     void *buffer = NULL;
285     int length;
286     int rc;
287
288     if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || response == NULL)
289         return -1;
290
291     length = ARIES_DATA_SIZE;
292     buffer = malloc(length);
293
294     rc = client->handlers->read(client->handlers->transport_data, buffer, length);
295     if (rc < (int) sizeof(struct ipc_fmt_header)) {
296         ipc_client_log(client, "Reading FMT data from the modem failed");
297         goto error;
298     }
299
300     header = (struct ipc_fmt_header *) buffer;
301
302     ipc_fmt_message_fill(header, response);
303
304     if (header->length > sizeof(struct ipc_fmt_header)) {
305         response->length = header->length - sizeof(struct ipc_fmt_header);
306         response->data = malloc(response->length);
307
308         memcpy(response->data, (void *) ((unsigned char *) buffer + sizeof(struct ipc_fmt_header)), response->length);
309     }
310
311     ipc_client_log_recv(client, response, __func__);
312
313     rc = 0;
314     goto complete;
315
316 error:
317     rc = -1;
318
319 complete:
320     if (buffer != NULL)
321         free(buffer);
322
323     return rc;
324
325     return 0;
326 }
327
328 int aries_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request)
329 {
330     struct ipc_rfs_header header;
331     void *buffer;
332     int rc;
333
334     if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || request == NULL)
335         return -1;
336
337     ipc_rfs_header_fill(&header, request);
338
339     buffer = malloc(header.length);
340
341     memcpy(buffer, &header, sizeof(struct ipc_rfs_header));
342     if (request->data != NULL && request->length > 0)
343         memcpy((void *) ((unsigned char *) buffer + sizeof(struct ipc_rfs_header)), request->data, request->length);
344
345     ipc_client_log_send(client, request, __func__);
346
347     rc = client->handlers->write(client->handlers->transport_data, buffer, header.length);
348     if (rc < 0) {
349         ipc_client_log(client, "Writing RFS data to the modem failed");
350         goto error;
351     }
352
353     rc = 0;
354     goto complete;
355
356 error:
357     rc = -1;
358
359 complete:
360     if (buffer != NULL)
361         free(buffer);
362
363     return rc;
364 }
365
366 int aries_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response)
367 {
368     struct ipc_rfs_header *header;
369     void *buffer = NULL;
370     int length;
371     int rc;
372
373     if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || response == NULL)
374         return -1;
375
376     length = ARIES_DATA_SIZE;
377     buffer = malloc(length);
378
379     rc = client->handlers->read(client->handlers->transport_data, buffer, length);
380     if (rc < (int) sizeof(struct ipc_rfs_header)) {
381         ipc_client_log(client, "Reading RFS data from the modem failed");
382         goto error;
383     }
384
385     header = (struct ipc_rfs_header *) buffer;
386
387     ipc_rfs_message_fill(header, response);
388
389     if (header->length > sizeof(struct ipc_rfs_header)) {
390         response->length = header->length - sizeof(struct ipc_rfs_header);
391         response->data = malloc(response->length);
392
393         memcpy(response->data, (void *) ((unsigned char *) buffer + sizeof(struct ipc_rfs_header)), response->length);
394     }
395
396     ipc_client_log_recv(client, response, __func__);
397
398     rc = 0;
399     goto complete;
400
401 error:
402     rc = -1;
403
404 complete:
405     if (buffer != NULL)
406         free(buffer);
407
408     return rc;
409 }
410
411 int aries_ipc_open(void *data, int type)
412 {
413     struct aries_ipc_transport_data *transport_data;
414     struct sockaddr_pn *spn;
415     struct ifreq ifr;
416
417     int reuse;
418     int socket_rfs_magic;
419
420     int fd;
421     int rc;
422
423     if (data == NULL)
424         return -1;
425
426     transport_data = (struct aries_ipc_transport_data *) data;
427     memset(data, 0, sizeof(struct aries_ipc_transport_data));
428
429     spn = &transport_data->spn;
430
431     memset(&ifr, 0, sizeof(ifr));
432     strncpy(ifr.ifr_name, ARIES_MODEM_IFACE, IFNAMSIZ);
433
434     spn->spn_family = AF_PHONET;
435     spn->spn_dev = 0;
436
437     switch (type) {
438         case IPC_CLIENT_TYPE_FMT:
439             spn->spn_resource = ARIES_MODEM_FMT_SPN;
440             break;
441         case IPC_CLIENT_TYPE_RFS:
442             spn->spn_resource = ARIES_MODEM_RFS_SPN;
443             break;
444         default:
445             break;
446     }
447
448     fd = socket(AF_PHONET, SOCK_DGRAM, 0);
449     if (fd < 0)
450         return -1;
451
452     rc = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifr.ifr_name, IFNAMSIZ);
453     if (rc < 0)
454         return -1;
455
456     rc = ioctl(fd, SIOCGIFINDEX, &ifr);
457     if (rc < 0)
458         return -1;
459
460     reuse = 1;
461     rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
462     if (rc < 0)
463         return -1;
464
465     rc = bind(fd, (const struct sockaddr *) spn, sizeof(struct sockaddr_pn));
466     if (rc < 0)
467         return -1;
468
469     transport_data->fd = fd;
470
471     if (type == IPC_CLIENT_TYPE_RFS)
472     {
473         socket_rfs_magic = ARIES_SOCKET_RFS_MAGIC;
474         rc = setsockopt(fd, SOL_SOCKET, SO_IPC_RFS, &socket_rfs_magic, sizeof(socket_rfs_magic));
475         if (rc < 0)
476             return -1;
477     }
478
479     rc = network_iface_up(ARIES_MODEM_IFACE, AF_PHONET, SOCK_DGRAM);
480     if (rc < 0)
481         return -1;
482
483     return 0;
484 }
485
486 int aries_ipc_close(void *data)
487 {
488     struct aries_ipc_transport_data *transport_data;
489     int fd;
490
491     if (data == NULL)
492         return -1;
493
494     transport_data = (struct aries_ipc_transport_data *) data;
495
496     fd = transport_data->fd;
497     if (fd < 0)
498         return -1;
499
500     transport_data->fd = -1;
501     close(fd);
502
503     return 0;
504 }
505
506 int aries_ipc_read(void *data, void *buffer, unsigned int length)
507 {
508     struct aries_ipc_transport_data *transport_data;
509     int spn_size;
510     int fd;
511     int rc;
512
513     if (data == NULL || buffer == NULL || length == 0)
514         return -1;
515
516     transport_data = (struct aries_ipc_transport_data *) data;
517
518     fd = transport_data->fd;
519     if (fd < 0)
520         return -1;
521
522     spn_size = sizeof(struct sockaddr_pn);
523
524     rc = recvfrom(fd, buffer, length, 0, (const struct sockaddr *) &transport_data->spn, &spn_size);
525     return rc;
526 }
527
528 int aries_ipc_write(void *data, void *buffer, unsigned int length)
529 {
530     struct aries_ipc_transport_data *transport_data;
531     int spn_size;
532     int fd;
533     int rc;
534
535     if (data == NULL || buffer == NULL || length == 0)
536         return -1;
537
538     transport_data = (struct aries_ipc_transport_data *) data;
539
540     fd = transport_data->fd;
541     if (fd < 0)
542         return -1;
543
544     spn_size = sizeof(struct sockaddr_pn);
545
546     rc = sendto(fd, buffer, length, 0, (const struct sockaddr *) &transport_data->spn, spn_size);
547     return rc;
548 }
549
550 int aries_ipc_poll(void *data, struct timeval *timeout)
551 {
552     struct aries_ipc_transport_data *transport_data;
553     fd_set fds;
554     int fd;
555     int rc;
556
557     if (data == NULL)
558         return -1;
559
560     transport_data = (struct aries_ipc_transport_data *) data;
561
562     fd = transport_data->fd;
563     if (fd < 0)
564         return -1;
565
566     FD_ZERO(&fds);
567     FD_SET(fd, &fds);
568
569     rc = select(fd + 1, &fds, NULL, NULL, timeout);
570     return rc;
571 }
572
573 int aries_ipc_power_on(void *data)
574 {
575     char buffer[] = "on\n";
576     int value;
577     int rc;
578
579     value = sysfs_value_read(ARIES_MODEMCTL_STATUS_SYSFS);
580     if (value < 0)
581         return -1;
582
583     /* The modem is already on */
584     if (value == 1)
585         return 0;
586
587     rc = sysfs_string_write(ARIES_MODEMCTL_CONTROL_SYSFS, (char *) &buffer, strlen(buffer));
588     if (rc < 0)
589         return -1;
590
591     return 0;
592 }
593
594 int aries_ipc_power_off(void *data)
595 {
596     char buffer[] = "off\n";
597     int value;
598     int rc;
599
600     value = sysfs_value_read(ARIES_MODEMCTL_STATUS_SYSFS);
601     if (value < 0)
602         return -1;
603
604     /* The modem is already off */
605     if (value == 0)
606         return 0;
607
608     rc = sysfs_string_write(ARIES_MODEMCTL_CONTROL_SYSFS, (char *) &buffer, strlen(buffer));
609     if (rc < 0)
610         return -1;
611
612     return 0;
613 }
614
615 int aries_ipc_data_create(void **transport_data, void **power_data, void **gprs_data)
616 {
617     if (transport_data == NULL)
618         return -1;
619
620     *transport_data = (void *) malloc(sizeof(struct aries_ipc_transport_data));
621     memset(*transport_data, 0, sizeof(struct aries_ipc_transport_data));
622
623     return 0;
624 }
625
626 int aries_ipc_data_destroy(void *transport_data, void *power_data, void *gprs_data)
627 {
628     if (transport_data == NULL)
629         return -1;
630
631     free(transport_data);
632
633     return 0;
634 }
635
636 int aries_ipc_gprs_activate(void *data, int cid)
637 {
638     int rc;
639
640     rc = sysfs_value_write(ARIES_MODEM_PDP_ACTIVATE_SYSFS, cid);
641     if (rc < 0)
642         return -1;
643
644     return 0;
645 }
646
647 int aries_ipc_gprs_deactivate(void *data, int cid)
648 {
649     int rc;
650
651     rc = sysfs_value_write(ARIES_MODEM_PDP_DEACTIVATE_SYSFS, cid);
652     if (rc < 0)
653         return -1;
654
655     return 0;
656 }
657
658 char *aries_ipc_gprs_get_iface(int cid)
659 {
660     struct ifreq ifr;
661     char *iface = NULL;
662     int fd;
663     int rc;
664     int i;
665
666     memset(&ifr, 0, sizeof(ifr));
667
668     fd = socket(AF_PHONET, SOCK_DGRAM, 0);
669     if (fd < 0)
670         return NULL;
671
672     for (i = (ARIES_GPRS_IFACE_COUNT - 1); i >= 0; i--) {
673         sprintf(ifr.ifr_name, "%s%d", ARIES_GPRS_IFACE_PREFIX, i);
674         rc = ioctl(fd, SIOCGIFFLAGS, &ifr);
675         if (rc < 0 || ifr.ifr_flags & IFF_UP) {
676             continue;
677         } else {
678             asprintf(&iface, "%s%d", ARIES_GPRS_IFACE_PREFIX, i);
679             return iface;
680         }
681     }
682
683     return NULL;
684 }
685
686 int aries_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities)
687 {
688     if (capabilities == NULL)
689         return -1;
690
691     capabilities->port_list = 1;
692     capabilities->cid_max = ARIES_GPRS_IFACE_COUNT;
693
694     return 0;
695 }
696
697 struct ipc_ops aries_ipc_fmt_ops = {
698     .bootstrap = aries_ipc_bootstrap,
699     .send = aries_ipc_fmt_send,
700     .recv = aries_ipc_fmt_recv,
701 };
702
703 struct ipc_ops aries_ipc_rfs_ops = {
704     .bootstrap = NULL,
705     .send = aries_ipc_rfs_send,
706     .recv = aries_ipc_rfs_recv,
707 };
708
709 struct ipc_handlers aries_ipc_handlers = {
710     .open = aries_ipc_open,
711     .close = aries_ipc_close,
712     .read = aries_ipc_read,
713     .write = aries_ipc_write,
714     .poll = aries_ipc_poll,
715     .transport_data = NULL,
716     .power_on = aries_ipc_power_on,
717     .power_off = aries_ipc_power_off,
718     .power_data = NULL,
719     .gprs_activate = aries_ipc_gprs_activate,
720     .gprs_deactivate = aries_ipc_gprs_deactivate,
721     .gprs_data = NULL,
722     .data_create = aries_ipc_data_create,
723     .data_destroy = aries_ipc_data_destroy,
724 };
725
726 struct ipc_gprs_specs aries_ipc_gprs_specs = {
727     .gprs_get_iface = aries_ipc_gprs_get_iface,
728     .gprs_get_capabilities = aries_ipc_gprs_get_capabilities,
729 };
730
731 // vim:ts=4:sw=4:expandtab