1. 程式人生 > >Bluedroid: 藍芽協議棧原始碼剖析

Bluedroid: 藍芽協議棧原始碼剖析

一、 基礎知識介紹

1.縮略語

BTIF: Bluetooth Interface 

BTU : Bluetooth Upper Layer 

BTM: Bluetooth Manager 

BTE: Bluetooth embedded system 

BTA :Blueetooth application layer 

CO: call out\CI: call in 

HF : Handsfree Profile 

HH: HID Host Profile 

HL: Health Device Profile

V:audio\vidio 

ag: audio gateway

r: audio/video registration 

gattc: GATT client 

BLE: Bluetooth Low Energy

2.藍芽協議棧框架圖:

1.基帶層(BB)提供了兩種不同的物理鏈路(同步面向連線鏈路SCO Synchronous Connection Oriented和非同步無連線鏈路ACL Asynchronous Connection Less),負責跳頻和藍芽資料及資訊幀的傳輸,且對所有型別的資料包提供了不同層次的前向糾錯碼(FEC Frequency Error Correction)或迴圈沉餘度差錯校驗(CTC Cyclic Redundancy Check);

2.LMP層負責兩個或多個裝置鏈路的建立和拆除及鏈路的安全和控制,如鑑權和加密、控制和協商基帶包的大小等,它為上層軟體模組提供了不同的訪問入口;

3.藍芽主機控制器介面HCI (Host Controller Interface)由基帶控制器、連線管理器、控制和事件暫存器等組成。它是藍芽協議中軟硬體之間的介面,它提供了一個呼叫下層BB、LM、狀態和控制暫存器等硬體的統一命令,上、下兩個模組介面之間的訊息和資料的傳遞必須通過HCI的解釋才能進行。HCI層以上的協議軟體實體執行在主機上,而HCI以下的功能由藍芽裝置耒完成,二者之間通過傳輸層進行互動。 

4.中間協議層由邏輯鏈路控制與適配協議L2CAP (Logical Link Control and Adaptation Protocol)、服務發現協議 SDP (Service Discovery Protocol)、串列埠模擬協議或稱線纜替換協議 RFCOM 和二進位制電話控制協議 TCS (Telephony Control protocol Spectocol)組成。

L2CAP 是藍芽協議棧的核心組成部分,也是其它協議實現的基礎。它位於基帶之上,向上層提供面向連線的和無連線的資料服務。它主要完成資料的拆裝、服務質量控制,協議的複用、分組的分割和重組(Segmentation And Reassembly)及組提取等功能。L2CAP允許高達64KB的資料分組。

5.SDP是一個基於客戶/伺服器結構的協議。它工作在 L2CAP層之上,為上層應用程式提供一種機制來發現可用的服務及其屬性,而服務的屬性包括服務的型別及該服務所需的機制或協議資訊。

6.RFCOMM 是一個模擬有線鏈路的無線資料模擬協議,符合ETSI 標準的 TS 07.10串列埠模擬協議。它在藍芽基帶上模擬RS-232的控制和資料訊號,為原先使用序列連線的上層業務提供傳送能力。

7.TCS是一個基於 ITU-T Q.931 建議的採用面向位元的協議,它定義了用於藍芽裝置之間建立語音和資料呼叫的控制信令(Call Control Signalling),並負責處理藍芽裝置組的移動管理過程。 

 

整個bluedroid可以分為兩大模組:BTIF,BTE

BTIF:提供bluedroid對外的介面

BTE:bluedroid的內部處理,又細分為BTA,BTU,BTM和HCI

BTA:bluedroid中各profile的邏輯實現和處理

BTU:承接BTA與HCI

BTM:藍芽配對與鏈路管理

HCI:讀取或寫入資料到藍芽hw

二、程式碼分析(寫hidraw節點資料流程):

1.初始化:

external\bluetooth\bluedroid\btif\src\bluetooth.c 

複製程式碼

static const bt_interface_t bluetoothInterface = {
    sizeof(bluetoothInterface),
    init,
    enable,
    disable,
    cleanup,
    get_adapter_properties,
    get_adapter_property,
    set_adapter_property,
    get_remote_device_properties,
    get_remote_device_property,
    set_remote_device_property,
    get_remote_service_record,
    get_remote_services,
    start_discovery,
    cancel_discovery,
    create_bond,
    remove_bond,
    cancel_bond,
    get_connection_state,
    pin_reply,
    ssp_reply,
    get_profile_interface, //根據profile獲得對應的介面
    dut_mode_configure,
    dut_mode_send,
#if BLE_INCLUDED == TRUE
    le_test_mode,
#else
    NULL,
#endif
    config_hci_snoop_log,
    set_os_callouts,
    read_energy_info,
};

......
if (is_profile(profile_id, BT_PROFILE_HIDHOST_ID))
        return btif_hh_get_interface(); //獲得HID Host Profile  

複製程式碼

external\bluetooth\bluedroid\btif\src\btif_hh.c

複製程式碼

static const bthh_interface_t bthhInterface = {
    sizeof(bthhInterface),
    init,
    connect,
    disconnect,
    virtual_unplug,
    set_info,
    get_protocol,
    set_protocol,
//    get_idle_time,
//    set_idle_time,
    get_report,
    set_report,
    send_data,
    cleanup,
};

複製程式碼

init函式裡註冊傳入的回撥函式:

複製程式碼

/*******************************************************************************
**
** Function         btif_hh_init
**
** Description     initializes the hh interface
**
** Returns         bt_status_t
**
*******************************************************************************/
static bt_status_t init( bthh_callbacks_t* callbacks )
{
    UINT32 i;
    BTIF_TRACE_EVENT("%s", __FUNCTION__);

    bt_hh_callbacks = callbacks;
    memset(&btif_hh_cb, 0, sizeof(btif_hh_cb));
    for (i = 0; i < BTIF_HH_MAX_HID; i++){
        btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN;
    }
    /* Invoke the enable service API to the core to set the appropriate service_id */
    btif_enable_service(BTA_HID_SERVICE_ID);
    return BT_STATUS_SUCCESS;
}

