1 /* Copyright (c) 2009,2011 Code Aurora Forum. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of Code Aurora Forum, Inc. nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30 #define LOG_NDDEBUG 0
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <ctype.h>
37 #include <math.h>
38 #include <pthread.h>
39
40 #include <rpc/rpc.h>
41 #include <loc_api_rpc_glue.h>
42
43 #include <hardware/gps.h>
44
45 #include <loc_eng.h>
46
47 #define LOG_TAG "lib_locapi"
48 #include <utils/Log.h>
49
50 // comment this out to enable logging
51 // #undef LOGD
52 // #define LOGD(...) {}
53
54 // Function declarations
55 static boolean loc_eng_ioctl_setup_cb(
56 rpc_loc_client_handle_type handle,
57 rpc_loc_ioctl_e_type ioctl_type
58 );
59
60 static boolean loc_eng_ioctl_wait_cb(
61 int timeout_msec, // Timeout in this number of msec
62 rpc_loc_ioctl_callback_s_type *cb_data_ptr // Output parameter for IOCTL calls
63 );
64
65 /*===========================================================================
66
67 FUNCTION loc_eng_ioctl
68
69 DESCRIPTION
70 This function calls loc_ioctl and waits for the callback result before
71 returning back to the user.
72
73 DEPENDENCIES
74 N/A
75
76 RETURN VALUE
77 TRUE if successful
78 FALSE if failed
79
80 SIDE EFFECTS
81 N/A
82
83 ===========================================================================*/
loc_eng_ioctl(rpc_loc_client_handle_type handle,rpc_loc_ioctl_e_type ioctl_type,rpc_loc_ioctl_data_u_type * ioctl_data_ptr,uint32 timeout_msec,rpc_loc_ioctl_callback_s_type * cb_data_ptr)84 boolean loc_eng_ioctl(
85 rpc_loc_client_handle_type handle,
86 rpc_loc_ioctl_e_type ioctl_type,
87 rpc_loc_ioctl_data_u_type* ioctl_data_ptr,
88 uint32 timeout_msec,
89 rpc_loc_ioctl_callback_s_type *cb_data_ptr
90 )
91 {
92 boolean ret_val;
93 int rpc_ret_val;
94 loc_eng_ioctl_data_s_type *ioctl_cb_data_ptr;
95
96 LOGV ("loc_eng_ioctl: client = %d, ioctl_type = %d, cb_data =0x%x\n", (int32) handle, ioctl_type, (uint32) cb_data_ptr);
97
98 ioctl_cb_data_ptr = &(loc_eng_data.ioctl_data);
99 // Select the callback we are waiting for
100 ret_val = loc_eng_ioctl_setup_cb (handle, ioctl_type);
101
102 if (ret_val == TRUE)
103 {
104 rpc_ret_val = loc_ioctl (handle,
105 ioctl_type,
106 ioctl_data_ptr);
107
108 LOGV ("loc_eng_ioctl: loc_ioctl returned %d \n", rpc_ret_val);
109
110 if (rpc_ret_val == RPC_LOC_API_SUCCESS)
111 {
112 // Wait for the callback of loc_ioctl
113 ret_val = loc_eng_ioctl_wait_cb (timeout_msec, cb_data_ptr);
114 }
115 else
116 {
117 ret_val = FALSE;
118 }
119 }
120
121 // Reset the state when we are done
122 pthread_mutex_lock(&ioctl_cb_data_ptr->cb_data_mutex);
123 ioctl_cb_data_ptr->cb_is_selected = FALSE;
124 ioctl_cb_data_ptr->cb_is_waiting = FALSE;
125 ioctl_cb_data_ptr->cb_has_arrived = FALSE;
126 pthread_mutex_unlock(&ioctl_cb_data_ptr->cb_data_mutex);
127
128 return ret_val;
129 }
130
131
132 /*===========================================================================
133
134 FUNCTION loc_eng_ioctl_setup_cb
135
136 DESCRIPTION
137 Selects which callback is going to be waited for
138
139 DEPENDENCIES
140 N/A
141
142 RETURN VALUE
143 TRUE if successful
144 FALSE if failed
145
146 SIDE EFFECTS
147 N/A
148
149 ===========================================================================*/
loc_eng_ioctl_setup_cb(rpc_loc_client_handle_type handle,rpc_loc_ioctl_e_type ioctl_type)150 static boolean loc_eng_ioctl_setup_cb(
151 rpc_loc_client_handle_type handle,
152 rpc_loc_ioctl_e_type ioctl_type
153 )
154 {
155 boolean ret_val;
156 loc_eng_ioctl_data_s_type *ioctl_cb_data_ptr;
157
158 ioctl_cb_data_ptr = &(loc_eng_data.ioctl_data);
159
160 pthread_mutex_lock(&ioctl_cb_data_ptr->cb_data_mutex);
161 if (ioctl_cb_data_ptr->cb_is_selected == TRUE)
162 {
163 LOGD ("loc_eng_ioctl_setup_cb: ERROR, another ioctl in progress \n");
164 ret_val = FALSE;
165 }
166 else
167 {
168 ioctl_cb_data_ptr->cb_is_selected = TRUE;
169 ioctl_cb_data_ptr->cb_is_waiting = FALSE;
170 ioctl_cb_data_ptr->cb_has_arrived = FALSE;
171 ioctl_cb_data_ptr->client_handle = handle;
172 ioctl_cb_data_ptr->ioctl_type = ioctl_type;
173 memset (&(ioctl_cb_data_ptr->cb_payload), 0, sizeof (rpc_loc_ioctl_callback_s_type));
174 ret_val = TRUE;
175 }
176 pthread_mutex_unlock(&ioctl_cb_data_ptr->cb_data_mutex);
177
178 return ret_val;
179 }
180
181 /*===========================================================================
182
183 FUNCTION loc_eng_ioctl_wait_cb
184
185 DESCRIPTION
186 Waits for a selected callback. The wait expires in timeout_msec.
187
188 If the function is called before an existing wait has finished, it will
189 immediately return EBUSY.
190
191 DEPENDENCIES
192 N/A
193
194 RETURN VALUE
195 TRUE if successful
196 FALSE if failed
197
198 SIDE EFFECTS
199 N/A
200
201 ===========================================================================*/
loc_eng_ioctl_wait_cb(int timeout_msec,rpc_loc_ioctl_callback_s_type * cb_data_ptr)202 boolean loc_eng_ioctl_wait_cb(
203 int timeout_msec, // Timeout in this number of msec
204 rpc_loc_ioctl_callback_s_type *cb_data_ptr
205 )
206 {
207 boolean ret_val = FALSE; // the return value of this function
208 int rc; // return code from pthread calls
209
210 struct timeval present_time;
211 struct timespec expire_time;
212 loc_eng_ioctl_data_s_type *ioctl_cb_data_ptr;
213
214 ioctl_cb_data_ptr = &(loc_eng_data.ioctl_data);
215
216 pthread_mutex_lock(&ioctl_cb_data_ptr->cb_data_mutex);
217
218 do {
219 if (ioctl_cb_data_ptr->cb_is_selected == FALSE)
220 {
221 LOGD ("loc_eng_ioctl_wait_cb: ERROR called when cb_is_waiting is set to FALSE \n");
222 ret_val = FALSE;
223 break;
224 }
225
226 // Calculate absolute expire time
227 gettimeofday(&present_time, NULL);
228 expire_time.tv_sec = present_time.tv_sec;
229 expire_time.tv_sec += timeout_msec / 1000;
230 if ((present_time.tv_usec + timeout_msec) >= 1000)
231 {
232 expire_time.tv_sec += 1;
233 }
234 expire_time.tv_nsec = (present_time.tv_usec + timeout_msec) % 1000 * 1000;
235
236 // Special case where callback is issued before loc_ioctl ever returns
237 if (ioctl_cb_data_ptr->cb_has_arrived == TRUE)
238 {
239 LOGD ("loc_eng_ioctl_wait_cb: cb has arrived without waiting \n");
240 ret_val = TRUE;
241 break;
242 }
243
244 ioctl_cb_data_ptr->cb_is_waiting = TRUE;
245 // Wait for the callback until timeout expires
246 rc = pthread_cond_timedwait(&ioctl_cb_data_ptr->cb_arrived_cond,
247 &ioctl_cb_data_ptr->cb_data_mutex,
248 &expire_time);
249
250 if (rc == 0)
251 {
252 ret_val = TRUE;
253 }
254 else
255 {
256 ret_val = FALSE;
257 }
258
259 LOGV ("loc_eng_ioctl_wait_cb: pthread_cond_timedwait returned %d\n", rc);
260
261 } while (0);
262
263 // Process the ioctl callback data when IOCTL is successful
264 if (ret_val == TRUE)
265 {
266 ioctl_cb_data_ptr = &(loc_eng_data.ioctl_data);
267 if (ioctl_cb_data_ptr->cb_payload.status == RPC_LOC_API_SUCCESS)
268 {
269 ret_val = TRUE;
270 if (cb_data_ptr != NULL)
271 {
272 memcpy (cb_data_ptr,
273 &(ioctl_cb_data_ptr->cb_payload),
274 sizeof (rpc_loc_ioctl_callback_s_type));
275 }
276 }
277 else
278 {
279 ret_val = FALSE;
280 }
281 }
282
283 pthread_mutex_unlock(&ioctl_cb_data_ptr->cb_data_mutex);
284
285 LOGV ("loc_eng_ioctl_wait_cb: returned %d\n", ret_val);
286 return ret_val;
287 }
288
289 /*===========================================================================
290
291 FUNCTION loc_eng_ioctl_process_cb
292
293 DESCRIPTION
294 This function process the IOCTL callback, parameter specifies the client
295 that receives the IOCTL callback.
296
297 DEPENDENCIES
298 N/A
299
300 RETURN VALUE
301 TRUE if successful
302 FALSE if failed
303
304 SIDE EFFECTS
305 N/A
306
307 ===========================================================================*/
loc_eng_ioctl_process_cb(rpc_loc_client_handle_type client_handle,const rpc_loc_ioctl_callback_s_type * cb_data_ptr)308 boolean loc_eng_ioctl_process_cb (
309 rpc_loc_client_handle_type client_handle,
310 const rpc_loc_ioctl_callback_s_type *cb_data_ptr
311 )
312 {
313 boolean ret_val = FALSE; // the return value of this function
314 loc_eng_ioctl_data_s_type *ioctl_cb_data_ptr;
315 ioctl_cb_data_ptr = &(loc_eng_data.ioctl_data);
316
317 pthread_mutex_lock(&ioctl_cb_data_ptr->cb_data_mutex);
318 if (client_handle != ioctl_cb_data_ptr->client_handle)
319 {
320 LOGD ("loc_eng_ioctl_process_cb: client handle mismatch, received = %d, expected = %d \n",
321 (int32) client_handle, (int32) ioctl_cb_data_ptr->client_handle);
322 ret_val = FALSE;
323 }
324 else if (cb_data_ptr->type != ioctl_cb_data_ptr->ioctl_type)
325 {
326 LOGD ("loc_eng_ioctl_process_cb: ioctl type mismatch, received = %d, expected = %d \n",
327 cb_data_ptr->type, ioctl_cb_data_ptr->ioctl_type);
328 ret_val = FALSE;
329 }
330 else // both matches
331 {
332 memcpy (&(ioctl_cb_data_ptr->cb_payload),
333 cb_data_ptr,
334 sizeof (rpc_loc_ioctl_callback_s_type));
335
336 ioctl_cb_data_ptr->cb_has_arrived = TRUE;
337
338 LOGV ("loc_eng_ioctl_process_cb: callback arrived for client = %d, ioctl = %d, status = %d\n",
339 (int32) ioctl_cb_data_ptr->client_handle, ioctl_cb_data_ptr->ioctl_type,
340 (int32) ioctl_cb_data_ptr->cb_payload.status);
341
342 ret_val = TRUE;
343 }
344
345 pthread_mutex_unlock(&ioctl_cb_data_ptr->cb_data_mutex);
346
347 // Signal the waiting thread that callback has arrived
348 if (ret_val == TRUE)
349 {
350 pthread_cond_signal (&ioctl_cb_data_ptr->cb_arrived_cond);
351 }
352
353 return ret_val;
354 }
355