sheldon_blogs

Bluedroid: 蓝牙协议栈源码剖析

一、 基础知识介绍

1.缩略语

BTIF: Bluetooth Interface 

BTU : Bluetooth Upper Layer 

BTM: Bluetooth Manager 

BTE: Bluetooth embedded system 

BTA :Blueetooth application layer 

CO: call out\CI: call in 

HF : Handsfree Profile 

HH: HID Host Profile 

HL: Health Device Profile

V:audio\vidio 

ag: audio gateway

r: audio/video registration 

gattc: GATT client 

BLE: Bluetooth Low Energy

 

2.蓝牙协议栈框架图:

 

1.基带层(BB)提供了两种不同的物理链路(同步面向连接链路SCO Synchronous Connection Oriented和异步无连接链路ACL Asynchronous Connection Less),负责跳频和蓝牙数据及信息帧的传输,且对所有类型的数据包提供了不同层次的前向纠错码(FEC Frequency Error Correction)或循环沉余度差错校验(CTC Cyclic Redundancy Check);

2.LMP层负责两个或多个设备链路的建立和拆除及链路的安全和控制,如鉴权和加密、控制和协商基带包的大小等,它为上层软件模块提供了不同的访问入口;

3.蓝牙主机控制器接口HCI (Host Controller Interface)由基带控制器、连接管理器、控制和事件寄存器等组成。它是蓝牙协议中软硬件之间的接口,它提供了一个调用下层BB、LM、状态和控制寄存器等硬件的统一命令,上、下两个模块接口之间的消息和数据的传递必须通过HCI的解释才能进行。HCI层以上的协议软件实体运行在主机上,而HCI以下的功能由蓝牙设备耒完成,二者之间通过传输层进行交互。 

4.中间协议层由逻辑链路控制与适配协议L2CAP (Logical Link Control and Adaptation Protocol)、服务发现协议 SDP (Service Discovery Protocol)、串口仿真协议或称线缆替换协议 RFCOM 和二进制电话控制协议 TCS (Telephony Control protocol Spectocol)组成。

L2CAP 是蓝牙协议栈的核心组成部分,也是其它协议实现的基础。它位于基带之上,向上层提供面向连接的和无连接的数据服务。它主要完成数据的拆装、服务质量控制,协议的复用、分组的分割和重组(Segmentation And Reassembly)及组提取等功能。L2CAP允许高达64KB的数据分组。

5.SDP是一个基于客户/服务器结构的协议。它工作在 L2CAP层之上,为上层应用程序提供一种机制来发现可用的服务及其属性,而服务的属性包括服务的类型及该服务所需的机制或协议信息。

6.RFCOMM 是一个仿真有线链路的无线数据仿真协议,符合ETSI 标准的 TS 07.10串口仿真协议。它在蓝牙基带上仿真RS-232的控制和数据信号,为原先使用串行连接的上层业务提供传送能力。

7.TCS是一个基于 ITU-T Q.931 建议的采用面向比特的协议,它定义了用于蓝牙设备之间建立语音和数据呼叫的控制信令(Call Control Signalling),并负责处理蓝牙设备组的移动管理过程。 

 

整个bluedroid可以分为两大模块:BTIF,BTE

BTIF:提供bluedroid对外的接口

BTE:bluedroid的内部处理,又细分为BTA,BTU,BTM和HCI

BTA:bluedroid中各profile的逻辑实现和处理

BTU:承接BTA与HCI

BTM:蓝牙配对与链路管理

HCI:读取或写入数据到蓝牙hw

 

二、代码分析(写hidraw节点数据流程):

1.初始化:

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

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

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

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

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

init函数里注册传入的回调函数:

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

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

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

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

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

    btif_enabled_services |= (1 << service_id);

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

    if (btif_is_enabled())
    {    //注册回调,发送消息
        btif_transfer_context(btif_dm_execute_service_request,
                              BTIF_DM_ENABLE_SERVICE,
                              (char*)p_id, sizeof(tBTA_SERVICE_ID), NULL);
    }

    return BT_STATUS_SUCCESS;
}

 

