android QMI机制---Modem消息接收

来源:互联网 发布:循序渐进学java 编辑:程序博客网 时间:2024/06/06 00:29

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侧的接收处理到此结束。

原创粉丝点击