static void transmit_command( BT_HDR *command, command_complete_cb complete_callback, command_status_cb status_callback, void *context) { uint8_t *stream; waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); if (!wait_entry) { LOG_ERROR("%s couldn't allocate space for wait entry.", __func__); return; } stream = command->data + command->offset; STREAM_TO_UINT16(wait_entry->opcode, stream); wait_entry->complete_callback = complete_callback; wait_entry->status_callback = status_callback; wait_entry->command = command; wait_entry->context = context; // Store the command message type in the event field // in case the upper layer didn't already command->event = MSG_STACK_TO_HC_HCI_CMD; LOG_DEBUG("HCI Enqueue Comamnd opcode=0x%x\n", wait_entry->opcode); BTTRC_DUMP_BUFFER(NULL, command->data + command->offset, command->len); fixed_queue_enqueue(hci_host_env.command_queue, wait_entry); hci_host_task_post(); }
static void transmit_downward(uint16_t type, void *data) { if (type == MSG_STACK_TO_HC_HCI_CMD) { transmit_command((BT_HDR *)data, NULL, NULL, NULL); LOG_WARN("%s legacy transmit of command. Use transmit_command instead.\n", __func__); } else { fixed_queue_enqueue(hci_host_env.packet_queue, data); } //ke_event_set(KE_EVENT_HCI_HOST_THREAD); hci_host_task_post(); }
static void transmit_downward(uint16_t type, void *data) { if (type == MSG_STACK_TO_HC_HCI_CMD) { transmit_command((BT_HDR *)data, NULL, NULL, NULL); HCI_TRACE_WARNING("%s legacy transmit of command. Use transmit_command instead.\n", __func__); } else { fixed_queue_enqueue(hci_host_env.packet_queue, data); } hci_host_task_post(TASK_POST_BLOCKING); }
static future_t *transmit_command_futured(BT_HDR *command) { waiting_command_t *wait_entry = osi_calloc(sizeof(waiting_command_t)); assert(wait_entry != NULL); future_t *future = future_new(); uint8_t *stream = command->data + command->offset; STREAM_TO_UINT16(wait_entry->opcode, stream); wait_entry->complete_future = future; wait_entry->command = command; // Store the command message type in the event field // in case the upper layer didn't already command->event = MSG_STACK_TO_HC_HCI_CMD; fixed_queue_enqueue(hci_host_env.command_queue, wait_entry); hci_host_task_post(); return future; }
// Returns true if the event was intercepted and should not proceed to // higher layers. Also inspects an incoming event for interesting // information, like how many commands are now able to be sent. static bool filter_incoming_event(BT_HDR *packet) { waiting_command_t *wait_entry = NULL; uint8_t *stream = packet->data + packet->offset; uint8_t event_code; command_opcode_t opcode; STREAM_TO_UINT8(event_code, stream); STREAM_SKIP_UINT8(stream); // Skip the parameter total length field LOG_DEBUG("Receive packet event_code=0x%x\n", event_code); if (event_code == HCI_COMMAND_COMPLETE_EVT) { STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT16(opcode, stream); wait_entry = get_waiting_command(opcode); if (!wait_entry) { LOG_WARN("%s command complete event with no matching command. opcode: 0x%x.", __func__, opcode); } else if (wait_entry->complete_callback) { wait_entry->complete_callback(packet, wait_entry->context); } else if (wait_entry->complete_future) { future_ready(wait_entry->complete_future, packet); } goto intercepted; } else if (event_code == HCI_COMMAND_STATUS_EVT) { uint8_t status; STREAM_TO_UINT8(status, stream); STREAM_TO_UINT8(hci_host_env.command_credits, stream); STREAM_TO_UINT16(opcode, stream); // If a command generates a command status event, it won't be getting a command complete event wait_entry = get_waiting_command(opcode); if (!wait_entry) { LOG_WARN("%s command status event with no matching command. opcode: 0x%x", __func__, opcode); } else if (wait_entry->status_callback) { wait_entry->status_callback(status, wait_entry->command, wait_entry->context); } goto intercepted; } return false; intercepted: restart_comamnd_waiting_response_timer(&hci_host_env.cmd_waiting_q, false); /*Tell HCI Host Task to continue TX Pending commands*/ if (hci_host_env.command_credits && !fixed_queue_is_empty(hci_host_env.command_queue)) { hci_host_task_post(); } //ke_event_set(KE_EVENT_HCI_HOST_THREAD); if (wait_entry) { // If it has a callback, it's responsible for freeing the packet if (event_code == HCI_COMMAND_STATUS_EVT || (!wait_entry->complete_callback && !wait_entry->complete_future)) { buffer_allocator->free(packet); } // If it has a callback, it's responsible for freeing the command if (event_code == HCI_COMMAND_COMPLETE_EVT || !wait_entry->status_callback) { buffer_allocator->free(wait_entry->command); } osi_free(wait_entry); } else { buffer_allocator->free(packet); } return true; }