Global include path
[libsamsung-ipc.git] / samsung-ipc / ipc.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com>
5  * Copyright (C) 2011 Simon Busch <morphis@gravedo.de>
6  * Copyright (C) 2013-2014 Paul Kocialkowsk <contact@paulk.fr>
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 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdint.h>
26 #include <stdarg.h>
27 #include <unistd.h>
28 #include <stdbool.h>
29 #include <termios.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <sys/ioctl.h>
34 #include <sys/stat.h>
35 #include <sys/types.h>
36 #include <asm/types.h>
37 #include <sys/utsname.h>
38
39 #include <samsung-ipc.h>
40
41 #include <ipc.h>
42 #include <ipc_devices.h>
43
44 int ipc_device_detect(void)
45 {
46     char buffer[4096] = { 0 };
47     struct utsname utsname;
48     char *board_name = NULL;
49     char *kernel_version = NULL;
50     char *name = NULL;
51     char *line, *p, *c;
52     int index = -1;
53     int fd = -1;
54     size_t length;
55     int rc;
56     int i;
57
58 #ifdef IPC_DEVICE_NAME
59     name = strdup(IPC_DEVICE_NAME);
60 #endif
61
62 #ifdef IPC_DEVICE_BOARD_NAME
63     board_name = strdup(IPC_DEVICE_BOARD_NAME);
64 #else
65     // Read board name from cpuinfo
66
67     fd = open("/proc/cpuinfo", O_RDONLY);
68     if (fd < 0)
69         goto error;
70
71     length = read(fd, &buffer, sizeof(buffer));
72
73     close(fd);
74     fd = -1;
75
76     line = strtok(buffer, "\n");
77     while (line != NULL) {
78         if (strncmp(line, "Hardware", 9) == 9) {
79             p = line + 11;
80             c = p;
81
82             while (*c != '\n' && *c != '\0') {
83                 *c = tolower(*c);
84                 c++;
85             }
86
87             *c = '\0';
88
89             board_name = strdup(p);
90             break;
91         }
92
93         line = strtok(NULL, "\n");
94     }
95 #endif
96
97 #ifdef IPC_DEVICE_KERNEL_VERSION
98     kernel_version = strdup(IPC_DEVICE_KERNEL_VERSION);
99 #else
100     memset(&utsname, 0, sizeof(utsname));
101
102     uname(&utsname);
103
104     kernel_version = strdup(utsname.release);
105 #endif
106
107     for (i = 0; i < (int) ipc_devices_count; i++) {
108         // Eliminate index if the name doesn't match
109         if (name != NULL && ipc_devices[i].name != NULL && strcmp(name, ipc_devices[i].name) != 0)
110             continue;
111
112         // Eliminate index if the board name doesn't match
113         if (board_name != NULL && ipc_devices[i].board_name != NULL && strcmp(board_name, ipc_devices[i].board_name) != 0)
114             continue;
115
116         // Keep index but don't break yet since we may have a better match with kernel version
117         index = i;
118
119         if (kernel_version == NULL || ipc_devices[i].kernel_version == NULL)
120             continue;
121
122         if (kernel_version != NULL && ipc_devices[i].kernel_version != NULL && strcmp(kernel_version, ipc_devices[i].kernel_version) != 0)
123             continue;
124
125         // Everything matches this particular index
126         break;
127     }
128
129     goto complete;
130
131 error:
132     index = -1;
133
134 complete:
135     if (board_name != NULL)
136         free(board_name);
137
138     if (kernel_version != NULL)
139         free(kernel_version);
140
141     if (fd >= 0)
142         close(fd);
143
144     return index;
145 }
146
147 struct ipc_client *ipc_client_create(int type)
148 {
149     struct ipc_client *client = NULL;
150     unsigned int device_index;
151     int rc;
152
153     if (type < 0 || type > IPC_CLIENT_TYPE_RFS)
154         return NULL;
155
156     rc = ipc_device_detect();
157     if (rc < 0)
158         goto error;
159
160     device_index = (unsigned int) rc;
161     if (device_index > ipc_devices_count)
162         goto error;
163
164     client = (struct ipc_client *) calloc(1, sizeof(struct ipc_client));
165     client->type = type;
166
167     switch (type) {
168         case IPC_CLIENT_TYPE_RFS:
169             client->ops = ipc_devices[device_index].rfs_ops;
170             break;
171         case IPC_CLIENT_TYPE_FMT:
172             client->ops = ipc_devices[device_index].fmt_ops;
173             break;
174         default:
175             goto error;
176     }
177
178     client->gprs_specs = ipc_devices[device_index].gprs_specs;
179     client->nv_data_specs = ipc_devices[device_index].nv_data_specs;
180
181     // Handlers can be modified
182     client->handlers = (struct ipc_client_handlers *) calloc(1, sizeof(struct ipc_client_handlers));
183
184     if (ipc_devices[device_index].handlers != NULL)
185         memcpy(client->handlers, ipc_devices[device_index].handlers, sizeof(struct ipc_client_handlers));
186
187     goto complete;
188
189 error:
190     if (client != NULL) {
191         free(client);
192         client = NULL;
193     }
194
195 complete:
196     return client;
197 }
198
199 int ipc_client_destroy(struct ipc_client *client)
200 {
201     if (client == NULL)
202         return -1;
203
204     if (client->handlers != NULL)
205         free(client->handlers);
206
207     memset(client, 0, sizeof(struct ipc_client));
208     free(client);
209
210     return 0;
211 }
212
213 int ipc_client_transport_handlers_register(struct ipc_client *client,
214     int (*open)(void *transport_data, int type),
215     int (*close)(void *transport_data),
216     int (*read)(void *transport_data, void *data, size_t size),
217     int (*write)(void *transport_data, const void *data, size_t size),
218     int (*poll)(void *transport_data, struct timeval *timeout),
219     void *transport_data)
220 {
221     if (client == NULL || client->handlers == NULL)
222         return -1;
223
224     if (read != NULL)
225         client->handlers->read = read;
226     if (write != NULL)
227         client->handlers->write = write;
228     if (poll != NULL)
229         client->handlers->poll = poll;
230     if (open != NULL)
231         client->handlers->open = open;
232     if (close != NULL)
233         client->handlers->close = close;
234     if (transport_data != NULL)
235         client->handlers->transport_data = transport_data;
236
237     return 0;
238 }
239
240 int ipc_client_power_handlers_register(struct ipc_client *client,
241     int (*power_on)(void *power_data), int (*power_off)(void *power_data),
242     void *power_data)
243 {
244     if (client == NULL || client->handlers == NULL)
245         return -1;
246
247     if (power_on != NULL)
248         client->handlers->power_on = power_on;
249     if (power_off != NULL)
250         client->handlers->power_off = power_off;
251     if (power_data != NULL)
252         client->handlers->power_data = power_data;
253
254     return 0;
255 }
256
257 int ipc_client_gprs_handlers_register(struct ipc_client *client,
258     int (*gprs_activate)(void *gprs_data, int cid),
259     int (*gprs_deactivate)(void *gprs_data, int cid), void *gprs_data)
260 {
261     if (client == NULL || client->handlers == NULL)
262         return -1;
263
264     if (gprs_activate != NULL)
265         client->handlers->gprs_activate = gprs_activate;
266     if (gprs_deactivate != NULL)
267         client->handlers->gprs_deactivate = gprs_deactivate;
268     if (gprs_data != NULL)
269         client->handlers->gprs_data = gprs_data;
270
271     return 0;
272 }
273
274 void ipc_client_log(struct ipc_client *client, const char *message, ...)
275 {
276     char buffer[4096];
277     va_list args;
278
279     if (client == NULL || client->log_callback == NULL || message == NULL)
280         return;
281
282     va_start(args, message);
283     vsnprintf((char *) &buffer, sizeof(buffer), message, args);
284     client->log_callback(client->log_data, buffer);
285     va_end(args);
286 }
287
288 int ipc_client_log_callback_register(struct ipc_client *client,
289     void (*log_callback)(void *log_data, const char *message), void *log_data)
290 {
291     if (client == NULL)
292         return -1;
293
294     client->log_callback = log_callback;
295     client->log_data = log_data;
296
297     return 0;
298 }
299
300 int ipc_client_boot(struct ipc_client *client)
301 {
302     if (client == NULL || client->ops == NULL || client->ops->boot == NULL)
303         return -1;
304
305     return client->ops->boot(client);
306 }
307
308 int ipc_client_send(struct ipc_client *client, unsigned char mseq,
309     unsigned short command, unsigned char type, const void *data, size_t size)
310 {
311     struct ipc_message message;
312
313     if (client == NULL || client->ops == NULL || client->ops->send == NULL)
314         return -1;
315
316     memset(&message, 0, sizeof(message));
317     message.mseq = mseq;
318     message.aseq = 0xff;
319     message.command = command;
320     message.type = type;
321     message.data = (void *) data;
322     message.size = size;
323
324     return client->ops->send(client, &message);
325 }
326
327 int ipc_client_recv(struct ipc_client *client, struct ipc_message *message)
328 {
329     if (client == NULL || client->ops == NULL || client->ops->recv == NULL || message == NULL)
330         return -1;
331
332     return client->ops->recv(client, message);
333 }
334
335 int ipc_client_open(struct ipc_client *client)
336 {
337     if (client == NULL || client->handlers == NULL || client->handlers->open == NULL)
338         return -1;
339
340     return client->handlers->open(client->handlers->transport_data, client->type);
341 }
342
343 int ipc_client_close(struct ipc_client *client)
344 {
345     if (client == NULL || client->handlers == NULL || client->handlers->close == NULL)
346         return -1;
347
348     return client->handlers->close(client->handlers->transport_data);
349 }
350
351 int ipc_client_poll(struct ipc_client *client, struct timeval *timeout)
352 {
353     if (client == NULL || client->handlers == NULL || client->handlers->poll == NULL)
354         return -1;
355
356     return client->handlers->poll(client->handlers->transport_data, timeout);
357 }
358
359 int ipc_client_power_on(struct ipc_client *client)
360 {
361     if (client == NULL || client->handlers == NULL || client->handlers->power_on == NULL)
362         return -1;
363
364     return client->handlers->power_on(client->handlers->power_data);
365 }
366
367 int ipc_client_power_off(struct ipc_client *client)
368 {
369     if (client == NULL || client->handlers == NULL || client->handlers->power_off == NULL)
370         return -1;
371
372     return client->handlers->power_off(client->handlers->power_data);
373 }
374
375 int ipc_client_gprs_activate(struct ipc_client *client, int cid)
376 {
377     if (client == NULL || client->handlers == NULL || client->handlers->gprs_activate == NULL)
378         return -1;
379
380     return client->handlers->gprs_activate(client->handlers->gprs_data, cid);
381 }
382
383 int ipc_client_gprs_deactivate(struct ipc_client *client, int cid)
384 {
385     if (client == NULL || client->handlers == NULL || client->handlers->gprs_deactivate == NULL)
386         return -1;
387
388     return client->handlers->gprs_deactivate(client->handlers->gprs_data, cid);
389 }
390
391 int ipc_client_data_create(struct ipc_client *client)
392 {
393     if (client == NULL || client->handlers == NULL || client->handlers->data_create == NULL)
394         return -1;
395
396     return client->handlers->data_create(&client->handlers->transport_data, &client->handlers->power_data, &client->handlers->power_data);
397 }
398
399 int ipc_client_data_destroy(struct ipc_client *client)
400 {
401     if (client == NULL || client->handlers == NULL || client->handlers->data_destroy == NULL)
402         return -1;
403
404     return client->handlers->data_destroy(client->handlers->transport_data, client->handlers->power_data, client->handlers->power_data);
405 }
406
407 char *ipc_client_gprs_get_iface(struct ipc_client *client, int cid)
408 {
409     if (client == NULL || client->gprs_specs == NULL || client->gprs_specs->gprs_get_iface == NULL)
410         return NULL;
411
412     return client->gprs_specs->gprs_get_iface(cid);
413 }
414
415 int ipc_client_gprs_get_capabilities(struct ipc_client *client,
416     struct ipc_client_gprs_capabilities *capabilities)
417 {
418     if (client == NULL || client->gprs_specs == NULL || client->gprs_specs->gprs_get_capabilities == NULL)
419         return -1;
420
421     return client->gprs_specs->gprs_get_capabilities(capabilities);
422 }
423
424 char *ipc_client_nv_data_path(struct ipc_client *client)
425 {
426     if (client == NULL || client->nv_data_specs == NULL || client->nv_data_specs->nv_data_path == NULL)
427         return NULL;
428
429     return client->nv_data_specs->nv_data_path;
430 }
431
432 char *ipc_client_nv_data_md5_path(struct ipc_client *client)
433 {
434     if (client == NULL || client->nv_data_specs == NULL || client->nv_data_specs->nv_data_md5_path == NULL)
435         return NULL;
436
437     return client->nv_data_specs->nv_data_md5_path;
438 }
439
440 char *ipc_client_nv_data_backup_path(struct ipc_client *client)
441 {
442     if (client == NULL || client->nv_data_specs == NULL || client->nv_data_specs->nv_data_backup_path == NULL)
443         return NULL;
444
445     return client->nv_data_specs->nv_data_backup_path;
446 }
447
448 char *ipc_client_nv_data_backup_md5_path(struct ipc_client *client)
449 {
450     if (client == NULL || client->nv_data_specs == NULL || client->nv_data_specs->nv_data_backup_md5_path == NULL)
451         return NULL;
452
453     return client->nv_data_specs->nv_data_backup_md5_path;
454 }
455
456 char *ipc_client_nv_data_secret(struct ipc_client *client)
457 {
458     if (client == NULL || client->nv_data_specs == NULL || client->nv_data_specs->nv_data_secret == NULL)
459         return NULL;
460
461     return client->nv_data_specs->nv_data_secret;
462 }
463
464 size_t ipc_client_nv_data_size(struct ipc_client *client)
465 {
466     if (client == NULL || client->nv_data_specs == NULL || client->nv_data_specs->nv_data_size == 0)
467         return 0;
468
469     return client->nv_data_specs->nv_data_size;
470 }
471
472 size_t ipc_client_nv_data_chunk_size(struct ipc_client *client)
473 {
474     if (client == NULL || client->nv_data_specs == NULL || client->nv_data_specs->nv_data_chunk_size == 0)
475         return 0;
476
477     return client->nv_data_specs->nv_data_chunk_size;
478 }
479
480 // vim:ts=4:sw=4:expandtab