http://blog.csdn.net/ussam/article/details/24393267

这里使用的是ath9k网卡驱动,硬件平台是TP-link TL-WR841N V7.1 路由器

1 ath_pci_init() 
驱动的主入口为ath_pci_init()(位于linux-3.3.8 /drivers/net/wireless/ath/ath9k文件夹下的pci.c文件中):

int ath_pci_init(void)
{return pci_register_driver(&ath_pci_driver);
}

可以看到ath_pci_driver作为参数传递给了pci_register_driver ()。ath_pci_driver的定义如下(位于linux-3.3.8 /drivers/net/wireless/ath/ath9k文件夹下的pci.c文件中):

static struct pci_driver ath_pci_driver = {.name       = "ath9k",.id_table   = ath_pci_id_table,.probe      = ath_pci_probe,.remove     = ath_pci_remove,.driver.pm  = ATH9K_PM_OPS,
};

2 ath_pci_probe() 
紧接着,系统会通过probe指针来调用ath_pci_probe函数(ath_pci_probe函数定义于linux-3.3.8 /drivers/net/wireless/ath/ath9k文件夹下的pci.c文件中)。

static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
…hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);if (!hw) {dev_err(&pdev->dev, "No memory for ieee80211_hw\n");ret = -ENOMEM;goto err_alloc_hw;}SET_IEEE80211_DEV(hw, &pdev->dev);pci_set_drvdata(pdev, hw);sc = hw->priv;sc->hw = hw;sc->dev = &pdev->dev;sc->mem = mem;/* Will be cleared in ath9k_start() */sc->sc_flags |= SC_OP_INVALID;ret = request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath9k", sc);if (ret) {dev_err(&pdev->dev, "request_irq failed\n");goto err_irq;}sc->irq = pdev->irq;ret = ath9k_init_device(id->device, sc, &ath_pci_bus_ops);if (ret) {dev_err(&pdev->dev, "Failed to initialize device\n");goto err_init;}
…
}

3 ieee80211_alloc_hw() 
注意ath_pci_probe()函数体中的这行代码: 
hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops); 
函数ieee80211_alloc_hw()定义于OpenWRT内核文件夹子目录/net/mac80211,文件main.c中,这里传入的参数是结构体ath9k_ops, 该结构体的定义如下(位于linux-3.3.8 /drivers/net/wireless/ath/ath9k文件夹下的main.c文件中):

struct ieee80211_ops ath9k_ops = {.tx             = ath9k_tx,.start          = ath9k_start,.stop            = ath9k_stop,.add_interface        = ath9k_add_interface,.change_interface   = ath9k_change_interface,.remove_interface   = ath9k_remove_interface,.config      = ath9k_config,.configure_filter   = ath9k_configure_filter,.sta_add      = ath9k_sta_add,.sta_remove        = ath9k_sta_remove,.sta_notify         = ath9k_sta_notify,.conf_tx        = ath9k_conf_tx,.bss_info_changed   = ath9k_bss_info_changed,.set_key            = ath9k_set_key,.get_tsf        = ath9k_get_tsf,.set_tsf       = ath9k_set_tsf,.reset_tsf         = ath9k_reset_tsf,.ampdu_action       = ath9k_ampdu_action,.get_survey        = ath9k_get_survey,.rfkill_poll        = ath9k_rfkill_poll_state,.set_coverage_class = ath9k_set_coverage_class,.flush           = ath9k_flush,.tx_frames_pending  = ath9k_tx_frames_pending,.tx_last_beacon     = ath9k_tx_last_beacon,.get_stats        = ath9k_get_stats,.set_antenna     = ath9k_set_antenna,.get_antenna       = ath9k_get_antenna,
};

将参数ath9k_ops传输ieee80211_alloc_hw()函数以后,系统将可以使用参数ath9k_ops中定义的函数指针。以tx为例,在tx.c中将会用到该函数指针。 
下面再来看看ieee80211_alloc_hw()函数:

struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,  const struct ieee80211_ops *ops)
{struct ieee80211_local *local;int priv_size, i;struct wiphy *wiphy;bool use_chanctx;
…/* Ensure 32-byte alignment of our private data and hw private data.* We use the wiphy priv data for both our ieee80211_local and for* the driver's private data** In memory it'll be like this:** +-------------------------+* | struct wiphy     |* +-------------------------+* | struct ieee80211_local  |* +-------------------------+* | driver's private data   |* +-------------------------+**/priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len;
// 注意这里的mac80211_config_ops
// 以其中的scan成员为例,scan时就会触发对应的函数ieee80211_scan()wiphy = wiphy_new(&mac80211_config_ops, priv_size); // 注意这里的mac80211_config_opsif (!wiphy)return NULL;
…
// 这里的local->ops就变成传进来的参数ath9k_opslocal->ops = ops;…
// 这个工作队列很重要, sw scan的情况下会schedule这个工作队列来做scanINIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work);…
// 这个tasklet跟接受数据紧密相关,后面会提到tasklet_init(&local->tasklet,ieee80211_tasklet_handler,(unsigned long) local);…return &local->hw;
}
EXPORT_SYMBOL(ieee80211_alloc_hw);

4 ath9k_init_device() 
在ath_pci_probe()的函数体中,完成了ieee80211_alloc_hw()之后的另一行重要代码就是: 
ret = ath9k_init_device(id->device, sc, &ath_pci_bus_ops); 
接着分析ath9k_init_device ()(位于OpenWRT内核文件夹子目录/net/mac80211,文件init.c中),观察设备的初始化过程。

int ath9k_init_device(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops)
{struct ieee80211_hw *hw = sc->hw;struct ath_common *common;struct ath_hw *ah;int error = 0;struct ath_regulatory *reg;/* Bring up device */error = ath9k_init_softc(devid, sc, bus_ops);if (error != 0)goto error_init;ah = sc->sc_ah;common = ath9k_hw_common(ah);ath9k_set_hw_capab(sc, hw);/* Initialize regulatory */error = ath_regd_init(&common->regulatory, sc->hw->wiphy,ath9k_reg_notifier);if (error)goto error_regd;reg = &common->regulatory;/* Setup TX DMA */error = ath_tx_init(sc, ATH_TXBUF);if (error != 0)goto error_tx;/* Setup RX DMA */error = ath_rx_init(sc, ATH_RXBUF);if (error != 0)goto error_rx;ath9k_init_txpower_limits(sc);
…error = ieee80211_register_hw(hw);if (error)goto error_register;error = ath9k_init_debug(ah);if (error) {ath_err(common, "Unable to create debugfs files\n");goto error_world;}…
}

4.1 首先初始化softc

static int ath9k_init_softc(u16 devid, struct ath_softc *sc,const struct ath_bus_ops *bus_ops)
{
…tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,(unsigned long)sc);…
}

在这个过程中会初始化tasklet(包括beacon帧的tasklet) 
4.2 初始化数据收发存储器访问

/* Setup TX DMA */error = ath_tx_init(sc, ATH_TXBUF);if (error != 0)goto error_tx;/* Setup RX DMA */error = ath_rx_init(sc, ATH_RXBUF);if (error != 0)goto error_rx;

4.3 注册设备

error = ieee80211_register_hw(hw);

至此,设备启动,驱动程序成功加载到设备上。

