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