• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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