• Bluedroid: 蓝牙协议栈源码剖析


    一、 基础知识介绍

    1.缩略语

    BTIF: Bluetooth Interface 

    BTU : Bluetooth Upper Layer 

    BTM: Bluetooth Manager 

    BTE: Bluetooth embedded system 

    BTA :Blueetooth application layer 

    CO: call outCI: call in 

    HF : Handsfree Profile 

    HH: HID Host Profile 

    HL: Health Device Profile

    V:audiovidio 

    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.初始化:

    externalluetoothluedroidtifsrcluetooth.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 

    externalluetoothluedroidtifsrctif_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;
    }

    externalluetoothluedroidtifsrctif_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;
    
    }

    externalluetoothluedroidtifsrctif_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;
    }

    externalluetoothluedroidtifsrctif_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;
    }

    externalluetoothluedroidtahhta_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);
        }
    }


    externalluetoothluedroidtifcota_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
    ", __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
    ");
            break;
        case UHID_STOP:
            APPL_TRACE_DEBUG("UHID_STOP from uhid-dev
    ");
            break;
        case UHID_OPEN:
            APPL_TRACE_DEBUG("UHID_OPEN from uhid-dev
    ");
            break;
        case UHID_CLOSE:
            APPL_TRACE_DEBUG("UHID_CLOSE from uhid-dev
    ");
            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
    ");
            break;
        case UHID_FEATURE:
            APPL_TRACE_DEBUG("UHID_FEATURE from uhid-dev
    ");
            break;
        case UHID_FEATURE_ANSWER:
            APPL_TRACE_DEBUG("UHID_FEATURE_ANSWER from uhid-dev
    ");
            break;
    
        default:
            APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u
    ", 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处理进程
        }
    }

    externalluetoothluedroidtahhta_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层:

    externalluetoothluedroidstacktutu_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) && 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_GAP_FAST_ADV:
                        case BTU_TTYPE_BLE_OBSERVE:
                            btm_ble_timeout(p_tle);
                            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 & TIMER_3_EVT_MASK) {
                BTM_TRACE_API("Received oneshot timer event complete");
                if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
                    TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
                    INT32 ticks_since_last_update = GKI_timer_ticks_getinitial(GKI_timer_getfirst(&btu_cb.timer_queue_oneshot));
                    GKI_update_timer_list(&btu_cb.timer_queue_oneshot, ticks_since_last_update);
                }
    
                while (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
                    TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
                    if (p_tle->ticks != 0)
                        break;
    
                    GKI_remove_from_timer_list(&btu_cb.timer_queue_oneshot, p_tle);
    
                    switch (p_tle->event) {
    #if (defined(BLE_INCLUDED) && BLE_INCLUDED == TRUE)
                        case BTU_TTYPE_BLE_RANDOM_ADDR:
                            btm_ble_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:
                            // FAIL
                            BTM_TRACE_WARNING("Received unexpected oneshot timer event:0x%x
    ",
                                p_tle->event);
                            break;
                    }
                }
    
                /* Update GKI timer with new tick value from first timer. */
                if (!GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
                    TIMER_LIST_ENT *p_tle = GKI_timer_getfirst(&btu_cb.timer_queue_oneshot);
                    if (p_tle->ticks > 0)
                      GKI_start_timer(TIMER_3, p_tle->ticks, FALSE);
                } else {
                    GKI_stop_timer(TIMER_3);
                }
            }
    
            if (event & EVENT_MASK(APPL_EVT_7))
                break;
        }
    
        return(0);
    }

     应用层注册的回调函数被调用:

    /*******************************************************************************
    **
    ** Function         bta_sys_event
    **
    ** Description      BTA event handler; called from task event handler.
    **
    **
    ** Returns          void
    **
    *******************************************************************************/
    BTA_API void bta_sys_event(BT_HDR *p_msg)
    {
        UINT8       id;
        BOOLEAN     freebuf = TRUE;
    
        APPL_TRACE_EVENT("BTA got event 0x%x", p_msg->event); //event = BTA_HH_API_WRITE_DEV_EVT                        
    
        /* get subsystem id from event */
        id = (UINT8) (p_msg->event >> 8);
    
        /* verify id and call subsystem event handler */
        if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL))
        {
            freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg); //Id为0x17,即BTA_ID_HH,回调函数为bta_hh_hdl_event,前面已分析
                                       //Id为0x1f,即为BTA_ID_GATTC,回调函数为bta_gattc_hdl_event,继续往后看 }     else { APPL_TRACE_WARNING("BTA got unregistered event id %d", id); } if (freebuf) { GKI_freebuf(p_msg); } }

    gatt client事件处理函数:

    /*******************************************************************************
    **
    ** Function         bta_gattc_hdl_event
    **
    ** Description      GATT client main event handling function.
    **
    **
    ** Returns          BOOLEAN
    **
    *******************************************************************************/
    BOOLEAN bta_gattc_hdl_event(BT_HDR *p_msg)
    {
        tBTA_GATTC_CB *p_cb = &bta_gattc_cb;
        tBTA_GATTC_CLCB *p_clcb = NULL;
        tBTA_GATTC_RCB      *p_clreg;
        BOOLEAN             rt = TRUE;
    #if BTA_GATT_DEBUG == TRUE
        APPL_TRACE_DEBUG("bta_gattc_hdl_event: Event [%s]", gattc_evt_code(p_msg->event));
    #endif
        switch (p_msg->event)
        {
            case BTA_GATTC_API_DISABLE_EVT:
                bta_gattc_disable(p_cb);
                break;
    
            case BTA_GATTC_API_REG_EVT:
                bta_gattc_register(p_cb, (tBTA_GATTC_DATA *) p_msg);
                break;
    
            case BTA_GATTC_INT_START_IF_EVT:
                bta_gattc_start_if(p_cb, (tBTA_GATTC_DATA *) p_msg);
                break;
    
            case BTA_GATTC_API_DEREG_EVT:
                p_clreg = bta_gattc_cl_get_regcb(((tBTA_GATTC_DATA *)p_msg)->api_dereg.client_if);
                bta_gattc_deregister(p_cb, p_clreg);
                break;
    
            case BTA_GATTC_API_OPEN_EVT:
                bta_gattc_process_api_open(p_cb, (tBTA_GATTC_DATA *) p_msg);
                break;
    
            case BTA_GATTC_API_CANCEL_OPEN_EVT:
                bta_gattc_process_api_open_cancel(p_cb, (tBTA_GATTC_DATA *) p_msg);
                break;
    
            case BTA_GATTC_API_REFRESH_EVT:
                bta_gattc_process_api_refresh(p_cb, (tBTA_GATTC_DATA *) p_msg);
                break;
    
    #if BLE_INCLUDED == TRUE
            case BTA_GATTC_API_LISTEN_EVT:
                bta_gattc_listen(p_cb, (tBTA_GATTC_DATA *) p_msg);
                break;
            case BTA_GATTC_API_BROADCAST_EVT:
                bta_gattc_broadcast(p_cb, (tBTA_GATTC_DATA *) p_msg);
                break;
    #endif
    
            case BTA_GATTC_ENC_CMPL_EVT:
                bta_gattc_process_enc_cmpl(p_cb, (tBTA_GATTC_DATA *) p_msg);
                break;
    
            default:
                if (p_msg->event == BTA_GATTC_INT_CONN_EVT)
                    p_clcb = bta_gattc_find_int_conn_clcb((tBTA_GATTC_DATA *) p_msg);
                else if (p_msg->event == BTA_GATTC_INT_DISCONN_EVT)
                    p_clcb = bta_gattc_find_int_disconn_clcb((tBTA_GATTC_DATA *) p_msg);
                else
                    p_clcb = bta_gattc_find_clcb_by_conn_id(p_msg->layer_specific);
    
                if (p_clcb != NULL)
                {
                    rt = bta_gattc_sm_execute(p_clcb, p_msg->event, (tBTA_GATTC_DATA *) p_msg); //事件处理
                }
                else
                {
                    APPL_TRACE_DEBUG("Ignore unknown conn ID: %d", p_msg->layer_specific);
                }
    
                break;
        }
    
    
        return rt;
    }

    gatt client事件处理状态机

    /*******************************************************************************
    **
    ** Function         bta_gattc_sm_execute
    **
    ** Description      State machine event handling function for GATTC
    **
    **
    ** Returns          BOOLEAN  : TRUE if queued client request buffer can be immediately released
    **                                        else FALSE
    **
    *******************************************************************************/
    BOOLEAN bta_gattc_sm_execute(tBTA_GATTC_CLCB *p_clcb, UINT16 event, tBTA_GATTC_DATA *p_data)
    {
        tBTA_GATTC_ST_TBL     state_table;
        UINT8               action;
        int                 i;
        BOOLEAN             rt = TRUE;
    #if BTA_GATT_DEBUG == TRUE
        tBTA_GATTC_STATE in_state = p_clcb->state;
        UINT16         in_event = event;
        APPL_TRACE_DEBUG("bta_gattc_sm_execute: State 0x%02x [%s], Event 0x%x[%s]", in_state,
                          gattc_state_code(in_state),
                          in_event,
                          gattc_evt_code(in_event));
    #endif
    
    
        /* look up the state table for the current state */
        state_table = bta_gattc_st_tbl[p_clcb->state];
    
        event &= 0x00FF;
    
        /* set next state */
        p_clcb->state = state_table[event][BTA_GATTC_NEXT_STATE];
    
        /* execute action functions */
        for (i = 0; i < BTA_GATTC_ACTIONS; i++)
        {
            if ((action = state_table[event][i]) != BTA_GATTC_IGNORE)
            {
                (*bta_gattc_action[action])(p_clcb, p_data); //执行bta_gattc_write,
                if (p_clcb->p_q_cmd == p_data) {
                    /* buffer is queued, don't free in the bta dispatcher.
                     * we free it ourselves when a completion event is received.
                     */
                    rt = FALSE;
                }
            }
            else
            {
                break;
            }
        }
    
    #if BTA_GATT_DEBUG == TRUE
        if (in_state != p_clcb->state)
        {
            APPL_TRACE_DEBUG("GATTC [%d] State Change: [%s] -> [%s] after Event [%s]",p_clcb->bta_conn_id,
                              gattc_state_code(in_state),
                              gattc_state_code(p_clcb->state),
                              gattc_evt_code(in_event));
        }
    #endif
        return rt;
    }

    ->

    /*******************************************************************************
    **
    ** Function         bta_gattc_write
    **
    ** Description      Write an attribute
    **
    ** Returns          None.
    **
    *******************************************************************************/
    void bta_gattc_write(tBTA_GATTC_CLCB *p_clcb, tBTA_GATTC_DATA *p_data)
    {
        UINT16              handle = 0;
        tGATT_VALUE         attr = {0};
        tBTA_GATTC_OP_CMPL  op_cmpl;
        tBTA_GATT_STATUS    status = BTA_GATT_OK;
    
        if (bta_gattc_enqueue(p_clcb, p_data))
        {
            if ((handle = bta_gattc_id2handle(p_clcb->p_srcb,
                                              &p_data->api_write.srvc_id,
                                              &p_data->api_write.char_id,
                                              p_data->api_write.p_descr_type)) == 0)
            {
                status = BTA_GATT_ERROR;
            }
            else
            {
                attr.handle= handle;
                attr.offset = p_data->api_write.offset;
                attr.len    = p_data->api_write.len;
                attr.auth_req = p_data->api_write.auth_req;
    
                if (p_data->api_write.p_value)
                    memcpy(attr.value, p_data->api_write.p_value, p_data->api_write.len);
    
                status = GATTC_Write(p_clcb->bta_conn_id, p_data->api_write.write_type, &attr);
            }
    
            /* write fail */
            if (status != BTA_GATT_OK)
            {
                memset(&op_cmpl, 0, sizeof(tBTA_GATTC_OP_CMPL));
    
                op_cmpl.status  = status;
                op_cmpl.op_code = GATTC_OPTYPE_WRITE;
                op_cmpl.p_cmpl  = NULL;
    
                bta_gattc_sm_execute(p_clcb, BTA_GATTC_OP_CMPL_EVT, (tBTA_GATTC_DATA *)&op_cmpl);
            }
        }
    }

    ->

    /*******************************************************************************
    **
    ** Function         GATTC_Write
    **
    ** Description      This function is called to write the value of an attribute to
    **                  the server.
    **
    ** Parameters       conn_id: connection identifier.
    **                  type    - attribute write type.
    **                  p_write  - write operation parameters.
    **
    ** Returns          GATT_SUCCESS if command started successfully.
    **
    *******************************************************************************/
    tGATT_STATUS GATTC_Write (UINT16 conn_id, tGATT_WRITE_TYPE type, tGATT_VALUE *p_write)
    {
        tGATT_STATUS status = GATT_SUCCESS;
        tGATT_CLCB      *p_clcb;
        tGATT_VALUE     *p;
        tGATT_IF        gatt_if=GATT_GET_GATT_IF(conn_id);
        UINT8           tcb_idx = GATT_GET_TCB_IDX(conn_id);
        tGATT_TCB       *p_tcb = gatt_get_tcb_by_idx(tcb_idx);
        tGATT_REG       *p_reg = gatt_get_regcb(gatt_if);
    
        if ( (p_tcb == NULL) || (p_reg==NULL) || (p_write == NULL) ||
             ((type != GATT_WRITE) && (type != GATT_WRITE_PREPARE) && (type != GATT_WRITE_NO_RSP)) )
        {
            GATT_TRACE_ERROR("GATT_Write Illegal param: conn_id %d, type 0%d,", conn_id, type);
            return GATT_ILLEGAL_PARAMETER;
        }
    
        if (gatt_is_clcb_allocated(conn_id))
        {
            GATT_TRACE_ERROR("GATTC_Write GATT_BUSY conn_id = %d", conn_id);
            return GATT_BUSY;
        }
    
        if ((p_clcb = gatt_clcb_alloc(conn_id)) != NULL )
        {
            p_clcb->operation  = GATTC_OPTYPE_WRITE;
            p_clcb->op_subtype = type;
            p_clcb->auth_req = p_write->auth_req;
    
            if (( p_clcb->p_attr_buf = (UINT8 *)GKI_getbuf((UINT16)sizeof(tGATT_VALUE))) != NULL)
            {
                memcpy(p_clcb->p_attr_buf, (void *)p_write, sizeof(tGATT_VALUE));
    
                p =  (tGATT_VALUE *)p_clcb->p_attr_buf;
                if (type == GATT_WRITE_PREPARE)
                {
                    p_clcb->start_offset = p_write->offset;
                    p->offset = 0;
                }
    
                if (gatt_security_check_start(p_clcb) == FALSE)
                {
                    status = GATT_NO_RESOURCES;
                }
            }
            else
            {
                status = GATT_NO_RESOURCES;
            }
    
            if (status == GATT_NO_RESOURCES)
                gatt_clcb_dealloc(p_clcb);
        }
        else
        {
            status = GATT_NO_RESOURCES;
        }
        return status;
    }

    ->

    /*******************************************************************************
    **
    ** Function         gatt_check_enc_req
    **
    ** Description      check link security.
    **
    ** Returns          TRUE if encrypted, otherwise FALSE.
    **
    *******************************************************************************/
    BOOLEAN gatt_security_check_start(tGATT_CLCB *p_clcb)
    {
        tGATT_TCB           *p_tcb = p_clcb->p_tcb;
        tGATT_SEC_ACTION    gatt_sec_act;
        tBTM_BLE_SEC_ACT    btm_ble_sec_act;
        BOOLEAN             status = TRUE;
        tBTM_STATUS         btm_status;
        tGATT_SEC_ACTION    sec_act_old =  gatt_get_sec_act(p_tcb);
    
        gatt_sec_act = gatt_determine_sec_act(p_clcb);
    
        if (sec_act_old == GATT_SEC_NONE)
            gatt_set_sec_act(p_tcb, gatt_sec_act);
    
        switch (gatt_sec_act )
        {
            case GATT_SEC_SIGN_DATA:
                GATT_TRACE_DEBUG("gatt_security_check_start: Do data signing");
                gatt_sign_data(p_clcb);
                break;
            case GATT_SEC_ENCRYPT:
            case GATT_SEC_ENCRYPT_NO_MITM:
            case GATT_SEC_ENCRYPT_MITM:
                if (sec_act_old < GATT_SEC_ENCRYPT)
                {
                    GATT_TRACE_DEBUG("gatt_security_check_start: Encrypt now or key upgreade first");
                    gatt_convert_sec_action(gatt_sec_act, &btm_ble_sec_act);
                    btm_status = BTM_SetEncryption(p_tcb->peer_bda, p_tcb->transport , gatt_enc_cmpl_cback, &btm_ble_sec_act);
                    if ( (btm_status != BTM_SUCCESS) && (btm_status != BTM_CMD_STARTED))
                    {
                        GATT_TRACE_ERROR("gatt_security_check_start BTM_SetEncryption failed btm_status=%d", btm_status);
                        status = FALSE;
                    }
                }
                if (status)
                    gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
                break;
            case GATT_SEC_ENC_PENDING:
                gatt_add_pending_enc_channel_clcb (p_tcb, p_clcb);
                /* wait for link encrypotion to finish */
                break;
            default:
                gatt_sec_check_complete(TRUE, p_clcb, gatt_sec_act);
                break;
        }
    
        if (status == FALSE)
        {
            gatt_set_sec_act(p_tcb, GATT_SEC_NONE);
            gatt_set_ch_state(p_tcb, GATT_CH_OPEN);
        }
    
        return status;
    }

    ->

    /*******************************************************************************
    **
    ** Function         gatt_sec_check_complete
    **
    ** Description      security check complete and proceed to data sending action.
    **
    ** Returns          void.
    **
    *******************************************************************************/
    void gatt_sec_check_complete(BOOLEAN sec_check_ok, tGATT_CLCB   *p_clcb, UINT8 sec_act)
    {
        if (p_clcb && p_clcb->p_tcb && GKI_queue_is_empty(&p_clcb->p_tcb->pending_enc_clcb))
            gatt_set_sec_act(p_clcb->p_tcb, GATT_SEC_NONE);
    
        if (!sec_check_ok)
        {
            gatt_end_operation(p_clcb, GATT_AUTH_FAIL, NULL);
        }
        else if (p_clcb->operation == GATTC_OPTYPE_WRITE)
        {
            gatt_act_write(p_clcb, sec_act);
        }
        else if (p_clcb->operation == GATTC_OPTYPE_READ)
        {
            gatt_act_read(p_clcb, p_clcb->counter);
        }
    }

    ->

    /*******************************************************************************
    **
    ** Function         gatt_act_write
    **
    ** Description      GATT write operation.
    **
    ** Returns          void.
    **
    *******************************************************************************/
    void gatt_act_write (tGATT_CLCB *p_clcb, UINT8 sec_act)
    {
        tGATT_TCB           *p_tcb = p_clcb->p_tcb;
        UINT8               rt = GATT_SUCCESS, op_code = 0;
        tGATT_VALUE         *p_attr = (tGATT_VALUE *)p_clcb->p_attr_buf;
    
        if (p_attr)
        {
            switch (p_clcb->op_subtype)
            {
                case GATT_WRITE_NO_RSP:
                    p_clcb->s_handle = p_attr->handle;
                    op_code = (sec_act == GATT_SEC_SIGN_DATA) ? GATT_SIGN_CMD_WRITE : GATT_CMD_WRITE;
                    rt = gatt_send_write_msg(p_tcb,
                                             p_clcb->clcb_idx,
                                             op_code,
                                             p_attr->handle,
                                             p_attr->len,
                                             0,
                                             p_attr->value);
                    break;
    
                case GATT_WRITE:
                    if (p_attr->len <= (p_tcb->payload_size - GATT_HDR_SIZE))
                    {
                        p_clcb->s_handle = p_attr->handle;
    
                        rt = gatt_send_write_msg(p_tcb,
                                                 p_clcb->clcb_idx,
                                                 GATT_REQ_WRITE,
                                                 p_attr->handle,
                                                 p_attr->len,
                                                 0,
                                                 p_attr->value);
                    }
                    else /* prepare write for long attribute */
                    {
                        gatt_send_prepare_write(p_tcb, p_clcb);
                    }
                    break;
    
                case GATT_WRITE_PREPARE:
                    gatt_send_prepare_write(p_tcb, p_clcb);
                    break;
    
                default:
                    rt = GATT_INTERNAL_ERROR;
                    GATT_TRACE_ERROR("Unknown write type: %d", p_clcb->op_subtype);
                    break;
            }
        }
        else
            rt = GATT_INTERNAL_ERROR;
    
        if ((rt != GATT_SUCCESS  && rt != GATT_CMD_STARTED && rt != GATT_CONGESTED)
            || (rt != GATT_CMD_STARTED && p_clcb->op_subtype == GATT_WRITE_NO_RSP))
        {
            if (rt != GATT_SUCCESS)
            {
                GATT_TRACE_ERROR("gatt_act_write() failed op_code=0x%x", op_code);
            }
            gatt_end_operation(p_clcb, rt, NULL);
        }
    }

    ->

    /*******************************************************************************
    **
    ** Function         gatt_send_write_msg
    **
    ** Description      This real function send out the ATT message for write.
    **
    ** Returns          status code
    **
    *******************************************************************************/
    UINT8 gatt_send_write_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code,
                               UINT16 handle, UINT16 len,
                               UINT16 offset, UINT8 *p_data)
    {
        tGATT_CL_MSG     msg;
    
        msg.attr_value.handle = handle;
        msg.attr_value.len = len;
        msg.attr_value.offset = offset;
    
        memcpy (msg.attr_value.value, p_data, len);
    
        /* write by handle */
        return attp_send_cl_msg(p_tcb, clcb_idx, op_code, &msg);
    }

    ->

    /*******************************************************************************
    **
    ** Function         attp_send_cl_msg
    **
    ** Description      This function sends the client request or confirmation message
    **                  to server.
    **
    ** Parameter        p_tcb: pointer to the connectino control block.
    **                  clcb_idx: clcb index
    **                  op_code: message op code.
    **                  p_msg: pointer to message parameters structure.
    **
    ** Returns          GATT_SUCCESS if sucessfully sent; otherwise error code.
    **
    **
    *******************************************************************************/
    tGATT_STATUS attp_send_cl_msg (tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 op_code, tGATT_CL_MSG *p_msg)
    {
        tGATT_STATUS     status = GATT_NO_RESOURCES;
        BT_HDR          *p_cmd = NULL;
        UINT16          offset = 0, handle;
    
        if (p_tcb != NULL)
        {
            switch (op_code)
            {
            case GATT_REQ_MTU:
                if (p_msg->mtu <= GATT_MAX_MTU_SIZE)
                {
                    p_tcb->payload_size = p_msg->mtu;
                    p_cmd = attp_build_mtu_cmd(GATT_REQ_MTU, p_msg->mtu);
                }
                else
                    status = GATT_ILLEGAL_PARAMETER;
                break;
    
            case GATT_REQ_FIND_INFO:
            case GATT_REQ_READ_BY_TYPE:
            case GATT_REQ_READ_BY_GRP_TYPE:
                if (GATT_HANDLE_IS_VALID (p_msg->browse.s_handle) &&
                    GATT_HANDLE_IS_VALID (p_msg->browse.e_handle)  &&
                    p_msg->browse.s_handle <= p_msg->browse.e_handle)
                {
                    p_cmd = attp_build_browse_cmd(op_code,
                                                p_msg->browse.s_handle,
                                                p_msg->browse.e_handle,
                                                p_msg->browse.uuid);
                }
                else
                    status = GATT_ILLEGAL_PARAMETER;
                break;
    
            case GATT_REQ_READ_BLOB:
                offset = p_msg->read_blob.offset;
                /* fall through */
            case GATT_REQ_READ:
                handle = (op_code == GATT_REQ_READ) ? p_msg->handle: p_msg->read_blob.handle;
                /*  handle checking */
                if (GATT_HANDLE_IS_VALID (handle))
                {
                    p_cmd = attp_build_handle_cmd(op_code, handle, offset);
                }
                else
                    status = GATT_ILLEGAL_PARAMETER;
                break;
    
            case GATT_HANDLE_VALUE_CONF:
                p_cmd = attp_build_opcode_cmd(op_code);
                break;
    
            case GATT_REQ_PREPARE_WRITE:
                offset = p_msg->attr_value.offset;
                /* fall through */
            case GATT_REQ_WRITE:
            case GATT_CMD_WRITE:
            case GATT_SIGN_CMD_WRITE:
                if (GATT_HANDLE_IS_VALID (p_msg->attr_value.handle))
                {
             //先调用这里 p_cmd
    = attp_build_value_cmd (p_tcb->payload_size, op_code, p_msg->attr_value.handle, offset, p_msg->attr_value.len, p_msg->attr_value.value); } else status = GATT_ILLEGAL_PARAMETER; break; case GATT_REQ_EXEC_WRITE: p_cmd = attp_build_exec_write_cmd(op_code, p_msg->exec_write); break; case GATT_REQ_FIND_TYPE_VALUE: p_cmd = attp_build_read_by_type_value_cmd(p_tcb->payload_size, &p_msg->find_type_value); break; case GATT_REQ_READ_MULTI: p_cmd = attp_build_read_multi_cmd(p_tcb->payload_size, p_msg->read_multi.num_handles, p_msg->read_multi.handles); break; default: break; }
         //再调用这里
    if (p_cmd != NULL) status = attp_cl_send_cmd(p_tcb, clcb_idx, op_code, p_cmd); } else { GATT_TRACE_ERROR("Peer device not connected"); } return status; }

    -->

    /*******************************************************************************
    **
    ** Function         attp_build_value_cmd
    **
    ** Description      Build a attribute value request
    **
    ** Returns          None.
    **
    *******************************************************************************/
    BT_HDR *attp_build_value_cmd (UINT16 payload_size, UINT8 op_code, UINT16 handle,
                                  UINT16 offset, UINT16 len, UINT8 *p_data)
    {
        BT_HDR      *p_buf = NULL;
        UINT8       *p, *pp, pair_len, *p_pair_len;
    
        if ((p_buf = (BT_HDR *)GKI_getbuf((UINT16)(sizeof(BT_HDR) + payload_size + L2CAP_MIN_OFFSET))) != NULL)
        {
            p = pp =(UINT8 *)(p_buf + 1) + L2CAP_MIN_OFFSET;
    
            UINT8_TO_STREAM (p, op_code);
            p_buf->offset = L2CAP_MIN_OFFSET;
            p_buf->len = 1;
    
            if (op_code == GATT_RSP_READ_BY_TYPE)
            {
                p_pair_len = p;
                pair_len = len + 2;
                UINT8_TO_STREAM (p, pair_len);
                p_buf->len += 1;
            }
            if (op_code != GATT_RSP_READ_BLOB && op_code != GATT_RSP_READ)
            {
                UINT16_TO_STREAM (p, handle);
                p_buf->len += 2;
            }
    
            if (op_code == GATT_REQ_PREPARE_WRITE ||op_code == GATT_RSP_PREPARE_WRITE )
            {
                UINT16_TO_STREAM (p, offset);
                p_buf->len += 2;
            }
    
            if (len > 0 && p_data != NULL)
            {
                /* ensure data not exceed MTU size */
                if (payload_size - p_buf->len < len)
                {
                    len = payload_size - p_buf->len;
                    /* update handle value pair length */
                    if (op_code == GATT_RSP_READ_BY_TYPE)
                        *p_pair_len = (len + 2);
    
                    GATT_TRACE_WARNING("attribute value too long, to be truncated to %d", len);
                }
    
                ARRAY_TO_STREAM (p, p_data, len);
                p_buf->len += len;
            }
        }
        return p_buf;
    }

    —>

    /*******************************************************************************
    **
    ** Function         attp_cl_send_cmd
    **
    ** Description      Send a ATT command or enqueue it.
    **
    ** Returns          GATT_SUCCESS if command sent
    **                  GATT_CONGESTED if command sent but channel congested
    **                  GATT_CMD_STARTED if command queue up in GATT
    **                  GATT_ERROR if command sending failure
    **
    *******************************************************************************/
    tGATT_STATUS attp_cl_send_cmd(tGATT_TCB *p_tcb, UINT16 clcb_idx, UINT8 cmd_code, BT_HDR *p_cmd)
    {
        tGATT_STATUS att_ret = GATT_SUCCESS;
    
        if (p_tcb != NULL)
        {
            cmd_code &= ~GATT_AUTH_SIGN_MASK;
    
            /* no pending request or value confirmation */
            if (p_tcb->pending_cl_req == p_tcb->next_slot_inq ||
                cmd_code == GATT_HANDLE_VALUE_CONF)
            {
                att_ret = attp_send_msg_to_l2cap(p_tcb, p_cmd); //发送数据到l2cap层
                if (att_ret == GATT_CONGESTED || att_ret == GATT_SUCCESS)
                {
                    /* do not enq cmd if handle value confirmation or set request */
                    if (cmd_code != GATT_HANDLE_VALUE_CONF && cmd_code != GATT_CMD_WRITE)
                    {
                        gatt_start_rsp_timer (clcb_idx); //如果是write request数据类型,则会创建定时器等待respond(5s超时)
                        gatt_cmd_enq(p_tcb, clcb_idx, FALSE, cmd_code, NULL);
                    }
                }
                else
                    att_ret = GATT_INTERNAL_ERROR;
            }
            else
            {
                att_ret = GATT_CMD_STARTED;
                gatt_cmd_enq(p_tcb, clcb_idx, TRUE, cmd_code, p_cmd);
            }
        }
        else
            att_ret = GATT_ERROR;
    
        return att_ret;
    }

    ->

    /*******************************************************************************
    **
    ** Function         attp_send_msg_to_l2cap
    **
    ** Description      Send message to L2CAP.
    **
    *******************************************************************************/
    tGATT_STATUS attp_send_msg_to_l2cap(tGATT_TCB *p_tcb, BT_HDR *p_toL2CAP)
    {
        UINT16      l2cap_ret;
    
    
        if (p_tcb->att_lcid == L2CAP_ATT_CID)
            l2cap_ret = L2CA_SendFixedChnlData (L2CAP_ATT_CID, p_tcb->peer_bda, p_toL2CAP);
        else
            l2cap_ret = (UINT16) L2CA_DataWrite (p_tcb->att_lcid, p_toL2CAP);
    
        if (l2cap_ret == L2CAP_DW_FAILED)
        {
            GATT_TRACE_ERROR("ATT   failed to pass msg:0x%0x to L2CAP",
                *((UINT8 *)(p_toL2CAP + 1) + p_toL2CAP->offset));
            return GATT_INTERNAL_ERROR;
        }
        else if (l2cap_ret == L2CAP_DW_CONGESTED)
        {
            GATT_TRACE_DEBUG("ATT congested, message accepted");
            return GATT_CONGESTED;
        }
        return GATT_SUCCESS;
    }

    ->

    /*******************************************************************************
    **
    **  Function        L2CA_SendFixedChnlData
    **
    **  Description     Write data on a fixed channel.
    **
    **  Parameters:     Fixed CID
    **                  BD Address of remote
    **                  Pointer to buffer of type BT_HDR
    **
    ** Return value     L2CAP_DW_SUCCESS, if data accepted
    **                  L2CAP_DW_FAILED,  if error
    **
    *******************************************************************************/
    UINT16 L2CA_SendFixedChnlData (UINT16 fixed_cid, BD_ADDR rem_bda, BT_HDR *p_buf)
    {
        tL2C_LCB        *p_lcb;
        tBT_TRANSPORT   transport = BT_TRANSPORT_BR_EDR;
    
        L2CAP_TRACE_API ("L2CA_SendFixedChnlData()  CID: 0x%04x  BDA: %08x%04x", fixed_cid,
                         (rem_bda[0]<<24)+(rem_bda[1]<<16)+(rem_bda[2]<<8)+rem_bda[3], (rem_bda[4]<<8)+rem_bda[5]);
    
    #if BLE_INCLUDED == TRUE
        if (fixed_cid >= L2CAP_ATT_CID && fixed_cid <= L2CAP_SMP_CID)
            transport = BT_TRANSPORT_LE;
    #endif
    
        /* Check CID is valid and registered */
        if ( (fixed_cid < L2CAP_FIRST_FIXED_CHNL) || (fixed_cid > L2CAP_LAST_FIXED_CHNL)
         ||  (l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].pL2CA_FixedData_Cb == NULL) )
        {
            L2CAP_TRACE_ERROR ("L2CA_SendFixedChnlData()  Invalid CID: 0x%04x", fixed_cid);
            GKI_freebuf (p_buf);
            return (L2CAP_DW_FAILED);
        }
    
        /* Fail if BT is not yet up */
        if (!BTM_IsDeviceUp())
        {
            L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData(0x%04x) - BTU not ready", fixed_cid);
            GKI_freebuf (p_buf);
            return (L2CAP_DW_FAILED);
        }
    
        /* We need to have a link up */
        if ((p_lcb = l2cu_find_lcb_by_bd_addr (rem_bda, transport)) == NULL ||
            /* if link is disconnecting, also report data sending failure */
            p_lcb->link_state == LST_DISCONNECTING)
        {
            L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData(0x%04x) - no LCB", fixed_cid);
            GKI_freebuf (p_buf);
            return (L2CAP_DW_FAILED);
        }
    
        if ((p_lcb->peer_chnl_mask[0] & (1 << fixed_cid)) == 0)
        {
            L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData() - peer does not support fixed chnl: 0x%04x", fixed_cid);
            GKI_freebuf (p_buf);
            return (L2CAP_DW_FAILED);
        }
    
        p_buf->event = 0;
        p_buf->layer_specific = L2CAP_FLUSHABLE_CH_BASED;
    
        if (!p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL])
        {
            if (!l2cu_initialize_fixed_ccb (p_lcb, fixed_cid, &l2cb.fixed_reg[fixed_cid - L2CAP_FIRST_FIXED_CHNL].fixed_chnl_opts))
            {
                L2CAP_TRACE_WARNING ("L2CA_SendFixedChnlData() - no CCB for chnl: 0x%4x", fixed_cid);
                GKI_freebuf (p_buf);
                return (L2CAP_DW_FAILED);
            }
        }
    
        /* If already congested, do not accept any more packets */
        if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent)
        {
            L2CAP_TRACE_ERROR ("L2CAP - CID: 0x%04x cannot send, already congested 
                xmit_hold_q.count: %u buff_quota: %u", fixed_cid,
                p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->xmit_hold_q.count,
                p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->buff_quota);
            GKI_freebuf (p_buf);
            return (L2CAP_DW_FAILED);
        }
    
        l2c_enqueue_peer_data (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL], p_buf);
    
        l2c_link_check_send_pkts (p_lcb, NULL, NULL);
    
        /* If there is no dynamic CCB on the link, restart the idle timer each time something is sent */
        if (p_lcb->in_use && p_lcb->link_state == LST_CONNECTED && !p_lcb->ccb_queue.p_first_ccb)
        {
            l2cu_no_dynamic_ccbs (p_lcb);
        }
    
        if (p_lcb->p_fixed_ccbs[fixed_cid - L2CAP_FIRST_FIXED_CHNL]->cong_sent)
            return (L2CAP_DW_CONGESTED);
    
        return (L2CAP_DW_SUCCESS);
    }

    调用 l2c_enqueue_peer_data 让数据进入到当前 ccb 的 xmit_hold_q 队列中,暂存此数据包。

    /*******************************************************************************
    **
    ** Function         l2c_enqueue_peer_data
    **
    ** Description      Enqueues data destined for the peer in the ccb. Handles
    **                  FCR segmentation and checks for congestion.
    **
    ** Returns          void
    **
    *******************************************************************************/
    void l2c_enqueue_peer_data (tL2C_CCB *p_ccb, BT_HDR *p_buf)
    {
        UINT8       *p;
    
        if (p_ccb->peer_cfg.fcr.mode != L2CAP_FCR_BASIC_MODE)
        {
            p_buf->event = 0;
        }
        else
        {
            /* Save the channel ID for faster counting */
            p_buf->event = p_ccb->local_cid;
    
            /* Step back to add the L2CAP header */
            p_buf->offset -= L2CAP_PKT_OVERHEAD;
            p_buf->len    += L2CAP_PKT_OVERHEAD;
    
            /* Set the pointer to the beginning of the data */
            p = (UINT8 *)(p_buf + 1) + p_buf->offset;
    
            /* Now the L2CAP header */
            UINT16_TO_STREAM (p, p_buf->len - L2CAP_PKT_OVERHEAD);
            UINT16_TO_STREAM (p, p_ccb->remote_cid);
        }
    
        GKI_enqueue (&p_ccb->xmit_hold_q, p_buf);
    
        l2cu_check_channel_congestion (p_ccb);  //检测当前 Channel 拥堵情况
    
    #if (L2CAP_ROUND_ROBIN_CHANNEL_SERVICE == TRUE)
        /* if new packet is higher priority than serving ccb and it is not overrun */
        if (( p_ccb->p_lcb->rr_pri > p_ccb->ccb_priority )
          &&( p_ccb->p_lcb->rr_serv[p_ccb->ccb_priority].quota > 0))
        {
            /* send out higher priority packet */
            p_ccb->p_lcb->rr_pri = p_ccb->ccb_priority;
        }
    #endif
    
        /* if we are doing a round robin scheduling, set the flag */
        if (p_ccb->p_lcb->link_xmit_quota == 0)
            l2cb.check_round_robin = TRUE;
    }

    -->

    /******************************************************************************
    **
    ** Function         l2cu_check_channel_congestion
    **
    ** Description      check if any change in congestion status
    **
    ** Returns          None
    **
    *******************************************************************************/
    void l2cu_check_channel_congestion (tL2C_CCB *p_ccb)
    {
        UINT16 q_count = GKI_queue_length(&p_ccb->xmit_hold_q);
    
    #if (L2CAP_UCD_INCLUDED == TRUE)
        if ( p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID )
        {
            q_count += p_ccb->p_lcb->ucd_out_sec_pending_q.count;
        }
    #endif
        /* If the CCB queue limit is subject to a quota, check for congestion */
        /* if this channel has outgoing traffic */
        if (p_ccb->buff_quota != 0)
        {
            /* If this channel was congested */
            if ( p_ccb->cong_sent )
            {
                /* If the channel is not congested now, tell the app */
            //在函数 l2c_link_adjust_chnl_allocation 中配置此值
            //p_ccb->buff_quota = quota_per_weighted_chnls[p_ccb->ertm_info.user_tx_pool_id] * p_ccb->tx_data_rate;
    if (q_count <= (p_ccb->buff_quota / 2)) //当前CCB中的 xmit_hold_q 小于 buffer_quota 值的一半,即认为已经不拥堵 { p_ccb->cong_sent = FALSE; if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) { L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (FALSE), CID: 0x%04x xmit_hold_q.count: %u buff_quota: %u", p_ccb->local_cid, q_count, p_ccb->buff_quota); /* Prevent recursive calling */ l2cb.is_cong_cback_context = TRUE; (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, FALSE); l2cb.is_cong_cback_context = FALSE; } #if (L2CAP_UCD_INCLUDED == TRUE) else if ( p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ) { if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb ) { L2CAP_TRACE_DEBUG ("L2CAP - Calling UCD CongestionStatus_Cb (FALSE), SecPendingQ:%u,XmitQ:%u,Quota:%u", p_ccb->p_lcb->ucd_out_sec_pending_q.count, p_ccb->xmit_hold_q.count, p_ccb->buff_quota); p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, FALSE ); } } #endif #if (L2CAP_NUM_FIXED_CHNLS > 0) else { UINT8 xx; for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx ++) { if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb) { if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL) (* l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(p_ccb->p_lcb->remote_bd_addr, FALSE); break; } } } #endif } } else { /* If this channel was not congested but it is congested now, tell the app */ if (q_count > p_ccb->buff_quota) { p_ccb->cong_sent = TRUE; if (p_ccb->p_rcb && p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb) { L2CAP_TRACE_DEBUG ("L2CAP - Calling CongestionStatus_Cb (TRUE),CID:0x%04x,XmitQ:%u,Quota:%u", p_ccb->local_cid, q_count, p_ccb->buff_quota); (*p_ccb->p_rcb->api.pL2CA_CongestionStatus_Cb)(p_ccb->local_cid, TRUE); } #if (L2CAP_UCD_INCLUDED == TRUE) else if ( p_ccb->p_rcb && p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID ) { if ( p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb ) { L2CAP_TRACE_DEBUG ("L2CAP - Calling UCD CongestionStatus_Cb (TRUE), SecPendingQ:%u,XmitQ:%u,Quota:%u", p_ccb->p_lcb->ucd_out_sec_pending_q.count, p_ccb->xmit_hold_q.count, p_ccb->buff_quota); p_ccb->p_rcb->ucd.cb_info.pL2CA_UCD_Congestion_Status_Cb( p_ccb->p_lcb->remote_bd_addr, TRUE ); } } #endif #if (L2CAP_NUM_FIXED_CHNLS > 0) else { UINT8 xx; for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx ++) { if (p_ccb->p_lcb->p_fixed_ccbs[xx] == p_ccb) { if (l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb != NULL) (* l2cb.fixed_reg[xx].pL2CA_FixedCong_Cb)(p_ccb->p_lcb->remote_bd_addr, TRUE); break; } } } #endif } } } }

    L2CAP层是通过 l2c_link_check_send_pkts 这个函数发送数据包:

    /*******************************************************************************
    **
    ** Function         l2c_link_check_send_pkts
    **
    ** Description      This function is called to check if it can send packets
    **                  to the Host Controller. It may be passed the address of
    **                  a packet to send.
    **
    ** Returns          void
    **
    *******************************************************************************/
    void l2c_link_check_send_pkts (tL2C_LCB *p_lcb, tL2C_CCB *p_ccb, BT_HDR *p_buf)
    {
        int         xx;
        BOOLEAN     single_write = FALSE; //最后 Link Disc 用来把 CCB 中的数据包放到 Link 上的队列发,速度加快
    
        /* Save the channel ID for faster counting */
        if (p_buf)//一般数据包都为空,只有发送 L2CAP 发送 command/response 或 发送 S-Frame 才用到
        {
            if (p_ccb != NULL) //这个 case 就是 当前 Link 即将断开的情况了
            {
                p_buf->event = p_ccb->local_cid;
                single_write = TRUE;
            }
            else
                p_buf->event = 0;
    
            p_buf->layer_specific = 0;
            //把这个数据包放到 当前 link 上的 link_xmit_data_q队列中
            GKI_enqueue (&p_lcb->link_xmit_data_q, p_buf);
    
            //没有发送窗口了,需要 RR 看看有没有别的数据包可以发
            if (p_lcb->link_xmit_quota == 0)
            {
    #if BLE_INCLUDED == TRUE
                
                if (p_lcb->transport == BT_TRANSPORT_LE)
                    l2cb.ble_check_round_robin = TRUE;
                else
    #endif
                    l2cb.check_round_robin = TRUE;
            }
        }
    
        /* If this is called from uncongested callback context break recursive calling.
        ** This LCB will be served when receiving number of completed packet event.
        */
        if (l2cb.is_cong_cback_context)//当前 Link 拥堵了,不发送数据包直接返回
            return;
    
        /* If we are in a scenario where there are not enough buffers for each link to
        ** have at least 1, then do a round-robin for all the LCBs
        */
        if ( (p_lcb == NULL) || (p_lcb->link_xmit_quota == 0) )
        {
            if (p_lcb == NULL)
                p_lcb = l2cb.lcb_pool;
            else if (!single_write)
                p_lcb++;
    
            /* Loop through, starting at the next */
            //没有足够buffer发送窗口了,在所有的 Link 上做一次 RR
            for (xx = 0; xx < MAX_L2CAP_LINKS; xx++, p_lcb++)
            {
                /* If controller window is full, nothing to do */
                if ( (l2cb.controller_xmit_window == 0
    #if (BLE_INCLUDED == TRUE)
                      && (p_lcb->transport == BT_TRANSPORT_BR_EDR)
    #endif
                    )
    #if (BLE_INCLUDED == TRUE)
                    || (p_lcb->transport == BT_TRANSPORT_LE && l2cb.controller_le_xmit_window == 0 )
    #endif
                  || (l2cb.round_robin_unacked >= l2cb.round_robin_quota) )
                    break;
    
                /* Check for wraparound */
                if (p_lcb == &l2cb.lcb_pool[MAX_L2CAP_LINKS])
                    p_lcb = &l2cb.lcb_pool[0];
    
                if ( (!p_lcb->in_use)
                   || (p_lcb->partial_segment_being_sent)
                   || (p_lcb->link_state != LST_CONNECTED)
                   || (p_lcb->link_xmit_quota != 0)
                   || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
                    continue;
    
                /* See if we can send anything from the Link Queue */
                //首先从当前 Link 上的 link_xmit_data_q 中取出数据包并发送  
                if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) != NULL)
                {
                    l2c_link_send_to_lower (p_lcb, p_buf);
                }
                else if (single_write)//如果是 single_write 设置为 TRUE,说明数据包 已经在 link_xmit_data_q 发送了,没必要在执行下面的 code 了
                {
                    /* If only doing one write, break out */
                    break;
                }
                /* If nothing on the link queue, check the channel queue */
                //Link 上的 Queue 中没有东西可以发送,查找 CCB 中的 Queue,直到找到一个为止。
                else if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) != NULL)
                {
                    l2c_link_send_to_lower (p_lcb, p_buf);
                }
            }
    
            /* If we finished without using up our quota, no need for a safety check */
            if ( (l2cb.controller_xmit_window > 0)
              && (l2cb.round_robin_unacked < l2cb.round_robin_quota)
    #if (BLE_INCLUDED == TRUE)
              && (p_lcb->transport == BT_TRANSPORT_BR_EDR)
    #endif
              )
                l2cb.check_round_robin = FALSE;
    
    #if (BLE_INCLUDED == TRUE)
            if ( (l2cb.controller_le_xmit_window > 0)
              && (l2cb.ble_round_robin_unacked < l2cb.ble_round_robin_quota)
              && (p_lcb->transport == BT_TRANSPORT_LE))
                l2cb.ble_check_round_robin = FALSE;
    #endif
        }
        else /* if this is not round-robin service */
        {
            /* If a partial segment is being sent, can't send anything else */
            if ( (p_lcb->partial_segment_being_sent)
              || (p_lcb->link_state != LST_CONNECTED)
              || (L2C_LINK_CHECK_POWER_MODE (p_lcb)) )
                return;
    
            /* See if we can send anything from the link queue */
    #if (BLE_INCLUDED == TRUE)
            while ( ((l2cb.controller_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
                     (l2cb.controller_le_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_LE)))
                 && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
    #else
            while ( (l2cb.controller_xmit_window != 0)
                 && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
    #endif
            {
                if ((p_buf = (BT_HDR *)GKI_dequeue (&p_lcb->link_xmit_data_q)) == NULL)
                    break;
    
                if (!l2c_link_send_to_lower (p_lcb, p_buf))
                    break;
            }
    
            if (!single_write)//确保不是在链路 disc 状态下
            {
                /* See if we can send anything for any channel */
    #if (BLE_INCLUDED == TRUE)
                while ( ((l2cb.controller_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
                        (l2cb.controller_le_xmit_window != 0 && (p_lcb->transport == BT_TRANSPORT_LE)))
                        && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
    #else
                while ((l2cb.controller_xmit_window != 0) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota))
    #endif
                {
                    if ((p_buf = l2cu_get_next_buffer_to_send (p_lcb)) == NULL)//找到一个数据包来发送
                        break;
    
                    if (!l2c_link_send_to_lower (p_lcb, p_buf))
                        break;
                }
            }
    
            /* There is a special case where we have readjusted the link quotas and  */
            /* this link may have sent anything but some other link sent packets so  */
            /* so we may need a timer to kick off this link's transmissions.         */
            if ( (p_lcb->link_xmit_data_q.count) && (p_lcb->sent_not_acked < p_lcb->link_xmit_quota) )
                btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, L2CAP_LINK_FLOW_CONTROL_TOUT);
        }
    
    }

    最终 l2c_link_check_send_pkts 把数据包交给了 l2c_link_send_to_lower 来做处理,我们的音乐数据包最终也被从某个 CCB 中的队列出队列给了 l2c_link_send_to_lower。l2c_link_send_to_lower 主要做了这些事情:

    1. 如果当前数据包 p_buf 的长度小于 ACL 包的最大值,sent_not_acked 加1,整个 L2CAP 的 controller_xmit_window 减1。然后通过 L2C_LINK_SEND_ACL_DATA 将此数据包发送出去。
    2. 如果当前数据包 p_buf 的长度大于 ACL 包的最大值,先看看能分成几个分包(为了求的几个窗口能容下),然后窗口值减掉这些分包个数,然后将整个数据包交给 L2C_LINK_SEND_ACL_DATA (大于ACL包长度),具体分包发送由 H5(串口) 部分来负责。
    /*******************************************************************************
    **
    ** Function         l2c_link_send_to_lower
    **
    ** Description      This function queues the buffer for HCI transmission
    **
    ** Returns          TRUE for success, FALSE for fail
    **
    *******************************************************************************/
    static BOOLEAN l2c_link_send_to_lower (tL2C_LCB *p_lcb, BT_HDR *p_buf)
    {
        UINT16      num_segs;
        UINT16      xmit_window, acl_data_size;
    
        if ((p_buf->len <= btu_cb.hcit_acl_pkt_size
    #if (BLE_INCLUDED == TRUE)
            && (p_lcb->transport == BT_TRANSPORT_BR_EDR)) ||
            ((p_lcb->transport == BT_TRANSPORT_LE) && (p_buf->len <= btu_cb.hcit_ble_acl_pkt_size))
    #else
            )
    #endif
            )
        {
            if (p_lcb->link_xmit_quota == 0)
            {
    #if (BLE_INCLUDED == TRUE)
                if (p_lcb->transport == BT_TRANSPORT_LE)
                    l2cb.ble_round_robin_unacked++;
                else
    #endif
                    l2cb.round_robin_unacked++;
            }
            p_lcb->sent_not_acked++;
            p_buf->layer_specific = 0;
    
    #if (BLE_INCLUDED == TRUE)
            if (p_lcb->transport == BT_TRANSPORT_LE)
            {
                l2cb.controller_le_xmit_window--;
                L2C_LINK_SEND_BLE_ACL_DATA (p_buf);
            }
            else
    #endif
            {
                l2cb.controller_xmit_window--;
                L2C_LINK_SEND_ACL_DATA (p_buf);
            }
        }
        else
        {
    #if BLE_INCLUDED == TRUE
            if (p_lcb->transport == BT_TRANSPORT_LE)
            {
                acl_data_size = btu_cb.hcit_ble_acl_data_size;
                xmit_window = l2cb.controller_le_xmit_window;
    
            }
            else
    #endif
            {
                acl_data_size = btu_cb.hcit_acl_data_size;
                xmit_window = l2cb.controller_xmit_window;
            }
            num_segs = (p_buf->len - HCI_DATA_PREAMBLE_SIZE + acl_data_size - 1) / acl_data_size;
    
    
            /* If doing round-robin, then only 1 segment each time */
            if (p_lcb->link_xmit_quota == 0)
            {
                num_segs = 1;
                p_lcb->partial_segment_being_sent = TRUE;
            }
            else
            {
                /* Multi-segment packet. Make sure it can fit */
                if (num_segs > xmit_window)
                {
                    num_segs = xmit_window;
                    p_lcb->partial_segment_being_sent = TRUE;
                }
    
                if (num_segs > (p_lcb->link_xmit_quota - p_lcb->sent_not_acked))
                {
                    num_segs = (p_lcb->link_xmit_quota - p_lcb->sent_not_acked);
                    p_lcb->partial_segment_being_sent = TRUE;
                }
            }
    
            p_buf->layer_specific        = num_segs;
    #if BLE_INCLUDED == TRUE
            if (p_lcb->transport == BT_TRANSPORT_LE)
            {
                l2cb.controller_le_xmit_window -= num_segs;
                if (p_lcb->link_xmit_quota == 0)
                    l2cb.ble_round_robin_unacked += num_segs;
            }
            else
    #endif
            {
                l2cb.controller_xmit_window -= num_segs;
    
                if (p_lcb->link_xmit_quota == 0)
                    l2cb.round_robin_unacked += num_segs;
            }
    
            p_lcb->sent_not_acked += num_segs;
    #if BLE_INCLUDED == TRUE
            if (p_lcb->transport == BT_TRANSPORT_LE)
            {
                L2C_LINK_SEND_BLE_ACL_DATA(p_buf);
            }
            else
    #endif
            {
                L2C_LINK_SEND_ACL_DATA (p_buf);
            }
        }
    
    #if (L2CAP_HCI_FLOW_CONTROL_DEBUG == TRUE)
    #if (BLE_INCLUDED == TRUE)
        if (p_lcb->transport == BT_TRANSPORT_LE)
        {
            L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
                    l2cb.controller_le_xmit_window,
                    p_lcb->handle,
                    p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
                    l2cb.ble_round_robin_quota, l2cb.ble_round_robin_unacked);
        }
        else
    #endif
        {
            L2CAP_TRACE_DEBUG ("TotalWin=%d,Hndl=0x%x,Quota=%d,Unack=%d,RRQuota=%d,RRUnack=%d",
                    l2cb.controller_xmit_window,
                    p_lcb->handle,
                    p_lcb->link_xmit_quota, p_lcb->sent_not_acked,
                    l2cb.round_robin_quota, l2cb.round_robin_unacked);
        }
    #endif
    
        return TRUE;
    }

    l2c_link_send_to_lower 把数据交给了 L2C_LINK_SEND_ACL_DATA,L2C_LINK_SEND_ACL_DATA 其实是 bte_main_hci_send 函数,bte_main_hci_send 函数通过调用 hci 的接口 transmit_buf 来转送数据包。transmit_buf 函数作用比较简单,将此数据包入 tx_q 队列,串口(H5)的守护线程 bt_hc_worker_thread 会从 tx_q 队列中获取数据包,并将其发送。

    /******************************************************************************
    **
    ** Function         bte_main_hci_send
    **
    ** Description      BTE MAIN API - This function is called by the upper stack to
    **                  send an HCI message. The function displays a protocol trace
    **                  message (if enabled), and then calls the 'transmit' function
    **                  associated with the currently selected HCI transport
    **
    ** Returns          None
    **
    ******************************************************************************/
    void bte_main_hci_send (BT_HDR *p_msg, UINT16 event)
    {
        UINT16 sub_event = event & BT_SUB_EVT_MASK;  /* local controller ID */
    
        p_msg->event = event;
    
        OS_PRINTF("bte_main_hci_send event 0x%2x
    ",event);
    
        if((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) || 
           (sub_event == LOCAL_BLE_CONTROLLER_ID))
        {
            if (bt_hc_if)
                bt_hc_if->transmit_buf((TRANSAC)p_msg, 
                                           (char *) (p_msg + 1), 
                                            p_msg->len);
            else
                GKI_freebuf(p_msg);
        }
        else
        {
            APPL_TRACE_ERROR("Invalid Controller ID. Discarding message.");
            GKI_freebuf(p_msg);
        }
    }

    在hci中,数据被写入bt driver中

    static int transmit_buf(TRANSAC transac, char *p_buf, int len)                                                                                                            
    {         
      utils_enqueue(&tx_q, (void *) transac);                                          
      bthc_signal_event(HC_EVENT_TX);                  
      return BT_HC_STATUS_SUCCESS;                                                                                                                  
    }   

    externalluetoothluedroidhcisrct_hci_bdroid.c

    bt_hc_worker_thread负责处理hci事件

    /*******************************************************************************
    **
    ** 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);
    
    #ifndef HCI_USE_MCT
            if (events & HC_EVENT_RX)
            {
                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;
                }
            }
    #endif
    
            if (events & HC_EVENT_PRELOAD)
            {
                userial_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
    }

    send to : userial.c

    最终write 系统调操作driver的 fops 操作接口集:

    /*******************************************************************************
    **
    ** Function        userial_write
    **
    ** Description     Write data to the userial port
    **
    ** Returns         Number of bytes actually written to the userial port. This
    **                 may be less than len.
    **
    *******************************************************************************/
    uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len)
    {
        int ret, total = 0;
    
        while(len != 0)
        {
    #if defined(ENABLE_USERIAL_TIMING_LOGS) && (ENABLE_USERIAL_TIMING_LOGS==TRUE)
            log_userial_tx_timing(len);
    #endif
            ret = write(userial_cb.fd, p_data+total, len);
            total += ret;
            len -= ret;
        }
    
        return ((uint16_t)total);
    }

    write /dev/hidraw* 节点数据下发流程大致如上,敬请勘误~!

  • 相关阅读:
    魔法跳舞链 51Nod
    反射
    JDBC---后端服务器与数据库交互的桥梁
    多线程
    IO流
    继承与重写
    java.util包
    多态
    Java.lang包
    异常
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/7010061.html
Copyright © 2020-2023  润新知