2.创建线程和准备启动调度:

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

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

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

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

    if (status != GKI_SUCCESS)
        return BT_STATUS_FAIL;

    return BT_STATUS_SUCCESS;
}

处理线程函数:

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

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

    BTIF_TRACE_DEBUG("btif task starting");

    btif_associate_evt();

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

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

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

        if (event & EVENT_MASK(GKI_SHUTDOWN_EVT))
            break;

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

                switch (p_msg->event)
                {
                    case BT_EVT_CONTEXT_SWITCH_EVT:
                        btif_context_switched(p_msg); //传递消息给注册的回调函数
                        break;
                    default:
                        BTIF_TRACE_ERROR("unhandled btif event (%d)", p_msg->event & BT_EVT_MASK);
                        break;
                }

                GKI_freebuf(p_msg);
            }
        }
    }

    btif_disassociate_evt();

    BTIF_TRACE_DEBUG("btif task exiting");
}

之前先开启了蓝牙服务:

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

    tBTA_DM_API_ENABLE    *p_msg;

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

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

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

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

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

}

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

根据消息请求对应服务:

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

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

执行A2DP/HID/HFP等服务

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

 

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

启动/关闭 HID服务

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

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

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

    /* register with BTA system manager */
    bta_sys_register(BTA_ID_HH, &bta_hh_reg); //注册主处理函数

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

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

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

        bta_sys_sendmsg(p_buf);
    }
}


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

HID Host Profile 部分初始化,创建HID事件监听线程:btif_hh_poll_event_thread

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

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

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

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

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

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


                break;
            }
        }
    }

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

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


poll监听HID驱动的事件:

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

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

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

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

 解析HID驱动的事件:

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

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

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

    return 0;
}

 --->

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

发送数据到HID设备:

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

 -->

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

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

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

        bta_sys_sendmsg(p_buf); //发送数据到hid处理进程
    }
}

 

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

BTA_HhEnable时注册的HID主处理函数进行数据接收和处理:

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

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

        case BTA_HH_API_DISABLE_EVT:
            bta_hh_api_disable();
            break;

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

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

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

#if BTA_HH_DEBUG
            APPL_TRACE_DEBUG("bta_hh_hdl_event:: handle = %d dev_cb[%d] ", p_msg->layer_specific, index);
#endif
            bta_hh_sm_execute(p_cb, p_msg->event, (tBTA_HH_DATA *) p_msg); //状态机处理函数
    }
    return (TRUE);
}

HID状态机事件处理函数

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

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

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

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

            case BTA_HH_API_CLOSE_EVT:
                cback_event = BTA_HH_CLOSE_EVT;

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

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

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

        event &= 0xff;

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

        if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE)
        {
            (*bta_hh_action[action])(p_cb, p_data); //各事件处理函数列表,写节点为action(8)-> bta_hh_write_dev_act
        }

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

    return;
}

--->

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

