static int ndisusb_detach(device_t self) { int i, error; struct ndis_softc *sc = device_get_softc(self); struct usb_attach_arg *uaa = device_get_ivars(self); wlan_serialize_enter(); sc->ndisusb_status |= NDISUSB_STATUS_DETACH; for (i = 0; i < NDISUSB_ENDPT_MAX; i++) { if (sc->ndisusb_ep[i] == NULL) continue; usbd_abort_pipe(sc->ndisusb_ep[i]); usbd_close_pipe(sc->ndisusb_ep[i]); sc->ndisusb_ep[i] = NULL; } if (sc->ndisusb_iin_buf != NULL) { kfree(sc->ndisusb_iin_buf, M_USBDEV); sc->ndisusb_iin_buf = NULL; } ndis_pnpevent_nic(self, NDIS_PNP_EVENT_SURPRISE_REMOVED); usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, uaa->device, self); error = ndis_detach(self); wlan_serialize_exit(); return error; }
/* * Module glue. */ static int onoe_modevent(module_t mod, int type, void *unused) { int error; wlan_serialize_enter(); switch (type) { case MOD_LOAD: if (bootverbose) { kprintf("ath_rate: <Atsushi Onoe's rate " "control algorithm>\n"); } error = 0; break; case MOD_UNLOAD: error = 0; break; default: error = EINVAL; break; } wlan_serialize_exit(); return error; }
/* * Send a Root Annoucement (RANN) to find all the nodes on the mesh. We are * called when the vap is configured as a HWMP RANN root node. */ static void hwmp_rootmode_rann_callout(void *arg) { struct ieee80211vap *vap = (struct ieee80211vap *)arg; struct ieee80211_hwmp_state *hs; struct ieee80211_mesh_state *ms; struct ieee80211_meshrann_ie rann; wlan_serialize_enter(); hs = vap->iv_hwmp; ms = vap->iv_mesh; IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss, "%s", "send broadcast RANN"); rann.rann_flags = 0; if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL) rann.rann_flags |= IEEE80211_MESHRANN_FLAGS_PR; rann.rann_hopcount = 0; rann.rann_ttl = ms->ms_ttl; IEEE80211_ADDR_COPY(rann.rann_addr, vap->iv_myaddr); rann.rann_seq = ++hs->hs_seq; rann.rann_metric = IEEE80211_MESHLMETRIC_INITIALVAL; vap->iv_stats.is_hwmp_rootrann++; hwmp_send_rann(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &rann); hwmp_rootmode_setup(vap); wlan_serialize_exit(); }
static int wi_pccard_probe(device_t dev) { const struct pccard_product *pp; u_int32_t fcn = PCCARD_FUNCTION_UNSPEC; wlan_serialize_enter(); /* Make sure we're a network driver */ fcn = pccard_get_function_number(dev); if (fcn != PCCARD_FUNCTION_NETWORK) { wlan_serialize_exit(); return ENXIO; } pp = pccard_product_lookup(dev, wi_pccard_products, sizeof(wi_pccard_products[0]), NULL); if (pp != NULL) { if (pp->pp_name != NULL) device_set_desc(dev, pp->pp_name); wlan_serialize_exit(); return 0; } wlan_serialize_exit(); return ENXIO; }
/* * Module glue. */ static int null_dfs_modevent(module_t mod, int type, void *unused) { int error; wlan_serialize_enter(); switch (type) { case MOD_LOAD: if (bootverbose) { kprintf("ath_dfs: WTF module\n"); } error = 0; break; case MOD_UNLOAD: error = 0; break; default: error = EINVAL; break; } wlan_serialize_exit(); return error; }
static void scan_signal_callout(void *arg) { struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg; wlan_serialize_enter(); scan_signal(ss); wlan_serialize_exit(); }
static void ath_led_done(void *arg) { struct ath_softc *sc = arg; wlan_serialize_enter(); sc->sc_blinking = 0; wlan_serialize_exit(); }
static int ndis_detach_pccard(device_t dev) { int error = 0; wlan_serialize_enter(); error = ndis_detach(dev); wlan_serialize_exit(); return(error); }
/* * Turn the LED off: flip the pin and then set a timer so no * update will happen for the specified duration. */ static void ath_led_off(void *arg) { struct ath_softc *sc = arg; wlan_serialize_enter(); ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon); callout_reset(&sc->sc_ledtimer, sc->sc_ledoff, ath_led_done, sc); wlan_serialize_exit(); }
static void cac_timeout_callout(void *arg) { struct ieee80211vap *vap = arg; struct ieee80211com *ic; struct ieee80211_dfs_state *dfs; int i; wlan_serialize_enter(); ic = vap->iv_ic; dfs = &ic->ic_dfs; if (vap->iv_state != IEEE80211_S_CAC) { /* NB: just in case */ wlan_serialize_exit(); return; } /* * When radar is detected during a CAC we are woken * up prematurely to switch to a new channel. * Check the channel to decide how to act. */ if (IEEE80211_IS_CHAN_RADAR(ic->ic_curchan)) { ieee80211_notify_cac(ic, ic->ic_curchan, IEEE80211_NOTIFY_CAC_RADAR); if_printf(vap->iv_ifp, "CAC timer on channel %u (%u MHz) stopped due to radar\n", ic->ic_curchan->ic_ieee, ic->ic_curchan->ic_freq); /* XXX clobbers any existing desired channel */ /* NB: dfs->newchan may be NULL, that's ok */ vap->iv_des_chan = dfs->newchan; /* XXX recursive lock need ieee80211_new_state_locked */ ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); } else { if_printf(vap->iv_ifp, "CAC timer on channel %u (%u MHz) expired; " "no radar detected\n", ic->ic_curchan->ic_ieee, ic->ic_curchan->ic_freq); /* * Mark all channels with the current frequency * as having completed CAC; this keeps us from * doing it again until we change channels. */ for (i = 0; i < ic->ic_nchans; i++) { struct ieee80211_channel *c = &ic->ic_channels[i]; if (c->ic_freq == ic->ic_curchan->ic_freq) c->ic_state |= IEEE80211_CHANSTATE_CACDONE; } ieee80211_notify_cac(ic, ic->ic_curchan, IEEE80211_NOTIFY_CAC_EXPIRE); ieee80211_cac_completeswitch(vap); } wlan_serialize_exit(); }
static int wi_pci_suspend(device_t dev) { struct wi_softc *sc = device_get_softc(dev); wlan_serialize_enter(); wi_stop(sc, 1); wlan_serialize_exit(); return (0); }
/* * Blink the LED according to the specified on/off times. */ static void ath_led_blink(struct ath_softc *sc, int on, int off) { DPRINTF(sc, ATH_DEBUG_LED, "%s: on %u off %u\n", __func__, on, off); wlan_serialize_enter(); ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, sc->sc_ledon); sc->sc_blinking = 1; sc->sc_ledoff = off; callout_reset(&sc->sc_ledtimer, on, ath_led_off, sc); wlan_serialize_exit(); }
static int wi_pci_probe(device_t dev) { struct wi_softc *sc; int i; wlan_serialize_enter(); sc = device_get_softc(dev); for(i=0; pci_ids[i].vendor != 0; i++) { if ((pci_get_vendor(dev) == pci_ids[i].vendor) && (pci_get_device(dev) == pci_ids[i].device)) { sc->wi_bus_type = pci_ids[i].bus_type; device_set_desc(dev, pci_ids[i].desc); wlan_serialize_exit(); return (BUS_PROBE_DEFAULT); } } wlan_serialize_exit(); return(ENXIO); }
static int wi_pci_resume(device_t dev) { struct wi_softc *sc = device_get_softc(dev); struct ifnet *ifp = sc->sc_ifp; wlan_serialize_enter(); if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) { wlan_serialize_exit(); return (0); } if (ifp->if_flags & IFF_UP) { ifp->if_init(ifp->if_softc); if (ifp->if_flags & IFF_RUNNING) if_devstart(ifp); } wlan_serialize_exit(); return (0); }
static void dfs_timeout_callout(void *arg) { struct ieee80211com *ic = arg; struct ieee80211_dfs_state *dfs = &ic->ic_dfs; struct ieee80211_channel *c; int i, oldest, now; wlan_serialize_enter(); now = oldest = ticks; for (i = 0; i < ic->ic_nchans; i++) { c = &ic->ic_channels[i]; if (IEEE80211_IS_CHAN_RADAR(c)) { if (time_after_eq(now, dfs->nol_event[i]+NOL_TIMEOUT)) { c->ic_state &= ~IEEE80211_CHANSTATE_RADAR; if (c->ic_state & IEEE80211_CHANSTATE_NORADAR) { /* * NB: do this here so we get only one * msg instead of one for every channel * table entry. */ if_printf(ic->ic_ifp, "radar on channel" " %u (%u MHz) cleared after timeout\n", c->ic_ieee, c->ic_freq); /* notify user space */ c->ic_state &= ~IEEE80211_CHANSTATE_NORADAR; ieee80211_notify_radar(ic, c); } } else if (dfs->nol_event[i] < oldest) oldest = dfs->nol_event[i]; } } if (oldest != now) { /* arrange to process next channel up for a status change */ callout_reset(&dfs->nol_timer, oldest + NOL_TIMEOUT - now, dfs_timeout_callout, ic); } wlan_serialize_exit(); }
/* * Module glue. */ static int ath_hal_modevent(module_t mod, int type, void *unused) { int error; wlan_serialize_enter(); switch (type) { case MOD_LOAD: error = 0; break; case MOD_UNLOAD: error = 0; break; default: error = EINVAL; break; } wlan_serialize_exit(); return error; }
static void hwmp_rootmode_callout(void *arg) { struct ieee80211vap *vap = (struct ieee80211vap *)arg; struct ieee80211_hwmp_state *hs; struct ieee80211_mesh_state *ms; struct ieee80211_meshpreq_ie preq; wlan_serialize_enter(); hs = vap->iv_hwmp; ms = vap->iv_mesh; IEEE80211_NOTE(vap, IEEE80211_MSG_HWMP, vap->iv_bss, "%s", "send broadcast PREQ"); preq.preq_flags = IEEE80211_MESHPREQ_FLAGS_AM; if (ms->ms_flags & IEEE80211_MESHFLAGS_PORTAL) preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PR; if (hs->hs_rootmode == IEEE80211_HWMP_ROOTMODE_PROACTIVE) preq.preq_flags |= IEEE80211_MESHPREQ_FLAGS_PP; preq.preq_hopcount = 0; preq.preq_ttl = ms->ms_ttl; preq.preq_id = ++hs->hs_preqid; IEEE80211_ADDR_COPY(preq.preq_origaddr, vap->iv_myaddr); preq.preq_origseq = ++hs->hs_seq; preq.preq_lifetime = ticks_to_msecs(ieee80211_hwmp_roottimeout); preq.preq_metric = IEEE80211_MESHLMETRIC_INITIALVAL; preq.preq_tcount = 1; IEEE80211_ADDR_COPY(PREQ_TADDR(0), broadcastaddr); PREQ_TFLAGS(0) = IEEE80211_MESHPREQ_TFLAGS_TO | IEEE80211_MESHPREQ_TFLAGS_RF; PREQ_TSEQ(0) = 0; vap->iv_stats.is_hwmp_rootreqs++; hwmp_send_preq(vap->iv_bss, vap->iv_myaddr, broadcastaddr, &preq); hwmp_rootmode_setup(vap); wlan_serialize_exit(); }
static int wi_pccard_attach(device_t dev) { struct wi_softc *sc; int error; wlan_serialize_enter(); sc = device_get_softc(dev); sc->wi_gone = 0; sc->wi_bus_type = WI_BUS_PCCARD; error = wi_alloc(dev, 0); if (error == 0) { /* Make sure interrupts are disabled. */ CSR_WRITE_2(sc, WI_INT_EN, 0); CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); error = wi_attach(dev); if (error != 0) wi_free(dev); } wlan_serialize_exit(); return error; }
static void scan_task(void *arg, int pending) { #define ISCAN_REP (ISCAN_MINDWELL | ISCAN_DISCARD) struct ieee80211_scan_state *ss = (struct ieee80211_scan_state *) arg; struct ieee80211vap *vap; struct ieee80211com *ic; struct ieee80211_channel *chan; unsigned long maxdwell, scanend; int scandone = 0; wlan_serialize_enter(); vap = ss->ss_vap; ic = ss->ss_ic; if (vap == NULL || (ic->ic_flags & IEEE80211_F_SCAN) == 0 || (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT)) { /* Cancelled before we started */ goto done; } if (ss->ss_next == ss->ss_last) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: no channels to scan\n", __func__); goto done; } if (vap->iv_opmode == IEEE80211_M_STA && vap->iv_state == IEEE80211_S_RUN) { if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) { /* Enable station power save mode */ ieee80211_sta_pwrsave(vap, 1); /* * Use an 1ms delay so the null data frame has a chance * to go out. Minimum one tick. * XXX Should use M_TXCB mechanism to eliminate this. */ wlan_cv_timedwait(&SCAN_PRIVATE(ss)->ss_scan_cv, hz / 1000 + 1); if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) goto done; } } scanend = ticks + SCAN_PRIVATE(ss)->ss_duration; ic->ic_scan_start(ic); /* notify driver */ for (;;) { scandone = (ss->ss_next >= ss->ss_last) || (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) != 0; if (scandone || (ss->ss_flags & IEEE80211_SCAN_GOTPICK) || (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) || time_after(ticks + ss->ss_mindwell, scanend)) break; chan = ss->ss_chans[ss->ss_next++]; /* * Watch for truncation due to the scan end time. */ if (time_after(ticks + ss->ss_maxdwell, scanend)) maxdwell = scanend - ticks; else maxdwell = ss->ss_maxdwell; IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: chan %3d%c -> %3d%c [%s, dwell min %lums max %lums]\n", __func__, ieee80211_chan2ieee(ic, ic->ic_curchan), channel_type(ic->ic_curchan), ieee80211_chan2ieee(ic, chan), channel_type(chan), (ss->ss_flags & IEEE80211_SCAN_ACTIVE) && (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0 ? "active" : "passive", ticks_to_msecs(ss->ss_mindwell), ticks_to_msecs(maxdwell)); /* * Potentially change channel and phy mode. */ ic->ic_curchan = chan; ic->ic_rt = ieee80211_get_ratetable(chan); /* * Perform the channel change and scan unlocked so the driver * may sleep. Once set_channel returns the hardware has * completed the channel change. */ ic->ic_set_channel(ic); ieee80211_radiotap_chan_change(ic); /* * Scan curchan. Drivers for "intelligent hardware" * override ic_scan_curchan to tell the device to do * the work. Otherwise we manage the work outselves; * sending a probe request (as needed), and arming the * timeout to switch channels after maxdwell ticks. * * scan_curchan should only pause for the time required to * prepare/initiate the hardware for the scan (if at all), the * below condvar is used to sleep for the channels dwell time * and allows it to be signalled for abort. */ ic->ic_scan_curchan(ss, maxdwell); SCAN_PRIVATE(ss)->ss_chanmindwell = ticks + ss->ss_mindwell; /* clear mindwell lock and initial channel change flush */ SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP; if ((SCAN_PRIVATE(ss)->ss_iflags & (ISCAN_CANCEL|ISCAN_ABORT))) continue; /* Wait to be signalled to scan the next channel */ wlan_cv_wait(&SCAN_PRIVATE(ss)->ss_scan_cv); } if (SCAN_PRIVATE(ss)->ss_iflags & ISCAN_ABORT) goto done; ic->ic_scan_end(ic); /* notify driver */ /* * Record scan complete time. Note that we also do * this when canceled so any background scan will * not be restarted for a while. */ if (scandone) ic->ic_lastscan = ticks; /* return to the bss channel */ if (ic->ic_bsschan != IEEE80211_CHAN_ANYC && ic->ic_curchan != ic->ic_bsschan) { ieee80211_setupcurchan(ic, ic->ic_bsschan); ic->ic_set_channel(ic); ieee80211_radiotap_chan_change(ic); } /* clear internal flags and any indication of a pick */ SCAN_PRIVATE(ss)->ss_iflags &= ~ISCAN_REP; ss->ss_flags &= ~IEEE80211_SCAN_GOTPICK; /* * If not canceled and scan completed, do post-processing. * If the callback function returns 0, then it wants to * continue/restart scanning. Unfortunately we needed to * notify the driver to end the scan above to avoid having * rx frames alter the scan candidate list. */ if ((SCAN_PRIVATE(ss)->ss_iflags & ISCAN_CANCEL) == 0 && !ss->ss_ops->scan_end(ss, vap) && (ss->ss_flags & IEEE80211_SCAN_ONCE) == 0 && time_before(ticks + ss->ss_mindwell, scanend)) { IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: done, restart " "[ticks %u, dwell min %lu scanend %lu]\n", __func__, ticks, ss->ss_mindwell, scanend); ss->ss_next = 0; /* reset to begining */ if (ss->ss_flags & IEEE80211_SCAN_ACTIVE) vap->iv_stats.is_scan_active++; else vap->iv_stats.is_scan_passive++; ss->ss_ops->scan_restart(ss, vap); /* XXX? */ ieee80211_runtask(ic, &SCAN_PRIVATE(ss)->ss_scan_task); goto done2; } /* past here, scandone is ``true'' if not in bg mode */ if ((ss->ss_flags & IEEE80211_SCAN_BGSCAN) == 0) scandone = 1; IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s: %s, [ticks %u, dwell min %lu scanend %lu]\n", __func__, scandone ? "done" : "stopped", ticks, ss->ss_mindwell, scanend); /* * Clear the SCAN bit first in case frames are * pending on the station power save queue. If * we defer this then the dispatch of the frames * may generate a request to cancel scanning. */ done: ic->ic_flags &= ~IEEE80211_F_SCAN; /* * Drop out of power save mode when a scan has * completed. If this scan was prematurely terminated * because it is a background scan then don't notify * the ap; we'll either return to scanning after we * receive the beacon frame or we'll drop out of power * save mode because the beacon indicates we have frames * waiting for us. */ if (scandone) { ieee80211_sta_pwrsave(vap, 0); if (ss->ss_next >= ss->ss_last) { ieee80211_notify_scan_done(vap); ic->ic_flags_ext &= ~IEEE80211_FEXT_BGSCAN; } } SCAN_PRIVATE(ss)->ss_iflags &= ~(ISCAN_CANCEL|ISCAN_ABORT); ss->ss_flags &= ~(IEEE80211_SCAN_ONCE | IEEE80211_SCAN_PICK1ST); done2: wlan_serialize_exit(); #undef ISCAN_REP }
/* * Tear down vap state and reclaim the ifnet. * The driver is assumed to have prepared for * this; e.g. by turning off interrupts for the * underlying device. */ void ieee80211_vap_detach(struct ieee80211vap *vap) { struct ieee80211com *ic = vap->iv_ic; struct ifnet *ifp = vap->iv_ifp; IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s parent %s\n", __func__, ieee80211_opmode_name[vap->iv_opmode], ic->ic_ifp->if_xname); /* * NB: bpfdetach is called by ether_ifdetach and claims all taps * * ether_ifdetach() must be called without the serializer held. */ wlan_assert_serialized(); wlan_serialize_exit(); /* exit to block */ ether_ifdetach(ifp); wlan_serialize_enter(); /* then reenter */ ieee80211_stop(vap); /* * Flush any deferred vap tasks. */ wlan_serialize_exit(); /* exit to block */ ieee80211_draintask(ic, &vap->iv_nstate_task); ieee80211_draintask(ic, &vap->iv_swbmiss_task); wlan_serialize_enter(); /* then reenter */ #ifdef __FreeBSD__ /* XXX band-aid until ifnet handles this for us */ taskqueue_drain(taskqueue_swi, &ifp->if_linktask); #endif KASSERT(vap->iv_state == IEEE80211_S_INIT , ("vap still running")); TAILQ_REMOVE(&ic->ic_vaps, vap, iv_next); ieee80211_syncflag_locked(ic, IEEE80211_F_WME); #ifdef IEEE80211_SUPPORT_SUPERG ieee80211_syncflag_locked(ic, IEEE80211_F_TURBOP); #endif ieee80211_syncflag_locked(ic, IEEE80211_F_PCF); ieee80211_syncflag_locked(ic, IEEE80211_F_BURST); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_HT); ieee80211_syncflag_ht_locked(ic, IEEE80211_FHT_USEHT40); /* NB: this handles the bpfdetach done below */ ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_BPF); ieee80211_syncifflag_locked(ic, IFF_PROMISC); ieee80211_syncifflag_locked(ic, IFF_ALLMULTI); ifmedia_removeall(&vap->iv_media); ieee80211_radiotap_vdetach(vap); ieee80211_regdomain_vdetach(vap); ieee80211_scan_vdetach(vap); #ifdef IEEE80211_SUPPORT_SUPERG ieee80211_superg_vdetach(vap); #endif ieee80211_ht_vdetach(vap); /* NB: must be before ieee80211_node_vdetach */ ieee80211_proto_vdetach(vap); ieee80211_crypto_vdetach(vap); ieee80211_power_vdetach(vap); ieee80211_node_vdetach(vap); ieee80211_sysctl_vdetach(vap); if_free(ifp); }
static int ndisusb_attach(device_t self) { struct drvdb_ent *db; struct ndisusb_softc *dummy = device_get_softc(self); struct usb_attach_arg *uaa = device_get_ivars(self); struct ndis_softc *sc; struct ndis_usb_type *t; driver_object *drv; int devidx = 0; usbd_status status; wlan_serialize_enter(); sc = (struct ndis_softc *)dummy; if (uaa->device == NULL) { wlan_serialize_exit(); return ENXIO; } db = windrv_match((matchfuncptr)ndisusb_devcompare, self); if (db == NULL) { wlan_serialize_exit(); return (ENXIO); } sc->ndis_dev = self; sc->ndis_dobj = db->windrv_object; sc->ndis_regvals = db->windrv_regvals; sc->ndis_iftype = PNPBus; /* Create PDO for this device instance */ drv = windrv_lookup(0, "USB Bus"); windrv_create_pdo(drv, self); status = usbd_set_config_no(uaa->device, NDISUSB_CONFIG_NO, 0); if (status != USBD_NORMAL_COMPLETION) { device_printf(self, "setting config no failed\n"); wlan_serialize_exit(); return (ENXIO); } /* Figure out exactly which device we matched. */ t = db->windrv_devlist; while (t->ndis_name != NULL) { if ((uaa->vendor == t->ndis_vid) && (uaa->product == t->ndis_did)) { sc->ndis_devidx = devidx; break; } t++; devidx++; } if (ndis_attach(self) != 0) { wlan_serialize_exit(); return ENXIO; } usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, uaa->device, self); wlan_serialize_exit(); return 0; }
static int wi_pci_attach(device_t dev) { struct wi_softc *sc; u_int32_t command, wanted; u_int16_t reg; int error; int timeout; wlan_serialize_enter(); sc = device_get_softc(dev); command = pci_read_config(dev, PCIR_COMMAND, 4); wanted = PCIM_CMD_PORTEN|PCIM_CMD_MEMEN; command |= wanted; pci_write_config(dev, PCIR_COMMAND, command, 4); command = pci_read_config(dev, PCIR_COMMAND, 4); if ((command & wanted) != wanted) { device_printf(dev, "wi_pci_attach() failed to enable pci!\n"); wlan_serialize_exit(); return (ENXIO); } if (sc->wi_bus_type != WI_BUS_PCI_NATIVE) { error = wi_alloc(dev, WI_PCI_IORES); if (error) { wlan_serialize_exit(); return (error); } /* Make sure interrupts are disabled. */ CSR_WRITE_2(sc, WI_INT_EN, 0); CSR_WRITE_2(sc, WI_EVENT_ACK, 0xFFFF); /* We have to do a magic PLX poke to enable interrupts */ sc->local_rid = WI_PCI_LOCALRES; sc->local = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->local_rid, RF_ACTIVE); sc->wi_localtag = rman_get_bustag(sc->local); sc->wi_localhandle = rman_get_bushandle(sc->local); command = bus_space_read_4(sc->wi_localtag, sc->wi_localhandle, WI_LOCAL_INTCSR); command |= WI_LOCAL_INTEN; bus_space_write_4(sc->wi_localtag, sc->wi_localhandle, WI_LOCAL_INTCSR, command); bus_release_resource(dev, SYS_RES_IOPORT, sc->local_rid, sc->local); sc->local = NULL; sc->mem_rid = WI_PCI_MEMRES; sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (sc->mem == NULL) { device_printf(dev, "couldn't allocate memory\n"); wi_free(dev); wlan_serialize_exit(); return (ENXIO); } sc->wi_bmemtag = rman_get_bustag(sc->mem); sc->wi_bmemhandle = rman_get_bushandle(sc->mem); /* * Write COR to enable PC card * This is a subset of the protocol that the pccard bus code * would do. In theory, we should parse the CIS to find the * COR offset. In practice, the COR_OFFSET is always 0x3e0. */ CSM_WRITE_1(sc, WI_COR_OFFSET, WI_COR_VALUE); reg = CSM_READ_1(sc, WI_COR_OFFSET); if (reg != WI_COR_VALUE) { device_printf(dev, "CSM_READ_1(WI_COR_OFFSET) " "wanted %d, got %d\n", WI_COR_VALUE, reg); wi_free(dev); wlan_serialize_exit(); return (ENXIO); } } else { error = wi_alloc(dev, WI_PCI_LMEMRES); if (error) { wlan_serialize_exit(); return (error); } CSR_WRITE_2(sc, WI_PCICOR_OFF, WI_PCICOR_RESET); DELAY(250000); CSR_WRITE_2(sc, WI_PCICOR_OFF, 0x0000); DELAY(500000); timeout=2000000; while ((--timeout > 0) && (CSR_READ_2(sc, WI_COMMAND) & WI_CMD_BUSY)) DELAY(10); if (timeout == 0) { device_printf(dev, "couldn't reset prism pci core.\n"); wi_free(dev); wlan_serialize_exit(); return(ENXIO); } } CSR_WRITE_2(sc, WI_HFA384X_SWSUPPORT0_OFF, WI_PRISM2STA_MAGIC); reg = CSR_READ_2(sc, WI_HFA384X_SWSUPPORT0_OFF); if (reg != WI_PRISM2STA_MAGIC) { device_printf(dev, "CSR_READ_2(WI_HFA384X_SWSUPPORT0_OFF) " "wanted %d, got %d\n", WI_PRISM2STA_MAGIC, reg); wi_free(dev); wlan_serialize_exit(); return (ENXIO); } error = wi_attach(dev); if (error != 0) wi_free(dev); wlan_serialize_exit(); return (error); }
/* * Attach the interface. Allocate softc structures, do ifmedia * setup and ethernet/BPF attach. */ static int ndis_attach_pccard(device_t dev) { struct ndis_softc *sc; int unit, error = 0, rid; struct ndis_pccard_type *t; int devidx = 0; const char *prodstr, *vendstr; struct drvdb_ent *db; wlan_serialize_enter(); sc = device_get_softc(dev); unit = device_get_unit(dev); sc->ndis_dev = dev; db = windrv_match((matchfuncptr)ndis_devcompare, dev); if (db == NULL) { wlan_serialize_exit(); return (ENXIO); } sc->ndis_dobj = db->windrv_object; sc->ndis_regvals = db->windrv_regvals; resource_list_init(&sc->ndis_rl); sc->ndis_io_rid = 0; sc->ndis_res_io = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->ndis_io_rid, RF_ACTIVE); if (sc->ndis_res_io == NULL) { device_printf(dev, "couldn't map iospace\n"); error = ENXIO; goto fail; } sc->ndis_rescnt++; resource_list_add(&sc->ndis_rl, SYS_RES_IOPORT, rid, rman_get_start(sc->ndis_res_io), rman_get_end(sc->ndis_res_io), rman_get_size(sc->ndis_res_io), -1); rid = 0; sc->ndis_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE | RF_ACTIVE); if (sc->ndis_irq == NULL) { device_printf(dev, "couldn't map interrupt\n"); error = ENXIO; goto fail; } sc->ndis_rescnt++; resource_list_add(&sc->ndis_rl, SYS_RES_IRQ, rid, rman_get_start(sc->ndis_irq), rman_get_start(sc->ndis_irq), 1, rman_get_cpuid(sc->ndis_irq)); sc->ndis_iftype = PCMCIABus; /* Figure out exactly which device we matched. */ t = db->windrv_devlist; prodstr = pccard_get_product_str(dev); vendstr = pccard_get_vendor_str(dev); while(t->ndis_name != NULL) { if (strcasecmp(vendstr, t->ndis_vid) == 0 && strcasecmp(prodstr, t->ndis_did) == 0) break; t++; devidx++; } sc->ndis_devidx = devidx; error = ndis_attach(dev); fail: wlan_serialize_exit(); return(error); }