本文主要是描述pci接口的atheros无线驱动的初始化流程
先贴一张网上找来的图片,atheros的驱动是分层的
从下到上的每一层为:
HAL:Hardware Abstraction Layer
LMAC: Lower MAC
UMAC: Upper MAC
OSIF: OS Interface Layer。
1. atheros的主要数据结构:
struct ath_softc_net80211 { //只列出几个重要的成员
struct ieee80211com sc_ic; /* NB: base class, must be first */
ath_dev_t sc_dev; /* Atheros device handle */
struct ath_ops *sc_ops; /* Atheros device callback table */
void (*sc_node_cleanup)(struct ieee80211_node *);
void (*sc_node_free)(struct ieee80211_node *);
osdev_t sc_osdev; /* handle to use OS-independent services */
}
ath_softc_net80211是UMAC层的核心数据结构,是net_device的private数据
ath_ops是设备回调函数表,定义了好多的回调函数
struct ath_softc { //只列出重要的几个成员
struct ath_ops sc_ath_ops;
ieee80211_handle_t sc_ieee;
struct ieee80211_ops *sc_ieee_ops;
osdev_t sc_osdev; /* Opaque handle to OS-specific device */
struct ath_hal *sc_ah; /* Atheros HAL */
}
ath_softc是LMAC层的核心数据结构
atheros的几个数据结构都比较大,好多是函数指针,充分体现了分层设计的思想
2. atheros无线驱动初始化流程
pci接口的无线网卡的初始化从ath_pci_probe(if_ath_pci.c)开始讲,不清楚的可以参考我的linux设备驱动的文章。
static int
ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
unsigned long mem;
struct ath_pci_softc *sc;
struct net_device *dev;
......
dev = alloc_netdev(sizeof(struct ath_pci_softc), "wifi%d", ether_setup);
if (dev == NULL) {
printk(KERN_ERR "ath_pci: no memory for device state\n");
goto bad2;
}
sc = ath_netdev_priv(dev);
sc->aps_osdev.netdev = dev;
sc->aps_osdev.bdev = (void *) pdev;
#ifdef ATH_SUPPORT_HTC
sc->aps_osdev.wmi_dev = (void *)sc;
#endif
dev->irq = pdev->irq;
dev->mem_start = mem;
dev->mem_end = mem + pci_resource_len(pdev, 0);
/*
* Don't leave arp type as ARPHRD_ETHER as this is no eth device
*/
dev->type = ARPHRD_IEEE80211;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
SET_MODULE_OWNER(dev);
#endif
SET_NETDEV_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev, dev);
if (__ath_attach(id->device, dev, &bus_context, &sc->aps_osdev) != 0)
goto bad3;
athname = ath_hal_probe(id->vendor, id->device);
..........
return 0;
bad3:
free_netdev(dev);
bad2:
iounmap((void *) mem);
bad1:
release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
bad:
pci_disable_device(pdev);
return (-ENODEV);
}
分配一个net_device和ath_pci_softc,其中ath_pci_softc内嵌了一个UMAC核心数据结构ath_softc_net80211
struct ath_pci_softc {
struct ath_softc_net80211 aps_sc;
struct _NIC_DEV aps_osdev;
#ifdef ATH_BUS_PM
u32 aps_pmstate[16];
#endif
};
其中__ath_attach(ath_linux.c)是一个非常重要,也是一个非常复杂的函数。
int
__ath_attach(u_int16_t devid, struct net_device *dev, HAL_BUS_CONTEXT *bus_context, osdev_t osdev)
{
struct ath_softc_net80211 *scn = ath_netdev_priv(dev);
struct ieee80211com *ic = &scn->sc_ic;
/*
* Set bus context to osdev
*/
osdev->bc = *bus_context;
//LMAC层数据结构的初始化
error = ath_attach(devid, bus_context, scn, osdev, &ath_params, &hal_conf_parm, &wlan_reg_params);
if (error != 0)
goto bad;
ald_init_netlink();
osif_attach(dev);
/*
* initialize tx/rx engine
*/
error = scn->sc_ops->tx_init(scn->sc_dev, ATH_TXBUF); //对应ath_tx_init
if (error != 0)
goto bad1;
error = scn->sc_ops->rx_init(scn->sc_dev, ATH_RXBUF); //对应ath_rx_init
if (error != 0)
goto bad2;
/*
* setup net device
*/
dev->netdev_ops = &athdev_net_ops;
/*
** Attach the iwpriv handlers
*/
ath_iw_attach(dev);
/*
* setup interrupt serivce routine
*/
ATH_INIT_TQUEUE(&osdev->intr_tq, (adf_os_defer_fn_t)ath_tasklet, (void*)dev); //定义tasklet
/*
* Resolving name to avoid a crash in request_irq() on new kernels
*/
dev_alloc_name(dev, dev->name);
//申请中断
if (request_irq(dev->irq, ath_isr, IRQF_SHARED | IRQF_SAMPLE_RANDOM, dev->name, dev)) {
printk(KERN_WARNING "%s: request_irq failed\n", dev->name);
error = -EIO;
goto bad3;
}
/*
* finally register netdev and ready to go
*/
if ((error = register_netdev(dev)) != 0) { //注册net_device
printk(KERN_ERR "%s: unable to register device\n", dev->name);
goto bad4;
}
}
上述函数省略了一些函数,只列出几个重要的函数。ath_attach函数太长了,定义了太多的函数接口,主要调用了ath_dev_attach。
ath_dev_attach位于lmac/ath_dev/ath_main.c文件
ath_dev_attach主要是分配ath_softc结构并且初始化,调用_ath_hal_attach,完成hal层接口的初始化
初始化流程先分析到这里,atheros无线网卡驱动非常复杂,有好多#ifdef。初始化时主要是分配几个重要的数据结构,并且把一些静态定义的函数表赋值到这几个重要数据结构的成员变量中,好多回调函数,等后面用到时再分析。