複製程式碼

external\bluetooth\bluedroid\btif\src\btif_core.c

複製程式碼

/*******************************************************************************
**
** Function         btif_enable_service
**
** Description      Enables the service 'service_ID' to the service_mask.
**                  Upon BT enable, BTIF core shall invoke the BTA APIs to
**                  enable the profiles
**
** Returns          bt_status_t
**
*******************************************************************************/
bt_status_t btif_enable_service(tBTA_SERVICE_ID service_id)
{
    tBTA_SERVICE_ID *p_id = &service_id;

    /* If BT is enabled, we need to switch to BTIF context and trigger the
     * enable for that profile
     *
     * Otherwise, we just set the flag. On BT_Enable, the DM will trigger
     * enable for the profiles that have been enabled */

    btif_enabled_services |= (1 << service_id);

    BTIF_TRACE_DEBUG("%s: current services:0x%x", __FUNCTION__, btif_enabled_services);

    if (btif_is_enabled())
    {    //註冊回撥,傳送訊息
        btif_transfer_context(btif_dm_execute_service_request,
                              BTIF_DM_ENABLE_SERVICE,
                              (char*)p_id, sizeof(tBTA_SERVICE_ID), NULL);
    }

    return BT_STATUS_SUCCESS;
}

複製程式碼

2.建立執行緒和準備啟動排程:

複製程式碼

/*******************************************************************************
**
** Function         btif_init_bluetooth
**
** Description      Creates BTIF task and prepares BT scheduler for startup
**
** Returns          bt_status_t
**
*******************************************************************************/

bt_status_t btif_init_bluetooth()
{
    UINT8 status;
    btif_config_init();
    bte_main_boot_entry();

    /* As part of the init, fetch the local BD ADDR */
    memset(&btif_local_bd_addr, 0, sizeof(bt_bdaddr_t));
    btif_fetch_local_bdaddr(&btif_local_bd_addr);

    /* start btif task */
    status = GKI_create_task(btif_task, BTIF_TASK, BTIF_TASK_STR,
                (UINT16 *) ((UINT8 *)btif_task_stack + BTIF_TASK_STACK_SIZE),
                sizeof(btif_task_stack));

    if (status != GKI_SUCCESS)
        return BT_STATUS_FAIL;

    return BT_STATUS_SUCCESS;
}

複製程式碼

處理執行緒函式:

複製程式碼

/*******************************************************************************
**
** Function         btif_task
**
** Description      BTIF task handler managing all messages being passed
**                  Bluetooth HAL and BTA.
**
** Returns          void
**
*******************************************************************************/

static void btif_task(UINT32 params)
{
    UINT16   event;
    BT_HDR   *p_msg;
    UNUSED(params);

    BTIF_TRACE_DEBUG("btif task starting");

    btif_associate_evt();

    for(;;)
    {
        /* wait for specified events */
        event = GKI_wait(0xFFFF, 0);

        /*
         * Wait for the trigger to init chip and stack. This trigger will
         * be received by btu_task once the UART is opened and ready
         */
        if (event == BT_EVT_TRIGGER_STACK_INIT)
        {
            BTIF_TRACE_DEBUG("btif_task: received trigger stack init event");
            #if (BLE_INCLUDED == TRUE)
            btif_dm_load_ble_local_keys();
            #endif
            BTA_EnableBluetooth(bte_dm_evt);
        }

        /*
         * Failed to initialize controller hardware, reset state and bring
         * down all threads
         */
        if (event == BT_EVT_HARDWARE_INIT_FAIL)
        {
            BTIF_TRACE_DEBUG("btif_task: hardware init failed");
            bte_main_disable();
            btif_queue_release();
            GKI_task_self_cleanup(BTIF_TASK);
            bte_main_shutdown();
            btif_dut_mode = 0;
            btif_core_state = BTIF_CORE_STATE_DISABLED;
            HAL_CBACK(bt_hal_cbacks,adapter_state_changed_cb,BT_STATE_OFF);
            break;
        }

        if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
            break;

        if(event & TASK_MBOX_1_EVT_MASK)
        {
            while((p_msg = GKI_read_mbox(BTU_BTIF_MBOX)) != NULL) //讀取訊息
            {
                BTIF_TRACE_VERBOSE("btif task fetched event %x", p_msg->event);

                switch (p_msg->event)
                {
                    case BT_EVT_CONTEXT_SWITCH_EVT:
                        btif_context_switched(p_msg); //傳遞訊息給註冊的回撥函式
                        break;
                    default:
                        BTIF_TRACE_ERROR("unhandled btif event (%d)", p_msg->event & BT_EVT_MASK);
                        break;
                }

                GKI_freebuf(p_msg);
            }
        }
    }

    btif_disassociate_evt();

    BTIF_TRACE_DEBUG("btif task exiting");
}

複製程式碼

之前先開啟了藍芽服務:

複製程式碼

/*******************************************************************************
**
** Function         BTA_EnableBluetooth
**
** Description      Enables bluetooth service.  This function must be
**                  called before any other functions in the BTA API are called.
**
**
** Returns          tBTA_STATUS
**
*******************************************************************************/
tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback)
{

    tBTA_DM_API_ENABLE    *p_msg;

    /* Bluetooth disabling is in progress */
    if (bta_dm_cb.disabling)
        return BTA_FAILURE;

    memset(&bta_dm_cb, 0, sizeof(bta_dm_cb));

    bta_sys_register (BTA_ID_DM, &bta_dm_reg );
    bta_sys_register (BTA_ID_DM_SEARCH, &bta_dm_search_reg );

    /* if UUID list is not provided as static data */
    bta_sys_eir_register(bta_dm_eir_update_uuid);

    if ((p_msg = (tBTA_DM_API_ENABLE *) GKI_getbuf(sizeof(tBTA_DM_API_ENABLE))) != NULL)
    {
        p_msg->hdr.event = BTA_DM_API_ENABLE_EVT;
        p_msg->p_sec_cback = p_cback;
        bta_sys_sendmsg(p_msg);
        return BTA_SUCCESS;
    }
    return BTA_FAILURE;

}

