AT: Better failure handling and removed wrong unlock
[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         { "AT+CREG",    at_creg_unexpect },
32         { "NO CARRIER", no_carrier_unexpect },
33         { "AT+CRING",   at_cring }
34 };
35
36 void ril_on_request(int request, void *data, size_t length, RIL_Token t)
37 {
38         if(at_freeze_get() != AT_FREEZE_OFF) {
39                 RIL_onRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
40                 return;
41         }
42
43         switch(request) {
44                 // Power
45                 case RIL_REQUEST_RADIO_POWER:
46                         ril_request_radio_power(t, data, length);
47                         break;
48                 // SIM
49                 case RIL_REQUEST_GET_SIM_STATUS:
50                         ril_request_get_sim_status(t, data, length);
51                         break;
52                 case RIL_REQUEST_ENTER_SIM_PIN:
53                         ril_request_enter_sim_pin(t, data, length);
54                         break;
55                 case RIL_REQUEST_SIM_IO:
56                         ril_request_sim_io(t, data, length);
57                         break;
58                 // Network
59                 case RIL_REQUEST_SIGNAL_STRENGTH:
60                         ril_request_signal_strength(t, data, length);
61                         break;
62                 case RIL_REQUEST_REGISTRATION_STATE:
63                         ril_request_registration_state(t, data, length);
64                         break;
65                 case RIL_REQUEST_OPERATOR:
66                         ril_request_operator(t, data, length);
67                         break;
68                 // Call
69                 case RIL_REQUEST_GET_CURRENT_CALLS:
70                         ril_request_get_current_calls(t, data, length);
71                         break;
72                 case RIL_REQUEST_DIAL:
73                         ril_request_dial(t, data, length);
74                         break;
75                 case RIL_REQUEST_ANSWER:        
76                         ril_request_anwswer(t, data, length);
77                         break;
78                 case RIL_REQUEST_HANGUP:
79                         ril_request_hangup(t, data, length);
80                         break;
81                 case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
82                         ril_request_hangup_waiting_or_background(t, data, length);
83                         break;
84                 case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
85                         ril_request_hangup_foreground_resume_background(t, data, length);
86                         break;
87                 case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
88                         ril_request_switch_waiting_or_holding_and_active(t, data, length);
89                         break;
90                 default:
91                         LOGE("Request not implemented: %d\n", request);
92                         RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
93                         break;
94         }
95 }
96
97 const char *ril_get_version(void)
98 {
99         return RIL_VERSION_STRING;
100 }
101
102 RIL_RadioState ril_on_state_request(void)
103 {
104         LOGD("State request");
105         return ril_globals.radio_state;
106 }
107
108 int ril_on_supports(int requestCode)
109 {
110         return 1;
111 }
112
113 void ril_on_cancel(RIL_Token t)
114 {
115         return;
116 }
117
118 static const RIL_RadioFunctions ril_ops = {
119         RIL_VERSION,
120         ril_on_request,
121         ril_on_state_request,
122         ril_on_supports,
123         ril_on_cancel,
124         ril_get_version
125 };
126
127 void *ril_dispatch(void *data)
128 {
129         struct at_response *response = NULL;
130         int rc;
131         int i, j;
132
133         for(i = 5 ; i > 0 ; i--) {
134                 while(1) {
135                         response = at_response_dequeue();
136
137                         if(response == NULL && at_freeze_get() == AT_FREEZE_SEND) {
138                                 ril_device_at_setup(ril_device);
139
140                                 // Respawn freezed requests
141                                 at_freeze_respawn();
142
143                                 // Stop freeze state
144                                 at_freeze_stop();
145
146                                 continue;
147                         } else if(response == NULL) {
148                                 break;
149                         }
150
151                         // Dequeue works now
152                         if(i != 5)
153                                 i = 5;
154
155                         // Handle async
156                         rc = at_async_response_dequeue(response);
157                         if(rc < 0) {
158                                 // Handle UNSOL
159                                 if(response->command == NULL) {
160                                         at_response_free(response);
161                                         continue;
162                                 }
163
164                                 for(j=0 ; j < ril_globals.dispatch_unsol_count ; j++) {
165                                         if(at_commands_compare(response->command, ril_globals.dispatch_unsol[j].command) && ril_globals.dispatch_unsol[j].func != NULL) {
166                                                 ril_globals.dispatch_unsol[j].func(response);
167                                         }
168                                 }
169                         }
170
171                         at_response_free(response);
172                 }
173
174                 LOGE("RIL dispatch failed, retrying!");
175         }
176
177         LOGE("RIL dispatch failed too many times, aborting");
178
179         return NULL;
180 }
181
182 int ril_dispatch_thread_start(void)
183 {
184         pthread_attr_t attr;
185         int rc;
186
187         pthread_attr_init(&attr);
188         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
189
190         rc = pthread_create(&ril_globals.dispatch_thread, &attr, ril_dispatch, NULL);
191         if(rc != 0) {
192                 LOGE("Creating dispatch thread failed!");
193                 return -1;
194         }
195
196         return 0;
197 }
198
199 void ril_globals_init(void)
200 {
201         memset(&ril_globals, 0, sizeof(struct ril_globals));
202         ril_globals.dispatch_unsol = &ril_dispatch_unsol;
203         ril_globals.dispatch_unsol_count = sizeof(ril_dispatch_unsol) / sizeof(struct ril_dispatch_unsol);
204
205         LOGE("Registered %d unsol requests handlers", ril_globals.dispatch_unsol_count);
206
207         ril_globals.radio_state = RADIO_STATE_OFF;
208
209         at_handling_init();
210 }
211
212 const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
213 {
214         int rc;
215
216         ril_globals_init();
217         ril_device_register(&ril_device);
218
219         LOGD("Starting %s for device: %s", RIL_VERSION_STRING, ril_device->name);
220
221         rc = ril_device_init(ril_device);
222         if(rc < 0) {
223                 LOGE("Failed to init device!");
224                 ril_device_deinit(ril_device);
225
226                 return NULL;
227         }
228
229         rc = ril_device_transport_recv_thread_start(ril_device);
230         if(rc < 0) {
231                 LOGE("Failed to start device recv thread!");
232                 ril_device_deinit(ril_device);
233
234                 return NULL;
235         }
236
237         rc = ril_dispatch_thread_start();
238         if(rc < 0) {
239                 LOGE("Failed to start dispatch thread!");
240                 ril_device_deinit(ril_device);
241
242                 return NULL;
243         }
244
245         rc = ril_device_setup(ril_device);
246         if(rc < 0) {
247                 LOGE("Failed to setup device!");
248                 ril_device_deinit(ril_device);
249
250                 return NULL;
251         }
252
253         LOGD("Initialization complete");
254
255         return &ril_ops;
256 }