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
55static boolean loc_eng_ioctl_setup_cb(
56    rpc_loc_client_handle_type    handle,
57    rpc_loc_ioctl_e_type          ioctl_type
58);
59
60static 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
67FUNCTION    loc_eng_ioctl
68
69DESCRIPTION
70   This function calls loc_ioctl and waits for the callback result before
71   returning back to the user.
72
73DEPENDENCIES
74   N/A
75
76RETURN VALUE
77   TRUE                 if successful
78   FALSE                if failed
79
80SIDE EFFECTS
81   N/A
82
83===========================================================================*/
84boolean 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
134FUNCTION    loc_eng_ioctl_setup_cb
135
136DESCRIPTION
137   Selects which callback is going to be waited for
138
139DEPENDENCIES
140   N/A
141
142RETURN VALUE
143   TRUE                 if successful
144   FALSE                if failed
145
146SIDE EFFECTS
147   N/A
148
149===========================================================================*/
150static 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
183FUNCTION    loc_eng_ioctl_wait_cb
184
185DESCRIPTION
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
191DEPENDENCIES
192   N/A
193
194RETURN VALUE
195   TRUE                 if successful
196   FALSE                if failed
197
198SIDE EFFECTS
199   N/A
200
201===========================================================================*/
202boolean 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
291FUNCTION    loc_eng_ioctl_process_cb
292
293DESCRIPTION
294   This function process the IOCTL callback, parameter specifies the client
295   that receives the IOCTL callback.
296
297DEPENDENCIES
298   N/A
299
300RETURN VALUE
301   TRUE                 if successful
302   FALSE                if failed
303
304SIDE EFFECTS
305   N/A
306
307===========================================================================*/
308boolean 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