複製程式碼

external\bluetooth\bluedroid\btif\src\btif_dm.c

根據訊息請求對應服務:

複製程式碼

void btif_dm_execute_service_request(UINT16 event, char *p_param)
{
    BOOLEAN b_enable = FALSE;
    bt_status_t status;
    if (event == BTIF_DM_ENABLE_SERVICE)
    {
        b_enable = TRUE;
    }
    status = btif_in_execute_service_request(*((tBTA_SERVICE_ID*)p_param), b_enable); //執行服務請求
    if (status == BT_STATUS_SUCCESS)
    {
        bt_property_t property;
        bt_uuid_t local_uuids[BT_MAX_NUM_UUIDS];

        /* Now send the UUID_PROPERTY_CHANGED event to the upper layer */
        BTIF_STORAGE_FILL_PROPERTY(&property, BT_PROPERTY_UUIDS,
                                    sizeof(local_uuids), local_uuids);
        btif_storage_get_adapter_property(&property);
        HAL_CBACK(bt_hal_cbacks, adapter_properties_cb,
                          BT_STATUS_SUCCESS, 1, &property);
    }
    return;
}

複製程式碼

執行A2DP/HID/HFP等服務

複製程式碼

bt_status_t btif_in_execute_service_request(tBTA_SERVICE_ID service_id,
                                                BOOLEAN b_enable)
{
    /* Check the service_ID and invoke the profile's BT state changed API */
    switch (service_id)
    {
         case BTA_HFP_SERVICE_ID:
         case BTA_HSP_SERVICE_ID:
         {
              btif_hf_execute_service(b_enable);
         }break;
         case BTA_A2DP_SERVICE_ID:
         {
              btif_av_execute_service(b_enable);
         }break;
         case BTA_HID_SERVICE_ID:
         {
              btif_hh_execute_service(b_enable);
         }break;
         case BTA_HFP_HS_SERVICE_ID:
         {
             btif_hf_client_execute_service(b_enable);
         }break;
         case BTA_MAP_SERVICE_ID:
         {
             btif_mce_execute_service(b_enable);
         }break;
         default:
              BTIF_TRACE_ERROR("%s: Unknown service being enabled", __FUNCTION__);
              return BT_STATUS_FAIL;
    }
    return BT_STATUS_SUCCESS;
}

複製程式碼

external\bluetooth\bluedroid\btif\src\btif_hh.c

啟動/關閉 HID服務

複製程式碼

/*******************************************************************************
**
** Function         btif_hh_execute_service
**
** Description      Initializes/Shuts down the service
**
** Returns          BT_STATUS_SUCCESS on success, BT_STATUS_FAIL otherwise
**
*******************************************************************************/
bt_status_t btif_hh_execute_service(BOOLEAN b_enable)
{
     if (b_enable)
     {
          /* Enable and register with BTA-HH */
          BTA_HhEnable(BTA_SEC_ENCRYPT, bte_hh_evt);
     }
     else {
         /* Disable HH */
         BTA_HhDisable();
     }
     return BT_STATUS_SUCCESS;
}

複製程式碼

external\bluetooth\bluedroid\bta\hh\bta_hh_api.c

複製程式碼

/*******************************************************************************
**
** Function         BTA_HhEnable
**
** Description      Enable the HID host.  This function must be called before
**                  any other functions in the HID host API are called. When the
**                  enable operation is complete the callback function will be
**                  called with BTA_HH_ENABLE_EVT.
**
**
** Returns          void
**
*******************************************************************************/
void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK *p_cback)
{
    tBTA_HH_API_ENABLE *p_buf;

    /* register with BTA system manager */
    bta_sys_register(BTA_ID_HH, &bta_hh_reg); //註冊主處理函式

    APPL_TRACE_ERROR("Calling BTA_HhEnable");
    p_buf = (tBTA_HH_API_ENABLE *)GKI_getbuf((UINT16)sizeof(tBTA_HH_API_ENABLE));

    if (p_buf != NULL)
    {
        memset(p_buf, 0, sizeof(tBTA_HH_API_ENABLE));

        p_buf->hdr.event = BTA_HH_API_ENABLE_EVT;
        p_buf->p_cback = p_cback;
        p_buf->sec_mask = sec_mask;

        bta_sys_sendmsg(p_buf);
    }
}

複製程式碼


external\bluetooth\bluedroid\btif\co\bta_hh_co.c

HID Host Profile 部分初始化,建立HID事件監聽執行緒:btif_hh_poll_event_thread

複製程式碼

