当前位置: 首页 > ds >正文

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 upip link set wlan0 up 时调用netdev_open
.ndo_stop当用户执行 ifconfig wlan0 downip 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);
http://www.xdnf.cn/news/17746.html

相关文章:

  • Java多线程并发控制:使用ReentrantLock实现生产者-消费者模型
  • MySQL杂项
  • 【网络运维】Linux:LNMP 项目实践
  • redis常见的性能问题
  • 用Python实现Excel转PDF并去除Spire.XLS水印
  • [Ubuntu] xrdp共享连接 Ubuntu 屏幕 | xfce4
  • 数据结构 双链表与LinkedList
  • 【排序算法】⑦归并排序
  • Python笔记之`getattr`和`hasattr`用法详解
  • (二)vscode搭建espidf环境,配置wsl2
  • 【Altium designer】一键添加多个器件参数的“备注”
  • GPT-5越狱与零点击AI代理攻击:云与IoT系统面临新型威胁
  • 如何在 Ubuntu 24.04 LTS Linux 上安装和使用 Flatpak
  • 使用dockge 安装 photoprism
  • Nacos添加权限
  • Springboot-vue 地图展现
  • C++多态是如何实现
  • 【Altium designer】解决报错“Access violation at address...“
  • 机器学习第九课之DBSCAN算法
  • 【接口自动化测试】---YAML、JSON Schema
  • 02Vue3
  • github上传项目
  • 视频前处理技术全解析:从基础到前沿
  • Elasticsearch 官方 Node.js 从零到生产
  • docker安装Engine stopped
  • AVS Video Converter视频转换与编辑工具深度评测
  • 功能、延迟、部署、成本全解析:本地化音视频 SDK 对比 云端方案
  • Go 多进程编程-socket(套接字)
  • 定制化4G专网架构,满足多行业专属需求
  • 区间修改 - 差分