1. 程式人生 > >6 android QMI機制---Modem訊息接收

6 android QMI機制---Modem訊息接收

原文:https://blog.csdn.net/u012439416/article/details/74277494 

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訊息的首地址。

mux_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方法進行初始化時,

mi_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, 

到此,幾乎所有的訊息型別最後都會呼叫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側的接收處理到此結束。