/*******************************************************************************
**
** Function      bta_hh_co_open
**
** Description   When connection is opened, this call-out function is executed
**               by HH to do platform specific initialization.
**
** Returns       void.
*******************************************************************************/
void bta_hh_co_open(UINT8 dev_handle, UINT8 sub_class, tBTA_HH_ATTR_MASK attr_mask,
                    UINT8 app_id)
{
    UINT32 i;
    btif_hh_device_t *p_dev = NULL;

    if (dev_handle == BTA_HH_INVALID_HANDLE) {
        APPL_TRACE_WARNING("%s: Oops, dev_handle (%d) is invalid...", __FUNCTION__, dev_handle);
        return;
    }

    for (i = 0; i < BTIF_HH_MAX_HID; i++) {
        p_dev = &btif_hh_cb.devices[i];
        if (p_dev->dev_status != BTHH_CONN_STATE_UNKNOWN && p_dev->dev_handle == dev_handle) {
            // We found a device with the same handle. Must be a device reconnected.
            APPL_TRACE_WARNING("%s: Found an existing device with the same handle "
                                                                "dev_status = %d",__FUNCTION__,
                                                                p_dev->dev_status);
            APPL_TRACE_WARNING("%s:     bd_addr = [%02X:%02X:%02X:%02X:%02X:]", __FUNCTION__,
                 p_dev->bd_addr.address[0], p_dev->bd_addr.address[1], p_dev->bd_addr.address[2],
                 p_dev->bd_addr.address[3], p_dev->bd_addr.address[4]);
                 APPL_TRACE_WARNING("%s:     attr_mask = 0x%04x, sub_class = 0x%02x, app_id = %d",
                                  __FUNCTION__, p_dev->attr_mask, p_dev->sub_class, p_dev->app_id);

            if(p_dev->fd<0) {
                p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
                if (p_dev->fd < 0){
                    APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
                                                                    __FUNCTION__,strerror(errno));
                }else
                    APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
            }
            p_dev->hh_keep_polling = 1;
            p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
            break;
        }
        p_dev = NULL;
    }

    if (p_dev == NULL) {
        // Did not find a device reconnection case. Find an empty slot now.
        for (i = 0; i < BTIF_HH_MAX_HID; i++) {
            if (btif_hh_cb.devices[i].dev_status == BTHH_CONN_STATE_UNKNOWN) {
                p_dev = &btif_hh_cb.devices[i];
                p_dev->dev_handle = dev_handle;
                p_dev->attr_mask  = attr_mask;
                p_dev->sub_class  = sub_class;
                p_dev->app_id     = app_id;
                p_dev->local_vup  = FALSE;

                btif_hh_cb.device_num++;
                // This is a new device,open the uhid driver now.
                p_dev->fd = open(dev_path, O_RDWR | O_CLOEXEC);
                if (p_dev->fd < 0){
                    APPL_TRACE_ERROR("%s: Error: failed to open uhid, err:%s",
                                                                    __FUNCTION__,strerror(errno));
                }else{
                    APPL_TRACE_DEBUG("%s: uhid fd = %d", __FUNCTION__, p_dev->fd);
                    p_dev->hh_keep_polling = 1;
                    p_dev->hh_poll_thread_id = create_thread(btif_hh_poll_event_thread, p_dev);
                }


                break;
            }
        }
    }

    if (p_dev == NULL) {
        APPL_TRACE_ERROR("%s: Error: too many HID devices are connected", __FUNCTION__);
        return;
    }

    p_dev->dev_status = BTHH_CONN_STATE_CONNECTED;
    APPL_TRACE_DEBUG("%s: Return device status %d", __FUNCTION__, p_dev->dev_status);
}

複製程式碼


poll監聽HID驅動的事件:

複製程式碼

/*******************************************************************************
**
** Function btif_hh_poll_event_thread
**
** Description the polling thread which polls for event from UHID driver
**
** Returns void
**
*******************************************************************************/
static void *btif_hh_poll_event_thread(void *arg)
{

    btif_hh_device_t *p_dev = arg;
    APPL_TRACE_DEBUG("%s: Thread created fd = %d", __FUNCTION__, p_dev->fd);
    struct pollfd pfds[1];
    int ret;
    pfds[0].fd = p_dev->fd;
    pfds[0].events = POLLIN;

    while(p_dev->hh_keep_polling){
        ret = poll(pfds, 1, 50);
        if (ret < 0) {
            APPL_TRACE_ERROR("%s: Cannot poll for fds: %s\n", __FUNCTION__, strerror(errno));
            break;
        }
        if (pfds[0].revents & POLLIN) {
            APPL_TRACE_DEBUG("btif_hh_poll_event_thread: POLLIN");
            ret = uhid_event(p_dev);
            if (ret){
                break;
            }
        }
    }

    p_dev->hh_poll_thread_id = -1;
    return 0;
}

複製程式碼

 解析HID驅動的事件:

複製程式碼

/* Internal function to parse the events received from UHID driver*/
static int uhid_event(btif_hh_device_t *p_dev)
{
    struct uhid_event ev;
    ssize_t ret;
    memset(&ev, 0, sizeof(ev));
    if(!p_dev)
    {
        APPL_TRACE_ERROR("%s: Device not found",__FUNCTION__)
        return -1;
    }
    ret = read(p_dev->fd, &ev, sizeof(ev));
    if (ret == 0) {
        APPL_TRACE_ERROR("%s: Read HUP on uhid-cdev %s", __FUNCTION__,
                                                 strerror(errno));
        return -EFAULT;
    } else if (ret < 0) {
        APPL_TRACE_ERROR("%s:Cannot read uhid-cdev: %s", __FUNCTION__,
                                                strerror(errno));
        return -errno;
    } else if (ret != sizeof(ev)) {
        APPL_TRACE_ERROR("%s:Invalid size read from uhid-dev: %ld != %lu",
                            __FUNCTION__, ret, sizeof(ev));
        return -EFAULT;
    }

    switch (ev.type) {
    case UHID_START:
        APPL_TRACE_DEBUG("UHID_START from uhid-dev\n");
        break;
    case UHID_STOP:
        APPL_TRACE_DEBUG("UHID_STOP from uhid-dev\n");
        break;
    case UHID_OPEN:
        APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev\n");
        break;
    case UHID_CLOSE:
        APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev\n");
        break;
    case UHID_OUTPUT:
        APPL_TRACE_DEBUG("UHID_OUTPUT: Report type = %d, report_size = %d"
                            ,ev.u.output.rtype, ev.u.output.size);
        //Send SET_REPORT with feature report if the report type in output event is FEATURE
        if(ev.u.output.rtype == UHID_FEATURE_REPORT)
            btif_hh_setreport(p_dev,BTHH_FEATURE_REPORT,ev.u.output.size,ev.u.output.data);
        else if(ev.u.output.rtype == UHID_OUTPUT_REPORT)
            btif_hh_setreport(p_dev,BTHH_OUTPUT_REPORT,ev.u.output.size,ev.u.output.data);
        else
            btif_hh_setreport(p_dev,BTHH_INPUT_REPORT,ev.u.output.size,ev.u.output.data);
           break;
    case UHID_OUTPUT_EV:
        APPL_TRACE_DEBUG("UHID_OUTPUT_EV from uhid-dev\n");
        break;
    case UHID_FEATURE:
        APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev\n");
        break;
    case UHID_FEATURE_ANSWER:
        APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev\n");
        break;

    default:
        APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
    }

    return 0;
}

