驱动结构框架
- LINUX RTL8852BS驱动框架很繁杂
- 结合Bear+Clangd+Vscode+Ubuntu阅读代码
- 梳理出下列流程框架
综述
c
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中断
c
rtw_init_netdev
rtw_hook_if_ops(pnetdev)
rtw_netdev_ops
pnetdev->wireless_handlers = (struct iw_handler_def *)&rtw_handlers_def;
rtw_netdev_ops
就是 Realtek Wi-Fi 驱动向内核注册的"网卡操作表",内核通过这些回调函数把用户态或协议栈的请求(打开网卡、发送数据、设置 MAC 等)转发给驱动里对应的处理函数
c
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() 调用私有命令时调用 |
c
rtw_xmit_entry
core_tx_call_phl
rtw_phl_add_tx_req
rtw_phl_tx_req_notify
phl_schedule_handler
- phl_tx_sdio_thrd_hdl核心线程
c
rtw_phl_init
phl_set_hci_ops
phl_hook_trx_ops_sdio
_phl_hci_ops_check
phl_trx_init_sdio
phl_register_trx_hdlr_sdio
phl_register_handler
phl_tx_callback_sdio
phl_handle_xmit_ring_sdio
phl_rx_callback_sdio
_os_thread_init(drv, &hci->tx_thrd, phl_tx_sdio_thrd_hdl,phl_info, "rtw_sdio_tx")
- 事实上也是调用rtw_sdio_raw_write
c
phl_tx_sdio_thrd_hdl
rtw_hal_sdio_tx
rtw_sdio_write_cmd53
sdio_io
d->intf_ops->write
rtw_sdio_raw_write
- 把 Realtek 驱动自定义的"标准 + 私有 ioctl 处理表"挂接到网卡设备
- 用户空间执行
iwconfig wlan0 essid "xxx"
时,内核会调用rtw_handlers_def.standard[]
里对应的函数 - 用户空间执行
iwpriv wlan0 set_mib txpower=100
时,内核会调用rtw_handlers_def.private[]
里对应的函数
c
iw_handler_def rtw_handlers_def
iw_handler rtw_handlers
iw_handler rtw_private_handler
- iwpriv扩展命令会调用
c
rtw_handlers_def
rtw_private_handler
rtw_wx_read32
rtw_phl_read32
rtw_hal_read32
hal_read32
_hal_read32
Part A
- drivers/net/wireless/rockchip_wlan/rtl8852bs/os_dep/linux/sdio_intf.c
C
module_init(rockchip_wifi_init_module_rtkwifi)
rtw_drv_entry
sdio_register_driver(&sdio_drvpriv.rtw_sdio_drv)
- 驱动程序加载时,内核会使用
sdio_register_driver
函数来注册 SDIO 设备驱动程序,并使用sdio_device_id
结构体数组sdio_ids
来匹配连接的 SDIO 设备
c
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 函数来初始化设备
c
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 处理函数
c
rtw_dev_probe
sdio_dvobj_init
rtw_sdio_init
sdio_set_block_size(func, 512)
dvobj->intf_ops = &sdio_ops
rtw_hw_init
c
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
c
rtw_dev_probe
sdio_dvobj_init
rtw_hw_init
rtw_phl_init
rtw_hal_init
set_intf_ops = hal_sdio_set_io_ops
hal_init_io_priv(hal_info->hal_com, set_intf_ops)
hal_set_ops(phl_com, hal_info)
CONFIG_SDIO_HCI
hal_set_ops_sdio(phl_com, hal_info)
CONFIG_RTL8852B
hal_set_ops_8852bs
- hal_set_ops_8852bs
c
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_WOWLAN
ops->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;
}
c
rtw_dev_probe
rtw_hw_init
hal_set_ops_8852b
c
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_BCN
ops->cfg_bcn = hal_config_beacon_8852b;
ops->upt_bcn = hal_update_beacon_8852b;
#endif
ops->pkt_ofld = rtw_hal_mac_pkt_ofld;
ops->pkt_update_ids = rtw_hal_mac_pkt_update_ids;
}
c
hal_set_ops_8852b
ops->read_bbreg = hal_read_bbreg;
_hal_read32
io_priv->io_ops._read32
rtw_hal_com_t *hal->hal_io_priv iopriv-> hal_io_ops io_ops
u32(*_read32)(struct rtw_hal_com_t *hal, u32 addr)
ops->write_bbreg = hal_write_bbreg;
_hal_write32
io_priv->io_ops._write32
rtw_hal_com_t *hal->hal_io_priv iopriv-> hal_io_ops io_ops
int (*_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
c
rtw_dev_probe
sdio_dvobj_init
rtw_hw_init
rtw_phl_init
rtw_hal_init
set_intf_ops = hal_sdio_set_io_ops
pops->_read32 = hal_mac_sdio_read32
pops->_write32 = hal_mac_sdio_write32
hal_init_io_priv(hal_info->hal_com, set_intf_ops)
hal_set_ops
Part C
- reg_read32哪里来的?
C
hal_mac_sdio_read32(struct rtw_hal_com_t *hal, u32 addr)
struct rtw_hal_com_t *hal
hal_info_t *hal_info = hal->hal_priv
mac_ax_adapter *mac = hal_to_mac(hal_info)
mac_ax_ops *mac_api = mac->ops
mac_ax_intf_ops *mac_intf_ops = mac_api->intf_ops
mac_intf_ops->reg_read32(mac, addr)
- mac_intf_ops 是 mac_ax_intf_ops类,mac_ax_intf_ops哪里定义?
c
rtw_dev_probe
sdio_dvobj_init
rtw_hw_init
rtw_phl_init
rtw_hal_init
set_intf_ops = hal_sdio_set_io_ops
hal_init_io_priv(hal_info->hal_com, set_intf_ops)
hal_set_ops
rtw_hal_mac_init
rtw_plt_cb_init
rtw_plt_cb.sdio_cmd52_r8 = hal_mac_sdio_cmd52_r8;
rtw_plt_cb.sdio_cmd53_r8 = hal_mac_sdio_cmd53_r8;
mac_ax_ops_init
get_mac_ax_adapter
get_mac_8852b_adapter
adapter->ops->intf_ops = mac_ax_intf_ops &mac8852b_sdio_ops
- mac8852b_sdio_ops为定义
c
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)
c
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
c
PLTFM_SDIO_CMD52_R8
sdio_cmd52_r8
hal_mac_sdio_cmd52_r8
_os_sdio_cmd52_r8
rtw_sdio_read_cmd52
sdio_io
d->intf_ops->write
#dvobj->intf_ops = &sdio_ops
rtw_sdio_raw_write
- rtw_plt_cb.sdio_cmd52_r8 在 rtw_plt_cb_init定义
c
void rtw_plt_cb_init(void)
{
/* R/W register */
#ifdef CONFIG_SDIO_HCI
rtw_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_H2C
rtw_plt_cb.tx = hal_pltfm_tx;
rtw_plt_cb.rtl_query_h2c = hal_query_h2c_pkt;
#endif
#if MAC_AX_FEATURE_DBGCMD
rtw_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
c
rtw_sdio_raw_write
sdio_f0_writeb & sdio_writeb
mmc_io_rw_direct
mmc_io_rw_direct_host
sdio_writesb & sdio_memcpy_toio
sdio_io_rw_ext_helper
mmc_io_rw_extended
mmc_wait_for_req
__mmc_start_req
mmc_start_request
__mmc_start_request
host->ops->request(host, mrq)
- host->ops哪来的,哪定义的?
- 提前公布答案
c
host->ops->request(host, mrq)
mmc_host_ops dw_mci_ops
Part D
- kernel\arch\arm64\boot\dts\rockchip
c
rk3568-atk-evb1-ddr4-v10-linux.dts
rk3568-atk-evb1-ddr4-v10.dtsi
rk3568.dtsi
rk3568-evb.dtsi
rk3568-linux.dtsi
rk3568-screen_choose.dtsi
rk3568-lcds.dtsi
- rk3568-atk-evb1-ddr4-v10.dtsi
c
&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
c
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
c
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
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
c
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
c
.compatible = "rockchip,rk3288-dw-mshc"
dw_mci_rockchip_probe
dw_mci_pltfm_register(pdev, drv_data) //dw_mci_drv_data rk3288_drv_data
dw_mci_probe
dw_mci_init_slot
mmc->ops = &dw_mci_ops
c
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
c
host->ops->request(host, mrq)
dw_mci_request
dw_mci_queue_request
dw_mci_start_request
__dw_mci_start_request
mci_writel
writel_relaxed
__raw_writel
asm 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
:告诉编译器"这段汇编有副作用,不能随意重排或删除"。
c
#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调用的。
c
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
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
c
void rtw_hook_if_ops(struct net_device *ndev)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29))
ndev->netdev_ops = &rtw_netdev_ops;
#else
ndev->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
}
c
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
c
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);