android QMI機制---Modem訊息接收
6 Modem訊息接收
3.1 訊息初始化
初始化:qmi_modem_taskàqmii_init()àqmux_init()。qmux_init方法完成對控制通道的初始化後,
通過函式qmuxi_process_rx_sig方法開始從共享記憶體接收資料。呼叫流程如如下,
(void)qmi_set_sig_handler(QMI_QMUX_RX_SIGNAL, qmuxi_process_rx_sig, NULL);
在qmuxi_process_rx_sig方法中,首先通過dsm_dequeue()讀取在佇列中等待的QMUX訊息,
賦值給指標qmux_pdu表示QMUX訊息的首地址。
qmux_pdu = dsm_dequeue( &qmux_s->io.rx_wm );
然後呼叫qmuxi_process_msg方法開始對AP側發過來的QMUX訊息解包。
qmuxi_process_msg( qmux_s, qmux_pdu );
qmuxi_process_msg方法首先拆分IF Type,通過函式dsm_pull8()進行解包。然後判斷IF Type型別,
然後把QMUX Message通過qmuxi_input()繼續處理。
在qmuxi_input()中,會拆分QMUX的訊息頭,將訊息頭大卸八塊,包括length,control_flags,client_id,service_id,
然後呼叫qmi_framework_svc_recv方法將剩下的QMUX SDU從拆分出來的QMUX訊息頭中,
找到BP側相對應的service處理。
if((svci == NULL) || (!(svci->registered))) { status = qmi_framework_svc_recv( qmi_instance_by_qmux_state(qmux_s), (qmux_service_e_type) qmux_hdr.svc_type, qmux_hdr.clid, *qmux_pdu ); *qmux_pdu = NULL; return status; }
在qmi_framework_svc_recv方法中,並不會馬上根據service_id等對QMUX訊息進行處理,這裡也是一個介面,
將訊息打包成BP側的QMI_framework的一個command,傳送出去。
qmi_framework_msg_hdr_type msg_hdr;
qmi_framework_svc_info_type * svc_info;
•••
svc_info = qmi_framework_svc_state[service];
定義一個qmi_framework_svc_info_type的指標變數,對svc_info的操作就等於對qmi_framework_svc_state的操作。
打包到msg_hdr
msg_hdr.common_hdr.service = service;
msg_hdr.common_hdr.client_id = client_id;
msg_hdr.common_hdr.qmi_instance = (int32)qmi_instance;
msg_hdr.common_hdr.transaction_id = msg_x_id;
msg_hdr.msg_ctl_flag = msg_ctl;
msg_hdr.msg_len = remaining_bytes;
最後
svc_info->cfg.cbs.cmd_hdlr(&msg_hdr,&sdu_in);
這個機制是怎麼樣呢?以phone相關的qmi_voice.c為例。
3.2 訊息分類處理
qmi_voice.c在qmi_voice_init方法進行初始化時,
qmi_mmode_set_cmd_handler(QMI_MMODE_CMD_VOICE_FW_CB, qmi_voice_handle_fw_cmd);
•••
qmi_voicei_cfg.cmn_svc_cfg.fw_cfg.cbs.alloc_clid = qmi_voice_fw_alloc_clid_cback;
qmi_voicei_cfg.cmn_svc_cfg.fw_cfg.cbs.dealloc_clid = qmi_voice_fw_dealloc_clid_cback;
qmi_voicei_cfg.cmn_svc_cfg.fw_cfg.cbs.init_cback = qmi_voice_fw_init_cback;
qmi_voicei_cfg.cmn_svc_cfg.fw_cfg.cbs.cmd_hdlr = qmi_voice_fw_req_cback;
qmi_voicei_cfg.cmn_svc_cfg.cmd_hdlr_array = qmi_voicei_cmd_callbacks;
qmi_voicei_cfg.cmn_svc_cfg.cmd_num_entries = VOICEI_CMD_MAX;
qmi_voicei_cfg.cmn_svc_cfg.service_id = QMUX_SERVICE_VOICE;
/*-----------------------------------------------------------------------
step 2: calling QMI Framework API to register the service.
----------------------------------------------------------------------*/
errval= qmi_framework_reg_service(QMUX_SERVICE_VOICE,
&qmi_voicei_cfg.cmn_svc_cfg.fw_cfg);
初始化的時候,用結構體指標&qmi_voicei _cfg,到qmi_framework裡面註冊服務,獲取AP測傳送過來的qmux,
可以關注給cmd_hdlr賦值的函式qmi_voice_fw_req_cback,這是從qmi_framework返回的回撥函式。
因此,對於phone訊息, qmi_framework_svc_recv都是回撥qmi_voice_fw_req_cback進行處理,
qmi_voice_fw_req_cback方法讀取QMUX訊息的頭指標,和QMUX SDU的首地址。傳送到voice服務裡面專門
的command_handle。
qmi_mmode_send_cmd(QMI_MMODE_CMD_VOICE_FW_CB, cmd_ptr);
在voice初始化可找到QMI_MMODE_CMD_VOICE_FW_CB對應的方法為qmi_voice_handle_fw_cmd。
qmi_mmode_send_cmd方法會呼叫qmi_voice_handle_fw_cmd方法,該方法根據不同的訊息型別呼叫不同的
方法進行處理,
switch(qmi_info->id)
{
case QMI_MMODE_FW_INIT_CB:
qmi_voicei_fw_init_cback_hdlr(qmi_info->data.qmi_fw_info.init_cb.num_instances);
break;
case QMI_MMODE_FW_ALLOC_CLID_CB:
qmi_voicei_fw_alloc_clid_hdlr(&qmi_info->data.qmi_fw_info.alloc_clid.msg_hdr);
break;
case QMI_MMODE_FW_DEALLOC_CLID_CB:
qmi_voicei_fw_dealloc_clid_hdlr(&qmi_info->data.qmi_fw_info.dealloc_clid.msg_hdr);
break;
case QMI_MMODE_FW_REQ_CB:
qmi_voicei_fw_req_hdlr(&qmi_info->data.qmi_fw_info.req_cb.msg_hdr,
qmi_info->data.qmi_fw_info.req_cb.sdu_in);
break;
default:
QM_MSG_ERROR("Unsupported qmi-voice fw cmd");
break;
}
qmi_voicei_fw_req_hdlr並不會馬上對獲取的訊息進行處理,而是判斷頭訊息中的client_id是否符合,
符合則通過函式qmi_mmode_svc_req_hdlr傳送到request_handler中,
if( msg_hdr->common_hdr.client_id > 0 )
{
cl_sp = (qmi_voicei_client_state_type *)
qmi_voice_state.client[msg_hdr->common_hdr.client_id - 1];
ASSERT(cl_sp);
/*-------------------------------------------------------------------------
Invoke the common svc request handler
-------------------------------------------------------------------------*/
qmi_mmode_svc_req_hdlr(&qmi_voicei_cfg.cmn_svc_cfg, msg_hdr, &cl_sp->common,
sdu_in);
到此,幾乎所有的訊息型別最後都會呼叫qmi_mmode_svc_req_hdlr方法傳送到request_handler中。
3.3 訊息分發
在qmi_mmode_svc_req_hdlr函式中,真正對QMUX訊息進行處理。首先拆分頭訊息中的service_id,control_flag等。
svc_id = svc_cfg->service_id;
然後通過一個while迴圈開始對QMUX SDU進行解包。
while (sdu_in)
{
/*-----------------------------------------------------------------------
Extract service message header
-----------------------------------------------------------------------*/
temp = dsm_pull16( &sdu_in );
解包函式dsm_pull16()作用,按照一定的大小,從&sdu_in這個地址中獲取資料。獲取完後,跳出while迴圈,
呼叫qmi_mmode_svci_dispatch_transaction方法進行處理。
qmi_mmode_svci_dispatch_transaction(&msg_hdr->common_hdr,svc_cfg,x_p);
其中引數x_p是解包後的qmux_sdu存放的buffer。
qmi_mmode_svci_input方法會通過request_handler對訊息進行處理分發。
response_ptr = cmd_hdlr->request_hdlr( svc_cfg->svc_sp, cmd_buf_p, cl_sp, sdu_in );
request_hdlr方法是被封裝了的,沒法繼續跟進,BP側的接收處理到此結束。