複製程式碼

 --->

複製程式碼

/*******************************************************************************
**
** Function         btif_btif_hh_setreport
**
** Description      setreport initiated from the BTIF thread context
**
** Returns          void
**
*******************************************************************************/
#define COMMAND_PATCH 
void btif_hh_setreport(btif_hh_device_t *p_dev, bthh_report_type_t r_type, UINT16 size,
                            UINT8* report)
{
    BT_HDR* p_buf = create_pbuf(size, report);
    if (p_buf == NULL) {
        APPL_TRACE_ERROR("%s: Error, failed to allocate RPT buffer, size = %d", __FUNCTION__, size);
        return;
    }
    
#ifdef COMMAND_PATCH 
        if(report[0] != 0x5B)     /*判斷report id!=0x5B,執行預設的request,需要response*/
                BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
        else{    /*判斷report id==0x5B,傳送command,不需要response*/
                BD_ADDR* bda = (BD_ADDR*)&p_dev->bd_addr;
                BTIF_TRACE_DEBUG("Send Command Size %",size);
                p_buf->layer_specific = BTA_HH_RPTT_OUTPUT;
                BTA_HhSendData(p_dev->dev_handle,*bda,p_buf);
        }
#else
        BTA_HhSetReport(p_dev->dev_handle, r_type, p_buf);
#endif
    
}

複製程式碼

傳送資料到HID裝置:

複製程式碼

/*******************************************************************************
**
** Function         BTA_HhSendData
**
** Description      This function send DATA transaction to HID device.
**
** Parameter        dev_handle: device handle
**                  dev_bda: remote device address
**                  p_data: data to be sent in the DATA transaction; or
**                          the data to be write into the Output Report of a LE HID
**                          device. The report is identified the report ID which is
**                          the value of the byte (UINT8 *)(p_buf + 1) + p_buf->offset.
**                          p_data->layer_specific needs to be set to the report type,
**                          it can be OUTPUT report, or FEATURE report.
**
** Returns          void
**
*******************************************************************************/
void BTA_HhSendData(UINT8 dev_handle, BD_ADDR dev_bda, BT_HDR  *p_data)
{
    UNUSED(dev_bda);
#if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE)
    if (p_data->layer_specific != BTA_HH_RPTT_OUTPUT)
    {
        APPL_TRACE_ERROR("ERROR! Wrong report type! Write Command only valid for output report!");
        return;
    }
#endif
    bta_hh_snd_write_dev(dev_handle, HID_TRANS_DATA, (UINT8)p_data->layer_specific, 0, 0, p_data);
}

複製程式碼

 -->

複製程式碼

/*******************************************************************************
**
** Function  bta_hh_snd_write_dev
**
*******************************************************************************/
static void bta_hh_snd_write_dev(UINT8 dev_handle, UINT8 t_type, UINT8 param,
                                 UINT16 data, UINT8 rpt_id, BT_HDR  *p_data)
{
    tBTA_HH_CMD_DATA *p_buf;
    UINT16          len = (UINT16) (sizeof(tBTA_HH_CMD_DATA) );

    if ((p_buf = (tBTA_HH_CMD_DATA *)GKI_getbuf(len))!= NULL)
    {
        memset(p_buf, 0, sizeof(tBTA_HH_CMD_DATA));

        p_buf->hdr.event = BTA_HH_API_WRITE_DEV_EVT;
        p_buf->hdr.layer_specific   = (UINT16) dev_handle;
        p_buf->t_type   = t_type;
        p_buf->data     = data;
        p_buf->param    = param;
        p_buf->p_data   = p_data;
        p_buf->rpt_id   = rpt_id;

        bta_sys_sendmsg(p_buf); //傳送資料到hid處理程序
    }
}

複製程式碼

external\bluetooth\bluedroid\bta\hh\bta_hh_main.c

BTA_HhEnable時註冊的HID主處理函式進行資料接收和處理:

複製程式碼

/*******************************************************************************
**
** Function         bta_hh_hdl_event
**
** Description      HID host main event handling function.
**
**
** Returns          void
**
*******************************************************************************/
BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg)
{
    UINT8           index = BTA_HH_IDX_INVALID;
    tBTA_HH_DEV_CB *p_cb = NULL;

    switch (p_msg->event)
    {
        case BTA_HH_API_ENABLE_EVT:
            bta_hh_api_enable((tBTA_HH_DATA *) p_msg);
            break;

        case BTA_HH_API_DISABLE_EVT:
            bta_hh_api_disable();
            break;

        case BTA_HH_DISC_CMPL_EVT:          /* disable complete */
            bta_hh_disc_cmpl();
            break;

        default:
            /* all events processed in state machine need to find corresponding
                CB before proceed */
            if (p_msg->event == BTA_HH_API_OPEN_EVT)
            {
                index = bta_hh_find_cb(((tBTA_HH_API_CONN *)p_msg)->bd_addr);
            }
            else if (p_msg->event == BTA_HH_API_MAINT_DEV_EVT)
            {
                /* if add device */
                if (((tBTA_HH_MAINT_DEV *)p_msg)->sub_event == BTA_HH_ADD_DEV_EVT)
                {
                    index = bta_hh_find_cb(((tBTA_HH_MAINT_DEV *)p_msg)->bda);
                }
                else /* else remove device by handle */
                {
                    index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);
// btla-specific ++
                    /* If BT disable is done while the HID device is connected and Link_Key uses unauthenticated combination
                      * then we can get into a situation where remove_bonding is called with the index set to 0 (without getting
                      * cleaned up). Only when VIRTUAL_UNPLUG is called do we cleanup the index and make it MAX_KNOWN.
                      * So if REMOVE_DEVICE is called and in_use is FALSE then we should treat this as a NULL p_cb. Hence we
                      * force the index to be IDX_INVALID
                      */
                    if ((index != BTA_HH_IDX_INVALID) &&
                        (bta_hh_cb.kdev[index].in_use == FALSE)) {
                        index = BTA_HH_IDX_INVALID;
                    }
// btla-specific --
                }
            }
            else if (p_msg->event == BTA_HH_INT_OPEN_EVT)
            {
                index = bta_hh_find_cb(((tBTA_HH_CBACK_DATA *)p_msg)->addr);
            }
            else
                index = bta_hh_dev_handle_to_cb_idx((UINT8)p_msg->layer_specific);

            if (index != BTA_HH_IDX_INVALID)
                p_cb = &bta_hh_cb.kdev[index];

#if BTA_HH_DEBUG
            APPL_TRACE_DEBUG("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", p_msg->layer_specific, index);
#endif
            bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg); //狀態機處理函式
    }
    return (TRUE);
}

