1. 驱动的主进口如下:
/**
* This is the main entry point for the brcmsmac driver.
*
* This function is scheduled upon module initialization and
* does the driver registration, which result in brcms_bcma_probe()
* call resulting in the driver bringup.
*/
staticvoid brcms_driver_init(struct work_struct *work)
{
int error;
error = bcma_driver_register(&brcms_bcma_driver);
if (error)
pr_err("%s: register returned %d\n", __func__, error);
}
可以看到brcms_bcma_driver作为参数传递给了bcma_driver_register(). brcms_bcma_driver的定义如下:
staticstruct bcma_driver brcms_bcma_driver = {
.name = KBUILD_MODNAME,
.probe = brcms_bcma_probe,
.suspend = brcms_suspend,
.resume = brcms_resume,
.remove = brcms_remove,
.id_table = brcms_coreid_table,
};
重视此中的probe函数。
2. 按照上方的解析,紧接着brcms_bcma_probe将会被调用。
staticint brcms_bcma_probe(struct bcma_device *pdev)
{
struct brcms_info *wl;
struct ieee80211_hw *hw;
dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n",
pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class,
pdev->irq);
if ((pdev->id.manuf != BCMA_MANUF_BCM) ||
(pdev->id.id != BCMA_CORE_80211))
return -ENODEV;
hw = ieee80211_alloc_hw(sizeof(struct brcms_info), &brcms_ops);
if (!hw) {
pr_err("%s: ieee80211_alloc_hw failed\n", __func__);
return -ENOMEM;
}
SET_IEEE80211_DEV(hw, &pdev->dev);
bcma_set_drvdata(pdev, hw);
memset(hw->priv, 0, sizeof(*wl));
wl = brcms_attach(pdev);
if (!wl) {
pr_err("%s: brcms_attach failed!\n", __func__);
return -ENODEV;
}
brcms_led_register(wl);
return0;
}
重视brcms_bcma_probe()函数体中的这行代码:
hw = ieee80211_alloc_hw(sizeof(struct brcms_info), &brcms_ops);
这里的参数是brcms_ops, 它的定义如下:
staticconststruct ieee80211_ops brcms_ops = {
.tx = brcms_ops_tx,
.start = brcms_ops_start,
.stop = brcms_ops_stop,
.add_interface = brcms_ops_add_interface,
.remove_interface = brcms_ops_remove_interface,
.config = brcms_ops_config,
.bss_info_changed = brcms_ops_bss_info_changed,
.configure_filter = brcms_ops_configure_filter,
.sw_scan_start = brcms_ops_sw_scan_start,
.sw_scan_complete = brcms_ops_sw_scan_complete,
.conf_tx = brcms_ops_conf_tx,
.sta_add = brcms_ops_sta_add,
.ampdu_action = brcms_ops_ampdu_action,
.rfkill_poll = brcms_ops_rfkill_poll,
.flush = brcms_ops_flush,
};
以tx为例,在tx.c中将会用到该函数指针。
这里有须要跟一下ieee80211_alloc_hw(), 关于该函数,Johannes Berg在他的《The mac80211 subsystem for kernel developers》中的申明是:
ieee80211_alloc_hw— Allocate a new hardware device
This must be called once for each hardware device. The returned pointer must be used to refer to this
device when calling other functions. mac80211 allocates a private data area for the driver pointed to by
priv in struct ieee80211_hw, the size of this area is given as priv_data_len.
我们重视到brcms_ops作为参数被传递给了ieee80211_alloc_hw(). 并且在该函数体中有如许的代码:
local->ops = ops;
这很首要,我们在后面会说起到。之后就是要new一个struct wiphy - wireless hardware description出来
/* 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;
wiphy = wiphy_new(&mac80211_config_ops, priv_size);
别的还有tasklet初始化的代码,是跟接管数据慎密相干的:
tasklet_init(&local->tasklet,
ieee80211_tasklet_handler,
(unsigned long) local);
在后面一节谈数据接管的时辰会胪陈。
在brcms_bcma_probe()的函数体中,完成了ieee80211_alloc_hw()之后的另一行首要代码就是:
wl = brcms_attach(pdev);
3. 接着解析brcms_attach()
3.1 起首初始化Tasklet
/* setup the bottom half handler */
tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl);
这里可以看到中断处理惩罚函数是brcms_dpc().
3.2 Download firmware
/* prepare ucode */
if (brcms_request_fw(wl, pdev)
wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in "
"%s\n", KBUILD_MODNAME, "/lib/firmware/brcm");
brcms_release_fw(wl);
brcms_remove(pdev);
return NULL;
}
3.3 初始化硬件
/*
* low level attach steps(all hw accesses go
* inside, no more in rest of the attach)
*/
err = brcms_b_attach(wlc, core, unit, piomode);
3.4 申请中断
/* register our interrupt handler */
if (request_irq(pdev->irq, brcms_isr,
IRQF_SHARED, KBUILD_MODNAME, wl)) {
wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);
goto fail;
}那么傍边断产生时比如稀有据过来须要接管时,brcms_isr()就会被触发。
3.5 注册设备
err = ieee80211_register_hw(hw);
if (err)
wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status"
"%d\n", __func__, err);
ieee80211_register_hw()将会调用到ieee80211_if_add()来注册网卡设备
经由过程ieee80211_if_add()的代码可以看到这里终于调用了熟悉的register_netdevice()
int ieee8