1/* Copyright (c) 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
31                     INCLUDE FILES FOR MODULE
32
33======================================================================*/
34#include <stdio.h>
35#include <pthread.h>
36#include <errno.h>
37#include <string.h>
38#include <sys/select.h>
39#include <sys/time.h>
40#include <sys/types.h>
41#include <sys/stat.h>
42#include <fcntl.h>
43#include <sys/mman.h>
44#include <unistd.h>
45#include <stdlib.h>
46#include <assert.h>
47#include <loc_api_log.h>
48
49#include <rpc/rpc.h>
50
51/* Include RPC headers */
52#include "rpc_inc/loc_api_rpc_glue.h"
53
54/* Callback init */
55#include "rpc_inc/loc_apicb_appinit.h"
56
57/* Logging */
58#define LOG_TAG "LocSvc_api_rpc_glue"
59#define LOG_NDDEBUG 0
60#include <utils/Log.h>
61
62/* Logging Improvement */
63#include "log_util.h"
64
65/* Uncomment to force LOGD messages */
66// #define LOGD LOGI
67
68/*=====================================================================
69     External declarations
70======================================================================*/
71
72CLIENT* loc_api_clnt = NULL;
73
74/* Callback ID and pointer */
75#define LOC_API_CB_MAX_CLIENTS 16
76typedef struct
77{
78    uint32 cb_id;                        /* same as rpc/types.h */
79    loc_event_cb_f_type *cb_func;      /* callback func */
80    loc_reset_notif_cb_f_type *rpc_cb; /* callback from RPC */
81    rpc_loc_client_handle_type handle; /* stores handle for client closing */
82    void* user;                        /* user's own data handle */
83} loc_glue_cb_entry_s_type;
84
85loc_glue_cb_entry_s_type loc_glue_callback_table[LOC_API_CB_MAX_CLIENTS];
86
87#define RPC_FUNC_VERSION_BASE(a,b) a ## b
88#define RPC_FUNC_VERSION(a,b) RPC_FUNC_VERSION_BASE(a,b)
89
90#define RPC_CALLBACK_FUNC_VERSION_BASE(a,v,b) a ## v ## b
91#define RPC_CALLBACK_FUNC_VERSION(a,v,b) RPC_CALLBACK_FUNC_VERSION_BASE(a,v,b)
92
93#define LOC_GLUE_CHECK_INIT(ret_type) \
94   if (loc_api_clnt == NULL) { EXIT_LOG_CALLFLOW(%d, RPC_LOC_API_RPC_FAILURE); return (ret_type) RPC_LOC_API_RPC_FAILURE; }
95
96#define LOC_GLUE_CHECK_RESULT(stat, ret_type) \
97  if (stat != RPC_SUCCESS) { \
98      LOC_LOGE("%s:%d] failure code %d", __func__, __LINE__, stat); \
99      return (ret_type)((stat == RPC_SUBSYSTEM_RESTART) ? \
100                        RPC_LOC_API_RPC_MODEM_RESTART : RPC_LOC_API_RPC_FAILURE); \
101  }
102
103/* Callback functions */
104/* Returns 1 if successful */
105bool_t rpc_loc_event_cb_f_type_svc(
106      rpc_loc_event_cb_f_type_args *argp,
107      rpc_loc_event_cb_f_type_rets *ret,
108      struct svc_req *req)
109{
110    // The lower word of cd_id is the index
111    int index = argp->cb_id & 0xFFFF;
112
113    /* Callback not registered, or unexpected ID (shouldn't happen) */
114    if (index >= LOC_API_CB_MAX_CLIENTS || loc_glue_callback_table[index].cb_func == NULL)
115    {
116        LOC_LOGE("Warning: No callback handler %d.\n", index);
117        ret->loc_event_cb_f_type_result = 0;
118        return 1; /* simply return */
119    }
120
121    LOC_LOGV("proc: %x  prog: %x  vers: %x\n",
122         (int) req->rq_proc,
123         (int) req->rq_prog,
124         (int) req->rq_vers);
125
126    LOC_LOGV("Callback received: %x (cb_id=%p handle=%d ret_ptr=%d)\n",
127         (int) argp->loc_event,
128               argp->cb_id,
129         (int) argp->loc_handle,
130         (int) ret);
131
132    /* Forward callback to real callback procedure */
133    rpc_loc_client_handle_type        loc_handle = argp->loc_handle;
134    rpc_loc_event_mask_type           loc_event  = argp->loc_event;
135    const rpc_loc_event_payload_u_type*  loc_event_payload =
136        (const rpc_loc_event_payload_u_type*) argp->loc_event_payload;
137
138    /* Gives control to synchronous call handler */
139    loc_api_callback_process_sync_call(loc_handle, loc_event, loc_event_payload);
140
141    int32 rc = (loc_glue_callback_table[index].cb_func)(loc_glue_callback_table[index].user,
142                                                        loc_handle, loc_event, loc_event_payload);
143
144    LOC_LOGV("cb_func=%p", loc_glue_callback_table[index].cb_func);
145
146    ret->loc_event_cb_f_type_result = rc;
147
148    return 1; /* ok */
149}
150
151int loc_apicbprog_freeresult (SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result)
152{
153   xdr_free (xdr_result, result);
154
155   /*
156    * Insert additional freeing code here, if needed
157    */
158   // LOC_LOGD("***** loc_apicbprog_freeresult\n");
159
160   return 1;
161}
162
163/*===========================================================================
164
165FUNCTION rpc_loc_event_cb_f_type_<version>_svc (MACRO)
166
167DESCRIPTION
168   Callback function for Loc API
169
170RETURN VALUE
171   1 for success
172   0 for failure
173
174===========================================================================*/
175bool_t RPC_CALLBACK_FUNC_VERSION(rpc_loc_event_cb_f_type_, RPC_LOC_EVENT_CB_F_TYPE_VERSION, _svc) (
176      rpc_loc_event_cb_f_type_args *argp,
177      rpc_loc_event_cb_f_type_rets *ret,
178      struct svc_req *req)
179{
180   return rpc_loc_event_cb_f_type_svc(argp, ret, req);
181}
182
183/*===========================================================================
184
185FUNCTION loc_apicbprog_<version>_freeresult (MACRO)
186
187DESCRIPTION
188   Free up RPC data structure
189
190RETURN VALUE
191   1 for success
192   0 for failure
193
194===========================================================================*/
195#define VERSION_CONCAT(MAJOR,MINOR) MAJOR##MINOR
196#define loc_apicb_prog_VER_freeresult(M,N) \
197int RPC_CALLBACK_FUNC_VERSION(loc_apicbprog_, VERSION_CONCAT(M,N), _freeresult) \
198(SVCXPRT *transp, xdrproc_t xdr_result, caddr_t result) \
199{ \
200   return loc_apicbprog_freeresult(transp, xdr_result, result); \
201}
202
203/* Define all of the possible minors */
204loc_apicb_prog_VER_freeresult(RPC_LOC_API_API_MAJOR_NUM, 0001);
205loc_apicb_prog_VER_freeresult(RPC_LOC_API_API_MAJOR_NUM, 0002);
206loc_apicb_prog_VER_freeresult(RPC_LOC_API_API_MAJOR_NUM, 0003);
207loc_apicb_prog_VER_freeresult(RPC_LOC_API_API_MAJOR_NUM, 0004);
208loc_apicb_prog_VER_freeresult(RPC_LOC_API_API_MAJOR_NUM, 0005);
209loc_apicb_prog_VER_freeresult(RPC_LOC_API_API_MAJOR_NUM, 0006);
210
211/*===========================================================================
212
213FUNCTION rpc_loc_api_cb_null_<version>_svc (MACRO) [Patch for wrong RPCGEN stubs]
214
215DESCRIPTION
216   Null callback function for Loc API
217
218RETURN VALUE
219   1 for success
220
221===========================================================================*/
222#define rpc_loc_api_cb_null_VER_svc(M,N) \
223bool_t RPC_CALLBACK_FUNC_VERSION(rpc_loc_api_cb_null_, VERSION_CONCAT(M,N), _svc) ( \
224      void *a, int *b, struct svc_req *req) \
225{ \
226   return 1; \
227}
228
229/* Define all of the possible minors */
230rpc_loc_api_cb_null_VER_svc(RPC_LOC_API_API_MAJOR_NUM, 0001);
231rpc_loc_api_cb_null_VER_svc(RPC_LOC_API_API_MAJOR_NUM, 0002);
232rpc_loc_api_cb_null_VER_svc(RPC_LOC_API_API_MAJOR_NUM, 0003);
233rpc_loc_api_cb_null_VER_svc(RPC_LOC_API_API_MAJOR_NUM, 0004);
234rpc_loc_api_cb_null_VER_svc(RPC_LOC_API_API_MAJOR_NUM, 0005);
235rpc_loc_api_cb_null_VER_svc(RPC_LOC_API_API_MAJOR_NUM, 0006);
236
237static void loc_api_glue_rpc_cb(CLIENT* client, enum rpc_reset_event event)
238{
239    int i;
240    for (i = 0; i < LOC_API_CB_MAX_CLIENTS; i++) {
241        if (NULL != loc_glue_callback_table[i].rpc_cb) {
242            loc_glue_callback_table[i].rpc_cb(loc_glue_callback_table[i].user, client, event);
243        }
244    }
245}
246
247/*===========================================================================
248
249FUNCTION loc_api_glue_init
250
251DESCRIPTION
252   Initiates the RPC client
253
254RETURN VALUE
255   1 for success
256   0 for failure
257
258===========================================================================*/
259int loc_api_glue_init(void)
260{
261   if (loc_api_clnt == NULL)
262   {
263      /* Initialize data */
264      int i;
265      int pid = getpid();
266      for (i = 0; i < LOC_API_CB_MAX_CLIENTS; i++)
267      {
268          loc_glue_callback_table[i].cb_id = i | (pid << 16);
269          loc_glue_callback_table[i].cb_func = NULL;
270          loc_glue_callback_table[i].handle = -1;
271          loc_glue_callback_table[i].rpc_cb = NULL;
272          loc_glue_callback_table[i].user = NULL;
273      }
274
275      /* Print msg */
276      LOC_LOGV("Trying to create RPC client...\n");
277      loc_api_clnt = clnt_create(NULL, LOC_APIPROG, LOC_APIVERS, NULL);
278      LOC_LOGV("Created loc_api_clnt ---- %x\n", (unsigned int)loc_api_clnt);
279
280      if (loc_api_clnt == NULL)
281      {
282         LOC_LOGE("Error: cannot create RPC client.\n");
283         return 0;
284      }
285
286      /* Init RPC callbacks */
287      loc_api_sync_call_init();
288
289      int rc = loc_apicb_app_init();
290      if (rc >= 0)
291      {
292         LOC_LOGD("Loc API RPC client initialized.\n");
293         clnt_register_reset_notification_cb(loc_api_clnt, loc_api_glue_rpc_cb);
294      }
295      else {
296         LOC_LOGE("Loc API callback initialization failed.\n");
297         return 0;
298      }
299   }
300
301   return 1;
302}
303
304rpc_loc_client_handle_type loc_open (
305    rpc_loc_event_mask_type       event_reg_mask,
306    loc_event_cb_f_type           *event_callback,
307    loc_reset_notif_cb_f_type     *rpc_cb,
308    void*                         userData
309)
310{
311    ENTRY_LOG();
312    LOC_GLUE_CHECK_INIT(rpc_loc_client_handle_type);
313
314    rpc_loc_client_handle_type ret_val;
315
316    rpc_loc_open_args args;
317    args.event_reg_mask = event_reg_mask;
318
319    int i;
320    for (i = 0; i < LOC_API_CB_MAX_CLIENTS; i++)
321    {
322        if (loc_glue_callback_table[i].cb_func == event_callback ||
323            loc_glue_callback_table[i].user == userData)
324        {
325            LOC_LOGW("Client already opened service (callback=%p)...\n",
326                  event_callback);
327            break;
328        }
329    }
330
331    if (i == LOC_API_CB_MAX_CLIENTS)
332    {
333        for (i = 0; i < LOC_API_CB_MAX_CLIENTS; i++)
334        {
335            if (loc_glue_callback_table[i].cb_func == NULL)
336            {
337                loc_glue_callback_table[i].cb_func = event_callback;
338                loc_glue_callback_table[i].rpc_cb = rpc_cb;
339                loc_glue_callback_table[i].user = userData;
340                break;
341            }
342        }
343    }
344
345    if (i == LOC_API_CB_MAX_CLIENTS)
346    {
347        LOC_LOGE("Too many clients opened at once...\n");
348        return RPC_LOC_CLIENT_HANDLE_INVALID;
349    }
350
351    args.event_callback = loc_glue_callback_table[i].cb_id;
352    LOC_LOGV("cb_id=%d, func=0x%x", i, (unsigned int) event_callback);
353
354    rpc_loc_open_rets rets;
355    enum clnt_stat stat = RPC_SUCCESS;
356
357    EXIT_LOG_CALLFLOW(%s, "loc client open");
358    stat = RPC_FUNC_VERSION(rpc_loc_open_, RPC_LOC_OPEN_VERSION)(&args, &rets, loc_api_clnt);
359    LOC_GLUE_CHECK_RESULT(stat, int32);
360
361    /* save the handle in the table */
362    loc_glue_callback_table[i].handle = (rpc_loc_client_handle_type) rets.loc_open_result;
363
364    ret_val = (rpc_loc_client_handle_type) rets.loc_open_result;
365
366    return ret_val;
367
368}
369
370int32 loc_close
371(
372      rpc_loc_client_handle_type handle
373)
374{
375    ENTRY_LOG();
376    LOC_GLUE_CHECK_INIT(int32);
377
378    int32 ret_val;
379
380    rpc_loc_close_args args;
381    args.handle = handle;
382
383    rpc_loc_close_rets rets;
384    enum clnt_stat stat = RPC_SUCCESS;
385
386    EXIT_LOG_CALLFLOW(%s, "loc client close");
387    stat = RPC_FUNC_VERSION(rpc_loc_close_, RPC_LOC_CLOSE_VERSION)(&args, &rets, loc_api_clnt);
388
389    loc_clear(handle);
390
391    LOC_GLUE_CHECK_RESULT(stat, int32);
392    ret_val = (int32) rets.loc_close_result;
393
394    return ret_val;
395}
396
397void loc_clear(rpc_loc_client_handle_type handle) {
398    /* Clean the client's callback function in callback table */
399    int i;
400    for (i = 0; i < LOC_API_CB_MAX_CLIENTS; i++)
401    {
402        if (loc_glue_callback_table[i].handle == handle)
403        {
404            /* Found the client */
405            loc_glue_callback_table[i].cb_func = NULL;
406            loc_glue_callback_table[i].rpc_cb = NULL;
407            loc_glue_callback_table[i].handle = -1;
408            break;
409        }
410    }
411
412    if (i == LOC_API_CB_MAX_CLIENTS)
413    {
414        LOC_LOGW("Handle not found (handle=%d)...\n", (int) handle);
415    }
416}
417
418int32 loc_start_fix
419(
420      rpc_loc_client_handle_type handle
421)
422{
423    ENTRY_LOG();
424    LOC_GLUE_CHECK_INIT(int32);
425
426    int32 ret_val;
427
428    rpc_loc_start_fix_args args;
429    args.handle = handle;
430
431    rpc_loc_start_fix_rets rets;
432    enum clnt_stat stat = RPC_SUCCESS;
433
434    EXIT_LOG_CALLFLOW(%s, "loc start fix");
435    stat = RPC_FUNC_VERSION(rpc_loc_start_fix_, RPC_LOC_START_FIX_VERSION)(&args, &rets, loc_api_clnt);
436    LOC_GLUE_CHECK_RESULT(stat, int32);
437
438    ret_val = (int32) rets.loc_start_fix_result;
439
440    return ret_val;
441}
442
443int32 loc_stop_fix
444(
445      rpc_loc_client_handle_type handle
446)
447{
448    ENTRY_LOG();
449    LOC_GLUE_CHECK_INIT(int32);
450
451    int32 ret_val;
452
453    rpc_loc_stop_fix_args args;
454    args.handle = handle;
455
456    rpc_loc_stop_fix_rets rets;
457    enum clnt_stat stat = RPC_SUCCESS;
458
459    EXIT_LOG_CALLFLOW(%s, "loc stop fix");
460    stat = RPC_FUNC_VERSION(rpc_loc_stop_fix_, RPC_LOC_STOP_FIX_VERSION)(&args, &rets, loc_api_clnt);
461    LOC_GLUE_CHECK_RESULT(stat, int32);
462
463    ret_val = (int32) rets.loc_stop_fix_result;
464
465    return ret_val;
466}
467
468int32 loc_ioctl
469(
470      rpc_loc_client_handle_type           handle,
471      rpc_loc_ioctl_e_type                 ioctl_type,
472      rpc_loc_ioctl_data_u_type*           ioctl_data
473)
474{
475    ENTRY_LOG();
476    LOC_GLUE_CHECK_INIT(int32);
477
478    int32 ret_val;
479
480    rpc_loc_ioctl_args args;
481    args.handle = handle;
482    args.ioctl_data = ioctl_data;
483    args.ioctl_type = ioctl_type;
484    if (ioctl_data != NULL)
485    {
486        /* Assign ioctl union discriminator */
487        ioctl_data->disc = ioctl_type;
488
489        /* In case the user hasn't filled in other disc fields,
490           automatically fill them in here */
491        switch (ioctl_type)
492        {
493        case RPC_LOC_IOCTL_GET_API_VERSION:
494            break;
495        case RPC_LOC_IOCTL_SET_FIX_CRITERIA:
496            break;
497        case RPC_LOC_IOCTL_GET_FIX_CRITERIA:
498            break;
499        case RPC_LOC_IOCTL_INFORM_NI_USER_RESPONSE:
500            break;
501        case RPC_LOC_IOCTL_INJECT_PREDICTED_ORBITS_DATA:
502            break;
503        case RPC_LOC_IOCTL_QUERY_PREDICTED_ORBITS_DATA_VALIDITY:
504            break;
505        case RPC_LOC_IOCTL_QUERY_PREDICTED_ORBITS_DATA_SOURCE:
506            break;
507        case RPC_LOC_IOCTL_SET_PREDICTED_ORBITS_DATA_AUTO_DOWNLOAD:
508            break;
509        case RPC_LOC_IOCTL_INJECT_UTC_TIME:
510            break;
511        case RPC_LOC_IOCTL_INJECT_RTC_VALUE:
512            break;
513        case RPC_LOC_IOCTL_INJECT_POSITION:
514            break;
515        case RPC_LOC_IOCTL_QUERY_ENGINE_STATE:
516            break;
517        case RPC_LOC_IOCTL_INFORM_SERVER_OPEN_STATUS:
518            break;
519        case RPC_LOC_IOCTL_INFORM_SERVER_CLOSE_STATUS:
520            break;
521        case RPC_LOC_IOCTL_SET_ENGINE_LOCK:
522            break;
523        case RPC_LOC_IOCTL_GET_ENGINE_LOCK:
524            break;
525        case RPC_LOC_IOCTL_SET_SBAS_CONFIG:
526            break;
527        case RPC_LOC_IOCTL_GET_SBAS_CONFIG:
528            break;
529        case RPC_LOC_IOCTL_SET_NMEA_TYPES:
530            break;
531        case RPC_LOC_IOCTL_GET_NMEA_TYPES:
532            break;
533        case RPC_LOC_IOCTL_SET_CDMA_PDE_SERVER_ADDR:
534        case RPC_LOC_IOCTL_SET_CDMA_MPC_SERVER_ADDR:
535        case RPC_LOC_IOCTL_SET_UMTS_SLP_SERVER_ADDR:
536        case RPC_LOC_IOCTL_SET_CUSTOM_PDE_SERVER_ADDR:
537            args.ioctl_data->rpc_loc_ioctl_data_u_type_u.server_addr.addr_info.disc =
538                args.ioctl_data->rpc_loc_ioctl_data_u_type_u.server_addr.addr_type;
539            break;
540        case RPC_LOC_IOCTL_GET_CDMA_PDE_SERVER_ADDR:
541        case RPC_LOC_IOCTL_GET_CDMA_MPC_SERVER_ADDR:
542        case RPC_LOC_IOCTL_GET_UMTS_SLP_SERVER_ADDR:
543        case RPC_LOC_IOCTL_GET_CUSTOM_PDE_SERVER_ADDR:
544            break;
545        case RPC_LOC_IOCTL_SET_ON_DEMAND_LPM:
546            break;
547        case RPC_LOC_IOCTL_GET_ON_DEMAND_LPM:
548            break;
549        case RPC_LOC_IOCTL_DELETE_ASSIST_DATA:
550            break;
551        default:
552            break;
553        } /* switch */
554    } /* ioctl_data != NULL */
555
556    rpc_loc_ioctl_rets rets;
557    enum clnt_stat stat = RPC_SUCCESS;
558
559    EXIT_LOG_CALLFLOW(%s, loc_get_ioctl_type_name(ioctl_type));
560    stat = RPC_FUNC_VERSION(rpc_loc_ioctl_, RPC_LOC_IOCTL_VERSION)(&args, &rets, loc_api_clnt);
561    LOC_GLUE_CHECK_RESULT(stat, int32);
562
563    ret_val = (int32) rets.loc_ioctl_result;
564
565    return ret_val;
566}
567
568/* Returns 0 if error */
569int32 loc_api_null(void)
570{
571    LOC_GLUE_CHECK_INIT(int32);
572
573    int32 rets;
574    enum clnt_stat stat = RPC_SUCCESS;
575
576    clnt_unregister_reset_notification_cb(loc_api_clnt);
577    stat = RPC_FUNC_VERSION(rpc_loc_api_null_, RPC_LOC_API_NULL_VERSION)(NULL, &rets, loc_api_clnt);
578    LOC_GLUE_CHECK_RESULT(stat, int32);
579
580    return (int32) rets;
581}
582
583/*===========================================================================
584
585FUNCTION    loc_eng_ioctl
586
587DESCRIPTION
588   This function calls loc_ioctl and waits for the callback result before
589   returning back to the user.
590
591DEPENDENCIES
592   N/A
593
594RETURN VALUE
595   TRUE                 if successful
596   FALSE                if failed
597
598SIDE EFFECTS
599   N/A
600
601===========================================================================*/
602int loc_eng_ioctl
603(
604      rpc_loc_client_handle_type           handle,
605      rpc_loc_ioctl_e_type                 ioctl_type,
606      rpc_loc_ioctl_data_u_type*           ioctl_data_ptr,
607      uint32                               timeout_msec,
608      rpc_loc_ioctl_callback_s_type       *cb_data_ptr
609)
610{
611    int ret_val = RPC_LOC_API_SUCCESS;
612
613    ret_val = loc_api_sync_ioctl(handle, ioctl_type, ioctl_data_ptr, timeout_msec, cb_data_ptr);
614
615    LOC_LOGD("loc_eng_ioctl result: client = %d, ioctl_type = %s, returt %s\n",
616             (int32) handle,
617             loc_get_ioctl_type_name(ioctl_type),
618             loc_get_ioctl_status_name(ret_val) );
619
620    return ret_val;
621}
622