Reworked AT queuing, with queues for send, recv, async recv and sync recv
[hayes-ril.git] / hayes-ril.c
1 /*
2  * This file is part of hayes-ril.
3  *
4  * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #define LOG_TAG "RIL"
20 #include <utils/Log.h>
21 #include <telephony/ril.h>
22
23 #include <hayes-ril.h>
24
25 #define RIL_VERSION_STRING "Hayes RIL"
26
27 struct ril_device *ril_device;
28 struct ril_globals ril_globals;
29
30 struct ril_dispatch_unsol ril_dispatch_unsol[] = {};
31
32 void ril_on_request(int request, void *data, size_t length, RIL_Token t)
33 {
34         switch(request) {
35                 // Power
36                 case RIL_REQUEST_RADIO_POWER:
37                         ril_request_radio_power(t, data, length);
38                         break;
39                 // SIM
40                 case RIL_REQUEST_GET_SIM_STATUS:
41                         ril_request_get_sim_status(t, data, length);
42                         break;
43                 case RIL_REQUEST_ENTER_SIM_PIN:
44                         ril_request_enter_sim_pin(t, data, length);
45                         break;
46                 // Call
47                 case RIL_REQUEST_GET_CURRENT_CALLS:
48                         ril_request_get_current_calls(t, data, length);
49                         break;
50                 default:
51                         LOGE("Request not implemented: %d\n", request);
52                         RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
53                         break;
54         }
55 }
56
57 const char *ril_get_version(void)
58 {
59         return RIL_VERSION_STRING;
60 }
61
62 RIL_RadioState ril_on_state_request(void)
63 {
64         LOGD("State request");
65         return ril_globals.radio_state;
66 }
67
68 int ril_on_supports(int requestCode)
69 {
70         return 1;
71 }
72
73 void ril_on_cancel(RIL_Token t)
74 {
75         return;
76 }
77
78 static const RIL_RadioFunctions ril_ops = {
79         RIL_VERSION,
80         ril_on_request,
81         ril_on_state_request,
82         ril_on_supports,
83         ril_on_cancel,
84         ril_get_version
85 };
86
87 void *ril_dispatch(void *data)
88 {
89         struct at_response *response = NULL;
90         int rc;
91         int i, j;
92
93         for(i = 5 ; i > 0 ; i--) {
94                 while(1) {
95                         response = at_response_dequeue();
96                         if(response == NULL)
97                                 break;
98
99                         // Dequeue works now
100                         if(i != 5)
101                                 i = 5;
102
103                         // Handle async
104                         rc = at_async_response_dequeue(response);
105                         if(rc < 0) {
106                                 // Handle UNSOL
107                                 if(response->command == NULL) {
108                                         at_response_free(response);
109                                         continue;
110                                 }
111
112                                 for(j=0 ; j < ril_globals.dispatch_unsol_count ; j++) {
113                                         if(at_commands_compare(response->command, ril_globals.dispatch_unsol[j].command) && ril_globals.dispatch_unsol[j].func != NULL) {
114                                                 ril_globals.dispatch_unsol[j].func(response);
115                                         }
116                                 }
117                         }
118
119                         at_response_free(response);
120                 }
121
122                 LOGE("RIL dispatch failed, retrying!");
123         }
124
125         LOGE("RIL dispatch failed too many times, aborting");
126
127         return NULL;
128 }
129
130 int ril_dispatch_thread_start(void)
131 {
132         pthread_attr_t attr;
133         int rc;
134
135         pthread_attr_init(&attr);
136         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
137
138         rc = pthread_create(&ril_globals.dispatch_thread, &attr, ril_dispatch, NULL);
139         if(rc != 0) {
140                 LOGE("Creating dispatch thread failed!");
141                 return -1;
142         }
143
144         return 0;
145 }
146
147 void ril_globals_init(void)
148 {
149         memset(&ril_globals, 0, sizeof(struct ril_globals));
150         ril_globals.dispatch_unsol = &ril_dispatch_unsol;
151         ril_globals.dispatch_unsol_count = sizeof(ril_dispatch_unsol) / sizeof(struct ril_dispatch_unsol);
152
153         LOGE("Registered %d unsol requests handlers", ril_globals.dispatch_unsol_count);
154
155         ril_globals.radio_state = RADIO_STATE_OFF;
156
157         at_handling_init();
158 }
159
160 const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
161 {
162         int rc;
163
164         ril_globals_init();
165         ril_device_register(&ril_device);
166
167         LOGD("Starting %s for device: %s", RIL_VERSION_STRING, ril_device->name);
168
169         rc = ril_device_init(ril_device);
170         if(rc < 0) {
171                 LOGE("Failed to init device!");
172                 ril_device_deinit(ril_device);
173
174                 return NULL;
175         }
176
177         rc = ril_device_recv_thread_start(ril_device);
178         if(rc < 0) {
179                 LOGE("Failed to start device thread!");
180                 ril_device_deinit(ril_device);
181
182                 return NULL;
183         }
184
185         rc = ril_dispatch_thread_start();
186         if(rc < 0) {
187                 LOGE("Failed to start dispatch thread!");
188                 ril_device_deinit(ril_device);
189
190                 return NULL;
191         }
192
193         LOGD("Initialization complete");
194
195         return &ril_ops;
196 }