UE侧使用android操作系统,高通平台,uicc软件架构如下:
uicc软件架构图
QCRIL传输的是GENERIC COMMANDS即上章中的命令(文件操作,pin,鉴权等),而QCRIL STK传输的是CAT COMMANDS(toolkit及文件操作)。
从MODEM侧的uimtask来看,一个卡槽会起一个task来跑,每个uim_task都有属于自己的uim_ptr,uim_ptr基本包括了uim卡的所有信息,结构体如下所示:
由于uim的每个task使用的是同一套代码,所以使用instance id来区分当前是哪个task。
从modem收到qmi命令mmgsdi收到命令后发生给uim的过程:
1.qmi_sim_internal.c中的qmi_sim_internal_init为sim qmi server端的初始化函数,其中关键函数为
注册了回调函数qmi_sim_internal_handle_req_cb,该函数每当qmi收到client发送过来的消息后就会调用该函数,该函数中的关键代码如下
2.从qmi_sim_internal_req_handle_table中找到对应命令的回调,然后执行,
在此我们分析下qmi_sim_internal_mmgsdi_session_get_all_pin_status_handler的代码流程,在该函数中直接调用了如下函数
其中qmi_sim_internal_mmgsdi_response_callback会在下篇文章中调用。
3.在mmgsdi_session_get_all_pin_status函数中填充了结构体task_cmd_ptr,并通过mmgsdi_cmd发送,如下
mmgsdi_cmd通过调用mmgsdi_cmd_ext接口发送命令如下
mmgsdi_cmd_ext函数则通过队列与信号的方式发送命令,这个是modem侧常用的任务间命令发送方式,代码如下:
4.在gsdimain主task中,初始化完成后会使用mmgsdi_wati一直在等待信号,这是modem的task基本流程。收到MMGSDI_TASK_CMD_Q_SIG信号
后会调用mmgsdi_handle_queue_sig来处理,过程如下:
mmgsdi_handle_queue_sig函数会从队列中取出mmgsdi_task_ptr然后通过mmgsdi_process_command发送出去,如下:
mmgsdi_process_command->mmgsdi_process_get_all_pin_status_cmd->mmgsdi_uicc_pin_status->mmgsdi_util_build_pin_req->mmgsdi_uim_common_verify_pin->
mmgsdi_send_cmd_to_uim_server->uim_cmd
在这里需要注意下,mmgsdi_process_command函数中,给mmgsdi_process_get_all_pin_status_cmd传递的参数task_cmd_ptr->cmd.cmd是一个共用体,这也是modem线程交互信息常用手法,采用共用体一般把命令头放在成员变量的头位置,这样使得在接收方能够解析不同命令发送过来的命令头。还有一种用法是,可以定义一个大的buff,大buff有一定长度的队列组成,每次传递信息时从这个大buff中取一个队列,使用完把队列放回去,以避免内存泄露哦问题。
上述函数中,mmgsdi_send_cmd_to_uim_server函数中会对把mmgsdi_uim_report函数指针赋给cmd_ptr->hdr.rpt_function,该回调函数会在uim task收到uim返回的数据后调用,最后的uim_cmd采用来本文所说到的信号队列机制发送命令给uim task。
注意中上诉函数中的cmd赋值
该值会在后续中使用。
5.在uim_task中跟gsdi_task类似,一样是一个无限循环,在循环中判断信号,然后调用对应处理函数,
在uim_handle_cmd_q_sig函数中取出队列函数,并赋值到uim_ptr的command结构体中,
然后在该函数中调用uim_process_command->uim_process_generic_command,在uim_process_generic_command函数中会对gsdi传过来的命令进行处理,
然后调用uim_gentric_command函数,
在该函数中会进行apdu填充,然后通过uim_send_command进行发送,在uim_send_command中会把uim_req_buf_static_ptr填充到uim_ptr->card_cmd中(该函数有个关键点,就是uim_req_buf_static_ptr->rsp_ptr指针指向uim_ptr->command.rsp_buf,在uim_send_command函数中,又会把该指针赋值给uim_ptr->card_cmd.resp_buf_ptr,该指针会用来存放sim回复的数据,下节分析),然后通过uim_send_apdu->uim_send_apdu_command_hdr->uim_tx写入URAT串口,发送到实体卡上。
至此分析了从qmi接口到实体卡的过程。