複製程式碼

HID狀態機事件處理函式

複製程式碼

/*******************************************************************************
**
** Function         bta_hh_sm_execute
**
** Description      State machine event handling function for HID Host
**
**
** Returns          void
**
*******************************************************************************/
void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data)
{
    tBTA_HH_ST_TBL  state_table;
    UINT8           action;
    tBTA_HH         cback_data;
    tBTA_HH_EVT     cback_event = 0;
#if BTA_HH_DEBUG == TRUE
    tBTA_HH_STATE   in_state ;
    UINT16          debug_event = event;
#endif

    memset(&cback_data, 0, sizeof(tBTA_HH));

    /* handle exception, no valid control block was found */
    if (!p_cb)
    {
        /* BTA HH enabled already? otherwise ignore the event although it's bad*/
        if (bta_hh_cb.p_cback != NULL)
        {
            switch (event)
            {
            /* no control block available for new connection */
            case BTA_HH_API_OPEN_EVT:
                cback_event = BTA_HH_OPEN_EVT;
                /* build cback data */
                bdcpy(cback_data.conn.bda, ((tBTA_HH_API_CONN *)p_data)->bd_addr);
                cback_data.conn.status  = BTA_HH_ERR_DB_FULL;
                cback_data.conn.handle  = BTA_HH_INVALID_HANDLE;
                break;
            /* DB full, BTA_HhAddDev */
            case BTA_HH_API_MAINT_DEV_EVT:
                cback_event = p_data->api_maintdev.sub_event;

                if (p_data->api_maintdev.sub_event == BTA_HH_ADD_DEV_EVT)
                {
                    bdcpy(cback_data.dev_info.bda, p_data->api_maintdev.bda);
                    cback_data.dev_info.status    = BTA_HH_ERR_DB_FULL;
                    cback_data.dev_info.handle    = BTA_HH_INVALID_HANDLE;
                }
                else
                {
                    cback_data.dev_info.status    = BTA_HH_ERR_HDL;
                    cback_data.dev_info.handle    = (UINT8)p_data->api_maintdev.hdr.layer_specific;
                }
                break;
            case BTA_HH_API_WRITE_DEV_EVT:
                cback_event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
                        BTA_HH_FST_TRANS_CB_EVT;
                if (p_data->api_sndcmd.p_data != NULL)
                {
                    GKI_freebuf(p_data->api_sndcmd.p_data);
                }
                if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL ||
                    p_data->api_sndcmd.t_type == HID_TRANS_SET_REPORT ||
                    p_data->api_sndcmd.t_type == HID_TRANS_SET_IDLE)
                {
                    cback_data.dev_status.status = BTA_HH_ERR_HDL;
                    cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
                }
                else if (p_data->api_sndcmd.t_type != HID_TRANS_DATA &&
                    p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
                {
                    cback_data.hs_data.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
                    cback_data.hs_data.status = BTA_HH_ERR_HDL;
                    /* hs_data.rsp_data will be all zero, which is not valid value */
                }
                else if (p_data->api_sndcmd.t_type == HID_TRANS_CONTROL &&
                         p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
                {
                    cback_data.status = BTA_HH_ERR_HDL;
                    cback_event = BTA_HH_VC_UNPLUG_EVT;
                }
                else
                    cback_event = 0;
                break;

            case BTA_HH_API_CLOSE_EVT:
                cback_event = BTA_HH_CLOSE_EVT;

                cback_data.dev_status.status = BTA_HH_ERR_HDL;
                cback_data.dev_status.handle = (UINT8)p_data->api_sndcmd.hdr.layer_specific;
                break;

            default:
                /* invalid handle, call bad API event */
                APPL_TRACE_ERROR("wrong device handle: [%d]", p_data->hdr.layer_specific);
                /* Free the callback buffer now */
                if (p_data != NULL && p_data->hid_cback.p_data != NULL)
                {
                    GKI_freebuf(p_data->hid_cback.p_data);
                    p_data->hid_cback.p_data = NULL;
                }
                break;
            }
           if (cback_event)
               (* bta_hh_cb.p_cback)(cback_event, &cback_data);
        }
    }
    /* corresponding CB is found, go to state machine */
    else
    {
#if BTA_HH_DEBUG == TRUE
        in_state = p_cb->state;
        APPL_TRACE_EVENT("bta_hh_sm_execute: State 0x%02x [%s], Event [%s]",
                          in_state, bta_hh_state_code(in_state),
                          bta_hh_evt_code(debug_event));
#endif

        if ((p_cb->state == BTA_HH_NULL_ST) || (p_cb->state >= BTA_HH_INVALID_ST))
        {
            APPL_TRACE_ERROR("bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d",
                              p_cb->state,event);
            return;
        }
        state_table = bta_hh_st_tbl[p_cb->state - 1];

        event &= 0xff;

        p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ;

        if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE)
        {
            (*bta_hh_action[action])(p_cb, p_data); //各事件處理函式列表,寫節點為action(8)-> bta_hh_write_dev_act
        }

#if BTA_HH_DEBUG == TRUE
        if (in_state != p_cb->state)
        {
            APPL_TRACE_DEBUG("HH State Change: [%s] -> [%s] after Event [%s]",
                          bta_hh_state_code(in_state),
                          bta_hh_state_code(p_cb->state),
                          bta_hh_evt_code(debug_event));
        }
#endif
    }

    return;
}

複製程式碼

--->

複製程式碼

