http://blog.csdn.net/ussam/article/details/24393267
The ath9k NIC driver is used here, the hardware platform is Tp-link tl-wr841n V7.1 Router 1 ath_pci_init ()
The main entrance of the drive is Ath_pci_init () (in the Pci.c file under the linux-3.3.8/drivers/net/wireless/ath/ath9k folder):
int ath_pci_init (void)
{
return pci_register_driver (&ath_pci_driver);
}
You can see that Ath_pci_driver is passed as a parameter to Pci_register_driver (). The ath_pci_driver is defined as follows (in the Pci.c file under the linux-3.3.8/drivers/net/wireless/ath/ath9k folder):
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 ()
Immediately thereafter, the Ath_pci_probe function is called with the probe pointer (the ATH_PCI_PROBE function is defined in the Pci.c file under the linux-3.3.8/drivers/net/wireless/ath/ath9k folder).
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;
/* 'll 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 ()
Note This line of code in the body of the Ath_pci_probe () function:
HW = IEEE80211_ALLOC_HW (sizeof (struct ATH_SOFTC), &ath9k_ops);
The function ieee80211_alloc_hw () is defined in the OpenWrt Kernel folder directory/net/mac80211, file main.c, where the parameters passed in are struct ath9k_ops, the structure is defined as follows (in linux-3.3.8/ In the Main.c file under the drivers/net/wireless/ath/ath9k folder):
struct Ieee80211_ops ath9k_ops = {. tx = Ath9k_tx,. Start = Ath9k_start,. Stop = Ath9k_stop,. add_in Terface = Ath9k_add_interface,. change_interface = Ath9k_change_interface,. Remove_interface = Ath9k_remove_int Erface,. 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_surve Y,. rfkill_poll = Ath9k_rfkill_poll_state,. Set_coverage_class = Ath9k_set_coverage_class,. Flush = Ath9k_f Lush,. 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,}; After the parameter ath9k_ops is transferred to the IEEE80211_ALLOC_HW () function, the system will be able to use the function pointer defined in the parameter ath9k_ops. In the case of TX, the function pointer will be used in tx.c.
Here's another look at the IEEE80211_ALLOC_HW () function:
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; Note that here Mac80211_config_ops//With the scan member as an example, the scan will trigger the corresponding function Ieee80211_scan () wiphy = Wiphy_new (&mac80211_config_ OPS, priv_size);
Notice here that the Mac80211_config_ops if (!wiphy) return is NULL;
...//The local->ops here becomes the passed in parameter ath9k_ops local->ops = OPS; ...//This Task Force column is very important, SW scan case will schedule this task queue to do scan init_dElayed_work (&local->scan_work, ieee80211_scan_work); ...//This tasklet is closely related to receiving data and will be referred to Tasklet_init (&local->tasklet, Ieee80211_tasklet_handler, unsigned lon
g) local);
... return &local->hw; } export_symbol (IEEE80211_ALLOC_HW);4 Ath9k_init_device ()
In the function body of ath_pci_probe (), the other important code after the completion of IEEE80211_ALLOC_HW () is:
ret = Ath9k_init_device (Id->device, SC, &ath_pci_bus_ops);
Then analyze Ath9k_init_device () (located in the OpenWrt Kernel folder directory/net/mac80211, file init.c) to observe the initialization process of the device.
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_not
Ifier);
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"); GotoError_world; } ... }4.1 First Initialize 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);
...
}
The Tasklet (including the Beacon Frame's Tasklet) is initialized during this process
4.2 Initializing the data transmit/receive memory access
/* 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 Registering the device
Error = IEEE80211_REGISTER_HW (HW);
At this point, the device starts and the driver is successfully loaded onto the device.