RK3568-RTL8852BS驱动框架
驱动结构框架
- LINUX RTL8852BS驱动框架很繁杂
- 结合Bear+Clangd+Vscode+Ubuntu阅读代码
- 梳理出下列流程框架
综述
module_init(rockchip_wifi_init_module_rtkwifi)
-->
//drivers\net\wireless\rockchip_wlan\rtl8852bs\os_dep\linux\sdio_intf.c
rtw_drv_entry
-->
//对比参考文档32 usb_register(&usb_drv->usbdrv) usb注册
sdio_register_driver(&sdio_drvpriv.rtw_sdio_drv)
-->
static struct sdio_drv_priv sdio_drvpriv
--->
.rtw_sdio_drv.probe = rtw_dev_probe
.rtw_sdio_drv.id_table = sdio_ids
--->
rtw_dev_probe() //drivers\net\wireless\rockchip_wlan\rtl8852bs\os_dep\linux\sdio_intf.c|---> sdio_dvobj_init() //初始化dvobj|---> devobj_init() //初始化dvobj_priv结构体,并将返回值赋给dvobj|---> sdio_set_drvdata() //将dvobj赋值给func的drvdata成员|---> dvobj_to_sdio //将dvobj转换为sdio_data结构体,并将返回值赋给psdio//对比参考文档32 usb_dvobj_init|---> rtw_sdio_init() // 初始化dvobj|---> sdio_claim_host()//获取SDIO功能|---> sdio_enable_func()//申请SDIO主机|---> sdio_set_block_size() //设置块大小|--->dvobj->intf_ops = &sdio_ops //drivers\net\wireless\rockchip_wlan\rtl8852bs\core\rtw_trx_sdio.c.read = rtw_sdio_raw_read
//drivers\net\wireless\rockchip_wlan\rtl8822bs\os_dep\linux\sdio_ops_linux.c|---> rtw_reset_continual_io_error()// 将sdio_ops赋值给dvobj的intf_ops|---> devobj_trx_resource_init() // 初始化dvobj的传输资源|---> rtw_init_lite_xmit_resource() // 初始化轻量级发送资源|---> rtw_init_lite_recv_resource() //初始化轻量级接收资源|---> rtw_init_recv_priv() //初始化接收私有数据结构|---> rtw_init_cmd_priv() //初始化命令私有数据结构|---> rtw_hw_init() //该函数负责初始化硬件设备 drivers\net\wireless\rockchip_wlan\rtl8852bs\core\rtw_phl.c|---> rtw_phl_init() // 初始化phl|---> phl_regulation_init() // 初始化phl_regulation|---> phl_com_init() // 初始化phl_com|---> phl_hci_init() // 初始化phl_hci|---> phl_set_hci_ops() // 设置phl_hci操作、|--->phl_hook_trx_ops_sdio|--->_phl_hci_ops_check|--->phl_trx_init_sdio|--->phl_register_trx_hdlr_sdio|--->phl_register_handler|--->phl_tx_sdio_thrd_hdl//核心线程|--->rtw_hal_sdio_tx|---> phl_fsm_init() phl_fsm_module_init(phl_info)// 初始化fsm状态|---> phl_twt_init() // 初始化TWT状态|---> rtw_hal_init() // 初始化hal状态|---> hal_set_ops |--->hal_set_ops_8852bs //设置操作函数|--->hal_set_ops_8852b |--->ops->read_macreg|--->ops->read_bbreg |--->hal_read32 _hal_read32|--->_read32 = io_priv->io_ops._read32|--->hal_mac_sdio_read32|--->reg_read32|--->reg_read32_sdio|--->rtw_sdio_raw_write|--->dw_mci_queue_request|--->__raw_writel|--->asm volatile|---> rtw_hal_hci_cfg() // 将总线信息发送给hal|---> rtw_hal_read_chip_info()// 从mac/bb/rf/btc/efuse/fw-defeature-rpt获取硬件能力|---> rtw_hal_var_init() // 初始化hal变量|---> phl_var_init()// 初始化phl变量|---> phl_mr_ctrl_init() // 初始化mr_ctrl和wifi_role[]|---> phl_module_init()// 初始化PHL模块|---> phl_msg_hub_init() // 初始化消息中心|---> phl_wow_mdl_init() // 初始化WoW模块|---> phl_pkt_ofld_init() // 初始化数据包转发模块|---> phl_test_module_init() // 初始化phl_test_module模块|---> phl_p2pps_init() // 初始化phl_p2pps模块|---> phl_disp_eng_init() // 初始化phl_disp_eng模块|---> phl_register_background_module_entry() // 注册phl_disp_eng模块的入口|---> phl_ecsa_ctrl_init()// 初始化ECDSA控制结构|---> phl_macid_ctrl_init() // 初始化macid_ctrl和stainfo_ctrl|---> phl_stainfo_ctrl_init() // 在hal_init后初始化hal_sta_info|---> rtw_core_update_default_setting()// 该函数用于更新默认设置,包括加载物理层参数、设置固件能力、控制LED模式以及设置RPQ聚合数|---> rtw_phl_cap_pre_config() //软件和硬件能力预配置|---> rtw_phl_init_ppdu_sts_para() //初始化PPDU状态参数 |---> rtw_phl_trx_alloc() //初始化数据路径部分|---> rtw_core_register_phl_msg() //注册PHL消息|---> rtw_phl_preload()//对dvobj->phl进行预处理|---> rtw_phl_final_cap_decision()//对dvobj->phl进行最终容量决策|---> rtw_core_register_mr_config()//注册mr配置|---> rtw_core_set_ecsa_ops //设置ecsa操作|---> rtw_hw_dump_hal_spec()//输出hal规范|---> rtw_phl_watchdog_init()//初始化watchdog|---> rtw_set_phl_regulation_ctx() //设置PHL的上下文|---> rtw_sdio_primary_adapter_init() //该函数用于初始化SDIO主适配器|---> rtw_load_registry() //加载注册表 /*registry_priv*/|---> chip_version|---> rfintfs|---> lbkmode|---> network_mode //设置模式, 可能和AP有关|---> _rtw_memcpy //SSID|---> band|---> channel|---> wireless_mode|---> band_type|---> rtw_init_drv_sw() //初始化驱动软件//drivers\net\wireless\rockchip_wlan\rtl8852bs\os_dep\linux\os_intfs.c|---> rtw_init_default_value()|---> rtw_init_hal_com_default_value()|---> rtw_init_cmd_priv() fail ---> rtw_free_cmd_priv()|---> rtw_init_evt_priv() fail ---> rtw_free_evt_priv()|---> rtw_init_mlme_priv()|---> init_mlme_ext_priv() fail ---> free_mlme_ext_priv() rtw_free_mlme_priv()|---> _rtw_init_xmit_priv() fail ---> _rtw_free_xmit_priv()|---> _rtw_init_recv_priv() fail ---> _rtw_free_recv_priv()|---> _rtw_init_sta_priv()|---> rtw_init_bcmc_stainfo()|---> rtw_init_pwrctrl_priv()|---> rtw_hal_dm_init()|---> rtw_hw_get_mac_addr() // 获取MAC地址|---> rtw_macaddr_cfg() //获取适配器的MAC地址,并将其作为参数传递给rtw_macaddr_cfg函数|---> rtw_drv_add_vir_ifaces(dvobj) //如果配置了并发模式,添加虚拟接口
|---> devobj_data_init() //从注册表和芯片规格初始化设备对象(dvobj)的数据|---> dev_set_drv_stopped() //将dvobj参数传入,将驱动程序设置为停止状态 |---> dev_clr_hw_start() //传入dvobj参数|---> devobj_set_phl_regulation_capability() //设置PHL调节能力|---> devobj_decide_init_chplan() // 初始化设备对象的数据计划|---> rtw_rfctl_init // 初始化设备对象的射频控制|---> rtw_edcca_mode_update()// 更新设备对象的EDCCA模式|---> rtw_update_phl_edcca_mode() // 更新PHL的EDCCA模式|---> rtw_rfctl_chplan_init()// 初始化设备对象的信道计划|---> rtw_hw_cap_init()// 初始化设备对象的硬件能力|---> RTW_ENABLE_FUNC(dvobj, DF_RX_BIT) // 启用设备对象的接收功能|---> RTW_ENABLE_FUNC(dvobj, DF_TX_BIT) // 启用设备对象的发送功能|---> rtw_os_ndevs_init() // 分配网络设备名称 注册网络设备
|---> rtw_sdio_alloc_irq() // 分配SDIO中断
rtw_init_netdevrtw_hook_if_ops(pnetdev)rtw_netdev_opspnetdev->wireless_handlers = (struct iw_handler_def *)&rtw_handlers_def;
rtw_netdev_ops
就是 Realtek Wi-Fi 驱动向内核注册的“网卡操作表”,内核通过这些回调函数把用户态或协议栈的请求(打开网卡、发送数据、设置 MAC 等)转发给驱动里对应的处理函数
static const struct net_device_ops rtw_netdev_ops = {.ndo_init = rtw_ndev_init,.ndo_uninit = rtw_ndev_uninit,.ndo_open = netdev_open,.ndo_stop = netdev_close,.ndo_start_xmit = rtw_xmit_entry,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)).ndo_select_queue = rtw_select_queue,
#endif.ndo_set_mac_address = rtw_net_set_mac_address,.ndo_get_stats = rtw_net_get_stats,.ndo_do_ioctl = rtw_ioctl,
};
字段名 | 作用 | 驱动中的对应函数 |
---|---|---|
.ndo_init | 当 网络设备被注册 时调用一次,做一次性初始化 | rtw_ndev_init |
.ndo_uninit | 当 网络设备被注销 时调用,做清理 | rtw_ndev_uninit |
.ndo_open | 当用户执行 ifconfig wlan0 up 或 ip link set wlan0 up 时调用 | netdev_open |
.ndo_stop | 当用户执行 ifconfig wlan0 down 或 ip link set wlan0 down 时调用 | netdev_close |
.ndo_start_xmit | 核心发送函数,协议栈每次要发包时都会调用 | rtw_xmit_entry |
.ndo_select_queue (内核 ≥ 2.6.35) | 多队列网卡选择哪个发送队列 | rtw_select_queue |
.ndo_set_mac_address | 用户通过 ifconfig wlan0 hw ether xx:xx:xx:xx:xx:xx 设置 MAC 地址时调用 | rtw_net_set_mac_address |
.ndo_get_stats | 用户通过 ifconfig wlan0 查看网卡统计信息时调用 | rtw_net_get_stats |
.ndo_do_ioctl | 用户通过 ioctl() 调用私有命令时调用 |
rtw_xmit_entrycore_tx_call_phlrtw_phl_add_tx_reqrtw_phl_tx_req_notifyphl_schedule_handler
- phl_tx_sdio_thrd_hdl核心线程
rtw_phl_initphl_set_hci_opsphl_hook_trx_ops_sdio_phl_hci_ops_checkphl_trx_init_sdiophl_register_trx_hdlr_sdiophl_register_handlerphl_tx_callback_sdiophl_handle_xmit_ring_sdiophl_rx_callback_sdio_os_thread_init(drv, &hci->tx_thrd, phl_tx_sdio_thrd_hdl,phl_info, "rtw_sdio_tx")
- 事实上也是调用rtw_sdio_raw_write
phl_tx_sdio_thrd_hdlrtw_hal_sdio_txrtw_sdio_write_cmd53sdio_iod->intf_ops->writertw_sdio_raw_write
- 把 Realtek 驱动自定义的“标准 + 私有 ioctl 处理表”挂接到网卡设备
- 用户空间执行
iwconfig wlan0 essid "xxx"
时,内核会调用rtw_handlers_def.standard[]
里对应的函数 - 用户空间执行
iwpriv wlan0 set_mib txpower=100
时,内核会调用rtw_handlers_def.private[]
里对应的函数
iw_handler_def rtw_handlers_defiw_handler rtw_handlersiw_handler rtw_private_handler
- iwpriv扩展命令会调用
rtw_handlers_defrtw_private_handlerrtw_wx_read32rtw_phl_read32rtw_hal_read32hal_read32_hal_read32
Part A
- drivers/net/wireless/rockchip_wlan/rtl8852bs/os_dep/linux/sdio_intf.c
module_init(rockchip_wifi_init_module_rtkwifi)rtw_drv_entrysdio_register_driver(&sdio_drvpriv.rtw_sdio_drv)
- 驱动程序加载时,内核会使用
sdio_register_driver
函数来注册 SDIO 设备驱动程序,并使用sdio_device_id
结构体数组sdio_ids
来匹配连接的 SDIO 设备
static struct sdio_drv_priv sdio_drvpriv = {.rtw_sdio_drv.probe = rtw_dev_probe,.rtw_sdio_drv.remove = rtw_dev_remove,.rtw_sdio_drv.name = (char *)DRV_NAME,.rtw_sdio_drv.id_table = sdio_ids,.rtw_sdio_drv.drv = {
#ifdef CONFIG_SDIO_HOOK_DEV_SHUTDOWN.shutdown = rtw_dev_shutdown,
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)).pm = &rtw_sdio_pm_ops,
#endif}
};
sdio_ids 匹配钥匙
-
sdio_ids 数组定义了几个不同的 SDIO 设备 ID,包括 RTL8852A 和 RTL8852B。每个条目都指定了设备制造商 ID(0x024c)和产品 ID(0x8852、0xa852、0xb852),以及设备类别(SDIO_CLASS_WLAN)和驱动程序数据(RTL8852A 或 RTL8852B)
-
当驱动程序加载时,内核会使用这个表来匹配连接的 SDIO 设备。如果找到匹配的条目,内核会调用驱动程序的 rtw_dev_probe 函数来初始化设备
static const struct sdio_device_id sdio_ids[] = {#ifdef CONFIG_RTL8852A{SDIO_DEVICE(0x024c, 0x8852), .class = SDIO_CLASS_WLAN, .driver_data = RTL8852A},{SDIO_DEVICE(0x024c, 0xa852), .class = SDIO_CLASS_WLAN, .driver_data = RTL8852A},
#endif#ifdef CONFIG_RTL8852B{SDIO_DEVICE(0x024c, 0xb852), .class = SDIO_CLASS_WLAN, .driver_data = RTL8852B},
#endif#if defined(RTW_ENABLE_WIFI_CONTROL_FUNC) /* temporarily add this to accept all sdio wlan id */{ SDIO_DEVICE_CLASS(SDIO_CLASS_WLAN) },
#endif{ /* end: all zeroes */ },
};MODULE_DEVICE_TABLE(sdio, sdio_ids);
Part B
- 注册sdio_ops 处理函数
rtw_dev_probesdio_dvobj_initrtw_sdio_initsdio_set_block_size(func, 512)dvobj->intf_ops = &sdio_opsrtw_hw_init
struct rtw_intf_ops sdio_ops = { // 定义一个结构体 rtw_intf_ops,用于存储 SDIO 操作函数.read = rtw_sdio_raw_read, // 读取函数.write = rtw_sdio_raw_write, // 写入函数/****************** data path *****************//****************** xmit *********************/.init_xmit_priv = sdio_init_xmit_priv, // 初始化发送私有数据.free_xmit_priv = sdio_free_xmit_priv, // 释放发送私有数据.data_xmit = sdio_data_xmit, // 数据发送函数.xmitframe_enqueue = sdio_xmitframe_enqueue, // 发送帧入队函数.start_xmit_frame_thread = sdio_start_xmit_frame_thread, // 启动发送帧线程函数.cancel_xmit_frame_thread = sdio_cancel_xmit_frame_thread, // 取消发送帧线程函数#if 0 /*def CONFIG_XMIT_THREAD_MODE*/ // #if 0 /*def CONFIG_XMIT_THREAD_MODE*/ 发送缓冲区处理函数 #endif.xmit_buf_handler = sdio_xmit_buf_handler,#endif/****************** recv *********************/.init_recv_priv = sdio_init_recv_priv, // 初始化接收私有数据.free_recv_priv = sdio_free_recv_priv, // 释放接收私有数据#ifdef CONFIG_RECV_THREAD_MODE.recv_hdl = sdio_recv_hdl,#endif
};
- hal_set_ops_sdio
rtw_dev_probesdio_dvobj_initrtw_hw_initrtw_phl_initrtw_hal_initset_intf_ops = hal_sdio_set_io_opshal_init_io_priv(hal_info->hal_com, set_intf_ops)hal_set_ops(phl_com, hal_info)CONFIG_SDIO_HCIhal_set_ops_sdio(phl_com, hal_info)CONFIG_RTL8852Bhal_set_ops_8852bs
- hal_set_ops_8852bs
void hal_set_ops_8852bs(struct rtw_phl_com_t *phl_com,struct hal_info_t *hal)
{struct hal_ops_t *ops = hal_get_ops(hal);hal_set_ops_8852b(phl_com, hal);ops->init_hal_spec = init_hal_spec_8852bs;ops->hal_get_efuse = hal_get_efuse_8852bs;ops->hal_init = hal_init_8852bs;ops->hal_deinit = hal_deinit_8852bs;ops->hal_start = hal_start_8852bs;ops->hal_stop = hal_stop_8852bs;
#ifdef CONFIG_WOWLANops->hal_wow_init = hal_wow_init_8852bs;ops->hal_wow_deinit = hal_wow_deinit_8852bs;
#endif /* CONFIG_WOWLAN */ops->hal_hci_configure = hal_hci_cfg_8852bs;ops->init_default_value = init_default_value_8852bs;ops->hal_mp_init = hal_mp_init_8852bs;ops->hal_mp_deinit = hal_mp_deinit_8852bs;ops->enable_interrupt = hal_enable_int_8852bs;ops->disable_interrupt = hal_disable_int_8852bs;ops->config_interrupt = hal_config_int_8852bs;ops->recognize_interrupt = hal_recognize_int_8852bs;ops->recognize_halt_c2h_interrupt = hal_recognize_halt_c2h_int_8852bs;ops->clear_interrupt = hal_clear_interrupt_8852bs;ops->interrupt_handler = hal_int_hdler_8852bs;ops->restore_interrupt = hal_enable_int_8852bs;
}
rtw_dev_probertw_hw_inithal_set_ops_8852b
void hal_set_ops_8852b(struct rtw_phl_com_t *phl_com,struct hal_info_t *hal)
{struct hal_ops_t *ops = hal_get_ops(hal);/*** initialize section ***/ops->read_chip_version = read_chip_version_8852b;ops->hal_cfg_fw = hal_cfg_fw_8852b;ops->read_macreg = hal_read_macreg;ops->write_macreg = hal_write_macreg;ops->read_bbreg = hal_read_bbreg;ops->write_bbreg = hal_write_bbreg;ops->read_rfreg = hal_read_rfreg;ops->write_rfreg = hal_write_rfreg;#ifdef RTW_PHL_BCNops->cfg_bcn = hal_config_beacon_8852b;ops->upt_bcn = hal_update_beacon_8852b;
#endifops->pkt_ofld = rtw_hal_mac_pkt_ofld;ops->pkt_update_ids = rtw_hal_mac_pkt_update_ids;
}
hal_set_ops_8852bops->read_bbreg = hal_read_bbreg;_hal_read32io_priv->io_ops._read32rtw_hal_com_t *hal->hal_io_priv iopriv-> hal_io_ops io_opsu32(*_read32)(struct rtw_hal_com_t *hal, u32 addr)ops->write_bbreg = hal_write_bbreg;_hal_write32io_priv->io_ops._write32rtw_hal_com_t *hal->hal_io_priv iopriv-> hal_io_ops io_opsint (*_write32)(struct rtw_hal_com_t *hal, u32 addr, u32 val);
io_ops 哪里注册了呢
- hal_init_io_priv 起到调用 set_intf_ops作用
- 其实就是将 hal_mac_sdio_read32 hal_mac_sdio_write32赋值给 rtw_hal_com_t
rtw_dev_probesdio_dvobj_initrtw_hw_initrtw_phl_initrtw_hal_initset_intf_ops = hal_sdio_set_io_opspops->_read32 = hal_mac_sdio_read32pops->_write32 = hal_mac_sdio_write32hal_init_io_priv(hal_info->hal_com, set_intf_ops)hal_set_ops
Part C
- reg_read32哪里来的?
hal_mac_sdio_read32(struct rtw_hal_com_t *hal, u32 addr)struct rtw_hal_com_t *halhal_info_t *hal_info = hal->hal_privmac_ax_adapter *mac = hal_to_mac(hal_info)mac_ax_ops *mac_api = mac->opsmac_ax_intf_ops *mac_intf_ops = mac_api->intf_opsmac_intf_ops->reg_read32(mac, addr)
- mac_intf_ops 是 mac_ax_intf_ops类,mac_ax_intf_ops哪里定义?
rtw_dev_probesdio_dvobj_initrtw_hw_initrtw_phl_initrtw_hal_initset_intf_ops = hal_sdio_set_io_opshal_init_io_priv(hal_info->hal_com, set_intf_ops)hal_set_opsrtw_hal_mac_initrtw_plt_cb_initrtw_plt_cb.sdio_cmd52_r8 = hal_mac_sdio_cmd52_r8;rtw_plt_cb.sdio_cmd53_r8 = hal_mac_sdio_cmd53_r8;mac_ax_ops_initget_mac_ax_adapterget_mac_8852b_adapteradapter->ops->intf_ops = mac_ax_intf_ops &mac8852b_sdio_ops
- mac8852b_sdio_ops为定义
static struct mac_ax_intf_ops mac8852b_sdio_ops = {reg_read8_sdio, /* reg_read8 */reg_write8_sdio, /* reg_write8 */reg_read16_sdio, /* reg_read16 */reg_write16_sdio, /* reg_write16 */reg_read32_sdio, /* reg_read32 */reg_write32_sdio, /* reg_write32 */tx_allow_sdio, /* tx_allow_sdio */tx_cmd_addr_sdio, /* tx_cmd_addr_sdio */sdio_pre_init, /* intf_pre_init */sdio_init, /* intf_init */sdio_deinit, /* intf_init */reg_read_n_sdio, /* reg_read_n_sdio */NULL, /*get_bulkout_id*/NULL, /* ltr_set_pcie */NULL, /*u2u3_switch*/NULL, /*get_usb_mode*/NULL, /*get_usb_support_ability*/NULL, /*usb_tx_agg_cfg*/NULL, /*usb_rx_agg_cfg*/set_sdio_wowlan, /*set_wowlan*/NULL, /*ctrl_txdma_ch*/NULL, /*clr_idx_all*/NULL, /*poll_txdma_ch_idle*/NULL, /*poll_rxdma_ch_idle*/NULL, /*ctrl_txhci*/NULL, /*ctrl_rxhci*/NULL, /*ctrl_dma_io*/NULL, /* get_io_stat */sdio_get_txagg_num, /*get_txagg_num*/NULL, /*get_usb_rx_state*/sdio_autok_counter_avg, /* pcie_autok_counter_avg */dbcc_hci_ctrl_sdio, /* dbcc_hci_ctrl */
};
#endif
- mac_intf_ops->reg_read32(mac, addr) 即为 reg_read32_sdio(mac, addr)
u32 reg_read32_sdio(struct mac_ax_adapter *adapter, u32 adr)
{u8 pwr_state, reg_domain;union {__le32 dword;u8 byte[4];} value32 = { 0x00000000 };pwr_state = pwr_state_chk_sdio(adapter);reg_domain = reg_chk_sdio(adapter, adr);if ((adr & (4 - 1)) == 0) {if (pwr_state == SDIO_PWR_OFF && reg_domain == SDIO_REG_LOCAL) {value32.byte[0] = PLTFM_SDIO_CMD52_R8(adr);value32.byte[1] = PLTFM_SDIO_CMD52_R8(adr + 1);value32.byte[2] = PLTFM_SDIO_CMD52_R8(adr + 2);value32.byte[3] = PLTFM_SDIO_CMD52_R8(adr + 3);return le32_to_cpu(value32.dword);}if (pwr_state == SDIO_PWR_ON &&(reg_domain == SDIO_REG_LOCAL ||reg_domain == SDIO_REG_WLAN_REG))return _pltfm_sdio_cmd53_r32(adapter, adr);return r_indir_sdio(adapter, adr, SDIO_IO_DWORD);}if (reg_domain == SDIO_REG_LOCAL) {value32.byte[0] = PLTFM_SDIO_CMD52_R8(adr);value32.byte[1] = PLTFM_SDIO_CMD52_R8(adr + 1);value32.byte[2] = PLTFM_SDIO_CMD52_R8(adr + 2);value32.byte[3] = PLTFM_SDIO_CMD52_R8(adr + 3);return le32_to_cpu(value32.dword);}value32.byte[0] = (u8)r_indir_sdio(adapter, adr, SDIO_IO_BYTE);value32.byte[1] = (u8)r_indir_sdio(adapter, adr + 1, SDIO_IO_BYTE);value32.byte[2] = (u8)r_indir_sdio(adapter, adr + 2, SDIO_IO_BYTE);value32.byte[3] = (u8)r_indir_sdio(adapter, adr + 3, SDIO_IO_BYTE);return le32_to_cpu(value32.dword);
}
- reg_read32_sdio 用到 PLTFM_SDIO_CMD52_R8
- PLTFM_SDIO_CMD52_R8 调用 hal_mac_sdio_cmd52_r8
- 本质调用了sdio_ops->write 也就是rtw_sdio_raw_write
PLTFM_SDIO_CMD52_R8sdio_cmd52_r8hal_mac_sdio_cmd52_r8_os_sdio_cmd52_r8rtw_sdio_read_cmd52sdio_iod->intf_ops->write#dvobj->intf_ops = &sdio_opsrtw_sdio_raw_write
- rtw_plt_cb.sdio_cmd52_r8 在 rtw_plt_cb_init定义
void rtw_plt_cb_init(void)
{/* R/W register */
#ifdef CONFIG_SDIO_HCIrtw_plt_cb.sdio_cmd52_r8 = hal_mac_sdio_cmd52_r8;rtw_plt_cb.sdio_cmd53_r8 = hal_mac_sdio_cmd53_r8;rtw_plt_cb.sdio_cmd53_r16 = hal_mac_sdio_cmd53_r16;rtw_plt_cb.sdio_cmd53_r32 = hal_mac_sdio_cmd53_r32;rtw_plt_cb.sdio_cmd53_rn = hal_mac_sdio_cmd53_rn;rtw_plt_cb.sdio_cmd52_w8 = hal_mac_sdio_cmd52_w8;rtw_plt_cb.sdio_cmd53_w8 = hal_mac_sdio_cmd53_w8;rtw_plt_cb.sdio_cmd53_w16 = hal_mac_sdio_cmd53_w16;rtw_plt_cb.sdio_cmd53_w32 = hal_mac_sdio_cmd53_w32;rtw_plt_cb.sdio_cmd53_wn = hal_mac_sdio_cmd53_wn;rtw_plt_cb.sdio_cmd52_cia_r8 = hal_mac_sdio_cmd52_cia_r8;
#endif /* CONFIG_SDIO_HCI */#if defined(CONFIG_USB_HCI) || defined(CONFIG_PCI_HCI)rtw_plt_cb.reg_r8 = hal_mac_reg_r8;rtw_plt_cb.reg_r16 = hal_mac_reg_r16;rtw_plt_cb.reg_r32 = hal_mac_reg_r32;rtw_plt_cb.reg_w8 = hal_mac_reg_w8;rtw_plt_cb.reg_w16 = hal_mac_reg_w16;rtw_plt_cb.reg_w32 = hal_mac_reg_w32;
#endif /* CONFIG_USB_HCI || CONFIG_PCI_HCI *//* Memory allocate */rtw_plt_cb.rtl_free = hal_mac_mem_free;rtw_plt_cb.rtl_malloc = hal_mac_mem_alloc;rtw_plt_cb.rtl_memcpy = hal_mac_mem_cpy;rtw_plt_cb.rtl_memset = hal_mac_mem_set;rtw_plt_cb.rtl_memcmp = hal_mac_mem_cmp;/* Sleep */rtw_plt_cb.rtl_delay_us = hal_mac_udelay;rtw_plt_cb.rtl_delay_ms = hal_mac_mdelay;/* Process Synchronization */rtw_plt_cb.rtl_mutex_init = hal_mac_mutex_init;rtw_plt_cb.rtl_mutex_deinit = hal_mac_mutex_deinit;rtw_plt_cb.rtl_mutex_lock = hal_mac_mutex_lock;rtw_plt_cb.rtl_mutex_unlock = hal_mac_mutex_unlock;rtw_plt_cb.msg_print = hal_mac_msg_print;rtw_plt_cb.event_notify = hal_mac_event_notify;rtw_plt_cb.ser_l2_notify = hal_ser_l2_notify;rtw_plt_cb.ld_fw_symbol = hal_mac_ld_fw_symbol;/*.tx = ; */
#if MAC_AX_PHL_H2Crtw_plt_cb.tx = hal_pltfm_tx;rtw_plt_cb.rtl_query_h2c = hal_query_h2c_pkt;
#endif
#if MAC_AX_FEATURE_DBGCMDrtw_plt_cb.rtl_sprintf = hal_mac_sprintf;rtw_plt_cb.rtl_strcmp = hal_mac_strcmp;rtw_plt_cb.rtl_strsep = hal_mac_strsep;rtw_plt_cb.rtl_strlen = hal_mac_strlen;rtw_plt_cb.rtl_strcpy = hal_mac_strcpy;rtw_plt_cb.rtl_strpbrk = hal_mac_strpbrk;rtw_plt_cb.rtl_strtoul = hal_mac_strtoul;
#endif
}
- 相当绕呀,reg_read32_sdio最终实现
- 是调用dvobj->intf_ops = &sdio_ops 中的rtw_sdio_raw_write
- 最终调用dw_mci_ops->request
rtw_sdio_raw_writesdio_f0_writeb & sdio_writebmmc_io_rw_directmmc_io_rw_direct_hostsdio_writesb & sdio_memcpy_toiosdio_io_rw_ext_helpermmc_io_rw_extendedmmc_wait_for_req__mmc_start_reqmmc_start_request__mmc_start_requesthost->ops->request(host, mrq)
- host->ops哪来的,哪定义的?
- 提前公布答案
host->ops->request(host, mrq)mmc_host_ops dw_mci_ops
Part D
- kernel\arch\arm64\boot\dts\rockchip
rk3568-atk-evb1-ddr4-v10-linux.dtsrk3568-atk-evb1-ddr4-v10.dtsirk3568.dtsirk3568-evb.dtsirk3568-linux.dtsirk3568-screen_choose.dtsirk3568-lcds.dtsi
- rk3568-atk-evb1-ddr4-v10.dtsi
&sdmmc2 {max-frequency = <150000000>;supports-sdio;bus-width = <4>;disable-wp;cap-sd-highspeed;cap-sdio-irq;keep-power-in-suspend;mmc-pwrseq = <&sdio_pwrseq>;non-removable;pinctrl-names = "default";pinctrl-0 = <&sdmmc2m0_bus4 &sdmmc2m0_cmd &sdmmc2m0_clk>;sd-uhs-sdr104;status = "okay";
};&wireless_wlan {pinctrl-names = "default";pinctrl-0 = <&wifi_host_wake_irq>;WIFI,host_wake_irq = <&gpio3 RK_PD4 GPIO_ACTIVE_HIGH>;wifi_chip_type = "rtl8852bs";//keep_wifi_power_on;//clocks = <&rk809 1>;//clock-names = "clk_wifi";
};&wireless_bluetooth {compatible = "bluetooth-platdata";clocks = <&rk809 1>;clock-names = "ext_clock";//wifi-bt-power-toggle;uart_rts_gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_LOW>;pinctrl-names = "default", "rts_gpio";pinctrl-0 = <&uart8m0_rtsn>;pinctrl-1 = <&uart8_gpios>;BT,reset_gpio = <&gpio3 RK_PA0 GPIO_ACTIVE_HIGH>;//BT,power_gpio = <&gpio3 RK_PA0 GPIO_ACTIVE_HIGH>;BT,wake_gpio = <&gpio3 RK_PA2 GPIO_ACTIVE_HIGH>;BT,wake_host_irq = <&gpio0 RK_PB7 GPIO_ACTIVE_HIGH>;status = "okay";
};
- rk3568-evb.dtsi
wireless_wlan: wireless-wlan {compatible = "wlan-platdata";rockchip,grf = <&grf>;wifi_chip_type = "ap6398s";status = "okay";
};wireless_bluetooth: wireless-bluetooth {compatible = "bluetooth-platdata";clocks = <&rk809 1>;clock-names = "ext_clock";//wifi-bt-power-toggle;uart_rts_gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_LOW>;pinctrl-names = "default", "rts_gpio";pinctrl-0 = <&uart8m0_rtsn>;pinctrl-1 = <&uart8_gpios>;BT,reset_gpio = <&gpio3 RK_PA0 GPIO_ACTIVE_HIGH>;BT,wake_gpio = <&gpio3 RK_PA1 GPIO_ACTIVE_HIGH>;BT,wake_host_irq = <&gpio3 RK_PA2 GPIO_ACTIVE_HIGH>;status = "okay";
};
- rk3568.dtsi
sdmmc2: dwmmc@fe000000 {compatible = "rockchip,rk3568-dw-mshc","rockchip,rk3288-dw-mshc";reg = <0x0 0xfe000000 0x0 0x4000>;interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;max-frequency = <150000000>;clocks = <&cru HCLK_SDMMC2>, <&cru CLK_SDMMC2>,<&cru SCLK_SDMMC2_DRV>, <&cru SCLK_SDMMC2_SAMPLE>;clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";fifo-depth = <0x100>;resets = <&cru SRST_SDMMC2>;reset-names = "reset";status = "disabled";
};
drivers/mmc/host/dw_mmc-rockchip.c
static const struct dw_mci_drv_data rk3288_drv_data = {.caps = dw_mci_rk3288_dwmmc_caps,.num_caps = ARRAY_SIZE(dw_mci_rk3288_dwmmc_caps),.set_ios = dw_mci_rk3288_set_ios,.execute_tuning = dw_mci_rk3288_execute_tuning,.parse_dt = dw_mci_rk3288_parse_dt,.init = dw_mci_rockchip_init,
};static const struct of_device_id dw_mci_rockchip_match[] = {{ .compatible = "rockchip,rk2928-dw-mshc",.data = &rk2928_drv_data },{ .compatible = "rockchip,rk3288-dw-mshc",.data = &rk3288_drv_data },{},
};MODULE_DEVICE_TABLE(of, dw_mci_rockchip_match);
dw_mci_rockchip_pltfm_driver
static struct platform_driver dw_mci_rockchip_pltfm_driver = {.probe = dw_mci_rockchip_probe,.remove = dw_mci_rockchip_remove,.driver = {.name = "dwmmc_rockchip",.of_match_table = dw_mci_rockchip_match,.pm = &dw_mci_rockchip_dev_pm_ops,},
};
- 由DTB 朔源 找到 mmc->ops = &dw_mci_ops
.compatible = "rockchip,rk3288-dw-mshc"dw_mci_rockchip_probedw_mci_pltfm_register(pdev, drv_data) //dw_mci_drv_data rk3288_drv_datadw_mci_probedw_mci_init_slotmmc->ops = &dw_mci_ops
static const struct mmc_host_ops dw_mci_ops = {.request = dw_mci_request,.pre_req = dw_mci_pre_req,.post_req = dw_mci_post_req,.set_ios = dw_mci_set_ios,.set_sdio_status = dw_mci_set_sdio_status,.get_ro = dw_mci_get_ro,.get_cd = dw_mci_get_cd,.hw_reset = dw_mci_hw_reset,.enable_sdio_irq = dw_mci_enable_sdio_irq,.ack_sdio_irq = dw_mci_ack_sdio_irq,.execute_tuning = dw_mci_execute_tuning,.card_busy = dw_mci_card_busy,.start_signal_voltage_switch = dw_mci_switch_voltage,.init_card = dw_mci_init_card,.prepare_hs400_tuning = dw_mci_prepare_hs400_tuning,
};
Part E
- 结合PartC
- host->ops->request(host, mrq) 即为 dw_mci_request
host->ops->request(host, mrq)dw_mci_requestdw_mci_queue_requestdw_mci_start_request__dw_mci_start_requestmci_writelwritel_relaxed__raw_writelasm volatile("str %w0, [%1]" : : "rZ" (val), "r" (addr))
asm volatile("str %w0, [%1]" : : "rZ" (val), "r" (addr));
这是 GCC 内联汇编,真正干活的只有一条指令:
str %w0, [%1]
:把寄存器%w0
(32 位宽)里的值,写到由%1
寄存器保存的地址处。"rZ" (val)
:告诉编译器“把val
放到一个通用寄存器里”,Z
表示允许使用零寄存器(XZR/WZR)做优化。"r" (addr)
:把addr
也放到一个通用寄存器里。volatile
:告诉编译器“这段汇编有副作用,不能随意重排或删除”。
#define __raw_writel __raw_writel
static inline void __raw_writel(u32 val, volatile void __iomem *addr)
{asm volatile("str %w0, [%1]" : : "rZ" (val), "r" (addr));
}
- 在probe的时候我们为wlan0的网络节点的接口中赋值了ndo_open和ndo_open函数,这两个接口是在ifconfig wlan0 up和ifconfig wlan0 down调用的。
if (!dev_is_hw_start(dvobj)) {
// 如果设备未启动,则清除意外移除标志位和驱动停止标志位,并启用接收和发送功能
status = rtw_hw_start(dvobj);// 调用硬件启动函数
rtw_led_control(padapter, LED_CTL_NO_LINK);
napi_enable(&padapter->napi);
rtw_hw_iface_init(padapter)// 如果网络设备未启用,则初始化网络设备
rtw_netif_wake_queue(pnetdev)// 唤醒网络设备队列
netdev_br_init(pnetdev)//
- drivers\net\wireless\rockchip_wlan\rtl8852bs\os_dep\linux\os_intfs.c
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
static const struct net_device_ops rtw_netdev_ops = {.ndo_init = rtw_ndev_init,.ndo_uninit = rtw_ndev_uninit,.ndo_open = netdev_open,.ndo_stop = netdev_close,.ndo_start_xmit = rtw_xmit_entry,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)).ndo_select_queue = rtw_select_queue,
#endif.ndo_set_mac_address = rtw_net_set_mac_address,.ndo_get_stats = rtw_net_get_stats,.ndo_do_ioctl = rtw_ioctl,
};
#endif
void rtw_hook_if_ops(struct net_device *ndev)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))ndev->netdev_ops = &rtw_netdev_ops;
#elsendev->init = rtw_ndev_init;ndev->uninit = rtw_ndev_uninit;ndev->open = netdev_open;ndev->stop = netdev_close;ndev->hard_start_xmit = rtw_xmit_entry;ndev->set_mac_address = rtw_net_set_mac_address;ndev->get_stats = rtw_net_get_stats;ndev->do_ioctl = rtw_ioctl;
#endif
}
rtw_hook_if_ops(pnetdev)
struct net_device *rtw_init_netdev(_adapter *old_padapter)
int rtw_os_ndev_alloc(_adapter *adapter)
int rtw_os_ndev_init(_adapter *adapter, const char *name)
cfg80211_rtw_add_virtual_intf
.add_virtual_intf = cfg80211_rtw_add_virtual_intf,
.del_virtual_intf = cfg80211_rtw_del_virtual_intf,
cfg80211_ops rtw_cfg80211_ops
wiphy = wiphy_new(&rtw_cfg80211_ops, sizeof(struct rtw_wiphy_data));
struct wiphy *rtw_wiphy_alloc(_adapter *padapter, struct device *dev)
int rtw_cfg80211_dev_res_alloc(struct dvobj_priv *dvobj)
int rtw_os_ndevs_alloc(struct dvobj_priv *dvobj)
int rtw_os_ndevs_init(struct dvobj_priv *dvobj)
rtw_dev_probe/* dev_alloc_name && register_netdev */
- sdio_register_driver ,具体在drivers\mmc\core\sdio_bus.c 文件中
- sdio_bus_probe识别sdio_bus_match,调用驱动匹配项的.probe
static struct bus_type sdio_bus_type = {.name = "sdio",.dev_groups = sdio_dev_groups,.match = sdio_bus_match,.uevent = sdio_bus_uevent,.probe = sdio_bus_probe,.remove = sdio_bus_remove,.pm = &sdio_bus_pm_ops,
};static const struct sdio_device_id *sdio_match_one(struct sdio_func *func,const struct sdio_device_id *id)
{if (id->class != (__u8)SDIO_ANY_ID && id->class != func->class)return NULL;if (id->vendor != (__u16)SDIO_ANY_ID && id->vendor != func->vendor)return NULL;if (id->device != (__u16)SDIO_ANY_ID && id->device != func->device)return NULL;return id;
}static const struct sdio_device_id *sdio_match_device(struct sdio_func *func,struct sdio_driver *sdrv)
{const struct sdio_device_id *ids;ids = sdrv->id_table;if (ids) {while (ids->class || ids->vendor || ids->device) {if (sdio_match_one(func, ids))return ids;ids++;}}return NULL;
}static int sdio_bus_match(struct device *dev, struct device_driver *drv)
{struct sdio_func *func = dev_to_sdio_func(dev);struct sdio_driver *sdrv = to_sdio_driver(drv);if (sdio_match_device(func, sdrv))return 1;return 0;
}/*** sdio_register_driver - register a function driver* @drv: SDIO function driver*/
int sdio_register_driver(struct sdio_driver *drv)
{drv->drv.name = drv->name;drv->drv.bus = &sdio_bus_type;return driver_register(&drv->drv);
}
EXPORT_SYMBOL_GPL(sdio_register_driver);