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