/** Closes the interface */
static void cleanup( void )
{
    BTHCDBG("cleanup");

    if (lib_running)
    {
        lib_running = 0;
        bthc_signal_event(HC_EVENT_EXIT);
        pthread_join(hc_cb.worker_thread, NULL);
    }


    userial_close();
    p_hci_if->cleanup();
    utils_cleanup();

    /* Calling vendor-specific part */
    if (bt_vnd_if)
        bt_vnd_if->cleanup();

    pthread_cond_destroy(&hc_cb.cond);
    pthread_mutex_destroy(&hc_cb.mutex);

    bt_hc_cbacks = NULL;
}
// Closes the interface.
// This routine is not thread safe.
static void cleanup(void)
{
    if (has_cleaned_up) {
        ALOGW("%s Already cleaned up for this session\n", __func__);
        return;
    }

    BTHCDBG("cleanup");

    if (hc_cb.worker_thread)
    {
        if (fwcfg_acked)
        {
            epilog_wait_timer();
            // Stop reading thread
            userial_close_reader();

            thread_post(hc_cb.worker_thread, event_epilog, NULL);
        }
        thread_free(hc_cb.worker_thread);

        pthread_mutex_lock(&hc_cb.worker_thread_lock);
        hc_cb.worker_thread = NULL;
        pthread_mutex_unlock(&hc_cb.worker_thread_lock);

        if (hc_cb.epilog_timer_created)
        {
            timer_delete(hc_cb.epilog_timer_id);
            hc_cb.epilog_timer_created = false;
        }
    }
    BTHCDBG("%s Finalizing cleanup\n", __func__);

    lpm_cleanup();
    userial_close();
    p_hci_if->cleanup();
    utils_cleanup();

    set_power(BT_VND_PWR_OFF);
    vendor_close();

    pthread_mutex_destroy(&hc_cb.worker_thread_lock);

    fwcfg_acked = false;
    bt_hc_cbacks = NULL;
    has_cleaned_up = true;
}
/** sends command HC controller to configure platform specific behaviour */
static int tx_hc_cmd(TRANSAC transac, char *p_buf, int len) {
  BTHCDBG("tx_hc_cmd: transac %p", transac);

  if (!transac)
    return BT_HC_STATUS_FAIL;

  thread_post(hc_cb.worker_thread, event_tx_cmd, transac);
  return BT_HC_STATUS_SUCCESS;
}
/** Controls HCI logging on/off */
static int logging(bt_hc_logging_state_t state, char *p_path, bool save_existing) {
  BTHCDBG("logging %d", state);

  if (state != BT_HC_LOGGING_ON)
    btsnoop_close();
  else if (p_path != NULL)
    btsnoop_open(p_path, save_existing);

  return BT_HC_STATUS_SUCCESS;
}
Esempio n. 5
0
/** Controls receive flow */
static int set_rxflow(bt_rx_flow_state_t state)
{
    BTHCDBG("set_rxflow %d", state);

    p_userial_if->ioctl(\
     ((state == BT_RXFLOW_ON) ? USERIAL_OP_RXFLOW_ON : USERIAL_OP_RXFLOW_OFF), \
     NULL);

    return BT_HC_STATUS_SUCCESS;
}
/** Chip power control */
static void set_power(bt_hc_chip_power_state_t state)
{
    int pwr_state;

    BTHCDBG("set_power %d", state);

    /* Calling vendor-specific part */
    pwr_state = (state == BT_HC_CHIP_PWR_ON) ? BT_VND_PWR_ON : BT_VND_PWR_OFF;

    vendor_send_command(BT_VND_OP_POWER_CTRL, &pwr_state);
}
Esempio n. 7
0
/** Chip power control */
static void set_power(bt_hc_chip_power_state_t state)
{
    int pwr_state;

    BTHCDBG("set_power %d", state);

    /* Calling vendor-specific part */
    pwr_state = (state == BT_HC_CHIP_PWR_ON) ? BT_VND_PWR_ON : BT_VND_PWR_OFF;

    if (bt_vnd_if)
        bt_vnd_if->op(BT_VND_OP_POWER_CTRL, &pwr_state);
    else
        ALOGE("vendor lib is missing!");
}
static void event_tx_cmd(void *msg) {
  HC_BT_HDR *p_msg = (HC_BT_HDR *)msg;

  BTHCDBG("%s: p_msg: %p, event: 0x%x", __func__, p_msg, p_msg->event);

  int event = p_msg->event & MSG_EVT_MASK;
  int sub_event = p_msg->event & MSG_SUB_EVT_MASK;
  if (event == MSG_CTRL_TO_HC_CMD && sub_event == BT_HC_AUDIO_STATE) {
    vendor_send_command(BT_VND_OP_SET_AUDIO_STATE, p_msg->data);
  } else {
    ALOGW("%s (event: 0x%x, sub_event: 0x%x) not supported", __func__, event, sub_event);
  }

  bt_hc_cbacks->dealloc(msg);
}
Esempio n. 9
0
/** Controls HCI logging on/off */
static int logging(bt_hc_logging_state_t state, char *p_path)
{
    BTHCDBG("logging %d", state);

    if (state == BT_HC_LOGGING_ON)
    {
        if (p_path != NULL)
            btsnoop_open(p_path);
    }
    else
    {
        btsnoop_close();
    }

    return BT_HC_STATUS_SUCCESS;
}
static void event_tx(UNUSED_ATTR void *context) {
  /*
   *  We will go through every packets in the tx queue.
   *  Fine to clear tx_cmd_pkts_pending.
   */
  tx_cmd_pkts_pending = false;
  HC_BT_HDR *sending_msg_que[64];
  size_t sending_msg_count = 0;
  int sending_hci_cmd_pkts_count = 0;
  utils_lock();
  HC_BT_HDR *p_next_msg = tx_q.p_first;
  while (p_next_msg && sending_msg_count < ARRAY_SIZE(sending_msg_que))
  {
    if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD)
    {
      /*
       *  if we have used up controller's outstanding HCI command
       *  credits (normally is 1), skip all HCI command packets in
       *  the queue.
       *  The pending command packets will be sent once controller
       *  gives back us credits through CommandCompleteEvent or
       *  CommandStatusEvent.
       */
      if (tx_cmd_pkts_pending ||
          (sending_hci_cmd_pkts_count >= num_hci_cmd_pkts))
      {
        tx_cmd_pkts_pending = true;
        p_next_msg = utils_getnext(p_next_msg);
        continue;
      }
      sending_hci_cmd_pkts_count++;
    }

    HC_BT_HDR *p_msg = p_next_msg;
    p_next_msg = utils_getnext(p_msg);
    utils_remove_from_queue_unlocked(&tx_q, p_msg);
    sending_msg_que[sending_msg_count++] = p_msg;
  }
  utils_unlock();
  for(size_t i = 0; i < sending_msg_count; i++)
    p_hci_if->send(sending_msg_que[i]);
  if (tx_cmd_pkts_pending)
    BTHCDBG("Used up Tx Cmd credits");
}
Esempio n. 11
0
/** Closes the interface */
static void cleanup( void )
{
    BTHCDBG("cleanup");

    if (lib_running)
    {
        if (fwcfg_acked == TRUE)
        {
            epilog_wait_timer();
            bthc_signal_event(HC_EVENT_EPILOG);
        }
        else
        {
            bthc_signal_event(HC_EVENT_EXIT);
        }

        pthread_join(hc_cb.worker_thread, NULL);

        if (hc_cb.epilog_timer_created == 1)
        {
            timer_delete(hc_cb.epilog_timer_id);
            hc_cb.epilog_timer_created = 0;
        }
    }

    lib_running = 0;

    lpm_cleanup();
    p_userial_if->close();
    p_hci_if->cleanup();
    utils_cleanup();

    /* Calling vendor-specific part */
    if (bt_vnd_if)
        bt_vnd_if->cleanup();

    fwcfg_acked = FALSE;
    bt_hc_cbacks = NULL;
}
/** Called post stack initialization */
static void postload(UNUSED_ATTR TRANSAC transac) {
  BTHCDBG("postload");
  thread_post(hc_cb.worker_thread, event_postload, NULL);
}
Esempio n. 13
0
/*******************************************************************************
**
** Function        bt_hc_worker_thread
**
** Description     Mian worker thread
**
** Returns         void *
**
*******************************************************************************/
static void *bt_hc_worker_thread(void *arg)
{
    uint16_t events;
    HC_BT_HDR *p_msg, *p_next_msg;

    ALOGI("bt_hc_worker_thread started");
    prctl(PR_SET_NAME, (unsigned long)"bt_hc_worker", 0, 0, 0);
    tx_cmd_pkts_pending = FALSE;

    raise_priority_a2dp(TASK_HIGH_HCI_WORKER);

    while (lib_running)
    {
        pthread_mutex_lock(&hc_cb.mutex);
        while (ready_events == 0)
        {
            pthread_cond_wait(&hc_cb.cond, &hc_cb.mutex);
        }
        events = ready_events;
        ready_events = 0;
        pthread_mutex_unlock(&hc_cb.mutex);

        if (events & HC_EVENT_RX && ( p_hci_if->rcv != NULL))
        {
            p_hci_if->rcv();

            if ((tx_cmd_pkts_pending == TRUE) && (num_hci_cmd_pkts > 0))
            {
                /* Got HCI Cmd Credits from Controller.
                 * Prepare to send prior pending Cmd packets in the
                 * following HC_EVENT_TX session.
                 */
                events |= HC_EVENT_TX;
            }
        }

        if (events & HC_EVENT_PRELOAD)
        {
            p_userial_if->open(USERIAL_PORT_1);

            /* Calling vendor-specific part */
            if (bt_vnd_if)
            {
                bt_vnd_if->op(BT_VND_OP_FW_CFG, NULL);
            }
            else
            {
                if (bt_hc_cbacks)
                    bt_hc_cbacks->preload_cb(NULL, BT_HC_PRELOAD_FAIL);
            }
        }

        if (events & HC_EVENT_POSTLOAD)
        {
            /* Start from SCO related H/W configuration, if SCO configuration
             * is required. Then, follow with reading requests of getting
             * ACL data length for both BR/EDR and LE.
             */
            int result = -1;

            /* Calling vendor-specific part */
            if (bt_vnd_if)
                result = bt_vnd_if->op(BT_VND_OP_SCO_CFG, NULL);

            if (result == -1)
                p_hci_if->get_acl_max_len();
        }

        if (events & HC_EVENT_TX)
        {
            /*
             *  We will go through every packets in the tx queue.
             *  Fine to clear tx_cmd_pkts_pending.
             */
            tx_cmd_pkts_pending = FALSE;
            HC_BT_HDR * sending_msg_que[64];
            int sending_msg_count = 0;
            int sending_hci_cmd_pkts_count = 0;
            utils_lock();
            p_next_msg = tx_q.p_first;
            while (p_next_msg && sending_msg_count <
                            (int)sizeof(sending_msg_que)/sizeof(sending_msg_que[0]))
            {
                if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD)
                {
                    /*
                     *  if we have used up controller's outstanding HCI command
                     *  credits (normally is 1), skip all HCI command packets in
                     *  the queue.
                     *  The pending command packets will be sent once controller
                     *  gives back us credits through CommandCompleteEvent or
                     *  CommandStatusEvent.
                     */
                    if ((tx_cmd_pkts_pending == TRUE) ||
                        (sending_hci_cmd_pkts_count >= num_hci_cmd_pkts))
                    {
                        tx_cmd_pkts_pending = TRUE;
                        p_next_msg = utils_getnext(p_next_msg);
                        continue;
                    }
                    sending_hci_cmd_pkts_count++;
                }

                p_msg = p_next_msg;
                p_next_msg = utils_getnext(p_msg);
                utils_remove_from_queue_unlocked(&tx_q, p_msg);
                sending_msg_que[sending_msg_count++] = p_msg;
            }
            utils_unlock();
            int i;
            for(i = 0; i < sending_msg_count; i++)
                p_hci_if->send(sending_msg_que[i]);
            if (tx_cmd_pkts_pending == TRUE)
                BTHCDBG("Used up Tx Cmd credits");

        }

        if (events & HC_EVENT_LPM_ENABLE)
        {
            lpm_enable(TRUE);
        }

        if (events & HC_EVENT_LPM_DISABLE)
        {
            lpm_enable(FALSE);
        }

        if (events & HC_EVENT_LPM_IDLE_TIMEOUT)
        {
            lpm_wake_deassert();
        }

        if (events & HC_EVENT_LPM_ALLOW_SLEEP)
        {
            lpm_allow_bt_device_sleep();
        }

        if (events & HC_EVENT_LPM_WAKE_DEVICE)
        {
            lpm_wake_assert();
        }

        if (events & HC_EVENT_EPILOG)
        {
            /* Calling vendor-specific part */
            if (bt_vnd_if)
                bt_vnd_if->op(BT_VND_OP_EPILOG, NULL);
            else
                break;  // equivalent to HC_EVENT_EXIT
        }

        if (events & HC_EVENT_EXIT)
            break;
    }

    ALOGI("bt_hc_worker_thread exiting");
    lib_running = 0;

    pthread_exit(NULL);

    return NULL;    // compiler friendly
}
Esempio n. 14
0
/** Called post stack initialization */
static void postload(TRANSAC transac)
{
    BTHCDBG("postload");
    bthc_signal_event(HC_EVENT_POSTLOAD);
}
Esempio n. 15
0
/** Called prio to stack initialization */
static void preload(TRANSAC transac)
{
    BTHCDBG("preload");
    bthc_signal_event(HC_EVENT_PRELOAD);
}
Esempio n. 16
0
static void ssr_cleanup (void) {
    BTHCDBG("ssr_cleanup");
    /* Calling vendor-specific part */
    if (bt_vnd_if)
        bt_vnd_if->ssr_cleanup();
}