/*******************************************************************************
**
** Function         bta_hh_write_dev_act
**
** Description      Write device action. can be SET/GET/DATA transaction.
**
** Returns          void
**
*******************************************************************************/
void bta_hh_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
{
    tBTA_HH_CBDATA     cbdata = {BTA_HH_OK, 0};
    UINT16  event = (p_data->api_sndcmd.t_type - BTA_HH_FST_BTE_TRANS_EVT) +
                        BTA_HH_FST_TRANS_CB_EVT;

#if BTA_HH_LE_INCLUDED == TRUE
    if (p_cb->is_le_device){
    //呼叫到這裡t_type為10(HID_TRANS_DATA)即開始通過 BTA_HhSendData 函式傳送資料方式:
        APPL_TRACE_DEBUG("bta_hh_le_write_dev_act : p_data->api_sndcmd.t_type = %d ",p_data->api_sndcmd.t_type); 
        bta_hh_le_write_dev_act(p_cb, p_data);
    }
    else
#endif
    {

    cbdata.handle = p_cb->hid_handle;

    /* match up BTE/BTA report/boot mode def */
    if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL)
    {
        p_data->api_sndcmd.param = ( p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE) ?\
                        HID_PAR_PROTOCOL_REPORT :HID_PAR_PROTOCOL_BOOT_MODE;
    }

    if (HID_HostWriteDev (p_cb->hid_handle,
                       p_data->api_sndcmd.t_type,
                       p_data->api_sndcmd.param,
                       p_data->api_sndcmd.data,
                       p_data->api_sndcmd.rpt_id,
                       p_data->api_sndcmd.p_data) != HID_SUCCESS)
    {
        APPL_TRACE_ERROR("HID_HostWriteDev Error ");
        cbdata.status = BTA_HH_ERR;

        if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL &&
            p_data->api_sndcmd.t_type != HID_TRANS_DATA)
            (* bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata);
        else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
            (* bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH *)&cbdata);
    }
    else
    {

        switch(p_data->api_sndcmd.t_type)
        {
        case HID_TRANS_SET_PROTOCOL:
            /* fall through */
        case HID_TRANS_GET_REPORT:
            /* fall through */
        case HID_TRANS_SET_REPORT:
            /* fall through */
        case HID_TRANS_GET_PROTOCOL:
            /* fall through */
        case HID_TRANS_GET_IDLE:
            /* fall through */
        case HID_TRANS_SET_IDLE:/* set w4_handsk event name for callback function use */
            p_cb->w4_evt = event;
            break;
        case HID_TRANS_DATA:  /* output report */
            /* fall through */
        case HID_TRANS_CONTROL:
            /* no handshake event will be generated */
            /* if VC_UNPLUG is issued, set flag */
            if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG)
                p_cb->vp = TRUE;

            break;
        /* currently not expected */
        case HID_TRANS_DATAC:
        default:
            APPL_TRACE_DEBUG("bta_hh_write_dev_act:: cmd type = %d",
                            p_data->api_sndcmd.t_type);
            break;
        }

        /* if not control type transaction, notify PM for energy control */
        if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL)
        {
            /* inform PM for mode change */
            bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
            bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr);
        }
        else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND)
        {
            bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr);
        }
        else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND)
        {
            bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr);
        }
    }

    }
    return;
}

複製程式碼

--->

複製程式碼

/*******************************************************************************
**
** Function         bta_hh_le_write_dev_act
**
** Description      Write LE device action. can be SET/GET/DATA transaction.
**
** Returns          void
**
*******************************************************************************/
void bta_hh_le_write_dev_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data)
{
    switch(p_data->api_sndcmd.t_type) //上面列印結果是10,即對應:HID_TRANS_DATA
    {
        case HID_TRANS_SET_PROTOCOL:
            p_cb->w4_evt = BTA_HH_SET_PROTO_EVT;
            bta_hh_le_set_protocol_mode(p_cb, p_data->api_sndcmd.param);
            break;

        case HID_TRANS_GET_PROTOCOL:
            bta_hh_le_get_protocol_mode(p_cb);
            break;

        case HID_TRANS_GET_REPORT:
            bta_hh_le_get_rpt(p_cb,
                              BTA_HH_LE_SRVC_DEF,
                              p_data->api_sndcmd.param,
                              p_data->api_sndcmd.rpt_id);
            break;

        case HID_TRANS_SET_REPORT:
            bta_hh_le_write_rpt(p_cb,
                                BTA_HH_LE_SRVC_DEF,
                                BTA_GATTC_TYPE_WRITE,
                                p_data->api_sndcmd.param,
                                p_data->api_sndcmd.p_data,
                                BTA_HH_SET_RPT_EVT);
            break;

        case HID_TRANS_DATA:  /* output report */

            bta_hh_le_write_rpt(p_cb,
                                BTA_HH_LE_SRVC_DEF,
                                BTA_GATTC_TYPE_WRITE_NO_RSP,
                                p_data->api_sndcmd.param,
                                p_data->api_sndcmd.p_data,
                                BTA_HH_DATA_EVT);
            break;

        case HID_TRANS_CONTROL:
            /* no handshake event will be generated */
            /* if VC_UNPLUG is issued, set flag */
            if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND ||
                p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND)
            {
                bta_hh_le_suspend(p_cb, p_data->api_sndcmd.param);
            }
            break;

        default:
            APPL_TRACE_ERROR("%s unsupported transaction for BLE HID device: %d",
                __func__, p_data->api_sndcmd.t_type);
            break;
    }
}

複製程式碼

-->

複製程式碼

