예제 #1
0
static void post_command(low_power_command_t command) {
  if (command > LPM_WAKE_DEASSERT) {
    LOG_ERROR(LOG_TAG, "%s unknown low power command %d", __func__, command);
    return;
  }

  thread_post(thread, event_functions[command], NULL);
}
void bthc_idle_timeout(void) {
  pthread_mutex_lock(&hc_cb.worker_thread_lock);

  if (hc_cb.worker_thread)
    thread_post(hc_cb.worker_thread, event_lpm_idle_timeout, NULL);

  pthread_mutex_unlock(&hc_cb.worker_thread_lock);
}
void bthc_rx_ready(void) {
  pthread_mutex_lock(&hc_cb.worker_thread_lock);

  if (hc_cb.worker_thread)
    thread_post(hc_cb.worker_thread, event_rx, NULL);

  pthread_mutex_unlock(&hc_cb.worker_thread_lock);
}
/** 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;
}
예제 #5
0
static void run_wrapped_start_up(void *context) {
  assert(context);

  callbacked_wrapper_t *wrapper = context;
  wrapper->success = module_start_up(wrapper->module);

  // Post the result back to the callback
  thread_post(wrapper->callback_thread, post_result_to_callback, wrapper);
}
void bthc_tx(HC_BT_HDR *buf) {
  pthread_mutex_lock(&hc_cb.worker_thread_lock);

  if (hc_cb.worker_thread) {
    if (buf)
      utils_enqueue(&tx_q, buf);
    thread_post(hc_cb.worker_thread, event_tx, NULL);
  }

  pthread_mutex_unlock(&hc_cb.worker_thread_lock);
}
/** Configure low power mode wake state */
static int lpm(bt_hc_low_power_event_t event)
{
    switch (event)
    {
        case BT_HC_LPM_DISABLE:
            thread_post(hc_cb.worker_thread, event_lpm_disable, NULL);
            break;

        case BT_HC_LPM_ENABLE:
            thread_post(hc_cb.worker_thread, event_lpm_enable, NULL);
            break;

        case BT_HC_LPM_WAKE_ASSERT:
            thread_post(hc_cb.worker_thread, event_lpm_wake_device, NULL);
            break;

        case BT_HC_LPM_WAKE_DEASSERT:
            thread_post(hc_cb.worker_thread, event_lpm_allow_sleep, NULL);
            break;
    }
    return BT_HC_STATUS_SUCCESS;
}
예제 #8
0
void module_start_up_callbacked_wrapper(
    const module_t *module,
    thread_t *callback_thread,
    thread_fn callback) {
  callbacked_wrapper_t *wrapper = osi_calloc(sizeof(callbacked_wrapper_t));

  wrapper->module = module;
  wrapper->lifecycle_thread = thread_new("module_wrapper");
  wrapper->callback_thread = callback_thread;
  wrapper->callback = callback;

  // Run the actual module start up
  thread_post(wrapper->lifecycle_thread, run_wrapped_start_up, wrapper);
}
// 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;
}
예제 #10
0
static future_t *shut_down() {
  LOG_INFO(LOG_TAG, "%s", __func__);

  hci_inject->close();

  if (thread) {
    if (firmware_is_configured) {
      non_repeating_timer_restart(epilog_timer);
      thread_post(thread, event_epilog, NULL);
    } else {
      thread_stop(thread);
    }

    thread_join(thread);
  }

  fixed_queue_free(command_queue, buffer_allocator->free);
  fixed_queue_free(packet_queue, buffer_allocator->free);
  list_free(commands_pending_response);

  pthread_mutex_destroy(&commands_pending_response_lock);

  packet_fragmenter->cleanup();

  non_repeating_timer_free(epilog_timer);
  non_repeating_timer_free(command_response_timer);
  non_repeating_timer_free(startup_timer);

  epilog_timer = NULL;
  command_response_timer = NULL;

  low_power_manager->cleanup();
  hal->close();

  // Turn off the chip
  int power_state = BT_VND_PWR_OFF;
  vendor->send_command(VENDOR_CHIP_POWER_CONTROL, &power_state);
  vendor->close();

  thread_free(thread);
  thread = NULL;
  firmware_is_configured = false;

  return NULL;
}
예제 #11
0
static bool lazy_initialize(void) {
  assert(alarms == NULL);

  pthread_mutex_init(&monitor, NULL);

  alarms = list_new(NULL);
  if (!alarms) {
    LOG_ERROR("%s unable to allocate alarm list.", __func__);
    return false;
  }

  struct sigevent sigevent;
  memset(&sigevent, 0, sizeof(sigevent));
  sigevent.sigev_notify = SIGEV_THREAD;
  sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
  if (timer_create(CLOCK_ID, &sigevent, &timer) == -1) {
    LOG_ERROR("%s unable to create timer: %s", __func__, strerror(errno));
    return false;
  }

  alarm_expired = semaphore_new(0);
  if (!alarm_expired) {
    LOG_ERROR("%s unable to create alarm expired semaphore", __func__);
    return false;
  }

  callback_thread_active = true;
  callback_thread = thread_new("alarm_callbacks");
  if (!callback_thread) {
    LOG_ERROR("%s unable to create alarm callback thread.", __func__);
    return false;
  }

  thread_set_priority(callback_thread, CALLBACK_THREAD_PRIORITY_HIGH);
  thread_post(callback_thread, callback_dispatch, NULL);
  return true;
}
/** Called post stack initialization */
static void postload(UNUSED_ATTR TRANSAC transac) {
  BTHCDBG("postload");
  thread_post(hc_cb.worker_thread, event_postload, NULL);
}
예제 #13
0
static void idle_timer_expired(UNUSED_ATTR void *context) {
  if (state == LPM_ENABLED && wake_state == LPM_WAKE_W4_TIMEOUT)
    thread_post(thread, event_idle_timeout, NULL);
}
예제 #14
0
static void do_postload() {
  LOG_DEBUG(LOG_TAG, "%s posting postload work item", __func__);
  thread_post(thread, event_postload, NULL);
}
예제 #15
0
static future_t *start_up(void) {
  LOG_INFO(LOG_TAG, "%s", __func__);

  // The host is only allowed to send at most one command initially,
  // as per the Bluetooth spec, Volume 2, Part E, 4.4 (Command Flow Control)
  // This value can change when you get a command complete or command status event.
  command_credits = 1;
  firmware_is_configured = false;

  pthread_mutex_init(&commands_pending_response_lock, NULL);

  // TODO(armansito): cutils/properties.h is only being used to pull-in runtime
  // settings on Android. Remove this conditional include once we have a generic
  // way to obtain system properties. For now, always use the default timeout on
  // non-Android builds.
  period_ms_t startup_timeout_ms = DEFAULT_STARTUP_TIMEOUT_MS;

#if !defined(OS_GENERIC)
  // Grab the override startup timeout ms, if present.
  char timeout_prop[PROPERTY_VALUE_MAX];
  if (!property_get("bluetooth.enable_timeout_ms", timeout_prop, STRING_VALUE_OF(DEFAULT_STARTUP_TIMEOUT_MS))
      || (startup_timeout_ms = atoi(timeout_prop)) < 100)
    startup_timeout_ms = DEFAULT_STARTUP_TIMEOUT_MS;
#endif  // !defined(OS_GENERIC)

  startup_timer = non_repeating_timer_new(startup_timeout_ms, startup_timer_expired, NULL);
  if (!startup_timer) {
    LOG_ERROR(LOG_TAG, "%s unable to create startup timer.", __func__);
    goto error;
  }

  // Make sure we run in a bounded amount of time
  non_repeating_timer_restart(startup_timer);

  epilog_timer = non_repeating_timer_new(EPILOG_TIMEOUT_MS, epilog_timer_expired, NULL);
  if (!epilog_timer) {
    LOG_ERROR(LOG_TAG, "%s unable to create epilog timer.", __func__);
    goto error;
  }

  command_response_timer = non_repeating_timer_new(COMMAND_PENDING_TIMEOUT, command_timed_out, NULL);
  if (!command_response_timer) {
    LOG_ERROR(LOG_TAG, "%s unable to create command response timer.", __func__);
    goto error;
  }

  command_queue = fixed_queue_new(SIZE_MAX);
  if (!command_queue) {
    LOG_ERROR(LOG_TAG, "%s unable to create pending command queue.", __func__);
    goto error;
  }

  packet_queue = fixed_queue_new(SIZE_MAX);
  if (!packet_queue) {
    LOG_ERROR(LOG_TAG, "%s unable to create pending packet queue.", __func__);
    goto error;
  }

  thread = thread_new("hci_thread");
  if (!thread) {
    LOG_ERROR(LOG_TAG, "%s unable to create thread.", __func__);
    goto error;
  }

  commands_pending_response = list_new(NULL);
  if (!commands_pending_response) {
    LOG_ERROR(LOG_TAG, "%s unable to create list for commands pending response.", __func__);
    goto error;
  }

  memset(incoming_packets, 0, sizeof(incoming_packets));

  packet_fragmenter->init(&packet_fragmenter_callbacks);

  fixed_queue_register_dequeue(command_queue, thread_get_reactor(thread), event_command_ready, NULL);
  fixed_queue_register_dequeue(packet_queue, thread_get_reactor(thread), event_packet_ready, NULL);

  vendor->open(btif_local_bd_addr.address, &interface);
  hal->init(&hal_callbacks, thread);
  low_power_manager->init(thread);

  vendor->set_callback(VENDOR_CONFIGURE_FIRMWARE, firmware_config_callback);
  vendor->set_callback(VENDOR_CONFIGURE_SCO, sco_config_callback);
  vendor->set_callback(VENDOR_DO_EPILOG, epilog_finished_callback);

  if (!hci_inject->open(&interface)) {
    // TODO(sharvil): gracefully propagate failures from this layer.
  }

  int power_state = BT_VND_PWR_OFF;
#if (defined (BT_CLEAN_TURN_ON_DISABLED) && BT_CLEAN_TURN_ON_DISABLED == TRUE)
  LOG_WARN(LOG_TAG, "%s not turning off the chip before turning on.", __func__);
  // So apparently this hack was needed in the past because a Wingray kernel driver
  // didn't handle power off commands in a powered off state correctly.

  // The comment in the old code said the workaround should be removed when the
  // problem was fixed. Sadly, I have no idea if said bug was fixed or if said
  // kernel is still in use, so we must leave this here for posterity. #sadpanda
#else
  // cycle power on the chip to ensure it has been reset
  vendor->send_command(VENDOR_CHIP_POWER_CONTROL, &power_state);
#endif
  power_state = BT_VND_PWR_ON;
  vendor->send_command(VENDOR_CHIP_POWER_CONTROL, &power_state);

  startup_future = future_new();
  LOG_DEBUG(LOG_TAG, "%s starting async portion", __func__);
  thread_post(thread, event_finish_startup, NULL);
  return startup_future;
error:;
  shut_down(); // returns NULL so no need to wait for it
  return future_new_immediate(FUTURE_FAIL);
}