Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys Add driver for Broadcom 802.11a/b/g/n/ac USB wireless de...
details: https://anonhg.NetBSD.org/src/rev/1ec04773f62b
branches: trunk
changeset: 356899:1ec04773f62b
user: jmcneill <jmcneill%NetBSD.org@localhost>
date: Thu Oct 19 23:58:41 2017 +0000
description:
Add driver for Broadcom 802.11a/b/g/n/ac USB wireless devices, based on
the OpenBSD bwfm(4) driver.
diffstat:
sys/conf/files | 6 +-
sys/dev/ic/bwfm.c | 1701 +++++++++++++++++++++++++++++++++++++++++++++
sys/dev/ic/bwfmreg.h | 540 ++++++++++++++
sys/dev/ic/bwfmvar.h | 170 ++++
sys/dev/usb/files.usb | 6 +-
sys/dev/usb/if_bwfm_usb.c | 845 ++++++++++++++++++++++
6 files changed, 3266 insertions(+), 2 deletions(-)
diffs (truncated from 3309 to 300 lines):
diff -r 4b0a1acbf409 -r 1ec04773f62b sys/conf/files
--- a/sys/conf/files Thu Oct 19 23:55:02 2017 +0000
+++ b/sys/conf/files Thu Oct 19 23:58:41 2017 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: files,v 1.1182 2017/10/09 10:28:33 kre Exp $
+# $NetBSD: files,v 1.1183 2017/10/19 23:58:41 jmcneill Exp $
# @(#)files.newconf 7.5 (Berkeley) 5/10/93
version 20170615
@@ -1415,6 +1415,10 @@
attach ld at nvme with ld_nvme
file dev/ic/ld_nvme.c ld_nvme
+# Broadcom FullMAC 802.11 driver
+device bwfm: arp, ifnet, wlan
+file dev/ic/bwfm.c bwfm
+
# legitimate pseudo-devices
#
defpseudodev vnd: disk
diff -r 4b0a1acbf409 -r 1ec04773f62b sys/dev/ic/bwfm.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/ic/bwfm.c Thu Oct 19 23:58:41 2017 +0000
@@ -0,0 +1,1701 @@
+/* $NetBSD: bwfm.c,v 1.1 2017/10/19 23:58:41 jmcneill Exp $ */
+/* $OpenBSD: bwfm.c,v 1.5 2017/10/16 22:27:16 patrick Exp $ */
+/*
+ * Copyright (c) 2010-2016 Broadcom Corporation
+ * Copyright (c) 2016,2017 Patrick Wildt <patrick%blueri.se@localhost>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/kmem.h>
+#include <sys/workqueue.h>
+#include <sys/pcq.h>
+
+#include <net/bpf.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_ether.h>
+
+#include <netinet/in.h>
+
+#include <net80211/ieee80211_var.h>
+
+#include <dev/ic/bwfmvar.h>
+#include <dev/ic/bwfmreg.h>
+
+/* #define BWFM_DEBUG */
+#ifdef BWFM_DEBUG
+#define DPRINTF(x) do { if (bwfm_debug > 0) printf x; } while (0)
+#define DPRINTFN(n, x) do { if (bwfm_debug >= (n)) printf x; } while (0)
+static int bwfm_debug = 1;
+#else
+#define DPRINTF(x) do { ; } while (0)
+#define DPRINTFN(n, x) do { ; } while (0)
+#endif
+
+#define DEVNAME(sc) device_xname((sc)->sc_dev)
+
+void bwfm_start(struct ifnet *);
+int bwfm_init(struct ifnet *);
+void bwfm_stop(struct ifnet *, int);
+void bwfm_watchdog(struct ifnet *);
+int bwfm_ioctl(struct ifnet *, u_long, void *);
+int bwfm_media_change(struct ifnet *);
+void bwfm_media_status(struct ifnet *, struct ifmediareq *);
+
+int bwfm_send_mgmt(struct ieee80211com *, struct ieee80211_node *,
+ int, int);
+void bwfm_recv_mgmt(struct ieee80211com *, struct mbuf *,
+ struct ieee80211_node *, int, int, uint32_t);
+int bwfm_key_set(struct ieee80211com *, const struct ieee80211_key *,
+ const uint8_t *);
+int bwfm_key_delete(struct ieee80211com *, const struct ieee80211_key *);
+int bwfm_newstate(struct ieee80211com *, enum ieee80211_state, int);
+void bwfm_newstate_cb(struct bwfm_softc *, struct bwfm_cmd_newstate *);
+void bwfm_task(struct work *, void *);
+
+int bwfm_chip_attach(struct bwfm_softc *);
+int bwfm_chip_detach(struct bwfm_softc *, int);
+struct bwfm_core *bwfm_chip_get_core(struct bwfm_softc *, int);
+struct bwfm_core *bwfm_chip_get_pmu(struct bwfm_softc *);
+int bwfm_chip_ai_isup(struct bwfm_softc *, struct bwfm_core *);
+void bwfm_chip_ai_disable(struct bwfm_softc *, struct bwfm_core *,
+ uint32_t, uint32_t);
+void bwfm_chip_ai_reset(struct bwfm_softc *, struct bwfm_core *,
+ uint32_t, uint32_t, uint32_t);
+void bwfm_chip_dmp_erom_scan(struct bwfm_softc *);
+int bwfm_chip_dmp_get_regaddr(struct bwfm_softc *, uint32_t *,
+ uint32_t *, uint32_t *);
+void bwfm_chip_cr4_set_passive(struct bwfm_softc *);
+void bwfm_chip_ca7_set_passive(struct bwfm_softc *);
+void bwfm_chip_cm3_set_passive(struct bwfm_softc *);
+
+int bwfm_proto_bcdc_query_dcmd(struct bwfm_softc *, int,
+ int, char *, size_t *);
+int bwfm_proto_bcdc_set_dcmd(struct bwfm_softc *, int,
+ int, char *, size_t);
+
+int bwfm_fwvar_cmd_get_data(struct bwfm_softc *, int, void *, size_t);
+int bwfm_fwvar_cmd_set_data(struct bwfm_softc *, int, void *, size_t);
+int bwfm_fwvar_cmd_get_int(struct bwfm_softc *, int, uint32_t *);
+int bwfm_fwvar_cmd_set_int(struct bwfm_softc *, int, uint32_t);
+int bwfm_fwvar_var_get_data(struct bwfm_softc *, const char *, void *, size_t);
+int bwfm_fwvar_var_set_data(struct bwfm_softc *, const char *, void *, size_t);
+int bwfm_fwvar_var_get_int(struct bwfm_softc *, const char *, uint32_t *);
+int bwfm_fwvar_var_set_int(struct bwfm_softc *, const char *, uint32_t);
+
+struct ieee80211_channel *bwfm_bss2chan(struct bwfm_softc *, struct bwfm_bss_info *);
+void bwfm_scan(struct bwfm_softc *);
+void bwfm_connect(struct bwfm_softc *);
+
+void bwfm_rx(struct bwfm_softc *, char *, size_t);
+void bwfm_rx_event(struct bwfm_softc *, char *, size_t);
+void bwfm_scan_node(struct bwfm_softc *, struct bwfm_bss_info *, size_t);
+
+uint8_t bwfm_2ghz_channels[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+};
+uint8_t bwfm_5ghz_channels[] = {
+ 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64, 100, 104, 108, 112,
+ 116, 120, 124, 128, 132, 136, 140, 144, 149, 153, 157, 161, 165,
+};
+
+struct bwfm_proto_ops bwfm_proto_bcdc_ops = {
+ .proto_query_dcmd = bwfm_proto_bcdc_query_dcmd,
+ .proto_set_dcmd = bwfm_proto_bcdc_set_dcmd,
+};
+
+void
+bwfm_attach(struct bwfm_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &sc->sc_if;
+ struct bwfm_task *t;
+ char fw_version[BWFM_DCMD_SMLEN];
+ uint32_t bandlist[3];
+ uint32_t tmp;
+ int i, error;
+
+ error = workqueue_create(&sc->sc_taskq, DEVNAME(sc),
+ bwfm_task, sc, PRI_NONE, IPL_NET, 0);
+ if (error != 0) {
+ printf("%s: could not create workqueue\n", DEVNAME(sc));
+ return;
+ }
+ sc->sc_freetask = pcq_create(BWFM_TASK_COUNT, KM_SLEEP);
+ for (i = 0; i < BWFM_TASK_COUNT; i++) {
+ t = &sc->sc_task[i];
+ t->t_sc = sc;
+ pcq_put(sc->sc_freetask, t);
+ }
+
+ if (bwfm_fwvar_cmd_get_int(sc, BWFM_C_GET_VERSION, &tmp)) {
+ printf("%s: could not read io type\n", DEVNAME(sc));
+ return;
+ } else
+ sc->sc_io_type = tmp;
+ if (bwfm_fwvar_var_get_data(sc, "cur_etheraddr", ic->ic_myaddr,
+ sizeof(ic->ic_myaddr))) {
+ printf("%s: could not read mac address\n", DEVNAME(sc));
+ return;
+ }
+
+ memset(fw_version, 0, sizeof(fw_version));
+ if (bwfm_fwvar_var_get_data(sc, "ver", fw_version, sizeof(fw_version)) == 0)
+ printf("%s: %s", DEVNAME(sc), fw_version);
+ printf("%s: address %s\n", DEVNAME(sc), ether_sprintf(ic->ic_myaddr));
+
+ ic->ic_ifp = ifp;
+ ic->ic_phytype = IEEE80211_T_OFDM;
+ ic->ic_opmode = IEEE80211_M_STA;
+ ic->ic_state = IEEE80211_S_INIT;
+
+ ic->ic_caps =
+ IEEE80211_C_WEP |
+ IEEE80211_C_TKIP |
+ IEEE80211_C_AES |
+ IEEE80211_C_AES_CCM |
+#if notyet
+ IEEE80211_C_MONITOR | /* monitor mode suported */
+ IEEE80211_C_IBSS |
+ IEEE80211_C_TXPMGT |
+ IEEE80211_C_WME |
+#endif
+ IEEE80211_C_SHSLOT | /* short slot time supported */
+ IEEE80211_C_SHPREAMBLE | /* short preamble supported */
+ IEEE80211_C_WPA | /* 802.11i */
+ /* IEEE80211_C_WPA_4WAY */0; /* WPA 4-way handshake in hw */
+
+ /* IBSS channel undefined for now. */
+ ic->ic_ibss_chan = &ic->ic_channels[0];
+
+ if (bwfm_fwvar_cmd_get_data(sc, BWFM_C_GET_BANDLIST, bandlist,
+ sizeof(bandlist))) {
+ printf("%s: couldn't get supported band list\n", DEVNAME(sc));
+ return;
+ }
+ const u_int nbands = le32toh(bandlist[0]);
+ for (i = 1; i <= MIN(nbands, __arraycount(bandlist) - 1); i++) {
+ switch (le32toh(bandlist[i])) {
+ case BWFM_BAND_2G:
+ ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
+ ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
+
+ for (i = 0; i < __arraycount(bwfm_2ghz_channels); i++) {
+ uint8_t chan = bwfm_2ghz_channels[i];
+ ic->ic_channels[chan].ic_freq =
+ ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ);
+ ic->ic_channels[chan].ic_flags =
+ IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM |
+ IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ;
+ }
+ break;
+ case BWFM_BAND_5G:
+ ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a;
+
+ for (i = 0; i < __arraycount(bwfm_5ghz_channels); i++) {
+ uint8_t chan = bwfm_5ghz_channels[i];
+ ic->ic_channels[chan].ic_freq =
+ ieee80211_ieee2mhz(chan, IEEE80211_CHAN_5GHZ);
+ ic->ic_channels[chan].ic_flags =
+ IEEE80211_CHAN_A;
+ }
+ break;
+ }
+ }
+
+ ifp->if_softc = sc;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_init = bwfm_init;
+ ifp->if_ioctl = bwfm_ioctl;
+ ifp->if_start = bwfm_start;
+ ifp->if_watchdog = bwfm_watchdog;
+ IFQ_SET_READY(&ifp->if_snd);
+ memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
+
+ if_initialize(ifp);
+ ieee80211_ifattach(ic);
+ ifp->if_percpuq = if_percpuq_create(ifp);
+ if_deferred_start_init(ifp, NULL);
+ if_register(ifp);
+
+ sc->sc_newstate = ic->ic_newstate;
+ ic->ic_newstate = bwfm_newstate;
+ ic->ic_send_mgmt = bwfm_send_mgmt;
+ ic->ic_recv_mgmt = bwfm_recv_mgmt;
+ ic->ic_crypto.cs_key_set = bwfm_key_set;
+ ic->ic_crypto.cs_key_delete = bwfm_key_delete;
+ ieee80211_media_init(ic, bwfm_media_change, bwfm_media_status);
+
+ ieee80211_announce(ic);
+
+ sc->sc_if_attached = true;
+}
+
+int
+bwfm_detach(struct bwfm_softc *sc, int flags)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = ic->ic_ifp;
+
+ if (sc->sc_if_attached) {
+ bpf_detach(ifp);
+ ieee80211_ifdetach(ic);
+ if_detach(ifp);
+ }
+
+ if (sc->sc_taskq)
+ workqueue_destroy(sc->sc_taskq);
+ if (sc->sc_freetask)
+ pcq_destroy(sc->sc_freetask);
+
+ return 0;
+}
+
+void
+bwfm_start(struct ifnet *ifp)
+{
Home |
Main Index |
Thread Index |
Old Index