linux 编译mtk无线驱动,Linux驱动(七)----MTK驱动注册分析
mtk7621驱动
无线驱动在完成驱动注册的同时,需要进行 cfg80211接口注册(提供命令支持)。
1.驱动
mtk wifi驱动基于pci进行扩展,第一个文件:/os/linux/pci_main_dev.c
文件用于创建和注册基于pci接口的网络设备,PCI设备上有三种地址空间:PCI的I/O空间、PCI的存储空间和PCI的配置空间。CPU可以访问PCI设备上的所有地址空间,其中I/O空间和存储空间提供给设备驱动程序使用,而配置空间则由Linux内核中的PCI初始化代码使用。内核在启动时负责对所有PCI设备进行初始化,配置好所有的PCI设备,包括中断号以及I/O基址,并在文件/proc/pci中列出所有找到的PCI设备,以及这些设备的参数和属性。
Linux驱动程序通常使用结构(struct)来表示一种设备,而结构体中的变量则代表某一具体设备,该变量存放了与该设备相关的所有信息。好的驱动程序都应该能驱动多个同种设备,每个设备之间用次设备号进行区分,如果采用结构数据来代表所有能由该驱动程序驱动的设备,那么就可以简单地使用数组下标来表示次设备号。
1.1数据结构
1 static struct pci_device_id rt_pci_tbl[]
DEVINITDATA =
{
{PCI_DEVICE(NIC_PCI_VENDOR_ID,
NIC3091_PCIe_DEVICE_ID)},
#ifdef RT8592
{PCI_DEVICE(NIC_PCI_VENDOR_ID,
NIC8592_PCIe_DEVICE_ID)},
#endif /* RT8592 */
#ifdef MT76x2
{PCI_DEVICE(0x1400, NIC7650_PCIe_DEVICE_ID)},
{PCI_DEVICE(0x1400,
NIC7662_PCIe_DEVICE_ID)},
{PCI_DEVICE(MTK_PCI_VENDOR_ID,
NIC7662_PCIe_DEVICE_ID)},
{PCI_DEVICE(MTK_PCI_VENDOR_ID,
NIC7632_PCIe_DEVICE_ID)},
{PCI_DEVICE(MTK_PCI_VENDOR_ID,
NIC7612_PCIe_DEVICE_ID)},
{PCI_DEVICE(MTK_PCI_VENDOR_ID,
NIC7602_PCIe_DEVICE_ID)},
#endif /* MT76x2 */
{} /* terminate list */
};
struct pci_device_id {
__u32
vendor,device;
//厂商和设备ID
__u32
subvendor,subdevice; //子系统和设备ID
__u32 class,class_mask;
//类、子类、prog-if三元组
kernel_ulong_t
driver_data; //驱动私有数据
pci_device_id 用MODULE_DEVICE_TABLE映射到用户空间。
2 struct pci_driver {
struct list_head node;
const char *name;
const struct pci_device_id *id_table; /* must
be non-NULL for probe to be called */
int (*probe) (struct pci_dev *dev, const
struct pci_device_id *id); /* New device inserted */
void (*remove) (struct pci_dev *dev); /*
Device removed (NULL if not a hot-plug capable driver) */
int (*suspend) (struct pci_dev *dev,
pm_message_t state); /* Device suspended */
int (*suspend_late) (struct pci_dev *dev,
pm_message_t state);
int (*resume_early) (struct pci_dev *dev);
int (*resume) (struct pci_dev *dev); /*
Device woken up */
void (*shutdown) (struct pci_dev *dev);
int (*sriov_configure) (struct pci_dev
*dev, int num_vfs); /* PF pdev */
const struct pci_error_handlers
*err_handler;
struct device_driver driver;
struct pci_dynids dynids;
};
3 struct pci_dev {
struct list_head bus_list;
/* 总线设备链表元素bus_list:每一个pci_dev结构除了链接到全局设备链表中外,还会通过这个成员连接到其所属PCI总线的设备链表中。每一条PCI总线都维护一条它自己的设备链表视图,以便描述所有连接在该PCI总线上的设备,其表头由PCI总线的pci_bus结构中的 devices成员所描述t*/
struct pci_bus *bus;
/* 总线指针bus:指向这个PCI设备所在的PCI总线的pci_bus结构。因此,对于桥设备而言,bus指针将指向桥设备的主总线(primary bus),也即指向桥设备所在的PCI总线*/
struct pci_bus *subordinate;
/* 指针subordinate:指向这个PCI设备所桥接的下级总线。这个指针成员仅对桥设备才有意义,而对于一般的非桥PCI设备而言,该指针成员总是为NULL*/
void *sysdata;
/* 无类型指针sysdata:指向一片特定于系统的扩展数据*/
struct proc_dir_entry *procent;
/* 指针procent:指向该PCI设备在/proc文件系统中对应的目录项*/
unsigned int devfn;
/* devfn:这个PCI设备的设备功能号,也成为PCI逻辑设备号(0-255)。其中bit[7:3]是物理设备号(取值范围0-31),bit[2:0]是功能号(取值范围0-7)。 */
unsigned short vendor;
/* vendor:这是一个16无符号整数,表示PCI设备的厂商ID*/
unsigned short device;
/*device:这是一个16无符号整数,表示PCI设备的设备ID */
unsigned short subsystem_vendor;
/* subsystem_vendor:这是一个16无符号整数,表示PCI设备的子系统厂商ID*/
unsigned short subsystem_device;
/* subsystem_device:这是一个16无符号整数,表示PCI设备的子系统设备ID。*/
unsigned int class;
/* class:32位的无符号整数,表示该PCI设备的类别,其中,bit[7:0]为编程接口,bit[15:8]为子类别代码,bit [23:16]为基类别代码,bit[31:24]无意义。显然,class成员的低3字节刚好对应与PCI配置空间中的类代码*/
u8 revision; /* PCI revision, low byte of
class word */
u8 hdr_type; /* PCI header type (`multi'
flag masked out) */
u8 pcie_cap; /* PCI-E capability offset */
u8 msi_cap; /* MSI capability offset */
u8 msix_cap; /* MSI-X capability offset */
u8 pcie_mpss:3; /* PCI-E Max Payload Size
Supported */
u8 rom_base_reg; /* which config register
controls the ROM */
u8 pin; /* which interrupt pin this device
uses */
u16 pcie_flags_reg; /* cached PCI-E
Capabilities Register */
struct pci_driver *driver;
/* 指针driver:指向这个PCI设备所对应的驱动程序定义的pci_driver结构。每一个pci设备驱动程序都必须定义它自己的pci_driver结构来描述它自己。*/
u64 dma_mask;
/*dma_mask:用于DMA的总线地址掩码,一般来说,这个成员的值是0xffffffff。数据类型dma_addr_t定义在include/asm/types.h中,在x86平台上,dma_addr_t类型就是u32类型*/
struct device_dma_parameters dma_parms;
pci_power_t current_state;
/* 当前操作状态 */
u8 pm_cap; /* PM capability offset */
unsigned int pme_support:5; /* Bitmask of
states from which PME#
can be generated */
unsigned int pme_interrupt:1;
unsigned int pme_poll:1; /* Poll device's
PME status bit */
unsigned int d1_support:1; /* Low power
state D1 is supported */
unsigned int d2_support:1; /* Low power
state D2 is supported */
unsigned int no_d1d2:1; /* D1 and D2 are
forbidden */
unsigned int no_d3cold:1; /* D3cold is
forbidden */
unsigned int d3cold_allowed:1; /* D3cold
is allowed by user */
unsigned int mmio_always_on:1; /* disallow
turning off io/mem
decoding during bar sizing */
unsigned int wakeup_prepared:1;
unsigned int runtime_d3cold:1; /* whether
go through runtime
D3cold, not set for devices
powered on/off by the
corresponding bridge */
unsigned int d3_delay; /* D3->D0
transition time in ms */
unsigned int d3cold_delay; /*
D3cold->D0 transition time in ms */
pci_channel_state_t error_state; /*
current connectivity state */
struct device dev; /* Generic device
interface */
int cfg_size;
/* 配置空间的大小 */
unsigned int irq;
struct resource
resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
bool match_driver; /* Skip attaching
driver */
/* These fields are used by common fixups
*/
unsigned int transparent:1; /* Transparent
PCI bridge */
unsigned int multifunction:1;/* Part of
multi-function device */
/* keep track of device state */
unsigned int is_added:1;
unsigned int is_busmaster:1; /* device is
busmaster */
unsigned int no_msi:1; /* device may not
use msi */
unsigned int block_cfg_access:1; /* config
space access is blocked */
unsigned int broken_parity_status:1; /*
Device generates false positive parity */
unsigned int irq_reroute_variant:2; /*
device needs IRQ rerouting variant */
unsigned int msi_enabled:1;
unsigned int msix_enabled:1;
unsigned int ari_enabled:1; /* ARI
forwarding */
unsigned int is_managed:1;
unsigned int is_pcie:1; /* Obsolete. Will
be removed.
Use pci_is_pcie() instead */
unsigned int needs_freset:1; /* Dev
requires fundamental reset */
unsigned int state_saved:1;
unsigned int is_physfn:1;
unsigned int is_virtfn:1;
unsigned int reset_fn:1;
unsigned int is_hotplug_bridge:1;
unsigned int __aer_firmware_first_valid:1;
unsigned int __aer_firmware_first:1;
unsigned int broken_intx_masking:1;
unsigned int io_window_1k:1; /* Intel P2P
bridge 1K I/O windows */
pci_dev_flags_t dev_flags;
atomic_t enable_cnt; /* pci_enable_device
has been called */
u32 saved_config_space[16]; /* config
space saved at suspend time */
struct hlist_head saved_cap_space;
struct bin_attribute *rom_attr; /*
attribute descriptor for sysfs ROM entry */
int rom_attr_enabled; /* has display of
the rom attribute been enabled? */
struct bin_attribute
*res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
struct bin_attribute
*res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources
*/
#ifdef CONFIG_PCI_MSI
struct list_head msi_list;
struct kset *msi_kset;
#endif
struct pci_vpd *vpd;
#ifdef CONFIG_PCI_ATS
union {
struct pci_sriov *sriov; /* SR-IOV
capability related */
struct pci_dev *physfn; /* the PF this VF
is associated with */
};
struct pci_ats *ats; /* Address
Translation Service */
#endif
phys_addr_t rom; /* Physical address of
ROM if it's not from the BAR */
size_t romlen; /* Length of ROM if it's
not from the BAR
};
1.2关键函数
1.2.1 rt_pci_init_module
调用函数pci_register_driver(&rt_pci_driver); 注册设备
1.2.2 rt_pci_probe
主要函数分析
1 rv = pci_enable_device(pdev)
唤醒和使能设备
2 rv = pci_request_regions(pdev,
print_name)
函数通知内核,当前PCI将使用这些内存地址,其他设备不能再使用了
3 csr_addr = (unsigned long)
ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
物理地址与虚拟地址进行映射
4 pci_set_master(pdev);
设置设备具有获得总线的能力,即调用这个函数,使设备具备申请使用PCI总线的能力
5 rv = RTMPAllocAdapterBlock(handle,
&pAd);
适配器申请内存, 并进行初始化。(包括beaconbuf申请\rx ring \tx ring 等初始化)。
6 RTMP_DRIVER_PCI_CSR_SET(pAd, csr_addr);
设置pci 对应的虚拟地址映射
7 RTMP_DRIVER_PCIE_INIT(pAd, pdev);
设置wlan芯片相关寄存器设置 以及pcie的初始化,调用mac目录下的接口函数,对寄存器进行设置.
8 net_dev = RtmpPhyNetDevInit(pAd,
&netDevHook);
实现物理层网络设备的创建、初始化、以及相关结构接口的初始化,主要是结构体的创建。
9 CFG80211_Register(pAd,
&(pdev->dev), net_dev);
实现cfg80211网络设备模块的注册, 提供设备cfg80211接口命令:
os/linux/cfg80211/cfg80211.c
struct cfg80211_ops CFG80211_Ops = {
#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0))
.set_beacon = CFG80211_OpsSetBeacon,
.add_beacon = CFG80211_OpsAddBeacon,
.del_beacon = CFG80211_OpsDelBeacon,
#else
.start_ap =
CFG80211_OpsStartAp,
.change_beacon = CFG80211_OpsChangeBeacon,
.stop_ap =
CFG80211_OpsStopAp,
#endif /* LINUX_VERSION_CODE 3.4 */
/* set channel for a given wireless
interface */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
//.set_monitor_channel =
CFG80211_OpsMonitorChannelSet,
#else
.set_channel =
CFG80211_OpsChannelSet,
#endif /* LINUX_VERSION_CODE: 3.6.0 */
/* change type/configuration of virtual
interface */
.change_virtual_intf =
CFG80211_OpsVirtualInfChg,
.add_virtual_intf
= CFG80211_OpsVirtualInfAdd,
.del_virtual_intf
= CFG80211_OpsVirtualInfDel,
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,6,0))
.start_p2p_device =
CFG80211_start_p2p_device,
.stop_p2p_device =
CFG80211_stop_p2p_device,
#endif /* LINUX_VERSION_CODE: 3.6.0 */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30))
/* request to do a scan */
/*
Note: must exist whatever AP or STA
mode; Or your kernel will crash
in v2.6.38.
*/
.scan = CFG80211_OpsScan,
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,31))
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32))
/* set the transmit power according to
the parameters */
.set_tx_power = CFG80211_OpsTxPwrSet,
/* store the current TX power into the
dbm variable */
.get_tx_power = CFG80211_OpsTxPwrGet,
/* configure WLAN power management */
.set_power_mgmt = CFG80211_OpsPwrMgmt,
/* get station information for the
station identified by @mac */
.get_station = CFG80211_OpsStaGet,
/* dump station callback */
.dump_station = CFG80211_OpsStaDump,
/* notify that wiphy parameters have
changed */
.set_wiphy_params =
CFG80211_OpsWiphyParamsSet,
/* add a key with the given parameters
*/
.add_key = CFG80211_OpsKeyAdd,
/* get information about the key with
the given parameters */
.get_key = CFG80211_OpsKeyGet,
/* remove a key given the @mac_addr */
.del_key = CFG80211_OpsKeyDel,
/* set the default key on an interface
*/
.set_default_key =
CFG80211_OpsKeyDefaultSet,
#ifdef DOT11W_PMF_SUPPORT
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0))
.set_default_mgmt_key =
CFG80211_OpsMgmtKeyDefaultSet,
#endif /* LINUX_VERSION_CODE */
#endif /* DOT11W_PMF_SUPPORT */
/* connect to the ESS with the specified
parameters */
.connect = CFG80211_OpsConnect,
/* disconnect from the BSS/ESS */
.disconnect = CFG80211_OpsDisconnect,
#endif /* LINUX_VERSION_CODE */
#ifdef RFKILL_HW_SUPPORT
/* polls the hw rfkill line */
.rfkill_poll = CFG80211_OpsRFKill,
#endif /* RFKILL_HW_SUPPORT */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,33))
/* get site survey information */
//.dump_survey = CFG80211_OpsSurveyGet,
/* cache a PMKID for a BSSID */
.set_pmksa = CFG80211_OpsPmksaSet,
/* delete a cached PMKID */
.del_pmksa = CFG80211_OpsPmksaDel,
/* flush all cached PMKIDs */
.flush_pmksa = CFG80211_OpsPmksaFlush,
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34))
/*
Request the driver to remain awake on
the specified
channel for the specified duration to
complete an off-channel
operation (e.g., public action frame exchange).
*/
.remain_on_channel =
CFG80211_OpsRemainOnChannel,
/* cancel an on-going remain-on-channel
operation */
.cancel_remain_on_channel =
CFG80211_OpsCancelRemainOnChannel,
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37))
/* transmit an action frame */
.action = NULL,
#else
.mgmt_tx
= CFG80211_OpsMgmtTx,
#endif /* LINUX_VERSION_CODE */
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
.mgmt_tx_cancel_wait
= CFG80211_OpsTxCancelWait,
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35))
/* configure connection quality monitor
RSSI threshold */
.set_cqm_rssi_config = NULL,
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37))
/* notify driver that a management frame
type was registered */
.mgmt_frame_register =
CFG80211_OpsMgmtFrameRegister,
#endif /* LINUX_VERSION_CODE */
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38))
/* set antenna configuration (tx_ant,
rx_ant) on the device */
.set_antenna = NULL,
/* get current antenna configuration
from device (tx_ant, rx_ant) */
.get_antenna = NULL,
#endif /* LINUX_VERSION_CODE */
.change_bss
=
CFG80211_OpsChangeBss,
.del_station
=
CFG80211_OpsStaDel,
.add_station
=
CFG80211_OpsStaAdd,
.change_station
=
CFG80211_OpsStaChg,
// .set_bitrate_mask
= CFG80211_OpsBitrateSet,
#ifdef CONFIG_NL80211_TESTMODE
.testmode_cmd
=
CFG80211_OpsTestModeCmd,
#endif /* CONFIG_NL80211_TESTMODE */
};
10 RTMP_DRIVER_OP_MODE_GET(pAd,
&OpMode);
获取当前设备wlan设备的工作模式
11 rv = RtmpOSNetDevAttach(OpMode,
net_dev, &netDevHook);
实现网络设备相应回调函数的初始化以及网络设备的注册
12 RtmpOSNetDevAddrSet(OpMode, net_dev,
&mac_addr[0], NULL);
设置网络设备的mac地址
注释: 一般调用ioctl接口实现一些相关命令处理,函数接口 RTMP_COM_IoctlHandle()
位置/src/common/comm_cfg.c文件
1.2.3 rt_pci_resume
驱动唤醒时调用函数.
1 调用函数rt28xx_open,调用函数进行网络设备相关初始化
linux 编译mtk无线驱动,Linux驱动(七)----MTK驱动注册分析相关推荐
- linux 编译指cpu内核,linux内核编译与配置
linux是如何组成的? 答:linux是由用户空间和内核空间组成的 为什么要划分用户空间和内核空间? 答:有关CPU体系结构,各处理器可以有多种模式,而LInux这样的划分是考虑到系统的 安全性,比 ...
- 修改linux编译配置文件,Porting:linux内核编译、配置、修改配置文件、添加.c文件到内核...
一.linux内核 $:'uname -a $:'uanme -r // 查看linux内核版本,开发板上进入linux后是一样的命令. 早起常常使用的版本:linux 2.6.x 开发板上使用的版本 ...
- linux编译内核支持pam,linux编译内核make menuconfig报错解决办法
linux编译内核时 输入make menuconfig命令 *** Unable to find the ncurses libraries or the *** required header f ...
- linux编译安装的好处,Linux学习—源码安装
源码安装--可以按照自己的需求安装,这是源码安装的好处,而二进制安装无法选择 大部分的源码安装步骤大致相同,具体细节可以参考解压缩之后的README和INSTALL README: 介绍了软件包的功能 ...
- linux编译谷歌浏览器方法,构建Linux版本的谷歌Chrome浏览器
Chromium编译说明(Linux版) 此页描述如果在Linux操作系统上编译构建Chromium浏览器.假如你对测试chromium或想移植chromium到别的平台请你继续阅读. 小提示:目前还 ...
- linux编译内核报错,linux编译内核时出报错;
因为以前已经编译了,所以就很简单的连接: [root@bache linux-2.6.29]# make defconfig *** Default configuration is based on ...
- Linux编译安装qt5.9,Linux CentOS7 安装 Qt 5.9.2
Linux CentOS7 安装 Qt 5.9.2 参考链接 http://doc.qt.io/qt-5/linux.html sudo yum groupinstall "C Develo ...
- linux编译blas,科学网—Linux下安装blas和lapack包小记 - 徐博伦的博文
系统是centOS6.5,机器上已有gfortran编译器 从网上搜索下载blas.cblas.lapack的tar压缩文件包 1.编译blas 先解压文件 tar xvf blas.tgz cd b ...
- amd显卡驱动linux编译安装,Debian 8 安装AMD/ATI显卡驱动
其实写出本文没有多少技术含量, 只是让新手少走弯路.大牛勿喷! 安装Debian 8后第一件事就是安装显卡驱动 sudo dpkg --add-architecture i386 sudo aptit ...
- linux编译运行uart,嵌入式Linux裸机开发(七)——UART串口通信
嵌入式Linux裸机开发(七)--UART串口通信 一.UART串口通信简介 通用异步收发器简称UART,即UNIVERSAL ASYNCHRONOUS RECEIVER AND TRANSMITTE ...
最新文章
- springboot 配置DRUID数据源
- Pytorch学习 - Task5 PyTorch卷积层原理和使用
- 凯撒密码加密算法 (8 分)
- Golang实现简单爬虫框架(5)——项目重构与数据存储
- ASP.NET AJAX入门系列(8):自定义异常处理
- linux环境变量权限不够,linux环境变量及权限的理解
- 使用docker镜像玩转steam挂卡
- 计算机网络---网络编程套接字(二)
- 关于代码运行速度与cpu关系的一点小事
- Recovered from a route's Handler('github.com/kataras/iris/mvc.(*ControllerActivator).handlerOf.func2
- excel分类_Excel 的10个神奇功能,你会用几个?
- PyTorch二分类时BCELoss,CrossEntropyLoss,Sigmoid等的选择和使用
- 传说中的“高温补贴”
- 三种方式细胞评分对比
- html5 iumpwzo cn,世界杯最神奇5分钟!踢默契球的队赢了杀人屠夫干
- 《阿里巴巴 Java 开发手册 》读书笔记
- VCIP2021:基于神经网络的双向预测blending过程
- 智能化办公系统解决方案
- Maya多版本下载和安装
- KiTTY及cnKiTTY中新的可用命令行选项的简单注释