예제 #1
0
파일: core.c 프로젝트: gxt/linux
void brcmf_remove_interface(struct brcmf_if *ifp, bool rtnl_locked)
{
	if (!ifp || WARN_ON(ifp->drvr->iflist[ifp->bsscfgidx] != ifp))
		return;
	brcmf_dbg(TRACE, "Enter, bsscfgidx=%d, ifidx=%d\n", ifp->bsscfgidx,
		  ifp->ifidx);
	brcmf_fws_del_interface(ifp);
	brcmf_del_if(ifp->drvr, ifp->bsscfgidx, rtnl_locked);
}
예제 #2
0
/**
 * brcmf_fweh_handle_if_event() - handle IF event.
 *
 * @drvr: driver information object.
 * @item: queue entry.
 * @ifpp: interface object (may change upon ADD action).
 */
static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
				       struct brcmf_event_msg *emsg,
				       void *data)
{
	struct brcmf_if_event *ifevent = data;
	struct brcmf_if *ifp;
	int err = 0;

	brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u role: %u\n",
		  ifevent->action, ifevent->ifidx, ifevent->bssidx,
		  ifevent->flags, ifevent->role);

	/* The P2P Device interface event must not be ignored
	 * contrary to what firmware tells us. The only way to
	 * distinguish the P2P Device is by looking at the ifidx
	 * and bssidx received.
	 */
	if (!(ifevent->ifidx == 0 && ifevent->bssidx == 1) &&
	    (ifevent->flags & BRCMF_E_IF_FLAG_NOIF)) {
		brcmf_dbg(EVENT, "event can be ignored\n");
		return;
	}
	if (ifevent->ifidx >= BRCMF_MAX_IFS) {
		brcmf_err("invalid interface index: %u\n",
			  ifevent->ifidx);
		return;
	}

	ifp = drvr->iflist[ifevent->bssidx];

	if (ifevent->action == BRCMF_E_IF_ADD) {
		brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
			  emsg->addr);
		ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx,
				   emsg->ifname, emsg->addr);
		if (IS_ERR(ifp))
			return;
		brcmf_fws_add_interface(ifp);
		if (!drvr->fweh.evt_handler[BRCMF_E_IF])
			if (brcmf_net_attach(ifp, false) < 0)
				return;
	}

	if (ifp && ifevent->action == BRCMF_E_IF_CHANGE)
		brcmf_fws_reset_interface(ifp);

	err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);

	if (ifp && ifevent->action == BRCMF_E_IF_DEL) {
		brcmf_fws_del_interface(ifp);
		brcmf_del_if(drvr, ifevent->bssidx);
	}
}
예제 #3
0
/**
 * brcmf_fweh_handle_if_event() - handle IF event.
 *
 * @drvr: driver information object.
 * @item: queue entry.
 * @ifpp: interface object (may change upon ADD action).
 */
static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
				       struct brcmf_event_msg *emsg,
				       void *data)
{
	struct brcmf_if_event *ifevent = data;
	struct brcmf_if *ifp;
	int err = 0;

	brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u role: %u\n",
		  ifevent->action, ifevent->ifidx, ifevent->bssidx,
		  ifevent->flags, ifevent->role);

	if (ifevent->flags & BRCMF_E_IF_FLAG_NOIF) {
		brcmf_dbg(EVENT, "event can be ignored\n");
		return;
	}
	if (ifevent->ifidx >= BRCMF_MAX_IFS) {
		brcmf_err("invalid interface index: %u\n",
			  ifevent->ifidx);
		return;
	}

	ifp = drvr->iflist[ifevent->bssidx];

	if (ifevent->action == BRCMF_E_IF_ADD) {
		brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
			  emsg->addr);
		ifp = brcmf_add_if(drvr, ifevent->bssidx, ifevent->ifidx,
				   emsg->ifname, emsg->addr);
		if (IS_ERR(ifp))
			return;
		brcmf_fws_add_interface(ifp);
		if (!drvr->fweh.evt_handler[BRCMF_E_IF])
			if (brcmf_net_attach(ifp, false) < 0)
				return;
	}

	if (ifevent->action == BRCMF_E_IF_CHANGE)
		brcmf_fws_reset_interface(ifp);

	err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);

	if (ifevent->action == BRCMF_E_IF_DEL) {
		brcmf_fws_del_interface(ifp);
		brcmf_del_if(drvr, ifevent->bssidx);
	}
}
예제 #4
0
파일: core.c 프로젝트: gxt/linux
int brcmf_bus_start(struct device *dev)
{
	int ret = -1;
	struct brcmf_bus *bus_if = dev_get_drvdata(dev);
	struct brcmf_pub *drvr = bus_if->drvr;
	struct brcmf_if *ifp;
	struct brcmf_if *p2p_ifp;

	brcmf_dbg(TRACE, "\n");

	/* add primary networking interface */
	ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d", NULL);
	if (IS_ERR(ifp))
		return PTR_ERR(ifp);

	p2p_ifp = NULL;

	/* signal bus ready */
	brcmf_bus_change_state(bus_if, BRCMF_BUS_UP);

	/* Bus is ready, do any initialization */
	ret = brcmf_c_preinit_dcmds(ifp);
	if (ret < 0)
		goto fail;

	brcmf_debugfs_add_entry(drvr, "revinfo", brcmf_revinfo_read);

	/* assure we have chipid before feature attach */
	if (!bus_if->chip) {
		bus_if->chip = drvr->revinfo.chipnum;
		bus_if->chiprev = drvr->revinfo.chiprev;
		brcmf_dbg(INFO, "firmware revinfo: chip %x (%d) rev %d\n",
			  bus_if->chip, bus_if->chip, bus_if->chiprev);
	}
	brcmf_feat_attach(drvr);

	ret = brcmf_fws_init(drvr);
	if (ret < 0)
		goto fail;

	brcmf_fws_add_interface(ifp);

	drvr->config = brcmf_cfg80211_attach(drvr, bus_if->dev,
					     drvr->settings->p2p_enable);
	if (drvr->config == NULL) {
		ret = -ENOMEM;
		goto fail;
	}

	ret = brcmf_net_attach(ifp, false);

	if ((!ret) && (drvr->settings->p2p_enable)) {
		p2p_ifp = drvr->iflist[1];
		if (p2p_ifp)
			ret = brcmf_net_p2p_attach(p2p_ifp);
	}

	if (ret)
		goto fail;

#ifdef CONFIG_INET
	drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed;
	ret = register_inetaddr_notifier(&drvr->inetaddr_notifier);
	if (ret)
		goto fail;

#if IS_ENABLED(CONFIG_IPV6)
	drvr->inet6addr_notifier.notifier_call = brcmf_inet6addr_changed;
	ret = register_inet6addr_notifier(&drvr->inet6addr_notifier);
	if (ret) {
		unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
		goto fail;
	}
#endif
#endif /* CONFIG_INET */

	return 0;

fail:
	brcmf_err("failed: %d\n", ret);
	if (drvr->config) {
		brcmf_cfg80211_detach(drvr->config);
		drvr->config = NULL;
	}
	if (drvr->fws) {
		brcmf_fws_del_interface(ifp);
		brcmf_fws_deinit(drvr);
	}
	if (ifp)
		brcmf_net_detach(ifp->ndev, false);
	if (p2p_ifp)
		brcmf_net_detach(p2p_ifp->ndev, false);
	drvr->iflist[0] = NULL;
	drvr->iflist[1] = NULL;
	if (drvr->settings->ignore_probe_fail)
		ret = 0;

	return ret;
}