8cbe0646ed937c0abcb954db8860b8d33714d354
[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 };
33
34 void ril_on_request(int request, void *data, size_t length, RIL_Token t)
35 {
36         switch(request) {
37                 // Power
38                 case RIL_REQUEST_RADIO_POWER:
39                         ril_request_radio_power(t, data, length);
40                         break;
41                 // SIM
42                 case RIL_REQUEST_GET_SIM_STATUS:
43                         ril_request_get_sim_status(t, data, length);
44                         break;
45                 case RIL_REQUEST_ENTER_SIM_PIN:
46                         ril_request_enter_sim_pin(t, data, length);
47                         break;
48                 case RIL_REQUEST_SIM_IO:
49                         ril_request_sim_io(t, data, length);
50                         break;
51                 // Network
52                 case RIL_REQUEST_SIGNAL_STRENGTH:
53                         ril_request_signal_strength(t, data, length);
54                         break;
55                 case RIL_REQUEST_REGISTRATION_STATE:
56                         ril_request_registration_state(t, data, length);
57                         break;
58                 // Call
59                 case RIL_REQUEST_GET_CURRENT_CALLS:
60                         ril_request_get_current_calls(t, data, length);
61                         break;
62                 default:
63                         LOGE("Request not implemented: %d\n", request);
64                         RIL_onRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
65                         break;
66         }
67 }
68
69 const char *ril_get_version(void)
70 {
71         return RIL_VERSION_STRING;
72 }
73
74 RIL_RadioState ril_on_state_request(void)
75 {
76         LOGD("State request");
77         return ril_globals.radio_state;
78 }
79
80 int ril_on_supports(int requestCode)
81 {
82         return 1;
83 }
84
85 void ril_on_cancel(RIL_Token t)
86 {
87         return;
88 }
89
90 static const RIL_RadioFunctions ril_ops = {
91         RIL_VERSION,
92         ril_on_request,
93         ril_on_state_request,
94         ril_on_supports,
95         ril_on_cancel,
96         ril_get_version
97 };
98
99 void *ril_dispatch(void *data)
100 {
101         struct at_response *response = NULL;
102         int rc;
103         int i, j;
104
105         for(i = 5 ; i > 0 ; i--) {
106                 while(1) {
107                         response = at_response_dequeue();
108                         if(response == NULL)
109                                 break;
110
111                         // Dequeue works now
112                         if(i != 5)
113                                 i = 5;
114
115                         // Handle async
116                         rc = at_async_response_dequeue(response);
117                         if(rc < 0) {
118                                 // Handle UNSOL
119                                 if(response->command == NULL) {
120                                         at_response_free(response);
121                                         continue;
122                                 }
123
124                                 for(j=0 ; j < ril_globals.dispatch_unsol_count ; j++) {
125                                         if(at_commands_compare(response->command, ril_globals.dispatch_unsol[j].command) && ril_globals.dispatch_unsol[j].func != NULL) {
126                                                 ril_globals.dispatch_unsol[j].func(response);
127                                         }
128                                 }
129                         }
130
131                         at_response_free(response);
132                 }
133
134                 LOGE("RIL dispatch failed, retrying!");
135         }
136
137         LOGE("RIL dispatch failed too many times, aborting");
138
139         return NULL;
140 }
141
142 int ril_dispatch_thread_start(void)
143 {
144         pthread_attr_t attr;
145         int rc;
146
147         pthread_attr_init(&attr);
148         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
149
150         rc = pthread_create(&ril_globals.dispatch_thread, &attr, ril_dispatch, NULL);
151         if(rc != 0) {
152                 LOGE("Creating dispatch thread failed!");
153                 return -1;
154         }
155
156         return 0;
157 }
158
159 void ril_globals_init(void)
160 {
161         memset(&ril_globals, 0, sizeof(struct ril_globals));
162         ril_globals.dispatch_unsol = &ril_dispatch_unsol;
163         ril_globals.dispatch_unsol_count = sizeof(ril_dispatch_unsol) / sizeof(struct ril_dispatch_unsol);
164
165         LOGE("Registered %d unsol requests handlers", ril_globals.dispatch_unsol_count);
166
167         ril_globals.radio_state = RADIO_STATE_OFF;
168
169         at_handling_init();
170 }
171
172 const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv)
173 {
174         int rc;
175
176         ril_globals_init();
177         ril_device_register(&ril_device);
178
179         LOGD("Starting %s for device: %s", RIL_VERSION_STRING, ril_device->name);
180
181         rc = ril_device_init(ril_device);
182         if(rc < 0) {
183                 LOGE("Failed to init device!");
184                 ril_device_deinit(ril_device);
185
186                 return NULL;
187         }
188
189         rc = ril_device_recv_thread_start(ril_device);
190         if(rc < 0) {
191                 LOGE("Failed to start device thread!");
192                 ril_device_deinit(ril_device);
193
194                 return NULL;
195         }
196
197         rc = ril_dispatch_thread_start();
198         if(rc < 0) {
199                 LOGE("Failed to start dispatch thread!");
200                 ril_device_deinit(ril_device);
201
202                 return NULL;
203         }
204
205         LOGD("Initialization complete");
206
207         return &ril_ops;
208 }