#if BTA_HH_LE_INCLUDED == TRUE
    if (p_cb->is_le_device){
    //调用到这里t_type为10(HID_TRANS_DATA)即开始通过 BTA_HhSendData 函数发送数据方式: APPL_TRACE_DEBUG("bta_hh_le_write_dev_act : p_data->api_sndcmd.t_type = %d ",p_data->api_sndcmd.t_type); bta_hh_le_write_dev_act(p_cb, p_data); } else #endif { cbdata.handle = p_cb->hid_handle; /* match up BTE/BTA report/boot mode def */ if (p_data->api_sndcmd.t_type == HID_TRANS_SET_PROTOCOL) { p_data->api_sndcmd.param = ( p_data->api_sndcmd.param == BTA_HH_PROTO_RPT_MODE) ?\ HID_PAR_PROTOCOL_REPORT :HID_PAR_PROTOCOL_BOOT_MODE; } if (HID_HostWriteDev (p_cb->hid_handle, p_data->api_sndcmd.t_type, p_data->api_sndcmd.param, p_data->api_sndcmd.data, p_data->api_sndcmd.rpt_id, p_data->api_sndcmd.p_data) != HID_SUCCESS) { APPL_TRACE_ERROR("HID_HostWriteDev Error "); cbdata.status = BTA_HH_ERR; if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL && p_data->api_sndcmd.t_type != HID_TRANS_DATA) (* bta_hh_cb.p_cback)(event, (tBTA_HH *)&cbdata); else if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) (* bta_hh_cb.p_cback)(BTA_HH_VC_UNPLUG_EVT, (tBTA_HH *)&cbdata); } else { switch(p_data->api_sndcmd.t_type) { case HID_TRANS_SET_PROTOCOL: /* fall through */ case HID_TRANS_GET_REPORT: /* fall through */ case HID_TRANS_SET_REPORT: /* fall through */ case HID_TRANS_GET_PROTOCOL: /* fall through */ case HID_TRANS_GET_IDLE: /* fall through */ case HID_TRANS_SET_IDLE:/* set w4_handsk event name for callback function use */ p_cb->w4_evt = event; break; case HID_TRANS_DATA: /* output report */ /* fall through */ case HID_TRANS_CONTROL: /* no handshake event will be generated */ /* if VC_UNPLUG is issued, set flag */ if (p_data->api_sndcmd.param == BTA_HH_CTRL_VIRTUAL_CABLE_UNPLUG) p_cb->vp = TRUE; break; /* currently not expected */ case HID_TRANS_DATAC: default: APPL_TRACE_DEBUG("bta_hh_write_dev_act:: cmd type = %d", p_data->api_sndcmd.t_type); break; } /* if not control type transaction, notify PM for energy control */ if (p_data->api_sndcmd.t_type != HID_TRANS_CONTROL) { /* inform PM for mode change */ bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr); bta_sys_idle(BTA_ID_HH, p_cb->app_id, p_cb->addr); } else if (p_data->api_sndcmd.param == BTA_HH_CTRL_SUSPEND) { bta_sys_sco_close(BTA_ID_HH, p_cb->app_id, p_cb->addr); } else if (p_data->api_sndcmd.param == BTA_HH_CTRL_EXIT_SUSPEND) { bta_sys_busy(BTA_ID_HH, p_cb->app_id, p_cb->addr); } } } return; }

--->

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

        case HID_TRANS_GET_PROTOCOL:
            bta_hh_le_get_protocol_mode(p_cb);
            break;

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

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

        case HID_TRANS_DATA:  /* output report */

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

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

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

-->

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

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

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

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

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

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

    p_cb->w4_evt = w4_evt;

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

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

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

}

-->

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

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

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

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


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

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

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

        bta_sys_sendmsg(p_buf); //设置数据类型后发送到gatt层
    }
    return;
}

 

应用层传下来的消息到GATT层:

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

