279eddbf7b9d26b4cffd86b2dc6cd9fe4e78b746
[libsamsung-ipc.git] / samsung-ipc / device / crespo / crespo_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 Joerie de Gram <j.de.gram@gmail.com>
7  *
8  * libsamsung-ipc is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * libsamsung-ipc is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with libsamsung-ipc.  If not, see <http://www.gnu.org/licenses/>.
20  *
21  */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <stdint.h>
26 #include <stdbool.h>
27 #include <string.h>
28 #include <fcntl.h>
29 #include <sys/ioctl.h>
30
31 #include <samsung-ipc.h>
32 #include <ipc.h>
33 #include <util.h>
34
35 #include "crespo_modem_ctl.h"
36
37 #include "xmm6160.h"
38 #include "crespo_ipc.h"
39
40 int crespo_ipc_bootstrap(struct ipc_client *client)
41 {
42     void *modem_image_data = NULL;
43
44     int modem_ctl_fd = -1;
45     int serial_fd = -1;
46
47     unsigned char *p;
48     int rc;
49
50     if (client == NULL)
51         return -1;
52
53     ipc_client_log(client, "Starting crespo modem bootstrap");
54
55     modem_image_data = file_data_read(CRESPO_MODEM_IMAGE_DEVICE, CRESPO_MODEM_IMAGE_SIZE, 0x1000);
56     if (modem_image_data == NULL) {
57         ipc_client_log(client, "Reading modem image data failed");
58         goto error;
59     }
60     ipc_client_log(client, "Read modem image data");
61
62     modem_ctl_fd = open(CRESPO_MODEM_CTL_DEVICE, O_RDWR | O_NDELAY);
63     if (modem_ctl_fd < 0) {
64         ipc_client_log(client, "Opening modem ctl failed");
65         goto error;
66     }
67     ipc_client_log(client, "Opened modem ctl");
68
69     rc = ioctl(modem_ctl_fd, IOCTL_MODEM_RESET);
70     if (rc < 0) {
71         ipc_client_log(client, "Resetting modem failed");
72         goto error;
73     }
74     ipc_client_log(client, "Reset modem");
75
76     serial_fd = open(CRESPO_MODEM_SERIAL_DEVICE, O_RDWR | O_NDELAY);
77     if (serial_fd < 0) {
78         ipc_client_log(client, "Opening serial failed");
79         goto error;
80     }
81     ipc_client_log(client, "Opened serial");
82
83     usleep(100000);
84
85     p = (unsigned char *) modem_image_data;
86
87     rc = xmm6160_psi_send(client, serial_fd, (void *) p, CRESPO_PSI_SIZE);
88     if (rc < 0) {
89         ipc_client_log(client, "Sending XMM6160 PSI failed");
90         goto error;
91     }
92     ipc_client_log(client, "Sent XMM6160 PSI");
93
94     p += CRESPO_PSI_SIZE;
95
96     lseek(modem_ctl_fd, 0, SEEK_SET);
97
98     rc = xmm6160_firmware_send(client, modem_ctl_fd, NULL, (void *) p, CRESPO_MODEM_IMAGE_SIZE - CRESPO_PSI_SIZE);
99     if (rc < 0) {
100         ipc_client_log(client, "Sending XMM6160 firmware failed");
101         goto error;
102     }
103     ipc_client_log(client, "Sent XMM6160 firmware");
104
105     lseek(modem_ctl_fd, CRESPO_MODEM_CTL_NV_DATA_OFFSET, SEEK_SET);
106
107     rc = xmm6160_nv_data_send(client, modem_ctl_fd, NULL);
108     if (rc < 0) {
109         ipc_client_log(client, "Sending XMM6160 nv_data failed");
110         goto error;
111     }
112     ipc_client_log(client, "Sent XMM6160 nv_data");
113
114     rc = 0;
115     goto complete;
116
117 error:
118     rc = -1;
119
120 complete:
121     if (modem_image_data != NULL)
122         free(modem_image_data);
123
124     if (serial_fd >= 0)
125         close(serial_fd);
126
127     if (modem_ctl_fd >= 0)
128         close(modem_ctl_fd);
129
130     return rc;
131 }
132
133 int crespo_ipc_fmt_send(struct ipc_client *client, struct ipc_message_info *request)
134 {
135     struct ipc_header header;
136     struct modem_io mio;
137     int rc;
138
139     if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || request == NULL)
140         return -1;
141
142     ipc_header_fill(&header, request);
143
144     memset(&mio, 0, sizeof(struct modem_io));
145     mio.size = request->length + sizeof(struct ipc_header);
146     mio.data = malloc(mio.size);
147
148     memcpy(mio.data, &header, sizeof(struct ipc_header));
149     if (request->data != NULL && request->length > 0)
150         memcpy((void *) ((unsigned char *) mio.data + sizeof(struct ipc_header)), request->data, request->length);
151
152     ipc_client_log_send(client, request, __func__);
153
154     rc = client->handlers->write(client->handlers->transport_data, (void *) &mio, sizeof(struct modem_io));
155     if (rc < 0) {
156         ipc_client_log(client, "Writing FMT data to the modem failed");
157         goto error;
158     }
159
160     rc = 0;
161     goto complete;
162
163 error:
164     rc = -1;
165
166 complete:
167     if (mio.data != NULL)
168         free(mio.data);
169
170     return rc;
171 }
172
173 int crespo_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response)
174 {
175     struct ipc_header *header;
176     struct modem_io mio;
177     int rc;
178
179     if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || response == NULL)
180         return -1;
181
182     memset(&mio, 0, sizeof(struct modem_io));
183     mio.size = CRESPO_DATA_SIZE;
184     mio.data = malloc(mio.size);
185
186     rc = client->handlers->read(client->handlers->transport_data, &mio, sizeof(struct modem_io) + mio.size);
187     if (rc < 0 || mio.data == NULL || mio.size < sizeof(struct ipc_header)) {
188         ipc_client_log(client, "Reading FMT data from the modem failed");
189         goto error;
190     }
191
192     header = (struct ipc_header *) mio.data;
193
194     ipc_message_info_fill(header, response);
195
196     if (mio.size > sizeof(struct ipc_header)) {
197         response->length = mio.size - sizeof(struct ipc_header);
198         response->data = malloc(response->length);
199
200         memcpy(response->data, (void *) ((unsigned char *) mio.data + sizeof(struct ipc_header)), response->length);
201     }
202
203     ipc_client_log_recv(client, response, __func__);
204
205     rc = 0;
206     goto complete;
207
208 error:
209     rc = -1;
210
211 complete:
212     if (mio.data != NULL)
213         free(mio.data);
214
215     return rc;
216 }
217
218 int crespo_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request)
219 {
220     struct modem_io mio;
221     int rc;
222
223     if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || request == NULL)
224         return -1;
225
226     memset(&mio, 0, sizeof(struct modem_io));
227     mio.id = request->mseq;
228     mio.cmd = request->index;
229     mio.size = request->length;
230
231     if (request->data != NULL && request->length > 0) {
232         mio.data = malloc(mio.size);
233
234         memcpy(mio.data, request->data, request->length);
235     }
236
237     ipc_client_log_send(client, request, __func__);
238
239     rc = client->handlers->write(client->handlers->transport_data, (void *) &mio, sizeof(struct modem_io));
240     if (rc < 0) {
241         ipc_client_log(client, "Writing RFS data to the modem failed");
242         goto error;
243     }
244
245     rc = 0;
246     goto complete;
247
248 error:
249     rc = -1;
250
251 complete:
252     if (mio.data != NULL)
253         free(mio.data);
254
255     return rc;
256 }
257
258 int crespo_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response)
259 {
260     struct modem_io mio;
261     int rc;
262
263     if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || response == NULL)
264         return -1;
265
266     memset(&mio, 0, sizeof(struct modem_io));
267     mio.size = CRESPO_DATA_SIZE;
268     mio.data = malloc(mio.size);
269
270     rc = client->handlers->read(client->handlers->transport_data, &mio, sizeof(struct modem_io) + mio.size);
271     if (rc < 0 || mio.data == NULL || mio.size <= 0) {
272         ipc_client_log(client, "Reading RFS data from the modem failed");
273         goto error;
274     }
275
276     memset(response, 0, sizeof(struct ipc_message_info));
277     response->aseq = mio.id;
278     response->group = IPC_GROUP_RFS;
279     response->index = mio.cmd;
280
281     if (mio.size > 0) {
282         response->length = mio.size;
283         response->data = malloc(response->length);
284
285         memcpy(response->data, mio.data, response->length);
286     }
287
288     ipc_client_log_recv(client, response, __func__);
289
290     rc = 0;
291     goto complete;
292
293 error:
294     rc = -1;
295
296 complete:
297     if (mio.data != NULL)
298         free(mio.data);
299
300     return rc;
301 }
302
303 int crespo_ipc_open(void *data, int type)
304 {
305     struct crespo_ipc_transport_data *transport_data;
306     int fd;
307
308     if (data == NULL)
309         return -1;
310
311     transport_data = (struct crespo_ipc_transport_data *) data;
312
313     switch (type) {
314         case IPC_CLIENT_TYPE_FMT:
315             fd = open(CRESPO_MODEM_FMT_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
316             break;
317         case IPC_CLIENT_TYPE_RFS:
318             fd = open(CRESPO_MODEM_RFS_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
319             break;
320         default:
321             return -1;
322     }
323
324     if (fd < 0)
325         return -1;
326
327     transport_data->fd = fd;
328
329     return 0;
330 }
331
332 int crespo_ipc_close(void *data)
333 {
334     struct crespo_ipc_transport_data *transport_data;
335     int fd;
336
337     if (data == NULL)
338         return -1;
339
340     transport_data = (struct crespo_ipc_transport_data *) data;
341
342     fd = transport_data->fd;
343     if (fd < 0)
344         return -1;
345
346     transport_data->fd = -1;
347     close(fd);
348
349     return 0;
350 }
351
352 int crespo_ipc_read(void *data, void *buffer, unsigned int length)
353 {
354     struct crespo_ipc_transport_data *transport_data;
355     int fd;
356     int rc;
357
358     if (data == NULL || buffer == NULL || length == 0)
359         return -1;
360
361     transport_data = (struct crespo_ipc_transport_data *) data;
362
363     fd = transport_data->fd;
364     if (fd < 0)
365         return -1;
366
367     rc = ioctl(fd, IOCTL_MODEM_RECV, buffer);
368     if (rc < 0)
369         return -1;
370
371     return 0;
372 }
373
374 int crespo_ipc_write(void *data, void *buffer, unsigned int length)
375 {
376     struct crespo_ipc_transport_data *transport_data;
377     int fd;
378     int rc;
379
380     if (data == NULL || buffer == NULL || length == 0)
381         return -1;
382
383     transport_data = (struct crespo_ipc_transport_data *) data;
384
385     fd = transport_data->fd;
386     if (fd < 0)
387         return -1;
388
389     rc = ioctl(fd, IOCTL_MODEM_SEND, buffer);
390     if (rc < 0)
391         return -1;
392
393     return 0;
394 }
395
396 int crespo_ipc_poll(void *data, struct timeval *timeout)
397 {
398     struct crespo_ipc_transport_data *transport_data;
399     fd_set fds;
400     int fd;
401     int rc;
402
403     if (data == NULL)
404         return -1;
405
406     transport_data = (struct crespo_ipc_transport_data *) data;
407
408     fd = transport_data->fd;
409     if (fd < 0)
410         return -1;
411
412     FD_ZERO(&fds);
413     FD_SET(fd, &fds);
414
415     rc = select(fd + 1, &fds, NULL, NULL, timeout);
416     return rc;
417 }
418
419 int crespo_ipc_power_on(void *data)
420 {
421     int fd;
422     int rc;
423
424     fd = open(CRESPO_MODEM_CTL_DEVICE, O_RDWR);
425     if (fd < 0)
426         return -1;
427
428     rc = ioctl(fd, IOCTL_MODEM_START);
429
430     close(fd);
431
432     if (rc < 0)
433         return -1;
434
435     return 0;
436 }
437
438 int crespo_ipc_power_off(void *data)
439 {
440     int fd;
441     int rc;
442
443     fd = open(CRESPO_MODEM_CTL_DEVICE, O_RDWR);
444     if (fd < 0)
445         return -1;
446
447     rc = ioctl(fd, IOCTL_MODEM_OFF);
448
449     close(fd);
450
451     if (rc < 0)
452         return -1;
453
454     return 0;
455 }
456
457 int crespo_ipc_data_create(void **transport_data, void **power_data, void **gprs_data)
458 {
459     if (transport_data == NULL)
460         return -1;
461
462     *transport_data = (void *) malloc(sizeof(struct crespo_ipc_transport_data));
463     memset(*transport_data, 0, sizeof(struct crespo_ipc_transport_data));
464
465     return 0;
466 }
467
468 int crespo_ipc_data_destroy(void *transport_data, void *power_data, void *gprs_data)
469 {
470     if (transport_data == NULL)
471         return -1;
472
473     free(transport_data);
474
475     return 0;
476 }
477
478 char *crespo_ipc_gprs_get_iface_single(int cid)
479 {
480     char *iface = NULL;
481
482     asprintf(&iface, "%s%d", CRESPO_GPRS_IFACE_PREFIX, 0);
483
484     return iface;
485 }
486
487 int crespo_ipc_gprs_get_capabilities_single(struct ipc_client_gprs_capabilities *capabilities)
488 {
489     if (capabilities == NULL)
490         return -1;
491
492     capabilities->port_list = 0;
493     capabilities->cid_max = 1;
494
495     return 0;
496 }
497
498 char *crespo_ipc_gprs_get_iface(int cid)
499 {
500     char *iface = NULL;
501
502     if (cid > CRESPO_GPRS_IFACE_COUNT)
503         return NULL;
504
505     asprintf(&iface, "%s%d", CRESPO_GPRS_IFACE_PREFIX, cid - 1);
506
507     return iface;
508 }
509
510 int crespo_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities)
511 {
512     if (capabilities == NULL)
513         return -1;
514
515     capabilities->port_list = 0;
516     capabilities->cid_max = CRESPO_GPRS_IFACE_COUNT;
517
518     return 0;
519 }
520
521 struct ipc_ops crespo_ipc_fmt_ops = {
522     .bootstrap = crespo_ipc_bootstrap,
523     .send = crespo_ipc_fmt_send,
524     .recv = crespo_ipc_fmt_recv,
525 };
526
527 struct ipc_ops crespo_ipc_rfs_ops = {
528     .bootstrap = NULL,
529     .send = crespo_ipc_rfs_send,
530     .recv = crespo_ipc_rfs_recv,
531 };
532
533 struct ipc_handlers crespo_ipc_handlers = {
534     .open = crespo_ipc_open,
535     .close = crespo_ipc_close,
536     .read = crespo_ipc_read,
537     .write = crespo_ipc_write,
538     .poll = crespo_ipc_poll,
539     .transport_data = NULL,
540     .power_on = crespo_ipc_power_on,
541     .power_off = crespo_ipc_power_off,
542     .power_data = NULL,
543     .gprs_activate = NULL,
544     .gprs_deactivate = NULL,
545     .gprs_data = NULL,
546     .data_create = crespo_ipc_data_create,
547     .data_destroy = crespo_ipc_data_destroy,
548 };
549
550 struct ipc_gprs_specs crespo_ipc_gprs_specs_single = {
551     .gprs_get_iface = crespo_ipc_gprs_get_iface_single,
552     .gprs_get_capabilities = crespo_ipc_gprs_get_capabilities_single,
553 };
554
555 struct ipc_gprs_specs crespo_ipc_gprs_specs = {
556     .gprs_get_iface = crespo_ipc_gprs_get_iface,
557     .gprs_get_capabilities = crespo_ipc_gprs_get_capabilities,
558 };
559
560 // vim:ts=4:sw=4:expandtab