9e7be96e055104c87fdddef5008ac96b857b93f2
[framework/telephony/libtcore.git] / src / hal.c
1 /*
2  * libtcore
3  *
4  * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Ja-young Gu <jygu@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <pthread.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <time.h>
27
28 #include <glib.h>
29
30 #include "tcore.h"
31 #include "hal.h"
32 #include "at.h"
33 #include "queue.h"
34 #include "plugin.h"
35 #include "user_request.h"
36 #include "server.h"
37 #include "mux.h"
38
39
40 //#define IDLE_SEND_PRIORITY G_PRIORITY_DEFAULT
41 #define IDLE_SEND_PRIORITY G_PRIORITY_HIGH
42
43 struct hook_send_type {
44         TcoreHalSendHook func;
45         void *user_data;
46 };
47
48 struct recv_callback_item_type {
49         TcoreHalReceiveCallback func;
50         void *user_data;
51 };
52
53 struct tcore_hal_type {
54         TcorePlugin *parent_plugin;
55         TcoreQueue *queue;
56         char *name;
57         struct tcore_hal_operations *ops;
58         void *user_data;
59         GSList *callbacks;
60         gboolean power_state;
61         GSList *hook_list_send;
62
63         enum tcore_hal_mode mode;
64         TcoreAT *at;
65 };
66
67 static gboolean _hal_idle_send(void *user_data)
68 {
69         TcoreHal *h = user_data;
70         TcorePending *p = NULL;
71         TcoreQueue *q;
72         int ret = 0;
73         void *data = NULL;
74         unsigned int data_len = 0;
75         gboolean renew = FALSE;
76
77         if (!h)
78                 return FALSE;
79
80         msg("--[Queue SEND]-------------------");
81
82         p = tcore_queue_ref_next_pending(h->queue);
83         if (!p) {
84                 dbg("next pending is NULL. no send, queue len=%d", tcore_queue_get_length(h->queue));
85                 goto out;
86         }
87
88         data = tcore_pending_ref_request_data(p, &data_len);
89         dbg("queue len=%d, pending=0x%x, id=0x%x, data_len=%d",
90                         tcore_queue_get_length(h->queue), (unsigned int)p, tcore_pending_get_id(p), data_len);
91
92         if (h->mode == TCORE_HAL_MODE_AT) {
93                 ret = tcore_at_set_request(h->at, data, TRUE);
94         }
95         else {
96                 ret = tcore_hal_send_data(h, data_len, data);
97         }
98
99         if (ret == TCORE_RETURN_SUCCESS) {
100                 tcore_pending_emit_send_callback(p, TRUE);
101         }
102         else {
103                 tcore_pending_emit_send_callback(p, FALSE);
104         }
105
106         if (ret != TCORE_RETURN_HOOK_STOP) {
107                 if (tcore_pending_get_auto_free_status_after_sent(p)) {
108                         q = tcore_hal_ref_queue(h);
109                         tcore_queue_pop_by_pending(q, p);
110                         tcore_pending_free(p);
111
112                         /* renew idler */
113                         renew = TRUE;
114                 }
115                 else {
116                         /* Send fail */
117                         if (ret != TCORE_RETURN_SUCCESS) {
118                                 dbg("send fail.");
119                                 q = tcore_hal_ref_queue(h);
120                                 p = tcore_queue_pop(q);
121                                 tcore_pending_free(p);
122                         }
123                 }
124         }
125
126 out:
127         msg("--[Queue SEND FINISH]------------\n");
128         return renew;
129 }
130
131 TcoreHal *tcore_hal_new(TcorePlugin *plugin, const char *name,
132                 struct tcore_hal_operations *hops,
133                 enum tcore_hal_mode mode)
134 {
135         TcoreHal *h;
136
137         if (!name)
138                 return NULL;
139
140         h = calloc(sizeof(struct tcore_hal_type), 1);
141         if (!h)
142                 return NULL;
143
144         h->parent_plugin = plugin;
145         h->ops = hops;
146         h->name = strdup(name);
147         h->queue = tcore_queue_new(h);
148         h->mode = mode;
149
150         if (mode == TCORE_HAL_MODE_AT)
151                 h->at = tcore_at_new(h);
152
153         if (plugin)
154                 tcore_server_add_hal(tcore_plugin_ref_server(plugin), h);
155
156         return h;
157 }
158
159 void tcore_hal_free(TcoreHal *hal)
160 {
161         if (!hal)
162                 return;
163
164         dbg("hal=%s", hal->name);
165
166         if (hal->name)
167                 free(hal->name);
168
169         if (hal->callbacks)
170                 g_slist_free(hal->callbacks);
171
172         if (hal->queue)
173                 tcore_queue_free(hal->queue);
174
175         if (hal->at)
176                 tcore_at_free(hal->at);
177
178         free(hal);
179 }
180
181 TReturn tcore_hal_set_name(TcoreHal *hal, const char *name)
182 {
183         if (!hal)
184                 return TCORE_RETURN_EINVAL;
185
186         if (hal->name) {
187                 free(hal->name);
188                 hal->name = NULL;
189         }
190
191         if (name)
192                 hal->name = strdup(name);
193
194         return TCORE_RETURN_SUCCESS;
195 }
196
197 char *tcore_hal_get_name(TcoreHal *hal)
198 {
199         if (!hal)
200                 return NULL;
201
202         if (hal->name)
203                 return strdup(hal->name);
204
205         return NULL;
206 }
207
208 TcoreAT *tcore_hal_get_at(TcoreHal *hal)
209 {
210         if (!hal)
211                 return NULL;
212
213         return hal->at;
214 }
215
216 enum tcore_hal_mode tcore_hal_get_mode(TcoreHal *hal)
217 {
218         if (!hal)
219                 return TCORE_HAL_MODE_UNKNOWN;
220
221         return hal->mode;
222 }
223
224 TReturn tcore_hal_set_mode(TcoreHal *hal, enum tcore_hal_mode mode)
225 {
226         if (!hal)
227                 return TCORE_RETURN_EINVAL;
228         
229         hal->mode = mode;
230
231         return TCORE_RETURN_SUCCESS;
232 }
233
234 TReturn tcore_hal_link_user_data(TcoreHal *hal, void *user_data)
235 {
236         if (!hal)
237                 return TCORE_RETURN_EINVAL;
238
239         hal->user_data = user_data;
240
241         return TCORE_RETURN_SUCCESS;
242 }
243
244 void *tcore_hal_ref_user_data(TcoreHal *hal)
245 {
246         if (!hal)
247                 return NULL;
248
249         return hal->user_data;
250 }
251
252 /* Send data without Queue */
253 TReturn tcore_hal_send_data(TcoreHal *hal, unsigned int data_len, void *data)
254 {
255         struct hook_send_type *hook;
256         GSList *list;
257
258         if (!hal || !hal->ops || !hal->ops->send)
259                 return TCORE_RETURN_EINVAL;
260
261         for (list = hal->hook_list_send; list; list = list->next) {
262                 hook = list->data;
263                 if (!hook) {
264                         continue;
265                 }
266
267                 if (hook->func(hal, data_len, data, hook->user_data) == TCORE_HOOK_RETURN_STOP_PROPAGATION) {
268                         return TCORE_RETURN_HOOK_STOP;
269                 }
270         }
271
272         return hal->ops->send(hal, data_len, data);
273 }
274
275 /* Send data by Queue */
276 TReturn tcore_hal_send_request(TcoreHal *hal, TcorePending *pending)
277 {
278         int qlen = 0;
279         enum tcore_pending_priority priority;
280
281         if (!hal || !pending)
282                 return TCORE_RETURN_EINVAL;
283
284         qlen = tcore_queue_get_length(hal->queue);
285         tcore_queue_push(hal->queue, pending);
286
287         tcore_pending_get_priority(pending, &priority);
288         if (priority == TCORE_PENDING_PRIORITY_IMMEDIATELY) {
289                 dbg("IMMEDIATELY pending !!");
290                 _hal_idle_send(hal);
291         }
292         else {
293                 if (tcore_queue_get_length(hal->queue) == 1) {
294                         g_idle_add_full(IDLE_SEND_PRIORITY, _hal_idle_send, hal, NULL);
295                 }
296         }
297
298         return TCORE_RETURN_SUCCESS;
299 }
300
301 TReturn tcore_hal_send_force(TcoreHal *hal)
302 {
303         if (!hal)
304                 return TCORE_RETURN_EINVAL;
305
306         _hal_idle_send(hal);
307
308         return TCORE_RETURN_SUCCESS;
309 }
310
311 TReturn tcore_hal_dispatch_response_data(TcoreHal *hal, int id,
312                 unsigned int data_len, const void *data)
313 {
314         TcorePending *p = NULL;
315
316         if (!hal)
317                 return TCORE_RETURN_EINVAL;
318
319         if (data_len > 0 && data == NULL)
320                 return TCORE_RETURN_EINVAL;
321
322         if (hal->mode == TCORE_HAL_MODE_AT) {
323                 gboolean ret;
324                 ret = tcore_at_process(hal->at, data_len, data);
325                 if (ret) {
326                         /* Send next request in queue */
327                         g_idle_add_full(IDLE_SEND_PRIORITY, _hal_idle_send, hal, NULL );
328                 }
329         }
330         else {
331                 if(hal->mode == TCORE_HAL_MODE_CUSTOM) {
332                         dbg("TCORE_HAL_MODE_CUSTOM");
333                         p = tcore_queue_pop_by_id(hal->queue, id);
334                         if (!p) {
335                                 dbg("unknown pending (id=0x%x)", id);
336                                 return TCORE_RETURN_PENDING_WRONG_ID;
337                         }
338
339                         tcore_pending_emit_response_callback(p, data_len, data);
340                         tcore_user_request_free(tcore_pending_ref_user_request(p));
341                         tcore_pending_free(p);
342                 }
343                 else if(hal->mode == TCORE_HAL_MODE_TRANSPARENT) {
344                         dbg("TCORE_HAL_MODE_TRANSPARENT");
345                         
346                         /* Invoke CMUX receive API for decoding */
347                         tcore_cmux_rcv_from_hal((unsigned char *)data, data_len);
348                 }
349                 /* Send next request in queue */
350                 g_idle_add_full(IDLE_SEND_PRIORITY, _hal_idle_send, hal, NULL );
351         }
352
353         return TCORE_RETURN_SUCCESS;
354 }
355
356 TReturn tcore_hal_add_recv_callback(TcoreHal *hal, TcoreHalReceiveCallback func,
357                 void *user_data)
358 {
359         struct recv_callback_item_type *item;
360
361         if (!hal)
362                 return TCORE_RETURN_EINVAL;
363
364         item = calloc(sizeof(struct recv_callback_item_type), 1);
365         if (!item)
366                 return TCORE_RETURN_ENOMEM;
367
368         item->func = func;
369         item->user_data = user_data;
370
371         hal->callbacks = g_slist_append(hal->callbacks, item);
372
373         return TCORE_RETURN_SUCCESS;
374 }
375
376 TReturn tcore_hal_remove_recv_callback(TcoreHal *hal, TcoreHalReceiveCallback func)
377 {
378         struct recv_callback_item_type *item;
379         GSList *list;
380
381         if (!hal)
382                 return TCORE_RETURN_EINVAL;
383
384         for (list = hal->callbacks; list; list = list->next) {
385                 item = list->data;
386                 if (!item) {
387                         continue;
388                 }
389
390                 if (item->func == func) {
391                         hal->callbacks = g_slist_remove(hal->callbacks, item);
392                         free(item);
393                         list = hal->callbacks;
394                 }
395         }
396
397         return TCORE_RETURN_SUCCESS;
398 }
399
400 TReturn tcore_hal_emit_recv_callback(TcoreHal *hal, unsigned int data_len,
401                 const void *data)
402 {
403         GSList *list;
404         struct recv_callback_item_type *item;
405
406         if (!hal)
407                 return TCORE_RETURN_EINVAL;
408
409         for (list = hal->callbacks; list; list = list->next) {
410                 item = list->data;
411
412                 if (item) {
413                         item->func(hal, data_len, data, item->user_data);
414                 }
415         }
416
417         return TCORE_RETURN_SUCCESS;
418 }
419
420
421 TReturn tcore_hal_add_send_hook(TcoreHal *hal, TcoreHalSendHook func, void *user_data)
422 {
423         struct hook_send_type *hook;
424
425         if (!hal || !func)
426                 return TCORE_RETURN_EINVAL;
427
428         hook = calloc(sizeof(struct hook_send_type), 1);
429         if (!hook)
430                 return TCORE_RETURN_ENOMEM;
431
432         hook->func = func;
433         hook->user_data = user_data;
434
435         hal->hook_list_send = g_slist_append(hal->hook_list_send, hook);
436
437         return TCORE_RETURN_SUCCESS;
438 }
439
440 TReturn tcore_hal_remove_send_hook(TcoreHal *hal, TcoreHalSendHook func)
441 {
442         struct hook_send_type *hook;
443         GSList *list;
444
445         if (!hal)
446                 return TCORE_RETURN_EINVAL;
447
448         for (list = hal->hook_list_send; list; list = list->next) {
449                 hook = list->data;
450                 if (!hook) {
451                         continue;
452                 }
453
454                 if (hook->func == func) {
455                         hal->hook_list_send = g_slist_remove(hal->hook_list_send, hook);
456                         free(hook);
457                         list = hal->hook_list_send;
458                 }
459         }
460
461         return TCORE_RETURN_SUCCESS;
462 }
463
464 TcoreQueue *tcore_hal_ref_queue(TcoreHal *hal)
465 {
466         if (!hal)
467                 return NULL;
468
469         return hal->queue;
470 }
471
472 TcorePlugin *tcore_hal_ref_plugin(TcoreHal *hal)
473 {
474         if (!hal)
475                 return NULL;
476
477         return hal->parent_plugin;
478 }
479
480 TReturn tcore_hal_set_power_state(TcoreHal *hal, gboolean flag)
481 {
482         if (!hal)
483                 return TCORE_RETURN_EINVAL;
484
485         hal->power_state = flag;
486
487         return TCORE_RETURN_SUCCESS;
488 }
489
490 gboolean tcore_hal_get_power_state(TcoreHal *hal)
491 {
492         if (!hal)
493                 return FALSE;
494
495         return hal->power_state;
496 }
497
498 TReturn tcore_hal_set_power(TcoreHal *hal, gboolean flag)
499 {
500         if (!hal || !hal->ops || !hal->ops->power)
501                 return TCORE_RETURN_EINVAL;
502
503         return hal->ops->power(hal, flag);
504 }