/*******************************************************************************
**
** Function         btu_task
**
** Description      This is the main task of the Bluetooth Upper Layers unit.
**                  It sits in a loop waiting for messages, and dispatches them
**                  to the appropiate handlers.
**
** Returns          should never return
**
*******************************************************************************/
BTU_API UINT32 btu_task (UINT32 param)
{
    UINT16           event;
    BT_HDR          *p_msg;
    UINT8            i;
    UINT16           mask;
    BOOLEAN          handled;
    UNUSED(param);

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

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

    BT_TRACE(TRACE_LAYER_BTU, TRACE_TYPE_API,
                "btu_task received preload complete event");
#endif

    /* Initialize the mandatory core stack control blocks
       (BTU, BTM, L2CAP, and SDP)
     */
    btu_init_core();

    /* Initialize any optional stack components */
    BTE_InitStack();

#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)
    bta_sys_init();
#endif

    /* Initialise platform trace levels at this point as BTE_InitStack() and bta_sys_init()
     * reset the control blocks and preset the trace level with XXX_INITIAL_TRACE_LEVEL
     */
#if ( BT_USE_TRACES==TRUE )
    BTE_InitTraceLevels();
#endif

    /* Send a startup evt message to BTIF_TASK to kickstart the init procedure */
    GKI_send_event(BTIF_TASK, BT_EVT_TRIGGER_STACK_INIT);

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

    raise_priority_a2dp(TASK_HIGH_BTU);

    /* Wait for, and process, events */
    for (;;)
    {
        event = GKI_wait (0xFFFF, 0);

        if (event & TASK_MBOX_0_EVT_MASK)
        {
            /* Process all messages in the queue */
            while ((p_msg = (BT_HDR *) GKI_read_mbox (BTU_HCI_RCV_MBOX)) != NULL)
            {
                /* Determine the input message type. */
                switch (p_msg->event & BT_EVT_MASK)
                {
                    case BT_EVT_TO_BTU_HCI_ACL:
                        /* All Acl Data goes to L2CAP */
                        l2c_rcv_acl_data (p_msg);
                        break;

                    case BT_EVT_TO_BTU_L2C_SEG_XMIT:
                        /* L2CAP segment transmit complete */
                        l2c_link_segments_xmitted (p_msg);
                        break;

                    case BT_EVT_TO_BTU_HCI_SCO:
#if BTM_SCO_INCLUDED == TRUE
                        btm_route_sco_data (p_msg);
                        break;
#endif

                    case BT_EVT_TO_BTU_HCI_EVT:
                        btu_hcif_process_event ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
                        GKI_freebuf(p_msg);

#if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE)
                        /* If host receives events which it doesn't response to, */
                        /* host should start idle timer to enter sleep mode.     */
                        btu_check_bt_sleep ();
#endif
                        break;

                    case BT_EVT_TO_BTU_HCI_CMD:
                        btu_hcif_send_cmd ((UINT8)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
                        break;

#if (defined(OBX_INCLUDED) && OBX_INCLUDED == TRUE)
#if (defined(OBX_SERVER_INCLUDED) && OBX_SERVER_INCLUDED == TRUE)
                    case BT_EVT_TO_OBX_SR_MSG:
                        obx_sr_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;

                    case BT_EVT_TO_OBX_SR_L2C_MSG:
                        obx_sr_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;
#endif

#if (defined(OBX_CLIENT_INCLUDED) && OBX_CLIENT_INCLUDED == TRUE)
                    case BT_EVT_TO_OBX_CL_MSG:
                        obx_cl_proc_evt((tOBX_PORT_EVT *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;

                    case BT_EVT_TO_OBX_CL_L2C_MSG:
                        obx_cl_proc_l2c_evt((tOBX_L2C_EVT_MSG *)(p_msg + 1));
                        GKI_freebuf (p_msg);
                        break;
#endif

#if (defined(BIP_INCLUDED) && BIP_INCLUDED == TRUE)
                    case BT_EVT_TO_BIP_CMDS :
                        bip_proc_btu_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
#endif /* BIP */
#if (BPP_SND_INCLUDED == TRUE || BPP_INCLUDED == TRUE)
                    case BT_EVT_TO_BPP_PR_CMDS:
                        bpp_pr_proc_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
                    case BT_EVT_TO_BPP_SND_CMDS:
                        bpp_snd_proc_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;

#endif /* BPP */

#endif /* OBX */

#if (defined(SAP_SERVER_INCLUDED) && SAP_SERVER_INCLUDED == TRUE)
                    case BT_EVT_TO_BTU_SAP :
                        sap_proc_btu_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
#endif /* SAP */
#if (defined(GAP_CONN_INCLUDED) && GAP_CONN_INCLUDED == TRUE && GAP_CONN_POST_EVT_INCLUDED == TRUE)
                    case BT_EVT_TO_GAP_MSG :
                        gap_proc_btu_event(p_msg);
                        GKI_freebuf (p_msg);
                        break;
#endif
                    case BT_EVT_TO_START_TIMER :
                        /* Start free running 1 second timer for list management */
                        GKI_start_timer (TIMER_0, GKI_SECS_TO_TICKS (1), TRUE);
                        GKI_freebuf (p_msg);
                        break;

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

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

                    case BT_EVT_TO_STOP_TIMER_ONESHOT:
                        if (GKI_timer_queue_is_empty(&btu_cb.timer_queue_oneshot)) {
                            GKI_stop_timer(TIMER_3);
                        } else {
                            BTM_TRACE_WARNING("Oneshot timer queue not empty when received stop request");
                        }
                        GKI_freebuf (p_msg);
                        break;

#if defined(QUICK_TIMER_TICKS_PER_SEC) && (QUICK_TIMER_TICKS_PER_SEC > 0)
                    case BT_EVT_TO_START_QUICK_TIMER :
                        GKI_start_timer (TIMER_2, QUICK_TIMER_TICKS, TRUE);
                        GKI_freebuf (p_msg);
                        break;
#endif

                    default:
                        i = 0;
                        mask = (UINT16) (p_msg->event & BT_EVT_MASK);
                        handled = FALSE;

                        for (; !handled && i < BTU_MAX_REG_EVENT; i++)
                        {
                            if (btu_cb.event_reg[i].event_cb == NULL)
                                continue;

                            if (mask == btu_cb.event_reg[i].event_range)
                            {
                                if (btu_cb.event_reg[i].event_cb)
                                {
                                    btu_cb.event_reg[i].event_cb(p_msg);
                                    handled = TRUE;
                                }
                            }
                        }

                        if (handled == FALSE)
                            GKI_freebuf (p_msg);

                        break;
                }
            }
        }


        if (event & TIMER_0_EVT_MASK) {
            GKI_update_timer_list (&btu_cb.timer_queue, 1);

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

                GKI_remove_from_timer_list(&btu_cb.timer_queue, p_tle);

                switch (p_tle->event) {
                    case BTU_TTYPE_BTM_DEV_CTL:
                        btm_dev_timeout(p_tle);
                        break;

                    case BTU_TTYPE_BTM_ACL:
                        btm_acl_timeout(p_tle);
                        break;

                    case BTU_TTYPE_L2CAP_LINK:
                    case BTU_TTYPE_L2CAP_CHNL:
                    case BTU_TTYPE_L2CAP_HOLD:
                    case BTU_TTYPE_L2CAP_INFO:
                    case BTU_TTYPE_L2CAP_FCR_ACK:
                        l2c_process_timeout (p_tle);
                        break;

                    case BTU_TTYPE_SDP:
                        sdp_conn_timeout ((tCONN_CB *)p_tle->param);
                        break;

                    case BTU_TTYPE_BTM_RMT_NAME:
                        btm_inq_rmt_name_failed();
                        break;

#if (defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE)
                    case BTU_TTYPE_RFCOMM_MFC:
                    case BTU_TTYPE_RFCOMM_PORT:
                        rfcomm_process_timeout (p_tle);
                        break;

#endif /* If defined(RFCOMM_INCLUDED) && RFCOMM_INCLUDED == TRUE */

#if ((defined(BNEP_INCLUDED) && BNEP_INCLUDED == TRUE))
                    case BTU_TTYPE_BNEP:
                        bnep_process_timeout(p_tle);
                        break;
#endif


#if (defined(AVDT_INCLUDED) && 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\n",
                            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\n",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;                                                                                                                  
}   

external\bluetooth\bluedroid\hci\src\bt_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* 节点数据下发流程大致如上,敬请勘误~!

 

posted on 2017-06-14 17:37  sheldon_blogs  阅读(23368)  评论(1编辑  收藏  举报

导航