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