Device detection mechanism improvments and more constitant devices naming
[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 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     int 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 = sizeof(buffer);
72     length = read(fd, &buffer, length);
73
74     close(fd);
75     fd = -1;
76
77     line = strtok(buffer, "\n");
78     while (line != NULL) {
79         if (strncmp(line, "Hardware", 9) == 9) {
80             p = line + 11;
81             c = p;
82
83             while (*c != '\n' && *c != '\0') {
84                 *c = tolower(*c);
85                 c++;
86             }
87
88             *c = '\0';
89
90             board_name = strdup(p);
91             break;
92         }
93
94         line = strtok(NULL, "\n");
95     }
96 #endif
97
98 #ifdef IPC_DEVICE_KERNEL_VERSION
99     kernel_version = strdup(IPC_DEVICE_KERNEL_VERSION);
100 #else
101     memset(&utsname, 0, sizeof(utsname));
102
103     uname(&utsname);
104
105     kernel_version = strdup(utsname.release);
106 #endif
107
108     for (i = 0; i < ipc_devices_count; i++) {
109         // Eliminate index if the name doesn't match
110         if (name != NULL && ipc_devices[i].name != NULL && strcmp(name, ipc_devices[i].name) != 0)
111             continue;
112
113         // Eliminate index if the board name doesn't match
114         if (board_name != NULL && ipc_devices[i].board_name != NULL && strcmp(board_name, ipc_devices[i].board_name) != 0)
115             continue;
116
117         // Keep index but don't break yet since we may have a better match with kernel version
118         index = i;
119
120         if (kernel_version == NULL || ipc_devices[i].kernel_version == NULL)
121             continue;
122
123         if (kernel_version != NULL && ipc_devices[i].kernel_version != NULL && strcmp(kernel_version, ipc_devices[i].kernel_version) != 0)
124             continue;
125
126         // Everything matches this particular index
127         break;
128     }
129
130     goto complete;
131
132 error:
133     index = -1;
134
135 complete:
136     if (board_name != NULL)
137         free(board_name);
138
139     if (kernel_version != NULL)
140         free(kernel_version);
141
142     if (fd >= 0)
143         close(fd);
144
145     return index;
146 }
147
148 struct ipc_client *ipc_client_create(int client_type)
149 {
150     struct ipc_client *client;
151     int device_index = -1;
152
153     device_index = ipc_device_detect();
154
155     if (device_index < 0 || device_index > ipc_devices_count)
156         return NULL;
157
158     if (client_type < 0 || client_type > IPC_CLIENT_TYPE_RFS)
159         return NULL;
160
161     client = (struct ipc_client *) malloc(sizeof(struct ipc_client));
162     memset(client, 0, sizeof(struct ipc_client));
163
164     client->type = client_type;
165
166     switch (client_type)
167     {
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             return NULL;
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 are subject to be modified
182     client->handlers = (struct ipc_handlers *) malloc(sizeof(struct ipc_handlers));
183     memset(client->handlers, 0, sizeof(struct ipc_handlers));
184
185     if (ipc_devices[device_index].handlers != 0)
186         memcpy(client->handlers, ipc_devices[device_index].handlers, sizeof(struct ipc_handlers));
187
188     return client;
189 }
190
191 int ipc_client_destroy(struct ipc_client *client)
192 {
193     if (client == NULL)
194         return -1;
195
196     if (client->handlers != NULL)
197         free(client->handlers);
198
199     memset(client, 0, sizeof(struct ipc_client));
200     free(client);
201
202     return 0;
203 }
204
205 void ipc_client_log(struct ipc_client *client, const char *message, ...)
206 {
207     char buffer[4096];
208     va_list args;
209
210     if (client == NULL || client->log_callback == NULL || message == NULL)
211         return;
212
213     va_start(args, message);
214     vsnprintf(buffer, 4096, message, args);
215     client->log_callback(client->log_data, buffer);
216     va_end(args);
217 }
218
219 int ipc_client_set_log_callback(struct ipc_client *client,
220     void (*log_callback)(void *log_data, const char *message), void *log_data)
221 {
222     if (client == NULL)
223         return -1;
224
225     client->log_callback = log_callback;
226     client->log_data = log_data;
227
228     return 0;
229 }
230
231 int ipc_client_set_transport_handlers(struct ipc_client *client,
232     int (*open)(void *transport_data, int type),
233     int (*close)(void *transport_data),
234     int (*read)(void *transport_data, void *buffer, unsigned int length),
235     int (*write)(void *transport_data, void *buffer, unsigned int length),
236     int (*poll)(void *transport_data, struct timeval *timeout),
237     void *transport_data)
238 {
239     if (client == NULL || client->handlers == NULL)
240         return -1;
241
242     if (read != NULL)
243         client->handlers->read = read;
244     if (write != NULL)
245         client->handlers->write = write;
246     if (poll != NULL)
247         client->handlers->poll = poll;
248     if (open != NULL)
249         client->handlers->open = open;
250     if (close != NULL)
251         client->handlers->close = close;
252     if (transport_data != NULL)
253         client->handlers->transport_data = transport_data;
254
255     return 0;
256 }
257
258 int ipc_client_set_power_handlers(struct ipc_client *client,
259     int (*power_on)(void *power_data),
260     int (*power_off)(void *power_data),
261     void *power_data)
262 {
263     if (client == NULL || client->handlers == NULL)
264         return -1;
265
266     if (power_on != NULL)
267         client->handlers->power_on = power_on;
268     if (power_off != NULL)
269         client->handlers->power_off = power_off;
270     if (power_data != NULL)
271         client->handlers->power_data = power_data;
272
273     return 0;
274 }
275
276 int ipc_client_set_gprs_handlers(struct ipc_client *client,
277     int (*gprs_activate)(void *gprs_data, int cid),
278     int (*gprs_deactivate)(void *gprs_data, int cid),
279     void *gprs_data)
280 {
281     if (client == NULL || client->handlers == NULL)
282         return -1;
283
284     if (gprs_activate != NULL)
285         client->handlers->gprs_activate = gprs_activate;
286     if (gprs_deactivate != NULL)
287         client->handlers->gprs_deactivate = gprs_deactivate;
288     if (gprs_data != NULL)
289         client->handlers->gprs_data = gprs_data;
290
291     return 0;
292 }
293
294 int ipc_client_bootstrap(struct ipc_client *client)
295 {
296     if (client == NULL || client->ops == NULL ||
297         client->ops->bootstrap == NULL)
298         return -1;
299
300     return client->ops->bootstrap(client);
301 }
302
303 int ipc_client_send(struct ipc_client *client, const unsigned short command,
304     const char type, unsigned char *data, const int length, unsigned char mseq)
305 {
306     struct ipc_message_info request;
307
308     if (client == NULL || client->ops == NULL || client->ops->send == NULL)
309         return -1;
310
311     request.mseq = mseq;
312     request.aseq = 0xff;
313     request.group = IPC_GROUP(command);
314     request.index = IPC_INDEX(command);
315     request.type = type;
316     request.length = length;
317     request.data = data;
318
319     return client->ops->send(client, &request);
320 }
321
322 int ipc_client_recv(struct ipc_client *client,
323     struct ipc_message_info *response)
324 {
325     if (client == NULL || client->ops == NULL || client->ops->recv == NULL)
326         return -1;
327
328     return client->ops->recv(client, response);
329 }
330
331 void ipc_client_response_free(struct ipc_client *client,
332     struct ipc_message_info *response)
333 {
334     if (response == NULL)
335         return;
336
337     if (response->data != NULL && response->length > 0) {
338         free(response->data);
339         response->data = NULL;
340     }
341
342     memset(response, 0, sizeof(struct ipc_message_info));
343 }
344
345 int ipc_client_open(struct ipc_client *client)
346 {
347     if (client == NULL || client->handlers == NULL ||
348         client->handlers->open == NULL)
349         return -1;
350
351     return client->handlers->open(client->handlers->transport_data, client->type);
352 }
353
354 int ipc_client_close(struct ipc_client *client)
355 {
356     if (client == NULL || client->handlers == NULL ||
357         client->handlers->close == NULL)
358         return -1;
359
360     return client->handlers->close(client->handlers->transport_data);
361 }
362
363 int ipc_client_poll(struct ipc_client *client, struct timeval *timeout)
364 {
365     if (client == NULL || client->handlers == NULL ||
366         client->handlers->poll == NULL)
367         return -1;
368
369     return client->handlers->poll(client->handlers->transport_data, timeout);
370 }
371
372 int ipc_client_power_on(struct ipc_client *client)
373 {
374     if (client == NULL || client->handlers == NULL ||
375         client->handlers->power_on == NULL)
376         return -1;
377
378     return client->handlers->power_on(client->handlers->power_data);
379 }
380
381 int ipc_client_power_off(struct ipc_client *client)
382 {
383     if (client == NULL || client->handlers == NULL ||
384         client->handlers->power_off == NULL)
385         return -1;
386
387     return client->handlers->power_off(client->handlers->power_data);
388 }
389
390 int ipc_client_gprs_activate(struct ipc_client *client, int cid)
391 {
392     if (client == NULL || client->handlers == NULL ||
393         client->handlers->gprs_activate == NULL)
394         return -1;
395
396     return client->handlers->gprs_activate(client->handlers->gprs_data, cid);
397 }
398
399 int ipc_client_gprs_deactivate(struct ipc_client *client, int cid)
400 {
401     if (client == NULL || client->handlers == NULL ||
402         client->handlers->gprs_deactivate == NULL)
403         return -1;
404
405     return client->handlers->gprs_deactivate(client->handlers->gprs_data, cid);
406 }
407
408 int ipc_client_data_create(struct ipc_client *client)
409 {
410     if (client == NULL || client->handlers == NULL ||
411         client->handlers->data_create == NULL)
412         return -1;
413
414     return client->handlers->data_create(&client->handlers->transport_data,
415         &client->handlers->power_data, &client->handlers->power_data);
416 }
417
418 int ipc_client_data_destroy(struct ipc_client *client)
419 {
420     if (client == NULL || client->handlers == NULL ||
421         client->handlers->data_destroy == NULL)
422         return -1;
423
424     return client->handlers->data_destroy(client->handlers->transport_data,
425         client->handlers->power_data, client->handlers->power_data);
426 }
427
428 char *ipc_client_gprs_get_iface(struct ipc_client *client, int cid)
429 {
430     if (client == NULL || client->gprs_specs == NULL ||
431         client->gprs_specs->gprs_get_iface == NULL)
432         return NULL;
433
434     return client->gprs_specs->gprs_get_iface(cid);
435 }
436
437 int ipc_client_gprs_get_capabilities(struct ipc_client *client,
438     struct ipc_client_gprs_capabilities *capabilities)
439 {
440     if (client == NULL || client->gprs_specs == NULL ||
441         client->gprs_specs->gprs_get_capabilities == NULL)
442         return -1;
443
444     return client->gprs_specs->gprs_get_capabilities(capabilities);
445 }
446
447 // vim:ts=4:sw=4:expandtab