ipc.c: Check heandlers data create/destroy pointers
[libsamsung-ipc.git] / samsung-ipc / ipc.c
1 /*
2  * This file is part of libsamsung-ipc.
3  *
4  * Copyright (C) 2011 Simon Busch <morphis@gravedo.de>
5  * Copyright (C) 2010-2011 Joerie de Gram <j.de.gram@gmail.com>
6  *
7  * libsamsung-ipc is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * libsamsung-ipc is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with libsamsung-ipc.  If not, see <http://www.gnu.org/licenses/>.
19  *
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 *board_name = NULL;
47     char *kernel_version = NULL;
48     int index = -1;
49     int i;
50
51 #ifdef IPC_BOARD_NAME_EXPLICIT
52     board_name = strdup(IPC_BOARD_NAME_EXPLICIT);
53 #else
54     char buf[4096];
55
56     // gather board name type from /proc/cpuinfo
57     int fd = open("/proc/cpuinfo", O_RDONLY);
58     int bytesread = read(fd, buf, 4096);
59     close(fd);
60
61     // match hardware name with our supported devices
62     char *pch = strtok(buf, "\n");
63     while (pch != NULL)
64     {
65         int rc;
66         if ((rc = strncmp(pch, "Hardware", 9)) == 9)
67         {
68             char *str = (void *) (pch + 9);
69             int len = strlen(str);
70             char tmp;
71
72             for (i=0; i < len; i++)
73             {
74                 tmp = (char) tolower(str[i]);
75                 str[i] = tmp;
76             }
77
78             board_name = strdup(pch);
79         }
80         pch = strtok(NULL, "\n");
81     }
82 #endif
83
84 #ifdef IPC_KERNEL_VERSION_EXPLICIT
85     kernel_version = strdup(IPC_KERNEL_VERSION_EXPLICIT);
86 #else
87     struct utsname utsname;
88     memset(&utsname, 0, sizeof(utsname));
89
90     uname(&utsname);
91
92     kernel_version = strdup(utsname.release);
93 #endif
94
95     for (i=0; i < ipc_devices_count; i++)
96     {
97         if (strstr(board_name, ipc_devices[i].board_name) != NULL)
98         {
99             if (ipc_devices[i].kernel_version != NULL)
100             {
101                 if (strncmp(kernel_version, ipc_devices[i].kernel_version, strlen(ipc_devices[i].kernel_version)) == 0)
102                 {
103                     index = i;
104                     break;
105                 } else {
106                     // Kernel version didn't match but it may still work
107                     index = i;
108                 }
109             } else {
110                 index = i;
111                 break;
112             }
113         }
114     }
115
116     if (board_name != NULL)
117         free(board_name);
118
119     if (kernel_version != NULL)
120         free(kernel_version);
121
122     return index;
123 }
124
125 struct ipc_client *ipc_client_create(int client_type)
126 {
127     struct ipc_client *client;
128     int device_index = -1;
129
130     device_index = ipc_device_detect();
131
132     if (device_index < 0 || device_index > ipc_devices_count)
133         return NULL;
134
135     if (client_type < 0 || client_type > IPC_CLIENT_TYPE_RFS)
136         return NULL;
137
138     client = (struct ipc_client *) malloc(sizeof(struct ipc_client));
139     memset(client, 0, sizeof(struct ipc_client));
140
141     client->type = client_type;
142
143     switch (client_type)
144     {
145         case IPC_CLIENT_TYPE_RFS:
146             client->ops = ipc_devices[device_index].rfs_ops;
147             break;
148         case IPC_CLIENT_TYPE_FMT:
149             client->ops = ipc_devices[device_index].fmt_ops;
150             break;
151         default:
152             return NULL;
153     }
154
155     client->gprs_specs = ipc_devices[device_index].gprs_specs;
156     client->nv_data_specs = ipc_devices[device_index].nv_data_specs;
157
158     // Handlers are subject to be modified
159     client->handlers = (struct ipc_handlers *) malloc(sizeof(struct ipc_handlers));
160     memset(client->handlers, 0, sizeof(struct ipc_handlers));
161
162     if (ipc_devices[device_index].handlers != 0)
163         memcpy(client->handlers, ipc_devices[device_index].handlers, sizeof(struct ipc_handlers));
164
165     return client;
166 }
167
168 int ipc_client_destroy(struct ipc_client *client)
169 {
170     if (client == NULL)
171         return -1;
172
173     if (client->handlers != NULL)
174         free(client->handlers);
175
176     memset(client, 0, sizeof(struct ipc_client));
177     free(client);
178
179     return 0;
180 }
181
182 void ipc_client_log(struct ipc_client *client, const char *message, ...)
183 {
184     char buffer[4096];
185     va_list args;
186
187     if (client == NULL || client->log_callback == NULL || message == NULL)
188         return;
189
190     va_start(args, message);
191     vsnprintf(buffer, 4096, message, args);
192     client->log_callback(client->log_data, buffer);
193     va_end(args);
194 }
195
196 int ipc_client_set_log_callback(struct ipc_client *client,
197     void (*log_callback)(void *log_data, const char *message), void *log_data)
198 {
199     if (client == NULL)
200         return -1;
201
202     client->log_callback = log_callback;
203     client->log_data = log_data;
204
205     return 0;
206 }
207
208 int ipc_client_set_transport_handlers(struct ipc_client *client,
209     int (*open)(void *transport_data, int type),
210     int (*close)(void *transport_data),
211     int (*read)(void *transport_data, void *buffer, unsigned int length),
212     int (*write)(void *transport_data, void *buffer, unsigned int length),
213     int (*poll)(void *transport_data, struct timeval *timeout),
214     void *transport_data)
215 {
216     if (client == NULL || client->handlers == NULL)
217         return -1;
218
219     if (read != NULL)
220         client->handlers->read = read;
221     if (write != NULL)
222         client->handlers->write = write;
223     if (poll != NULL)
224         client->handlers->poll = poll;
225     if (open != NULL)
226         client->handlers->open = open;
227     if (close != NULL)
228         client->handlers->close = close;
229     if (transport_data != NULL)
230         client->handlers->transport_data = transport_data;
231
232     return 0;
233 }
234
235 int ipc_client_set_power_handlers(struct ipc_client *client,
236     int (*power_on)(void *power_data),
237     int (*power_off)(void *power_data),
238     void *power_data)
239 {
240     if (client == NULL || client->handlers == NULL)
241         return -1;
242
243     if (power_on != NULL)
244         client->handlers->power_on = power_on;
245     if (power_off != NULL)
246         client->handlers->power_off = power_off;
247     if (power_data != NULL)
248         client->handlers->power_data = power_data;
249
250     return 0;
251 }
252
253 int ipc_client_set_gprs_handlers(struct ipc_client *client,
254     int (*gprs_activate)(void *gprs_data, int cid),
255     int (*gprs_deactivate)(void *gprs_data, int cid),
256     void *gprs_data)
257 {
258     if (client == NULL || client->handlers == NULL)
259         return -1;
260
261     if (gprs_activate != NULL)
262         client->handlers->gprs_activate = gprs_activate;
263     if (gprs_deactivate != NULL)
264         client->handlers->gprs_deactivate = gprs_deactivate;
265     if (gprs_data != NULL)
266         client->handlers->gprs_data = gprs_data;
267
268     return 0;
269 }
270
271 int ipc_client_bootstrap(struct ipc_client *client)
272 {
273     if (client == NULL || client->ops == NULL ||
274         client->ops->bootstrap == NULL)
275         return -1;
276
277     return client->ops->bootstrap(client);
278 }
279
280 int ipc_client_send(struct ipc_client *client, const unsigned short command,
281     const char type, unsigned char *data, const int length, unsigned char mseq)
282 {
283     struct ipc_message_info request;
284
285     if (client == NULL || client->ops == NULL || client->ops->send == NULL)
286         return -1;
287
288     request.mseq = mseq;
289     request.aseq = 0xff;
290     request.group = IPC_GROUP(command);
291     request.index = IPC_INDEX(command);
292     request.type = type;
293     request.length = length;
294     request.data = data;
295
296     return client->ops->send(client, &request);
297 }
298
299 int ipc_client_recv(struct ipc_client *client,
300     struct ipc_message_info *response)
301 {
302     if (client == NULL || client->ops == NULL || client->ops->recv == NULL)
303         return -1;
304
305     return client->ops->recv(client, response);
306 }
307
308 void ipc_client_response_free(struct ipc_client *client,
309     struct ipc_message_info *response)
310 {
311     if (response == NULL)
312         return;
313
314     if (response->data != NULL && response->length > 0) {
315         free(response->data);
316         response->data = NULL;
317     }
318
319     memset(response, 0, sizeof(struct ipc_message_info));
320 }
321
322 int ipc_client_open(struct ipc_client *client)
323 {
324     if (client == NULL || client->handlers == NULL ||
325         client->handlers->open == NULL)
326         return -1;
327
328     return client->handlers->open(client->handlers->transport_data, client->type);
329 }
330
331 int ipc_client_close(struct ipc_client *client)
332 {
333     if (client == NULL || client->handlers == NULL ||
334         client->handlers->close == NULL)
335         return -1;
336
337     return client->handlers->close(client->handlers->transport_data);
338 }
339
340 int ipc_client_poll(struct ipc_client *client, struct timeval *timeout)
341 {
342     if (client == NULL || client->handlers == NULL ||
343         client->handlers->poll == NULL)
344         return -1;
345
346     return client->handlers->poll(client->handlers->transport_data, timeout);
347 }
348
349 int ipc_client_power_on(struct ipc_client *client)
350 {
351     if (client == NULL || client->handlers == NULL ||
352         client->handlers->power_on == NULL)
353         return -1;
354
355     return client->handlers->power_on(client->handlers->power_data);
356 }
357
358 int ipc_client_power_off(struct ipc_client *client)
359 {
360     if (client == NULL || client->handlers == NULL ||
361         client->handlers->power_off == NULL)
362         return -1;
363
364     return client->handlers->power_off(client->handlers->power_data);
365 }
366
367 int ipc_client_gprs_activate(struct ipc_client *client, int cid)
368 {
369     if (client == NULL || client->handlers == NULL ||
370         client->handlers->gprs_activate == NULL)
371         return -1;
372
373     return client->handlers->gprs_activate(client->handlers->gprs_data, cid);
374 }
375
376 int ipc_client_gprs_deactivate(struct ipc_client *client, int cid)
377 {
378     if (client == NULL || client->handlers == NULL ||
379         client->handlers->gprs_deactivate == NULL)
380         return -1;
381
382     return client->handlers->gprs_deactivate(client->handlers->gprs_data, cid);
383 }
384
385 int ipc_client_data_create(struct ipc_client *client)
386 {
387     if (client == NULL || client->handlers == NULL ||
388         client->handlers->data_create == NULL)
389         return -1;
390
391     return client->handlers->data_create(&client->handlers->transport_data,
392         &client->handlers->power_data, &client->handlers->power_data);
393 }
394
395 int ipc_client_data_destroy(struct ipc_client *client)
396 {
397     if (client == NULL || client->handlers == NULL ||
398         client->handlers->data_destroy == NULL)
399         return -1;
400
401     return client->handlers->data_destroy(client->handlers->transport_data,
402         client->handlers->power_data, client->handlers->power_data);
403 }
404
405 char *ipc_client_gprs_get_iface(struct ipc_client *client, int cid)
406 {
407     if (client == NULL || client->gprs_specs == NULL ||
408         client->gprs_specs->gprs_get_iface == NULL)
409         return NULL;
410
411     return client->gprs_specs->gprs_get_iface(cid);
412 }
413
414 int ipc_client_gprs_get_capabilities(struct ipc_client *client,
415     struct ipc_client_gprs_capabilities *capabilities)
416 {
417     if (client == NULL || client->gprs_specs == NULL ||
418         client->gprs_specs->gprs_get_capabilities == NULL)
419         return -1;
420
421     return client->gprs_specs->gprs_get_capabilities(capabilities);
422 }
423
424 // vim:ts=4:sw=4:expandtab