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