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