/** * attach to the WL device. * * Attach to the WL device identified by vendor and device parameters. * regs is a host accessible memory address pointing to WL device registers. * * is called in brcms_bcma_probe() context, therefore no locking required. */ static struct brcms_info *brcms_attach(struct bcma_device *pdev) { struct brcms_info *wl = NULL; int unit, err; struct ieee80211_hw *hw; u8 perm[ETH_ALEN]; unit = n_adapters_found; err = 0; if (unit < 0) return NULL; /* allocate private info */ hw = bcma_get_drvdata(pdev); if (hw != NULL) wl = hw->priv; if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL)) return NULL; wl->wiphy = hw->wiphy; atomic_set(&wl->callbacks, 0); init_waitqueue_head(&wl->tx_flush_wq); /* setup the bottom half handler */ tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl); spin_lock_init(&wl->lock); spin_lock_init(&wl->isr_lock); /* common load-time initialization */ wl->wlc = brcms_c_attach((void *)wl, pdev, unit, false, &err); if (!wl->wlc) { wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n", KBUILD_MODNAME, err); goto fail; } wl->pub = brcms_c_pub(wl->wlc); wl->pub->ieee_hw = hw; /* 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; } wl->irq = pdev->irq; /* register module */ brcms_c_module_register(wl->pub, "linux", wl, NULL); if (ieee_hw_init(hw)) { wiphy_err(wl->wiphy, "wl%d: %s: ieee_hw_init failed!\n", unit, __func__); goto fail; } brcms_c_regd_init(wl->wlc); memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN); if (WARN_ON(!is_valid_ether_addr(perm))) goto fail; SET_IEEE80211_PERM_ADDR(hw, perm); err = ieee80211_register_hw(hw); if (err) wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status" "%d\n", __func__, err); if (wl->pub->srom_ccode[0] && regulatory_hint(wl->wiphy, wl->pub->srom_ccode)) wiphy_err(wl->wiphy, "%s: regulatory hint failed\n", __func__); brcms_debugfs_attach(wl->pub); brcms_debugfs_create_files(wl->pub); n_adapters_found++; return wl; fail: brcms_free(wl); return NULL; }
/** * attach to the WL device. * * Attach to the WL device identified by vendor and device parameters. * regs is a host accessible memory address pointing to WL device registers. * * brcms_attach is not defined as static because in the case where no bus * is defined, wl_attach will never be called, and thus, gcc will issue * a warning that this function is defined but not used if we declare * it as static. * * * is called in brcms_pci_probe() context, therefore no locking required. */ static struct brcms_info *brcms_attach(u16 vendor, u16 device, unsigned long regs, uint bustype, void *btparam, uint irq) { struct brcms_info *wl = NULL; int unit, err; unsigned long base_addr; struct ieee80211_hw *hw; u8 perm[ETH_ALEN]; unit = n_adapters_found; err = 0; if (unit < 0) { return NULL; } /* allocate private info */ hw = pci_get_drvdata(btparam); /* btparam == pdev */ if (hw != NULL) wl = hw->priv; if (WARN_ON(hw == NULL) || WARN_ON(wl == NULL)) return NULL; wl->wiphy = hw->wiphy; atomic_set(&wl->callbacks, 0); /* setup the bottom half handler */ tasklet_init(&wl->tasklet, brcms_dpc, (unsigned long) wl); base_addr = regs; if (bustype == PCI_BUS || bustype == RPC_BUS) { /* Do nothing */ } else { bustype = PCI_BUS; BCMMSG(wl->wiphy, "force to PCI\n"); } wl->bcm_bustype = bustype; wl->regsva = ioremap_nocache(base_addr, PCI_BAR0_WINSZ); if (wl->regsva == NULL) { wiphy_err(wl->wiphy, "wl%d: ioremap() failed\n", unit); goto fail; } spin_lock_init(&wl->lock); spin_lock_init(&wl->isr_lock); /* prepare ucode */ if (brcms_request_fw(wl, (struct pci_dev *)btparam) < 0) { wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in " "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm"); brcms_release_fw(wl); brcms_remove((struct pci_dev *)btparam); return NULL; } /* common load-time initialization */ wl->wlc = brcms_c_attach((void *)wl, vendor, device, unit, false, wl->regsva, wl->bcm_bustype, btparam, &err); brcms_release_fw(wl); if (!wl->wlc) { wiphy_err(wl->wiphy, "%s: attach() failed with code %d\n", KBUILD_MODNAME, err); goto fail; } wl->pub = brcms_c_pub(wl->wlc); wl->pub->ieee_hw = hw; if (brcms_c_set_par(wl->wlc, IOV_MPC, 0) < 0) { wiphy_err(wl->wiphy, "wl%d: Error setting MPC variable to 0\n", unit); } /* register our interrupt handler */ if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) { wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit); goto fail; } wl->irq = irq; /* register module */ brcms_c_module_register(wl->pub, "linux", wl, wl_linux_watchdog, NULL); if (ieee_hw_init(hw)) { wiphy_err(wl->wiphy, "wl%d: %s: ieee_hw_init failed!\n", unit, __func__); goto fail; } memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN); if (WARN_ON(!is_valid_ether_addr(perm))) goto fail; SET_IEEE80211_PERM_ADDR(hw, perm); err = ieee80211_register_hw(hw); if (err) { wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status" "%d\n", __func__, err); } if (wl->pub->srom_ccode[0]) err = brcms_set_hint(wl, wl->pub->srom_ccode); else err = brcms_set_hint(wl, "US"); if (err) { wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n", __func__, err); } n_adapters_found++; return wl; fail: brcms_free(wl); return NULL; }