blob: a43d8cca2ed7e0457e87b3d9079f905300737025 [file] [log] [blame]
/* Copyright (c) 2009,2011 Code Aurora Forum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Code Aurora Forum, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 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.
*
*/
#define LOG_NDDEBUG 0
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <ctype.h>
#include <math.h>
#include <pthread.h>
#include <rpc/rpc.h>
#include <loc_api_rpc_glue.h>
#include <hardware/gps.h>
#include <loc_eng.h>
#define LOG_TAG "lib_locapi"
#include <utils/Log.h>
// comment this out to enable logging
// #undef LOGD
// #define LOGD(...) {}
// Function declarations
static boolean loc_eng_ioctl_setup_cb(
rpc_loc_client_handle_type handle,
rpc_loc_ioctl_e_type ioctl_type
);
static boolean loc_eng_ioctl_wait_cb(
int timeout_msec, // Timeout in this number of msec
rpc_loc_ioctl_callback_s_type *cb_data_ptr // Output parameter for IOCTL calls
);
/*===========================================================================
FUNCTION loc_eng_ioctl
DESCRIPTION
This function calls loc_ioctl and waits for the callback result before
returning back to the user.
DEPENDENCIES
N/A
RETURN VALUE
TRUE if successful
FALSE if failed
SIDE EFFECTS
N/A
===========================================================================*/
boolean 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
)
{
boolean ret_val;
int rpc_ret_val;
loc_eng_ioctl_data_s_type *ioctl_cb_data_ptr;
LOGV ("loc_eng_ioctl: client = %d, ioctl_type = %d, cb_data =0x%x\n", (int32) handle, ioctl_type, (uint32) cb_data_ptr);
ioctl_cb_data_ptr = &(loc_eng_data.ioctl_data);
// Select the callback we are waiting for
ret_val = loc_eng_ioctl_setup_cb (handle, ioctl_type);
if (ret_val == TRUE)
{
rpc_ret_val = loc_ioctl (handle,
ioctl_type,
ioctl_data_ptr);
LOGV ("loc_eng_ioctl: loc_ioctl returned %d \n", rpc_ret_val);
if (rpc_ret_val == RPC_LOC_API_SUCCESS)
{
// Wait for the callback of loc_ioctl
ret_val = loc_eng_ioctl_wait_cb (timeout_msec, cb_data_ptr);
}
else
{
ret_val = FALSE;
}
}
// Reset the state when we are done
pthread_mutex_lock(&ioctl_cb_data_ptr->cb_data_mutex);
ioctl_cb_data_ptr->cb_is_selected = FALSE;
ioctl_cb_data_ptr->cb_is_waiting = FALSE;
ioctl_cb_data_ptr->cb_has_arrived = FALSE;
pthread_mutex_unlock(&ioctl_cb_data_ptr->cb_data_mutex);
return ret_val;
}
/*===========================================================================
FUNCTION loc_eng_ioctl_setup_cb
DESCRIPTION
Selects which callback is going to be waited for
DEPENDENCIES
N/A
RETURN VALUE
TRUE if successful
FALSE if failed
SIDE EFFECTS
N/A
===========================================================================*/
static boolean loc_eng_ioctl_setup_cb(
rpc_loc_client_handle_type handle,
rpc_loc_ioctl_e_type ioctl_type
)
{
boolean ret_val;
loc_eng_ioctl_data_s_type *ioctl_cb_data_ptr;
ioctl_cb_data_ptr = &(loc_eng_data.ioctl_data);
pthread_mutex_lock(&ioctl_cb_data_ptr->cb_data_mutex);
if (ioctl_cb_data_ptr->cb_is_selected == TRUE)
{
LOGD ("loc_eng_ioctl_setup_cb: ERROR, another ioctl in progress \n");
ret_val = FALSE;
}
else
{
ioctl_cb_data_ptr->cb_is_selected = TRUE;
ioctl_cb_data_ptr->cb_is_waiting = FALSE;
ioctl_cb_data_ptr->cb_has_arrived = FALSE;
ioctl_cb_data_ptr->client_handle = handle;
ioctl_cb_data_ptr->ioctl_type = ioctl_type;
memset (&(ioctl_cb_data_ptr->cb_payload), 0, sizeof (rpc_loc_ioctl_callback_s_type));
ret_val = TRUE;
}
pthread_mutex_unlock(&ioctl_cb_data_ptr->cb_data_mutex);
return ret_val;
}
/*===========================================================================
FUNCTION loc_eng_ioctl_wait_cb
DESCRIPTION
Waits for a selected callback. The wait expires in timeout_msec.
If the function is called before an existing wait has finished, it will
immediately return EBUSY.
DEPENDENCIES
N/A
RETURN VALUE
TRUE if successful
FALSE if failed
SIDE EFFECTS
N/A
===========================================================================*/
boolean loc_eng_ioctl_wait_cb(
int timeout_msec, // Timeout in this number of msec
rpc_loc_ioctl_callback_s_type *cb_data_ptr
)
{
boolean ret_val = FALSE; // the return value of this function
int rc; // return code from pthread calls
struct timeval present_time;
struct timespec expire_time;
loc_eng_ioctl_data_s_type *ioctl_cb_data_ptr;
ioctl_cb_data_ptr = &(loc_eng_data.ioctl_data);
pthread_mutex_lock(&ioctl_cb_data_ptr->cb_data_mutex);
do {
if (ioctl_cb_data_ptr->cb_is_selected == FALSE)
{
LOGD ("loc_eng_ioctl_wait_cb: ERROR called when cb_is_waiting is set to FALSE \n");
ret_val = FALSE;
break;
}
// Calculate absolute expire time
gettimeofday(&present_time, NULL);
expire_time.tv_sec = present_time.tv_sec;
expire_time.tv_sec += timeout_msec / 1000;
if ((present_time.tv_usec + timeout_msec) >= 1000)
{
expire_time.tv_sec += 1;
}
expire_time.tv_nsec = (present_time.tv_usec + timeout_msec) % 1000 * 1000;
// Special case where callback is issued before loc_ioctl ever returns
if (ioctl_cb_data_ptr->cb_has_arrived == TRUE)
{
LOGD ("loc_eng_ioctl_wait_cb: cb has arrived without waiting \n");
ret_val = TRUE;
break;
}
ioctl_cb_data_ptr->cb_is_waiting = TRUE;
// Wait for the callback until timeout expires
rc = pthread_cond_timedwait(&ioctl_cb_data_ptr->cb_arrived_cond,
&ioctl_cb_data_ptr->cb_data_mutex,
&expire_time);
if (rc == 0)
{
ret_val = TRUE;
}
else
{
ret_val = FALSE;
}
LOGV ("loc_eng_ioctl_wait_cb: pthread_cond_timedwait returned %d\n", rc);
} while (0);
// Process the ioctl callback data when IOCTL is successful
if (ret_val == TRUE)
{
ioctl_cb_data_ptr = &(loc_eng_data.ioctl_data);
if (ioctl_cb_data_ptr->cb_payload.status == RPC_LOC_API_SUCCESS)
{
ret_val = TRUE;
if (cb_data_ptr != NULL)
{
memcpy (cb_data_ptr,
&(ioctl_cb_data_ptr->cb_payload),
sizeof (rpc_loc_ioctl_callback_s_type));
}
}
else
{
ret_val = FALSE;
}
}
pthread_mutex_unlock(&ioctl_cb_data_ptr->cb_data_mutex);
LOGV ("loc_eng_ioctl_wait_cb: returned %d\n", ret_val);
return ret_val;
}
/*===========================================================================
FUNCTION loc_eng_ioctl_process_cb
DESCRIPTION
This function process the IOCTL callback, parameter specifies the client
that receives the IOCTL callback.
DEPENDENCIES
N/A
RETURN VALUE
TRUE if successful
FALSE if failed
SIDE EFFECTS
N/A
===========================================================================*/
boolean loc_eng_ioctl_process_cb (
rpc_loc_client_handle_type client_handle,
const rpc_loc_ioctl_callback_s_type *cb_data_ptr
)
{
boolean ret_val = FALSE; // the return value of this function
loc_eng_ioctl_data_s_type *ioctl_cb_data_ptr;
ioctl_cb_data_ptr = &(loc_eng_data.ioctl_data);
pthread_mutex_lock(&ioctl_cb_data_ptr->cb_data_mutex);
if (client_handle != ioctl_cb_data_ptr->client_handle)
{
LOGD ("loc_eng_ioctl_process_cb: client handle mismatch, received = %d, expected = %d \n",
(int32) client_handle, (int32) ioctl_cb_data_ptr->client_handle);
ret_val = FALSE;
}
else if (cb_data_ptr->type != ioctl_cb_data_ptr->ioctl_type)
{
LOGD ("loc_eng_ioctl_process_cb: ioctl type mismatch, received = %d, expected = %d \n",
cb_data_ptr->type, ioctl_cb_data_ptr->ioctl_type);
ret_val = FALSE;
}
else // both matches
{
memcpy (&(ioctl_cb_data_ptr->cb_payload),
cb_data_ptr,
sizeof (rpc_loc_ioctl_callback_s_type));
ioctl_cb_data_ptr->cb_has_arrived = TRUE;
LOGV ("loc_eng_ioctl_process_cb: callback arrived for client = %d, ioctl = %d, status = %d\n",
(int32) ioctl_cb_data_ptr->client_handle, ioctl_cb_data_ptr->ioctl_type,
(int32) ioctl_cb_data_ptr->cb_payload.status);
ret_val = TRUE;
}
pthread_mutex_unlock(&ioctl_cb_data_ptr->cb_data_mutex);
// Signal the waiting thread that callback has arrived
if (ret_val == TRUE)
{
pthread_cond_signal (&ioctl_cb_data_ptr->cb_arrived_cond);
}
return ret_val;
}