ath9K 驱动注册过程相关推荐

  1. LINUX驱动注册过程失败处理不当引起的恶果

    LINUX驱动注册过程失败处理不当引起的恶果 LINUX设备驱动有标准的结构,注册的时候对比device和driver的名字,如果相等就调用probe函数将资源注册进去,但是如果注册失败,在probe ...

  2. ath9k驱动内的数据发送过程

    这是usb接口的wifi驱动 for (n = 0; n < urb->number_of_packets; n++) {             len = urb->iso_fr ...

  3. linux platform驱动注册过程

    以下取自linux内核版本2.6.28. platform总线定义在drivers/base/platform.c文件中,如下: struct bus_type platform_bus_type = ...

  4. cmd52命令发送 mmc_Linux SD/MMC/SDIO驱动分析(新)

    一.SD/MMC/SDIO概念区分 SD(SecureDigital)与 MMC(MultimediaCard) SD 是一种 flash memory card 的标准,也就是一般常见的 SD 记忆 ...

  5. linux 音频驱动的流程,Intel平台下Linux音频驱动流程分析

    [软件框架] 在对要做的事情一无所知的时候,从全局看看系统的拓扑图对我们认识新事物有很大的帮助.Audio 部分的驱动程序框架如下图所示: 这幅图明显地分为 3 级. 上方蓝色系的 ALSA Kern ...

  6. Linux USB 驱动开发实例(二)—— USB 鼠标驱动注解及测试

    参考2.6.14版本中的driver/usb/input/usbmouse.c.鼠标驱动可分为几个部分:驱动加载部分.probe部分.open部分.urb回调函数处理部分. 一.驱动加载部分 [cpp ...

  7. 【实践驱动开发3-006】TI WL1835MODCOM8 在android的移植 - SDIO wifi驱动的注册步骤

     说明之前:文档建立在实际的项目中: 硬件环境是三星x210,软件是android4.0 ubuntu13.04 EDITING AREA Linux的platform 机制简介 从 Linux ...

  8. Android 驱动开发(14)---深入学习Linux Device Tree

    深入学习Linux Device Tree 这个世界需要的是全力以赴,战胜他人先战胜子自己!! Linux Device Tree可描述的信息包括: cpu的数量和类型 内存基地址和大小 总线 外设 ...

  9. android 驱动(7)---.设备、总线、驱动

    1.platform device是怎么"自动"关联到platform driver上的? 转向linux driver有些时间了,前段时间碰到个问题,在Linux kernel ...

最新文章

  1. OCA读书笔记(6) - 配置Oracle网络环境
  2. 富文本编辑_博客的后台富文本编辑和阅读计数
  3. ETSI GS MEC 012,RNIS API
  4. jquery-migrate.js
  5. Pandas 表格样式设置指南,看这一篇就够了!
  6. mysql 连接openfire_修改openfire数据库连接(转)
  7. lt;++mysql_php+js+mysql设计的仿webQQ-lt;1gt;邮箱验证
  8. 分类算法-逻辑回归与二分类
  9. 2015/08/24
  10. python实现json文件中向量写入Excel中
  11. 浏览器嗅探器检测(BrowserDetect.js)程序神器使用
  12. 【IDEA】idea工程打包成jar包
  13. 两个小故事告诉你静下来的力量
  14. 527. Word Abbreviation
  15. Python带我飞:50个有趣而又鲜为人知的Python特性
  16. 算法的时间复杂度排序
  17. 数组转化为集合的方式asList()
  18. [论文笔记]Maiter:一种基于Delta的累积迭代计算的异步图处理框架
  19. 【Mysql SQLZOO练习命令练习】
  20. windows下修改黑苹果config_黑苹果家用PC安装苹果Mac OS操作系统经验(下)工具和资源...

热门文章

  1. 2022届秋招面经--秋招面试(3)
  2. 脑科学读物阅读笔记系列 - 拉马钱德兰《脑中魅影》- 2. 幻肢痛
  3. default默认值 unique单列唯一和联合唯一 primary key主键 auto_increment自增 外键foregin key 表与表之间关系
  4. 【Java网络编程与IO流】Java之Java Servlet详解
  5. 奥比中光深度相机使用笔记一
  6. 原生JS无缝轮播图(左右切换、导航跟随)
  7. AV1编码标准整体概述
  8. c语言学生学籍管理程序,C语言实现简单学籍管理系统
  9. 《中国人史纲》读书笔记:第四章 半信史时代 第五章 信史时代
  10. 前端每日三问#200501怎样在文本框中禁用中文输入法?