闲的时候查阅了MTK BT/WIFI相应资料,了解了一点框架知识,并且对底层驱动做了简单的代码流程跟踪,也留有一些问题,现做简单记录,不确定以后是否还有时间和机会再继续完善。
下图是MT6589平台,SDIO接口的硬件电路图,该平台有四组SDIO,其中MT6520/28会用到其中一组,当然SDIO仅用于WIFI的数据通信。
在init.project.rc文件,
mknod/dev/stpbt c 192 0;
insmod/system/lib/modules/mtk_hif_sdio.ko
查看生成mtk_hif_sdio.ko的MakeFile文件,从而可以找到对应的源文件,
obj-$(CONFIG_MTK_COMBO) += mtk_hif_sdio$(EXT_FLAG).o
mtk_hif_sdio$(EXT_FLAG)-objs := linux/pub/hif_sdio.o
mtk_hif_sdio$(EXT_FLAG)-objs += linux/pub/hif_sdio_chrdev.o
mtk_hif_sdio$(EXT_FLAG)-objs += platform/alps/mtk_wcn_cmb_hw.o
mtk_hif_sdio$(EXT_FLAG)-objs += platform/alps/wmt_plat_alps.o
mtk_hif_sdio$(EXT_FLAG)-objs += linux/pub/osal.o
模块入口:
mediatek\kernel\drivers\combo\common\linux\pub\hif_sdio.c
同理,可得到如下结果,
insmod/system/lib/modules/mtk_stp_wmt.ko
# WMT DRIVER
obj-$(CONFIG_MTK_COMBO) += mtk_stp_wmt$(EXT_FLAG).o
# WMT DRIVER-core part
mtk_stp_wmt$(EXT_FLAG)-objs := core/wmt_core.o core/wmt_ctrl.o core/wmt_func.o core/wmt_ic_6620.ocore/wmt_lib.o core/wmt_conf.o
#ifeq ($(MTK_COMBO_CHIP), MT6628)
mtk_stp_wmt$(EXT_FLAG)-objs += core/wmt_ic_6628.o
#endif
# WMT DRIVER-linux private part
mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/wmt_dev.o linux/pri/wmt_exp.o
mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/wmt_tm.o
# WMT DRIVER-OSAL
mtk_stp_wmt$(EXT_FLAG)-objs += linux/pub/osal.o
# WMT DRIVER-platform implementation
ccflags-y += -D WMT_PLAT_ALPS
mtk_stp_wmt$(EXT_FLAG)-objs += platform/alps/wmt_plat_alps.o
mtk_stp_wmt$(EXT_FLAG)-objs += platform/alps/wmt_plat_stub.o
# FIXME: select desired hw according to projectconfiguration
#ifeq ($(MTK_COMBO_CHIP), MT6628)
#mtk_stp_wmt$(EXT_FLAG)-objs += platform/alps/mtk_wcn_cmb_hw_6628.o
#else
mtk_stp_wmt$(EXT_FLAG)-objs += platform/alps/mtk_wcn_cmb_hw.o
#endif
mtk_stp_wmt$(EXT_FLAG)-objs += linux/pri/stp_exp.o core/stp_core.ocore/psm_core.o core/btm_core.o linux/pri/stp_dbg.o
#ifeq ($(MTK_COMBO_CHIP), MT6628)
# WMT stub part (built-in kernel image)
obj-y += platform/alps/mtk_wcn_cmb_stub_alps.o
#endif
模块入口为:mediatek\kernel\drivers\combo\common\linux\pri\wmt_dev.c
insmod/system/lib/modules/mtk_stp_uart.ko
mediatek\kernel\drivers\combo\common\linux\pri\stp_uart.c
insmod/system/lib/modules/mtk_stp_bt.ko
mediatek\kernel\drivers\combo\common\linux\pub\stp_chrdev_bt.c
hif_sdio.c文件简单分析
hif_sdio_init:
第1794行,注册sdio总线上的驱动mtk_sdio_client_drv,
sdio总线上驱动与设备匹配时通过mtk_sdio_id_tbl来配对。
而对的sdio_func设备,由host给设备上电,识别等一系列动作找到并生成。
hif_sdio_probe函数:找到对应的sdio_func后,加入list表;使能该func,设置host与之通信时最大的数据传输buf。
////enables a SDIO functionfor usage
SDIO设备的识别过程大概如下,
kernel\drivers\mmc\core\host.c
mmc_alloc_host函数中INIT_DELAYED_WORK(&host->detect,mmc_rescan);
mmc_rescan ----> mmc_rescan_try_freq ---->mmc_attach_sdio
如果有时间可以继续了解Mtk host 的实现代码及host->detect调用。
回到hif_sdio_init函数,第1798行,调用hifsdiod_start函数,
创建consys-id-query线程,每10s运行一次,还不明白这样做的目的是什么?
回到hif_sdio_init函数,第1800行,调用hif_sdio_create_dev_node函数
创建hifsdiod字符设备,获取ChipId。
WMT驱动
mediatek\kernel\drivers\combo\common\linux\pri\wmt_dev.c
WMT_init函数,
第1680行,调用stp_drv_init,主要是初始化stp_core_ctx结构体。
第1682~1696行,注册mtk_stp_wmt字符设备,mknod /dev/stpwmt c 190 0;即其设备为/dev/stpwmt
后续会简单跟踪BT数据的简单流程,在BT驱动加载后,会生成/dev/stpbt设备文件,mtk 库文件中的操作函数,通过对内核stpbt设备文件进行操作控制。
BT
mediatek\kernel\drivers\combo\common\linux\pub\Stp_chrdev_bt.c
注册mtk_stp_BT_chrdev字符设备,而BT_DEV_MAJOR为192,在init.project.rc: mknod /dev/stpbt c 192 0;故该字符设备为/dev/stpbt,对应的设备操作如下:
BT_open:
mtk_wcn_wmt_func_on(WMTDRV_TYPE_BT)->mtk_wcn_wmt_func_ctrl(WMTDRV_TYPE_BT,WMT_OPID_FUNC_ON); 即发送(WMTDRV_TYPE_BT,WMT_OPID_FUNC_ON)的消息给处理中心,
第81行从gDevWmt.rFreeOpQ.queue数组中获取P_OSAL_OP,
gDevWmt.rFreeOpQ.queue队列在
mediatek\kernel\drivers\combo\common\core\wmt_lib.c:wmt_lib_init函数中由gDevWmt.arQue完全填充,如下代码所示,
第98行,wmt_lib_host_awake_get ->wmt_plat_wake_lock_ctrl(WL_OP_GET);如下面代码所示,
根据counter是否大于0来加/解睡眠锁wmtWakeLock。
第100行,DISABLE_PSM_MONITOR ->wmt_lib_ps_disable ->mtk_wcn_stp_psm_disable
mtk_wcn_stp_is_uart_fullset_mode判断是否为MTKSTP_UART_FULL_MODE
STP_SET_SUPPORT_PROTOCOL <- mtk_wcn_stp_set_mode <-wmt_ctrl_stp_conf_ex <-
wmt_ctrl_stp_conf 对应函数指针数组wmt_ctrl_func中的WMT_CTRL_STP_CONF数据成员,<- wmt_ctrl <-
mt6628_sw_init <- wmt_ic_ops_mt6628 <-wmt_core_hw_check 对应的操作入口保存在gMtkWmtCtx.p_ic_ops。
opfunc_pwr_on -> wmt_core_stp_init
mediatek\kernel\drivers\combo\common\core\wmt_lib.c:wmtd_thread消息队列转发机制处理中心,
由WMT_init -> wmt_lib_init创建。
mtk_wcn_stp_is_ready判断stp是否ready
第106行,wmt_lib_put_act_op将P_OSAL_OP加入rActiveOpQ队列,唤醒消息处理线程,并等待处理结果的返回。
处理流程:
pOp->op.opId= WMT_OPID_FUNC_ON;
pOp->op.au4OpData[0]= WMTDRV_TYPE_BT;
wmt_core_opid-> wmt_core_opid_handler -> opfunc_func_on ->
iRet= (*(gpWmtFuncOps[drvType]->func_on))(gMtkWmtCtx.p_ic_ops,wmt_conf_get_cfg()); ->
wmt_func_bt_ops-> wmt_func_bt_on -> wmt_core_func_ctrl_cmd(WMTDRV_TYPE_BT,MTK_WCN_BOOL_TRUE);该函数代码如下,
wmt_core_tx -> wmt_ctrl_tx_ex ->mtk_wcn_stp_send_data(pData, size, WMT_TASK_INDX);
-> stp_send_tx_queue(stp_core_ctx.sequence.txseq);->
(*sys_if_tx)(&stp_core_ctx.tx_buf[tx_read],last_len, &ret);
sys_if_tx函数指针在mtk_wcn_stp_init函数中赋值,从stp_drv_init函数中可得知对应的函数为mtk_wcn_sys_if_tx,其代码如下,
stp_uart_if_tx由stp_uart_tty_open函数调用mtk_wcn_stp_register_if_tx赋值为mtk_wcn_uart_tx,即最终的数据由uart发送出去。
后续uart是怎么确定哪个及如何衔接数据调用流程,还是继续分析。
mtk_wcn_wmt_msgcb_reg(WMTDRV_TYPE_BT, bt_cdev_rst_cb)
WIFI