Example #1
0
/*******************************************************************************
**
** Function         GKI_isend_event
**
** Description      This function is called from ISRs to send events to other
**                  tasks. The only difference between this function and GKI_send_event
**                  is that this function assumes interrupts are already disabled.
**
** Parameters:      task_id -  (input) The destination task Id for the event.
**                  event   -  (input) The event flag
**
** Returns          GKI_SUCCESS if all OK, else GKI_FAILURE
**
** NOTE             This function is NOT called by the Widcomm stack and
**                  profiles. If you want to use it in your own implementation,
**                  put your code here, otherwise you can delete the entire
**                  body of the function.
**
*******************************************************************************/
UINT8 GKI_isend_event (UINT8 task_id, UINT16 event)
{

    GKI_TRACE_2("GKI_isend_event %d %x", task_id, event);
    GKI_TRACE_2("GKI_isend_event %d %x done", task_id, event);
    return    GKI_send_event(task_id, event);
}
/*******************************************************************************
**
** Function         nfc_hal_main_userial_cback
**
** Description      USERIAL callback for NCI transport
**
** Returns          nothing
**
*******************************************************************************/
static void nfc_hal_main_userial_cback (tUSERIAL_PORT port, tUSERIAL_EVT evt, tUSERIAL_EVT_DATA *p_data)
{
    if (evt == USERIAL_RX_READY_EVT)
    {
        /* Notify transport task of serial port event */
        GKI_send_event (NFC_HAL_TASK, NFC_HAL_TASK_EVT_DATA_RDY);
    }
    else if (evt == USERIAL_TX_DONE_EVT)
    {
        /* Serial driver has finshed sending data from USERIAL_Write */
        /* Currently, no action is needed for this event */
    }
    else if (evt == USERIAL_ERR_EVT)
    {
        HAL_TRACE_ERROR0 ("nfc_hal_main_userial_cback: USERIAL_ERR_EVT. Notifying NFC_TASK of transport error");
        if (nfc_hal_cb.ncit_cb.nci_wait_rsp != NFC_HAL_WAIT_RSP_NONE)
        {
            nfc_hal_main_stop_quick_timer (&nfc_hal_cb.ncit_cb.nci_wait_rsp_timer);
            nfc_hal_nci_cmd_timeout_cback ((void *)&nfc_hal_cb.ncit_cb.nci_wait_rsp_timer);
        }
        else
        {
            nfc_hal_main_send_error (HAL_NFC_STATUS_ERR_TRANSPORT);
        }
    }
    else if (evt == USERIAL_WAKEUP_EVT)
    {
        HAL_TRACE_DEBUG1 ("nfc_hal_main_userial_cback: USERIAL_WAKEUP_EVT: %d", p_data->sigs);
    }
    else
    {
        HAL_TRACE_DEBUG1 ("nfc_hal_main_userial_cback: unhandled userial evt: %i", evt);
    }
}
void GKI_destroy_task(UINT8 task_id)
{
#if ( FALSE == GKI_PTHREAD_JOINABLE )
        int i = 0;
#else
        int result;
#endif
    if (gki_cb.com.OSRdyTbl[task_id] != TASK_DEAD)
    {
        gki_cb.com.OSRdyTbl[task_id] = TASK_DEAD;

        /* paranoi settings, make sure that we do not execute any mailbox events */
        gki_cb.com.OSWaitEvt[task_id] &= ~(TASK_MBOX_0_EVT_MASK|TASK_MBOX_1_EVT_MASK|
                                            TASK_MBOX_2_EVT_MASK|TASK_MBOX_3_EVT_MASK);

#if (GKI_NUM_TIMERS > 0)
        gki_cb.com.OSTaskTmr0R[task_id] = 0;
        gki_cb.com.OSTaskTmr0 [task_id] = 0;
#endif

#if (GKI_NUM_TIMERS > 1)
        gki_cb.com.OSTaskTmr1R[task_id] = 0;
        gki_cb.com.OSTaskTmr1 [task_id] = 0;
#endif

#if (GKI_NUM_TIMERS > 2)
        gki_cb.com.OSTaskTmr2R[task_id] = 0;
        gki_cb.com.OSTaskTmr2 [task_id] = 0;
#endif

#if (GKI_NUM_TIMERS > 3)
        gki_cb.com.OSTaskTmr3R[task_id] = 0;
        gki_cb.com.OSTaskTmr3 [task_id] = 0;
#endif

        GKI_send_event(task_id, EVENT_MASK(GKI_SHUTDOWN_EVT));

#if ( FALSE == GKI_PTHREAD_JOINABLE )
        i = 0;

        while ((gki_cb.com.OSWaitEvt[task_id] != 0) && (++i < 10))
            usleep(100 * 1000);
#else
        result = pthread_join( gki_cb.os.thread_id[task_id], NULL );
        if ( result < 0 )
        {
            GKI_ERROR_LOG( "pthread_join() FAILED: result: %d", result );
        }
#endif
        GKI_exit_task(task_id);
        GKI_INFO( "GKI_shutdown(): task [%s] terminated\n", gki_cb.com.OSTName[task_id]);
    }
}
/******************************************************************************
**
** Function         preload_cb
**
** Description      HOST/CONTROLLER LIB CALLBACK API - This function is called
**                  when the libbt-hci completed stack preload process
**
** Returns          None
**
******************************************************************************/
static void preload_cb(TRANSAC transac, bt_hc_preload_result_t result)
{
    APPL_TRACE_EVENT1("HC preload_cb %d [0:SUCCESS 1:FAIL]", result);


    if (result == BT_HC_PRELOAD_SUCCESS)
    {
        preload_stop_wait_timer();

        /* notify BTU task that libbt-hci is ready */
        GKI_send_event(BTU_TASK, BT_EVT_PRELOAD_CMPL);
    }
}
/*******************************************************************************
**
** Function         GKI_send_msg
**
** Description      Called by applications to send a buffer to a task
**
** Returns          Nothing
**
*******************************************************************************/
void GKI_send_msg (UINT8 task_id, UINT8 mbox, void *msg)
{
    BUFFER_HDR_T    *p_hdr;
    tGKI_COM_CB *p_cb = &gki_cb.com;

    /* If task non-existant or not started, drop buffer */
    if ((task_id >= GKI_MAX_TASKS) || (mbox >= NUM_TASK_MBOX) || (p_cb->OSRdyTbl[task_id] == TASK_DEAD))
    {
        GKI_exception(GKI_ERROR_SEND_MSG_BAD_DEST, "Sending to unknown dest");
        GKI_freebuf (msg);
        return;
    }

#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
    if (gki_chk_buf_damage(msg))
    {
        GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Send - Buffer corrupted");
        return;
    }
#endif

    p_hdr = (BUFFER_HDR_T *) ((UINT8 *) msg - BUFFER_HDR_SIZE);

    if (p_hdr->status != BUF_STATUS_UNLINKED)
    {
        GKI_exception(GKI_ERROR_SEND_MSG_BUF_LINKED, "Send - buffer linked");
        return;
    }

    GKI_disable();

    if (p_cb->OSTaskQFirst[task_id][mbox])
        p_cb->OSTaskQLast[task_id][mbox]->p_next = p_hdr;
    else
        p_cb->OSTaskQFirst[task_id][mbox] = p_hdr;

    p_cb->OSTaskQLast[task_id][mbox] = p_hdr;

    p_hdr->p_next = NULL;
    p_hdr->status = BUF_STATUS_QUEUED;
    p_hdr->task_id = task_id;


    GKI_enable();

    GKI_send_event(task_id, (UINT16)EVENT_MASK(mbox));

    return;
}
/*******************************************************************************
**
** Function        preload_wait_timeout
**
** Description     Timeout thread of preload watchdog timer
**
** Returns         None
**
*******************************************************************************/
static void preload_wait_timeout(union sigval arg)
{
    APPL_TRACE_ERROR2("...preload_wait_timeout (retried:%d/max-retry:%d)...",
                        preload_retry_cb.retry_counts,
                        PRELOAD_MAX_RETRY_ATTEMPTS);

    if (preload_retry_cb.retry_counts++ < PRELOAD_MAX_RETRY_ATTEMPTS)
    {
        bte_hci_disable();
        GKI_delay(100);
        bte_hci_enable();
    }
    else
    {
        /* Notify BTIF_TASK that the init procedure had failed*/
        GKI_send_event(BTIF_TASK, BT_EVT_HARDWARE_INIT_FAIL);
    }
}
Example #7
0
/*******************************************************************************
**
** Function         GKI_timer_update
**
** Description      This function is called by an OS to drive the GKI's timers.
**                  It is typically called at every system tick to
**                  update the timers for all tasks, and check for timeouts.
**
**                  Note: It has been designed to also allow for variable tick updates
**                      so that systems with strict power savings requirements can
**                      have the update occur at variable intervals.
**
** Parameters:      ticks_since_last_update - (input) This is the number of TICKS that have
**                          occurred since the last time GKI_timer_update was called.
**
** Returns          void
**
*******************************************************************************/
void GKI_timer_update (INT32 ticks_since_last_update)
{
    UINT8   task_id;
    long    next_expiration;        /* Holds the next soonest expiration time after this update */

    /* Increment the number of ticks used for time stamps */
    gki_cb.com.OSTicks += ticks_since_last_update;

    /* If any timers are running in any tasks, decrement the remaining time til
     * the timer updates need to take place (next expiration occurs)
     */
    gki_cb.com.OSTicksTilExp -= ticks_since_last_update;

    /* Don't allow timer interrupt nesting */
    if (gki_cb.com.timer_nesting)
        return;

    gki_cb.com.timer_nesting = 1;

#if (defined(GKI_DELAY_STOP_SYS_TICK) && (GKI_DELAY_STOP_SYS_TICK > 0))
    /* if inactivity delay timer is set and expired */
    if (gki_cb.com.OSTicksTilStop)
    {
        if( gki_cb.com.OSTicksTilStop <= (UINT32)ticks_since_last_update )
        {
            if(gki_cb.com.p_tick_cb)
            {
                gki_cb.com.system_tick_running = FALSE;
                (gki_cb.com.p_tick_cb) (FALSE); /* stop system tick */
            }
            gki_cb.com.OSTicksTilStop = 0;      /* clear inactivity delay timer */
            gki_cb.com.timer_nesting = 0;
            return;
        }
        else
            gki_cb.com.OSTicksTilStop -= ticks_since_last_update;
    }
#endif

    /* No need to update the ticks if no timeout has occurred */
    if (gki_cb.com.OSTicksTilExp > 0)
    {
        gki_cb.com.timer_nesting = 0;
        return;
    }

    GKI_disable();

    next_expiration = GKI_NO_NEW_TMRS_STARTED;

    /* If here then gki_cb.com.OSTicksTilExp <= 0. If negative, then increase gki_cb.com.OSNumOrigTicks
       to account for the difference so timer updates below are decremented by the full number
       of ticks. gki_cb.com.OSNumOrigTicks is reset at the bottom of this function so changing this
       value only affects the timer updates below
     */
    gki_cb.com.OSNumOrigTicks -= gki_cb.com.OSTicksTilExp;

    /* Check for OS Task Timers */
    for (task_id = 0; task_id < GKI_MAX_TASKS; task_id++)
    {
        if (gki_cb.com.OSWaitTmr[task_id] > 0) /* If timer is running */
        {
            gki_cb.com.OSWaitTmr[task_id] -= gki_cb.com.OSNumOrigTicks;
            if (gki_cb.com.OSWaitTmr[task_id] <= 0)
            {
                /* Timer Expired */
                gki_cb.com.OSRdyTbl[task_id] = TASK_READY;
            }
        }

#if (GKI_NUM_TIMERS > 0)
         /* If any timer is running, decrement */
        if (gki_cb.com.OSTaskTmr0[task_id] > 0)
        {
            gki_cb.com.OSTaskTmr0[task_id] -= gki_cb.com.OSNumOrigTicks;

            if (gki_cb.com.OSTaskTmr0[task_id] <= 0)
            {
                /* Set Timer 0 Expired event mask and reload timer */
#if (defined(GKI_TIMER_UPDATES_FROM_ISR) &&  GKI_TIMER_UPDATES_FROM_ISR == TRUE)
                GKI_isend_event (task_id, TIMER_0_EVT_MASK);
#else
                GKI_send_event (task_id, TIMER_0_EVT_MASK);
#endif
                gki_cb.com.OSTaskTmr0[task_id] = gki_cb.com.OSTaskTmr0R[task_id];
            }
        }

        /* Check to see if this timer is the next one to expire */
        if (gki_cb.com.OSTaskTmr0[task_id] > 0 && gki_cb.com.OSTaskTmr0[task_id] < next_expiration)
            next_expiration = gki_cb.com.OSTaskTmr0[task_id];
#endif

#if (GKI_NUM_TIMERS > 1)
         /* If any timer is running, decrement */
        if (gki_cb.com.OSTaskTmr1[task_id] > 0)
        {
            gki_cb.com.OSTaskTmr1[task_id] -= gki_cb.com.OSNumOrigTicks;

            if (gki_cb.com.OSTaskTmr1[task_id] <= 0)
            {
                /* Set Timer 1 Expired event mask and reload timer */
#if (defined(GKI_TIMER_UPDATES_FROM_ISR) &&  GKI_TIMER_UPDATES_FROM_ISR == TRUE)
                GKI_isend_event (task_id, TIMER_1_EVT_MASK);
#else
                GKI_send_event (task_id, TIMER_1_EVT_MASK);
#endif
                gki_cb.com.OSTaskTmr1[task_id] = gki_cb.com.OSTaskTmr1R[task_id];
            }
        }

        /* Check to see if this timer is the next one to expire */
        if (gki_cb.com.OSTaskTmr1[task_id] > 0 && gki_cb.com.OSTaskTmr1[task_id] < next_expiration)
            next_expiration = gki_cb.com.OSTaskTmr1[task_id];
#endif

#if (GKI_NUM_TIMERS > 2)
         /* If any timer is running, decrement */
        if (gki_cb.com.OSTaskTmr2[task_id] > 0)
        {
            gki_cb.com.OSTaskTmr2[task_id] -= gki_cb.com.OSNumOrigTicks;

            if (gki_cb.com.OSTaskTmr2[task_id] <= 0)
            {
                /* Set Timer 2 Expired event mask and reload timer */
#if (defined(GKI_TIMER_UPDATES_FROM_ISR) &&  GKI_TIMER_UPDATES_FROM_ISR == TRUE)
                GKI_isend_event (task_id, TIMER_2_EVT_MASK);
#else
                GKI_send_event (task_id, TIMER_2_EVT_MASK);
#endif
                gki_cb.com.OSTaskTmr2[task_id] = gki_cb.com.OSTaskTmr2R[task_id];
            }
        }

        /* Check to see if this timer is the next one to expire */
        if (gki_cb.com.OSTaskTmr2[task_id] > 0 && gki_cb.com.OSTaskTmr2[task_id] < next_expiration)
            next_expiration = gki_cb.com.OSTaskTmr2[task_id];
#endif

#if (GKI_NUM_TIMERS > 3)
         /* If any timer is running, decrement */
        if (gki_cb.com.OSTaskTmr3[task_id] > 0)
        {
            gki_cb.com.OSTaskTmr3[task_id] -= gki_cb.com.OSNumOrigTicks;

            if (gki_cb.com.OSTaskTmr3[task_id] <= 0)
            {
                /* Set Timer 3 Expired event mask and reload timer */
#if (defined(GKI_TIMER_UPDATES_FROM_ISR) &&  GKI_TIMER_UPDATES_FROM_ISR == TRUE)
                GKI_isend_event (task_id, TIMER_3_EVT_MASK);
#else
                GKI_send_event (task_id, TIMER_3_EVT_MASK);
#endif
                gki_cb.com.OSTaskTmr3[task_id] = gki_cb.com.OSTaskTmr3R[task_id];
            }
        }

        /* Check to see if this timer is the next one to expire */
        if (gki_cb.com.OSTaskTmr3[task_id] > 0 && gki_cb.com.OSTaskTmr3[task_id] < next_expiration)
            next_expiration = gki_cb.com.OSTaskTmr3[task_id];
#endif

    }

    /* Set the next timer experation value if there is one to start */
    if (next_expiration < GKI_NO_NEW_TMRS_STARTED)
    {
        gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = next_expiration;
    }
    else
    {
        gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = 0;
    }

    gki_cb.com.timer_nesting = 0;

    GKI_enable();

    return;
}
void GKI_shutdown(void)
{
    UINT8 task_id;
#if ( FALSE == GKI_PTHREAD_JOINABLE )
    int i = 0;
#else
    int result;
#endif

#ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS
    gki_dealloc_free_queue();
#endif

    /* release threads and set as TASK_DEAD. going from low to high priority fixes
     * GKI_exception problem due to btu->hci sleep request events  */
    for (task_id = GKI_MAX_TASKS; task_id > 0; task_id--)
    {
        if (gki_cb.com.OSRdyTbl[task_id - 1] != TASK_DEAD)
        {
            gki_cb.com.OSRdyTbl[task_id - 1] = TASK_DEAD;

            /* paranoi settings, make sure that we do not execute any mailbox events */
            gki_cb.com.OSWaitEvt[task_id-1] &= ~(TASK_MBOX_0_EVT_MASK|TASK_MBOX_1_EVT_MASK|
                                                TASK_MBOX_2_EVT_MASK|TASK_MBOX_3_EVT_MASK);
            GKI_send_event(task_id - 1, EVENT_MASK(GKI_SHUTDOWN_EVT));

#if ( FALSE == GKI_PTHREAD_JOINABLE )
            i = 0;

            while ((gki_cb.com.OSWaitEvt[task_id - 1] != 0) && (++i < 10))
                usleep(100 * 1000);
#else
            result = pthread_join( gki_cb.os.thread_id[task_id-1], NULL );

            if ( result < 0 )
            {
                ALOGE( "pthread_join() FAILED: result: %d", result );
            }
#endif
            // GKI_ERROR_LOG( "GKI_shutdown(): task %s dead\n", gki_cb.com.OSTName[task_id]);
            GKI_exit_task(task_id - 1);
        }
    }

    /* Destroy mutex and condition variable objects */
    pthread_mutex_destroy(&gki_cb.os.GKI_mutex);

    /*    pthread_mutex_destroy(&GKI_sched_mutex); */
#if (GKI_DEBUG == TRUE)
    pthread_mutex_destroy(&gki_cb.os.GKI_trace_mutex);
#endif
    /*    pthread_mutex_destroy(&thread_delay_mutex);
     pthread_cond_destroy (&thread_delay_cond); */
#if ( FALSE == GKI_PTHREAD_JOINABLE )
    i = 0;
#endif

#ifdef NO_GKI_RUN_RETURN
    shutdown_timer = 1;
#endif
    if (g_GkiTimerWakeLockOn)
    {
        GKI_TRACE("GKI_shutdown :  release_wake_lock(brcm_btld)");
        release_wake_lock(WAKE_LOCK_ID);
        g_GkiTimerWakeLockOn = 0;
    }
}
Example #9
0
/*******************************************************************************
**
** Function         GKI_timer_update
**
** Description      This function is called by an OS to drive the GKI's timers.
**                  It is typically called at every system tick to
**                  update the timers for all tasks, and check for timeouts.
**
**                  Note: It has been designed to also allow for variable tick updates
**                      so that systems with strict power savings requirements can
**                      have the update occur at variable intervals.
**
** Parameters:      ticks_since_last_update - (input) This is the number of TICKS that have
**                          occurred since the last time GKI_timer_update was called.
**
** Returns          void
**
*******************************************************************************/
void GKI_timer_update (INT32 ticks_since_last_update)
{
    UINT8   task_id;
    long    next_expiration;        /* Holds the next soonest expiration time after this update */

    /* Increment the number of ticks used for time stamps */
    gki_cb.com.OSTicks += ticks_since_last_update;

    /* If any timers are running in any tasks, decrement the remaining time til
     * the timer updates need to take place (next expiration occurs)
     */
    gki_cb.com.OSTicksTilExp -= ticks_since_last_update;

    /* Don't allow timer interrupt nesting */
    if (gki_cb.com.timer_nesting)
        return;

    gki_cb.com.timer_nesting = 1;

    /* No need to update the ticks if no timeout has occurred */
    if (gki_cb.com.OSTicksTilExp > 0)
    {
        // When using alarms from AlarmService we should
        // always have work to be done here.
        ALOGE("%s no work to be done when expected work", __func__);
        gki_cb.com.timer_nesting = 0;
        return;
    }

    next_expiration = GKI_NO_NEW_TMRS_STARTED;

    /* If here then gki_cb.com.OSTicksTilExp <= 0. If negative, then increase gki_cb.com.OSNumOrigTicks
       to account for the difference so timer updates below are decremented by the full number
       of ticks. gki_cb.com.OSNumOrigTicks is reset at the bottom of this function so changing this
       value only affects the timer updates below
     */
    gki_cb.com.OSNumOrigTicks -= gki_cb.com.OSTicksTilExp;

    /* Protect this section because if a GKI_timer_stop happens between:
     *   - gki_cb.com.OSTaskTmr0[task_id] -= gki_cb.com.OSNumOrigTicks;
     *   - gki_cb.com.OSTaskTmr0[task_id] = gki_cb.com.OSTaskTmr0R[task_id];
     * then the timer may appear stopped while it is about to be reloaded.
     */
    GKI_disable();

    /* Check for OS Task Timers */
    for (task_id = 0; task_id < GKI_MAX_TASKS; task_id++)
    {
        if (gki_cb.com.OSWaitTmr[task_id] > 0) /* If timer is running */
        {
            gki_cb.com.OSWaitTmr[task_id] -= gki_cb.com.OSNumOrigTicks;
            if (gki_cb.com.OSWaitTmr[task_id] <= 0)
            {
                /* Timer Expired */
                gki_cb.com.OSRdyTbl[task_id] = TASK_READY;
            }
        }

#if (GKI_NUM_TIMERS > 0)
         /* If any timer is running, decrement */
        if (gki_cb.com.OSTaskTmr0[task_id] > 0)
        {
            gki_cb.com.OSTaskTmr0[task_id] -= gki_cb.com.OSNumOrigTicks;

            if (gki_cb.com.OSTaskTmr0[task_id] <= 0)
            {
                /* Reload timer and set Timer 0 Expired event mask */
                gki_cb.com.OSTaskTmr0[task_id] = gki_cb.com.OSTaskTmr0R[task_id];
                GKI_send_event (task_id, TIMER_0_EVT_MASK);
            }
        }

        /* Check to see if this timer is the next one to expire */
        if (gki_cb.com.OSTaskTmr0[task_id] > 0 && gki_cb.com.OSTaskTmr0[task_id] < next_expiration)
            next_expiration = gki_cb.com.OSTaskTmr0[task_id];
#endif

#if (GKI_NUM_TIMERS > 1)
         /* If any timer is running, decrement */
        if (gki_cb.com.OSTaskTmr1[task_id] > 0)
        {
            gki_cb.com.OSTaskTmr1[task_id] -= gki_cb.com.OSNumOrigTicks;

            if (gki_cb.com.OSTaskTmr1[task_id] <= 0)
            {
                /* Reload timer and set Timer 1 Expired event mask */
                gki_cb.com.OSTaskTmr1[task_id] = gki_cb.com.OSTaskTmr1R[task_id];
                GKI_send_event (task_id, TIMER_1_EVT_MASK);
            }
        }

        /* Check to see if this timer is the next one to expire */
        if (gki_cb.com.OSTaskTmr1[task_id] > 0 && gki_cb.com.OSTaskTmr1[task_id] < next_expiration)
            next_expiration = gki_cb.com.OSTaskTmr1[task_id];
#endif

#if (GKI_NUM_TIMERS > 2)
         /* If any timer is running, decrement */
        if (gki_cb.com.OSTaskTmr2[task_id] > 0)
        {
            gki_cb.com.OSTaskTmr2[task_id] -= gki_cb.com.OSNumOrigTicks;

            if (gki_cb.com.OSTaskTmr2[task_id] <= 0)
            {
                /* Reload timer and set Timer 2 Expired event mask */
                gki_cb.com.OSTaskTmr2[task_id] = gki_cb.com.OSTaskTmr2R[task_id];
                GKI_send_event (task_id, TIMER_2_EVT_MASK);
            }
        }

        /* Check to see if this timer is the next one to expire */
        if (gki_cb.com.OSTaskTmr2[task_id] > 0 && gki_cb.com.OSTaskTmr2[task_id] < next_expiration)
            next_expiration = gki_cb.com.OSTaskTmr2[task_id];
#endif

#if (GKI_NUM_TIMERS > 3)
         /* If any timer is running, decrement */
        if (gki_cb.com.OSTaskTmr3[task_id] > 0)
        {
            gki_cb.com.OSTaskTmr3[task_id] -= gki_cb.com.OSNumOrigTicks;

            if (gki_cb.com.OSTaskTmr3[task_id] <= 0)
            {
                /* Reload timer and set Timer 3 Expired event mask */
                gki_cb.com.OSTaskTmr3[task_id] = gki_cb.com.OSTaskTmr3R[task_id];
                GKI_send_event (task_id, TIMER_3_EVT_MASK);
            }
        }

        /* Check to see if this timer is the next one to expire */
        if (gki_cb.com.OSTaskTmr3[task_id] > 0 && gki_cb.com.OSTaskTmr3[task_id] < next_expiration)
            next_expiration = gki_cb.com.OSTaskTmr3[task_id];
#endif

    }
    /* Set the next timer experation value if there is one to start */
    if (next_expiration < GKI_NO_NEW_TMRS_STARTED)
    {
        gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = next_expiration;
    }
    else
    {
        gki_cb.com.OSTicksTilExp = gki_cb.com.OSNumOrigTicks = 0;
    }

    // Set alarm service for next alarm.
    alarm_service_reschedule();

    GKI_enable();

    gki_cb.com.timer_nesting = 0;

    return;
}
Example #10
0
void GKI_shutdown(void)
{
    UINT8 task_id;
    volatile int    *p_run_cond = &gki_cb.os.no_timer_suspend;
    int     oldCOnd = 0;
#if ( FALSE == GKI_PTHREAD_JOINABLE )
    int i = 0;
#else
    int result;
#endif

    /* release threads and set as TASK_DEAD. going from low to high priority fixes
     * GKI_exception problem due to btu->hci sleep request events  */
    for (task_id = GKI_MAX_TASKS; task_id > 0; task_id--)
    {
        if (gki_cb.com.OSRdyTbl[task_id - 1] != TASK_DEAD)
        {
            gki_cb.com.OSRdyTbl[task_id - 1] = TASK_DEAD;

            /* paranoi settings, make sure that we do not execute any mailbox events */
            gki_cb.com.OSWaitEvt[task_id-1] &= ~(TASK_MBOX_0_EVT_MASK|TASK_MBOX_1_EVT_MASK|
                                                TASK_MBOX_2_EVT_MASK|TASK_MBOX_3_EVT_MASK);
            GKI_send_event(task_id - 1, EVENT_MASK(GKI_SHUTDOWN_EVT));

#if ( FALSE == GKI_PTHREAD_JOINABLE )
            i = 0;

            while ((gki_cb.com.OSWaitEvt[task_id - 1] != 0) && (++i < 10))
                usleep(100 * 1000);
#else
            /* wait for proper Arnold Schwarzenegger task state */
            result = pthread_join( gki_cb.os.thread_id[task_id-1], NULL );
            if ( result < 0 )
            {
                GKI_TRACE_1( "pthread_join() FAILED: result: %d", result );
            }
#endif
            GKI_TRACE_1( "GKI_shutdown(): task %s dead", gki_cb.com.OSTName[task_id]);
            GKI_exit_task(task_id - 1);
        }
    }

    /* Destroy mutex and condition variable objects */
    pthread_mutex_destroy(&gki_cb.os.GKI_mutex);
    /*    pthread_mutex_destroy(&GKI_sched_mutex); */
#if (GKI_DEBUG == TRUE)
    pthread_mutex_destroy(&gki_cb.os.GKI_trace_mutex);
#endif
    /*    pthread_mutex_destroy(&thread_delay_mutex);
     pthread_cond_destroy (&thread_delay_cond); */
#if ( FALSE == GKI_PTHREAD_JOINABLE )
    i = 0;
#endif

#ifdef NO_GKI_RUN_RETURN
    shutdown_timer = 1;
#endif
    if (gki_cb.os.gki_timer_wake_lock_on)
    {
        GKI_TRACE_0("GKI_shutdown :  release_wake_lock(brcm_btld)");
        release_wake_lock(WAKE_LOCK_ID);
        gki_cb.os.gki_timer_wake_lock_on = 0;
    }
    oldCOnd = *p_run_cond;
    *p_run_cond = GKI_TIMER_TICK_EXIT_COND;
    if (oldCOnd == GKI_TIMER_TICK_STOP_COND)
        pthread_cond_signal( &gki_cb.os.gki_timer_cond );

}
Example #11
0
/*******************************************************************************
**
** Function         btu_task
**
** Description      This is the main task of the Bluetooth Upper Layers unit.
**                  It sits in a loop waiting for messages, and dispatches them
**                  to the appropiate handlers.
**
** Returns          should never return
**
*******************************************************************************/
BTU_API UINT32 btu_task (UINT32 param)
{
    UINT16           event;
    BT_HDR          *p_msg;
    UINT8            i;
    UINT16           mask;
    BOOLEAN          handled;

#if (defined(HCISU_H4_INCLUDED) && HCISU_H4_INCLUDED == TRUE)
    /* wait an event that HCISU is ready */
    GKI_wait(0xFFFF, 0);
#endif
    /* Initialize the mandatory core stack control blocks
       (BTU, BTM, L2CAP, and SDP)
     */
    btu_init_core();

    /* Initialize any optional stack components */
    BTE_InitStack();

#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
    bta_sys_init();
#endif

    /* Initialise platform trace levels at this point as BTE_InitStack() and bta_sys_init()
     * reset the control blocks and preset the trace level with XXX_INITIAL_TRACE_LEVEL
     */
#if ( BT_USE_TRACES==TRUE )
    BTE_InitTraceLevels();
#endif

    /* Send a startup evt message to BTIF_TASK to kickstart the init procedure */
    GKI_send_event(BTIF_TASK, BT_EVT_TRIGGER_STACK_INIT);

    raise_priority_a2dp(TASK_HIGH_BTU);

    /* Wait for, and process, events */
    for (;;)
    {
        event = GKI_wait (0xFFFF, 0);

        if (event & TASK_MBOX_0_EVT_MASK)
        {
            /* Process all messages in the queue */
            while ((p_msg = (BT_HDR *) GKI_read_mbox (BTU_HCI_RCV_MBOX)) != NULL)
            {
                /* Determine the input message type. */
                switch (p_msg->event & BT_EVT_MASK)
                {
                    case BT_EVT_TO_BTU_HCI_ACL:
                        /* All Acl Data goes to L2CAP */
                        l2c_rcv_acl_data (p_msg);
                        break;

                    case BT_EVT_TO_BTU_L2C_SEG_XMIT:
                        /* L2CAP segment transmit complete */
                        l2c_link_segments_xmitted (p_msg);
                        break;

                    case BT_EVT_TO_BTU_HCI_SCO:
#if BTM_SCO_INCLUDED == TRUE
                        btm_route_sco_data (p_msg);
                        break;
#endif

                    case BT_EVT_TO_BTU_HCI_EVT:
                        btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
                        GKI_freebuf(p_msg);

#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
                        /* If host receives events which it doesn't response to, */
                        /* host should start idle timer to enter sleep mode.     */
                        btu_check_bt_sleep ();
#endif
                        break;

                    case BT_EVT_TO_BTU_HCI_CMD:
                        btu_hcif_send_cmd ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
                        break;

#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
#if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE)
                    case BT_EVT_TO_OBX_SR_MSG:
                        obx_sr_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;

                    case BT_EVT_TO_OBX_SR_L2C_MSG:
                        obx_sr_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;
#endif

#if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE)
                    case BT_EVT_TO_OBX_CL_MSG:
                        obx_cl_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;

                    case BT_EVT_TO_OBX_CL_L2C_MSG:
                        obx_cl_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;
#endif

#if (defined(BIP_INCLUDED) && BIP_INCLUDED == TRUE)
                    case BT_EVT_TO_BIP_CMDS :
                        bip_proc_btu_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
#endif /* BIP */
#if (BPP_SND_INCLUDED == TRUE || BPP_INCLUDED == TRUE)
                    case BT_EVT_TO_BPP_PR_CMDS:
                        bpp_pr_proc_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
                    case BT_EVT_TO_BPP_SND_CMDS:
                        bpp_snd_proc_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;

#endif /* BPP */

#endif /* OBX */

#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
                    case BT_EVT_TO_BTU_SAP :
                        sap_proc_btu_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
#endif /* SAP */
#if (defined(GAP_CONN_INCLUDED) && GAP_CONN_INCLUDED == TRUE && GAP_CONN_POST_EVT_INCLUDED == TRUE)
                    case BT_EVT_TO_GAP_MSG :
                        gap_proc_btu_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
#endif
                    case BT_EVT_TO_START_TIMER :
                        /* Start free running 1 second timer for list management */
                        GKI_start_timer (TIMER_0, GKI_SECS_TO_TICKS (1), TRUE);
                        GKI_freebuf (p_msg);
                        break;

#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
                    case BT_EVT_TO_START_QUICK_TIMER :
                        GKI_start_timer (TIMER_2, QUICK_TIMER_TICKS, TRUE);
                        GKI_freebuf (p_msg);
                        break;
#endif

                    default:
                        i = 0;
                        mask = (UINT16) (p_msg->event & BT_EVT_MASK);
                        handled = FALSE;

                        for (; !handled && i < BTU_MAX_REG_EVENT; i++)
                        {
                            if (btu_cb.event_reg[i].event_cb == NULL)
                                continue;

                            if (mask == btu_cb.event_reg[i].event_range)
                            {
                                if (btu_cb.event_reg[i].event_cb)
                                {
                                    btu_cb.event_reg[i].event_cb(p_msg);
                                    handled = TRUE;
                                }
                            }
                        }

                        if (handled == FALSE)
                            GKI_freebuf (p_msg);

                        break;
                }
            }
        }


        if (event & TIMER_0_EVT_MASK)
        {
            TIMER_LIST_ENT  *p_tle;

            GKI_update_timer_list (&btu_cb.timer_queue, 1);

            while ((btu_cb.timer_queue.p_first) && (!btu_cb.timer_queue.p_first->ticks))
            {
                p_tle = btu_cb.timer_queue.p_first;
                GKI_remove_from_timer_list (&btu_cb.timer_queue, p_tle);

                switch (p_tle->event)
                {
                    case BTU_TTYPE_BTM_DEV_CTL:
                        btm_dev_timeout(p_tle);
                        break;

                    case BTU_TTYPE_BTM_ACL:
                        btm_acl_timeout(p_tle);
                        break;

                    case BTU_TTYPE_L2CAP_LINK:
                    case BTU_TTYPE_L2CAP_CHNL:
                    case BTU_TTYPE_L2CAP_HOLD:
                    case BTU_TTYPE_L2CAP_INFO:
                    case BTU_TTYPE_L2CAP_FCR_ACK:

                        l2c_process_timeout (p_tle);
                        break;

                    case BTU_TTYPE_SDP:
                        sdp_conn_timeout ((tCONN_CB *)p_tle->param);
                        break;

                    case BTU_TTYPE_BTM_RMT_NAME:
                        btm_inq_rmt_name_failed();
                        break;

#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE)
                    case BTU_TTYPE_RFCOMM_MFC:
                    case BTU_TTYPE_RFCOMM_PORT:
                        rfcomm_process_timeout (p_tle);
                        break;

#endif /* If defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE */

#if ((defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE))
                    case BTU_TTYPE_BNEP:
                        bnep_process_timeout(p_tle);
                        break;
#endif


#if (defined(AVDT_INCLUDED) && AVDT_INCLUDED == TRUE)
                    case BTU_TTYPE_AVDT_CCB_RET:
                    case BTU_TTYPE_AVDT_CCB_RSP:
                    case BTU_TTYPE_AVDT_CCB_IDLE:
                    case BTU_TTYPE_AVDT_SCB_TC:
                        avdt_process_timeout(p_tle);
                        break;
#endif

#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
#if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE)
                    case BTU_TTYPE_OBX_CLIENT_TO:
                        obx_cl_timeout(p_tle);
                        break;
#endif
#if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE)
                    case BTU_TTYPE_OBX_SERVER_TO:
                        obx_sr_timeout(p_tle);
                        break;

                    case BTU_TTYPE_OBX_SVR_SESS_TO:
                        obx_sr_sess_timeout(p_tle);
                        break;
#endif
#endif

#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
                    case BTU_TTYPE_SAP_TO:
                        sap_process_timeout(p_tle);
                        break;
#endif

                    case BTU_TTYPE_BTU_CMD_CMPL:
                        btu_hcif_cmd_timeout((UINT8)(p_tle->event - BTU_TTYPE_BTU_CMD_CMPL));
                        break;

#if (defined(HID_HOST_INCLUDED) && HID_HOST_INCLUDED == TRUE)
                    case BTU_TTYPE_HID_HOST_REPAGE_TO :
                        hidh_proc_repage_timeout(p_tle);
                        break;
#endif

#if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
                    case BTU_TTYPE_BLE_INQUIRY:
                    case BTU_TTYPE_BLE_GAP_LIM_DISC:
                    case BTU_TTYPE_BLE_RANDOM_ADDR:
                        btm_ble_timeout(p_tle);
                        break;

                    case BTU_TTYPE_BLE_SCAN_PARAM_IDLE:
                        btm_ble_scan_param_idle();
                        break;

                    case BTU_TTYPE_ATT_WAIT_FOR_RSP:
                        gatt_rsp_timeout(p_tle);
                        break;

                    case BTU_TTYPE_ATT_WAIT_FOR_IND_ACK:
                        gatt_ind_ack_timeout(p_tle);
                        break;
#if (defined(SMP_INCLUDED) && SMP_INCLUDED == TRUE)
                    case BTU_TTYPE_SMP_PAIRING_CMD:
                        smp_rsp_timeout(p_tle);
                        break;
#endif

#endif

#if (MCA_INCLUDED == TRUE)
                    case BTU_TTYPE_MCA_CCB_RSP:
                        mca_process_timeout(p_tle);
                        break;
#endif
                    case BTU_TTYPE_USER_FUNC:
                        {
                            tUSER_TIMEOUT_FUNC  *p_uf = (tUSER_TIMEOUT_FUNC *)p_tle->param;
                            (*p_uf)(p_tle);
                        }
                        break;

                    default:
                        i = 0;
                        handled = FALSE;

                        for (; !handled && i < BTU_MAX_REG_TIMER; i++)
                        {
                            if (btu_cb.timer_reg[i].timer_cb == NULL)
                                continue;
                            if (btu_cb.timer_reg[i].p_tle == p_tle)
                            {
                                btu_cb.timer_reg[i].timer_cb(p_tle);
                                handled = TRUE;
                            }
                        }
                        break;
                }
            }

            /* if timer list is empty stop periodic GKI timer */
            if (btu_cb.timer_queue.p_first == NULL)
            {
                GKI_stop_timer(TIMER_0);
            }
        }

#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
        if (event & TIMER_2_EVT_MASK)
        {
            btu_process_quick_timer_evt();
        }
#endif


#if (RPC_INCLUDED == TRUE)
        /* if RPC message queue event */
        if (event & RPCGEN_MSG_EVT)
        {
            if ((p_msg = (BT_HDR *) GKI_read_mbox(RPCGEN_MSG_MBOX)) != NULL)
                RPCT_RpcgenMsg(p_msg);  /* handle RPC message queue */
        }
#endif

#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
        if (event & TASK_MBOX_2_EVT_MASK)
        {
            while ((p_msg = (BT_HDR *) GKI_read_mbox(TASK_MBOX_2)) != NULL)
            {
                bta_sys_event(p_msg);
            }
        }

        if (event & TIMER_1_EVT_MASK)
        {
            bta_sys_timer_update();
        }
#endif

        if (event & EVENT_MASK(APPL_EVT_7))
            break;
    }

    return(0);
}
/*******************************************************************************
**
** Function         nfc_hal_main_task
**
** Description      NFC HAL NCI transport event processing task
**
** Returns          0
**
*******************************************************************************/
UINT32 nfc_hal_main_task (UINT32 param)
{
    UINT16   event;
    UINT8    byte;
    UINT8    num_interfaces;
    UINT8    *p;
    NFC_HDR  *p_msg;
    BOOLEAN  free_msg;

    HAL_TRACE_DEBUG0 ("NFC_HAL_TASK started");

    /* Main loop */
    while (TRUE)
    {
        event = GKI_wait (0xFFFF, 0);

        /* Handle NFC_HAL_TASK_EVT_INITIALIZE (for initializing NCI transport) */
        if (event & NFC_HAL_TASK_EVT_INITIALIZE)
        {
            HAL_TRACE_DEBUG0 ("NFC_HAL_TASK got NFC_HAL_TASK_EVT_INITIALIZE signal. Opening NFC transport...");

            nfc_hal_main_open_transport ();
        }

        /* Check for terminate event */
        if (event & NFC_HAL_TASK_EVT_TERMINATE)
        {
            HAL_TRACE_DEBUG0 ("NFC_HAL_TASK got NFC_HAL_TASK_EVT_TERMINATE");
            nfc_hal_main_handle_terminate ();

            /* Close uart */
            USERIAL_Close (USERIAL_NFC_PORT);

            if (nfc_hal_cb.p_stack_cback)
            {
                nfc_hal_cb.p_stack_cback (HAL_NFC_CLOSE_CPLT_EVT, HAL_NFC_STATUS_OK);
                nfc_hal_cb.p_stack_cback = NULL;
            }
            continue;
        }

        /* Check for power cycle event */
        if (event & NFC_HAL_TASK_EVT_POWER_CYCLE)
        {
            HAL_TRACE_DEBUG0 ("NFC_HAL_TASK got NFC_HAL_TASK_EVT_POWER_CYCLE");
            nfc_hal_main_handle_terminate ();

            /* Close uart */
            USERIAL_Close (USERIAL_NFC_PORT);

            /* power cycle timeout */
            nfc_hal_main_start_quick_timer (&nfc_hal_cb.timer, NFC_HAL_TTYPE_POWER_CYCLE,
                                            (NFC_HAL_POWER_CYCLE_DELAY*QUICK_TIMER_TICKS_PER_SEC)/1000);
            continue;
        }

        /* NCI message ready to be sent to NFCC */
        if (event & NFC_HAL_TASK_EVT_MBOX)
        {
            while ((p_msg = (NFC_HDR *) GKI_read_mbox (NFC_HAL_TASK_MBOX)) != NULL)
            {
                free_msg = TRUE;
                switch (p_msg->event & NFC_EVT_MASK)
                {
                case NFC_HAL_EVT_TO_NFC_NCI:
                    nfc_hal_main_send_message (p_msg);
                    /* do not free buffer. NCI VS code may keep it for processing later */
                    free_msg = FALSE;
                    break;

                case NFC_HAL_EVT_POST_CORE_RESET:
                    NFC_HAL_SET_INIT_STATE (NFC_HAL_INIT_STATE_W4_POST_INIT_DONE);

                    /* set NCI Control packet size from CORE_INIT_RSP */
                    p = (UINT8 *) (p_msg + 1) + p_msg->offset + NCI_MSG_HDR_SIZE;
                    p += 5;
                    STREAM_TO_UINT8 (num_interfaces, p);
                    p += (num_interfaces + 3);
                    nfc_hal_cb.ncit_cb.nci_ctrl_size = *p;

                    /* start post initialization */
                    nfc_hal_cb.dev_cb.next_dm_config = NFC_HAL_DM_CONFIG_LPTD;
                    nfc_hal_cb.dev_cb.next_startup_vsc = 1;

                    nfc_hal_dm_config_nfcc ();
                    break;

                case NFC_HAL_EVT_TO_START_QUICK_TIMER:
                    GKI_start_timer (NFC_HAL_QUICK_TIMER_ID, ((GKI_SECS_TO_TICKS (1) / QUICK_TIMER_TICKS_PER_SEC)), TRUE);
                    break;

                case NFC_HAL_EVT_HCI:
                    nfc_hal_hci_evt_hdlr ((tNFC_HAL_HCI_EVENT_DATA *) p_msg);
                    break;

                case NFC_HAL_EVT_PRE_DISCOVER:
                    NFC_HAL_SET_INIT_STATE(NFC_HAL_INIT_STATE_W4_PREDISCOVER_DONE);
                    nfa_hal_send_pre_discover_cfg ();
                    break;

                case NFC_HAL_EVT_CONTROL_GRANTED:
                    nfc_hal_dm_send_pend_cmd ();
                    break;

                default:
                    break;
                }

                if (free_msg)
                    GKI_freebuf (p_msg);
            }
        }

        /* Data waiting to be read from serial port */
        if (event & NFC_HAL_TASK_EVT_DATA_RDY)
        {
            while (TRUE)
            {
                /* Read one byte to see if there is anything waiting to be read */
                if (USERIAL_Read (USERIAL_NFC_PORT, &byte, 1) == 0)
                {
                    break;
                }

                if (nfc_hal_nci_receive_msg (byte))
                {
                    /* complete of receiving NCI message */
                    nfc_hal_nci_assemble_nci_msg ();
                    if (nfc_hal_cb.ncit_cb.p_rcv_msg)
                    {
                        if (nfc_hal_nci_preproc_rx_nci_msg (nfc_hal_cb.ncit_cb.p_rcv_msg))
                        {
                            /* Send NCI message to the stack */
                            nfc_hal_send_nci_msg_to_nfc_task (nfc_hal_cb.ncit_cb.p_rcv_msg);
                        }
                        else
                        {
                            if (nfc_hal_cb.ncit_cb.p_rcv_msg)
                                GKI_freebuf(nfc_hal_cb.ncit_cb.p_rcv_msg);
                        }
                        nfc_hal_cb.ncit_cb.p_rcv_msg = NULL;
                        #ifdef SWISSKNIFEVERSION
                            GKI_send_event (NFC_HAL_TASK, NFC_HAL_TASK_EVT_DATA_RDY); //Try to search for another message after we are done with this one.
                        #endif
                    }
                }
            } /* while (TRUE) */
        }

        /* Process quick timer tick */
        if (event & NFC_HAL_QUICK_TIMER_EVT_MASK)
        {
            nfc_hal_main_process_quick_timer_evt ();
        }
    }

    HAL_TRACE_DEBUG0 ("nfc_hal_main_task terminated");

    GKI_exit_task (GKI_get_taskid ());
    return 0;
}