/*******************************************************************************
**
** Function         bta_hh_le_write_rpt
**
** Description      SET_REPORT/or DATA output on a LE HID Report
**
** Returns          void
**
*******************************************************************************/
void bta_hh_le_write_rpt(tBTA_HH_DEV_CB *p_cb, UINT8 srvc_inst,
                         tBTA_GATTC_WRITE_TYPE   write_type,
                         tBTA_HH_RPT_TYPE r_type,
                         BT_HDR *p_buf, UINT16 w4_evt )
{
    tBTA_HH_LE_RPT  *p_rpt;
    tBTA_GATTC_CHAR_ID  char_id;
    UINT8   *p_value, rpt_id;

    if (p_buf == NULL || p_buf->len == 0)
    {
        APPL_TRACE_ERROR("bta_hh_le_write_rpt: Illegal data");
        return;
    }

    /* strip report ID from the data */
    p_value = (UINT8 *)(p_buf + 1) + p_buf->offset;
    STREAM_TO_UINT8(rpt_id, p_value);
    p_buf->len -= 1;

    p_rpt = bta_hh_le_find_rpt_by_idtype(p_cb->hid_srvc[srvc_inst].report, p_cb->mode, r_type, rpt_id);

    if (p_rpt == NULL)
    {
        APPL_TRACE_ERROR("bta_hh_le_write_rpt: no matching report 0x%02x",rpt_id);
        GKI_freebuf(p_buf);
        return;
    }

    APPL_TRACE_ERROR("bta_hh_le_write_rpt: ReportID: 0x%02x Data Len: %d", rpt_id, p_buf->len);

    p_cb->w4_evt = w4_evt;

    bta_hh_le_fill_16bits_srvc_id(TRUE, srvc_inst, UUID_SERVCLASS_LE_HID, &char_id.srvc_id);
    bta_hh_le_fill_16bits_char_id(p_rpt->inst_id, p_rpt->uuid, &char_id.char_id);

    LOG_DEBUG("%s: BTA_GATTC_WriteCharValue::", __FUNCTION__);

    BTA_GATTC_WriteCharValue(p_cb->conn_id,
                             &char_id,
                             write_type, /* default to use write request */ //之前reportid 0x5b的patch使 write_type為BTA_GATTC_TYPE_WRITE_NO_RSP
                             p_buf->len,
                             p_value,
                             BTA_GATT_AUTH_REQ_NONE);

}

複製程式碼

-->

複製程式碼

/*******************************************************************************
**
** Function         BTA_GATTC_WriteCharValue
**
** Description      This function is called to write characteristic value.
**
** Parameters       conn_id - connection ID.
**                    p_char_id - characteristic ID to write.
**                    write_type - type of write.
**                  len: length of the data to be written.
**                  p_value - the value to be written.
**
** Returns          None
**
*******************************************************************************/
void BTA_GATTC_WriteCharValue ( UINT16 conn_id,
                                tBTA_GATTC_CHAR_ID *p_char_id,
                                tBTA_GATTC_WRITE_TYPE  write_type,
                                UINT16 len,
                                UINT8 *p_value,
                                tBTA_GATT_AUTH_REQ auth_req)
{
    tBTA_GATTC_API_WRITE  *p_buf;

    if ((p_buf = (tBTA_GATTC_API_WRITE *) GKI_getbuf((UINT16)(sizeof(tBTA_GATTC_API_WRITE) + len))) != NULL)
    {
        memset(p_buf, 0, sizeof(tBTA_GATTC_API_WRITE) + len);

        p_buf->hdr.event = BTA_GATTC_API_WRITE_EVT;
        p_buf->hdr.layer_specific = conn_id;
        p_buf->auth_req = auth_req;

        memcpy(&p_buf->srvc_id, &p_char_id->srvc_id, sizeof(tBTA_GATT_SRVC_ID));
        memcpy(&p_buf->char_id, &p_char_id->char_id, sizeof(tBTA_GATT_ID));


        APPL_TRACE_DEBUG("BTA_GATTC_WriteCharValue : write_type=%d",write_type);

        p_buf->write_type = write_type;
        p_buf->len = len;

        if (p_value && len > 0)
        {
            p_buf->p_value = (UINT8 *)(p_buf + 1);
            memcpy(p_buf->p_value, p_value, len);
        }

        bta_sys_sendmsg(p_buf); //設定資料型別後傳送到gatt層
    }
    return;
}

複製程式碼

應用層傳下來的訊息到GATT層:

external\bluetooth\bluedroid\stack\btu\btu_task.c

複製程式碼

/*******************************************************************************
**
** 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;
    UNUSED(param);

#if (defined(HCISU_H4_INCLUDED) && HCISU_H4_INCLUDED == TRUE)
    /* wait an event that HCISU is ready */
    BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
                "btu_task pending for preload complete event");

    for (;;)
    {
        event = GKI_wait (0xFFFF, 0);
        if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
        {
            /* indicates BT ENABLE abort */
            BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_WARNING,
                        "btu_task start abort!");
            return (0);
        }
        else if (event & BT_EVT_PRELOAD_CMPL)
        {
            break;
        }
        else
        {
            BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_WARNING,
                "btu_task ignore evt %04x while pending for preload complete",
                event);
        }
    }

    BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
                "btu_task received preload complete event");
#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);

    prctl(PR_SET_NAME, (unsigned long)"BTU TASK", 0, 0, 0);

    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;

                    case BT_EVT_TO_STOP_TIMER:
                        if (GKI_timer_queue_is_empty(&btu_cb.timer_queue)) {
                            GKI_stop_timer(TIMER_0);
                        }
                        GKI_freebuf (p_msg);
                        break;

                    case BT_EVT_TO_START_TIMER_ONESHOT:
                        if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
                            TIMER_LIST_ENT *tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
                            // Start non-repeating timer.
                            GKI_start_timer(TIMER_3, tle->ticks, FALSE);
                        } else {
                            BTM_TRACE_WARNING("Oneshot timer queue empty when received start request");
                        }
                        GKI_freebuf(p_msg);
                        break;

                    case BT_EVT_TO_STOP_TIMER_ONESHOT:
                        if (GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
                            GKI_stop_timer(TIMER_3);
                        } else {
                            BTM_TRACE_WARNING("Oneshot timer queue not empty when received stop request");
                        }
                        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) {
            GKI_update_timer_list (&btu_cb.timer_queue, 1);

            while (!GKI_timer_queue_is_empty(&btu_cb.timer_queue)) {
                TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue);
                if (p_tle->ticks != 0)
                    break;

                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) &&