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  -----------------------------------------------------------------------------
12Copyright (c) 2009, QUALCOMM USA, INC.
13
14All rights reserved.
15
16Redistribution 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
24THIS 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 ALOGD
56// #define ALOGD(...) {}
57
58// Function declarations
59static boolean loc_eng_ioctl_setup_cb(
60    rpc_loc_client_handle_type    handle,
61    rpc_loc_ioctl_e_type          ioctl_type
62);
63
64static 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
71FUNCTION    loc_eng_ioctl
72
73DESCRIPTION
74   This function calls loc_ioctl and waits for the callback result before
75   returning back to the user.
76
77DEPENDENCIES
78   N/A
79
80RETURN VALUE
81   TRUE                 if successful
82   FALSE                if failed
83
84SIDE EFFECTS
85   N/A
86
87===========================================================================*/
88boolean 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    ALOGV ("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        ALOGV ("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
138FUNCTION    loc_eng_ioctl_setup_cb
139
140DESCRIPTION
141   Selects which callback is going to be waited for
142
143DEPENDENCIES
144   N/A
145
146RETURN VALUE
147   TRUE                 if successful
148   FALSE                if failed
149
150SIDE EFFECTS
151   N/A
152
153===========================================================================*/
154static 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        ALOGD ("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
187FUNCTION    loc_eng_ioctl_wait_cb
188
189DESCRIPTION
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
195DEPENDENCIES
196   N/A
197
198RETURN VALUE
199   TRUE                 if successful
200   FALSE                if failed
201
202SIDE EFFECTS
203   N/A
204
205===========================================================================*/
206boolean 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            ALOGD ("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            ALOGD ("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        ALOGV ("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    ALOGV ("loc_eng_ioctl_wait_cb: returned %d\n", ret_val);
290    return ret_val;
291}
292
293/*===========================================================================
294
295FUNCTION    loc_eng_ioctl_process_cb
296
297DESCRIPTION
298   This function process the IOCTL callback, parameter specifies the client
299   that receives the IOCTL callback.
300
301DEPENDENCIES
302   N/A
303
304RETURN VALUE
305   TRUE                 if successful
306   FALSE                if failed
307
308SIDE EFFECTS
309   N/A
310
311===========================================================================*/
312boolean 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        ALOGD ("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        ALOGD ("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        ALOGV ("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