xmm6160: Use device-specific sizes and offsets
[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_modem_image_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 modem image failed");
101         goto error;
102     }
103     ipc_client_log(client, "Sent XMM6160 modem image");
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     memcpy(mio.data, &header, sizeof(struct ipc_header));
148     if (request->data != NULL && request->length > 0)
149         memcpy((void *) ((unsigned char *) mio.data + sizeof(struct ipc_header)), request->data, request->length);
150
151     ipc_client_log_send(client, request, __func__);
152
153     rc = client->handlers->write(client->handlers->transport_data, (void *) &mio, sizeof(struct modem_io));
154
155     free(mio.data);
156
157     return rc;
158 }
159
160 int crespo_ipc_fmt_recv(struct ipc_client *client, struct ipc_message_info *response)
161 {
162     struct ipc_header *header;
163     struct modem_io mio;
164     int rc;
165
166     if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || response == NULL)
167         return -1;
168
169     memset(&mio, 0, sizeof(struct modem_io));
170     mio.size = CRESPO_DATA_SIZE;
171     mio.data = malloc(mio.size);
172
173     rc = client->handlers->read(client->handlers->transport_data, &mio, sizeof(struct modem_io) + mio.size);
174     if (rc < 0 || mio.data == NULL || mio.size < sizeof(struct ipc_header)) {
175         ipc_client_log(client, "Reading FMT data from the modem failed");
176         goto error;
177     }
178
179     header = (struct ipc_header *) mio.data;
180     ipc_message_info_fill(header, response);
181
182     if (mio.size > sizeof(struct ipc_header)) {
183         response->length = mio.size - sizeof(struct ipc_header);
184         response->data = malloc(response->length);
185         memcpy(response->data, (void *) ((unsigned char *) mio.data + sizeof(struct ipc_header)), response->length);
186     }
187
188     ipc_client_log_recv(client, response, __func__);
189
190     goto complete;
191
192 error:
193     rc = -1;
194
195 complete:
196     if (mio.data != NULL)
197         free(mio.data);
198
199     return rc;
200 }
201
202 int crespo_ipc_rfs_send(struct ipc_client *client, struct ipc_message_info *request)
203 {
204     struct modem_io mio;
205     int rc;
206
207     if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || request == NULL)
208         return -1;
209
210     memset(&mio, 0, sizeof(struct modem_io));
211     mio.id = request->mseq;
212     mio.cmd = request->index;
213     mio.size = request->length;
214     if (request->data != NULL && request->length > 0) {
215         mio.data = malloc(mio.size);
216         memcpy(mio.data, request->data, request->length);
217     }
218
219     ipc_client_log_send(client, request, __func__);
220
221     rc = client->handlers->write(client->handlers->transport_data, (void *) &mio, sizeof(struct modem_io));
222
223     if (mio.data != NULL)
224         free(mio.data);
225
226     return rc;
227 }
228
229 int crespo_ipc_rfs_recv(struct ipc_client *client, struct ipc_message_info *response)
230 {
231     struct modem_io mio;
232     int rc;
233
234     if (client == NULL || client->handlers == NULL || client->handlers->read == NULL || response == NULL)
235         return -1;
236
237     memset(&mio, 0, sizeof(struct modem_io));
238     mio.size = CRESPO_DATA_SIZE;
239     mio.data = malloc(mio.size);
240
241     rc = client->handlers->read(client->handlers->transport_data, &mio, sizeof(struct modem_io) + mio.size);
242     if (rc < 0 || mio.data == NULL || mio.size <= 0) {
243         ipc_client_log(client, "Reading RFS data from the modem failed");
244         goto error;
245     }
246
247     memset(response, 0, sizeof(struct ipc_message_info));
248     response->aseq = mio.id;
249     response->group = IPC_GROUP_RFS;
250     response->index = mio.cmd;
251
252     if (mio.size > 0) {
253         response->length = mio.size;
254         response->data = malloc(response->length);
255         memcpy(response->data, mio.data, response->length);
256     }
257
258     ipc_client_log_recv(client, response, __func__);
259
260     goto complete;
261
262 error:
263     rc = -1;
264
265 complete:
266     if (mio.data != NULL)
267         free(mio.data);
268
269     return rc;
270 }
271
272 int crespo_ipc_open(void *data, int type)
273 {
274     struct crespo_ipc_transport_data *transport_data;
275     int fd;
276
277     if (data == NULL)
278         return -1;
279
280     transport_data = (struct crespo_ipc_transport_data *) data;
281
282     switch(type)
283     {
284         case IPC_CLIENT_TYPE_FMT:
285             fd = open(CRESPO_MODEM_FMT_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
286             break;
287         case IPC_CLIENT_TYPE_RFS:
288             fd = open(CRESPO_MODEM_RFS_DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
289             break;
290         default:
291             return -1;
292     }
293
294     if(fd < 0)
295         return -1;
296
297     transport_data->fd = fd;
298
299     return 0;
300 }
301
302 int crespo_ipc_close(void *data)
303 {
304     struct crespo_ipc_transport_data *transport_data;
305     int fd;
306
307     if (data == NULL)
308         return -1;
309
310     transport_data = (struct crespo_ipc_transport_data *) data;
311
312     fd = transport_data->fd;
313     if (fd < 0)
314         return -1;
315
316     transport_data->fd = -1;
317     close(fd);
318
319     return 0;
320 }
321
322 int crespo_ipc_read(void *data, void *buffer, unsigned int length)
323 {
324     struct crespo_ipc_transport_data *transport_data;
325     int fd;
326     int rc;
327
328     if (data == NULL || buffer == NULL || length == 0)
329         return -1;
330
331     transport_data = (struct crespo_ipc_transport_data *) data;
332
333     fd = transport_data->fd;
334     if (fd < 0)
335         return -1;
336
337     rc = ioctl(fd, IOCTL_MODEM_RECV, buffer);
338     if(rc < 0)
339         return -1;
340
341     return 0;
342 }
343
344 int crespo_ipc_write(void *data, void *buffer, unsigned int length)
345 {
346     struct crespo_ipc_transport_data *transport_data;
347     int fd;
348     int rc;
349
350     if (data == NULL || buffer == NULL || length == 0)
351         return -1;
352
353     transport_data = (struct crespo_ipc_transport_data *) data;
354
355     fd = transport_data->fd;
356     if (fd < 0)
357         return -1;
358
359     rc = ioctl(fd, IOCTL_MODEM_SEND, buffer);
360     if (rc < 0)
361         return -1;
362
363     return 0;
364 }
365
366 int crespo_ipc_poll(void *data, struct timeval *timeout)
367 {
368     struct crespo_ipc_transport_data *transport_data;
369     fd_set fds;
370     int fd;
371     int rc;
372
373     if (data == NULL)
374         return -1;
375
376     transport_data = (struct crespo_ipc_transport_data *) data;
377
378     fd = transport_data->fd;
379     if (fd < 0)
380         return -1;
381
382     FD_ZERO(&fds);
383     FD_SET(fd, &fds);
384
385     rc = select(FD_SETSIZE, &fds, NULL, NULL, timeout);
386     return rc;
387 }
388
389 int crespo_ipc_power_on(void *data)
390 {
391     int fd;
392     int rc;
393
394     fd = open(CRESPO_MODEM_CTL_DEVICE, O_RDWR);
395     if (fd < 0)
396         return -1;
397
398     rc = ioctl(fd, IOCTL_MODEM_START);
399
400     close(fd);
401
402     if (rc < 0)
403         return -1;
404
405     return 0;
406 }
407
408 int crespo_ipc_power_off(void *data)
409 {
410     int fd;
411     int rc;
412
413     fd = open(CRESPO_MODEM_CTL_DEVICE, O_RDWR);
414     if (fd < 0)
415         return -1;
416
417     rc = ioctl(fd, IOCTL_MODEM_OFF);
418
419     close(fd);
420
421     if (rc < 0)
422         return -1;
423
424     return 0;
425 }
426
427 int crespo_ipc_data_create(void **transport_data, void **power_data, void **gprs_data)
428 {
429     if (transport_data == NULL)
430         return -1;
431
432     *transport_data = (void *) malloc(sizeof(struct crespo_ipc_transport_data));
433     memset(*transport_data, 0, sizeof(struct crespo_ipc_transport_data));
434
435     return 0;
436 }
437
438 int crespo_ipc_data_destroy(void *transport_data, void *power_data, void *gprs_data)
439 {
440     if (transport_data == NULL)
441         return -1;
442
443     free(transport_data);
444
445     return 0;
446 }
447
448 char *crespo_ipc_gprs_get_iface_single(int cid)
449 {
450     char *iface = NULL;
451
452     asprintf(&iface, "%s%d", CRESPO_GPRS_IFACE_PREFIX, 0);
453
454     return iface;
455 }
456
457 int crespo_ipc_gprs_get_capabilities_single(struct ipc_client_gprs_capabilities *capabilities)
458 {
459     if (capabilities == NULL)
460         return -1;
461
462     capabilities->port_list = 0;
463     capabilities->cid_max = 1;
464
465     return 0;
466 }
467
468 char *crespo_ipc_gprs_get_iface(int cid)
469 {
470     char *iface = NULL;
471
472     if (cid > CRESPO_GPRS_IFACE_COUNT)
473         return NULL;
474
475     asprintf(&iface, "%s%d", CRESPO_GPRS_IFACE_PREFIX, cid - 1);
476
477     return iface;
478 }
479
480 int crespo_ipc_gprs_get_capabilities(struct ipc_client_gprs_capabilities *capabilities)
481 {
482     if (capabilities == NULL)
483         return -1;
484
485     capabilities->port_list = 0;
486     capabilities->cid_max = CRESPO_GPRS_IFACE_COUNT;
487
488     return 0;
489 }
490
491 struct ipc_ops crespo_ipc_fmt_ops = {
492     .bootstrap = crespo_ipc_bootstrap,
493     .send = crespo_ipc_fmt_send,
494     .recv = crespo_ipc_fmt_recv,
495 };
496
497 struct ipc_ops crespo_ipc_rfs_ops = {
498     .bootstrap = NULL,
499     .send = crespo_ipc_rfs_send,
500     .recv = crespo_ipc_rfs_recv,
501 };
502
503 struct ipc_handlers crespo_ipc_handlers = {
504     .open = crespo_ipc_open,
505     .close = crespo_ipc_close,
506     .read = crespo_ipc_read,
507     .write = crespo_ipc_write,
508     .poll = crespo_ipc_poll,
509     .transport_data = NULL,
510     .power_on = crespo_ipc_power_on,
511     .power_off = crespo_ipc_power_off,
512     .power_data = NULL,
513     .gprs_activate = NULL,
514     .gprs_deactivate = NULL,
515     .gprs_data = NULL,
516     .data_create = crespo_ipc_data_create,
517     .data_destroy = crespo_ipc_data_destroy,
518 };
519
520 struct ipc_gprs_specs crespo_ipc_gprs_specs_single = {
521     .gprs_get_iface = crespo_ipc_gprs_get_iface_single,
522     .gprs_get_capabilities = crespo_ipc_gprs_get_capabilities_single,
523 };
524
525 struct ipc_gprs_specs crespo_ipc_gprs_specs = {
526     .gprs_get_iface = crespo_ipc_gprs_get_iface,
527     .gprs_get_capabilities = crespo_ipc_gprs_get_capabilities,
528 };
529
530 // vim:ts=4:sw=4:expandtab