summaryrefslogtreecommitdiff
path: root/sys/dev/ic
diff options
context:
space:
mode:
authorMarcus Glocker <mglocker@cvs.openbsd.org>2006-10-29 11:41:35 +0000
committerMarcus Glocker <mglocker@cvs.openbsd.org>2006-10-29 11:41:35 +0000
commitbd0c4759fecd753a639ca6d94f62b4f8748cea74 (patch)
tree08ec9e77d8141a572c57f5ca6f565bcd1ade8ad4 /sys/dev/ic
parentbc74e8301fa7d7fb37682d26fe2989589e00832e (diff)
Add first TX path and active scan bits. Don't expect to much yet.
ok claudio@
Diffstat (limited to 'sys/dev/ic')
-rw-r--r--sys/dev/ic/malo.c372
-rw-r--r--sys/dev/ic/malo.h5
2 files changed, 366 insertions, 11 deletions
diff --git a/sys/dev/ic/malo.c b/sys/dev/ic/malo.c
index 39b64eb5f99..b89e30e05b7 100644
--- a/sys/dev/ic/malo.c
+++ b/sys/dev/ic/malo.c
@@ -1,7 +1,8 @@
-/* $OpenBSD: malo.c,v 1.11 2006/10/25 20:42:57 mglocker Exp $ */
+/* $OpenBSD: malo.c,v 1.12 2006/10/29 11:41:34 mglocker Exp $ */
/*
* Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2006 Marcus Glocker <mglocker@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -72,8 +73,9 @@ struct malo_rx_data {
struct malo_tx_data {
bus_dmamap_t map;
struct mbuf *m;
+ uint32_t softstat;
/* additional info for rate adaption */
-// struct ieee80211_node *ni;
+ struct ieee80211_node *ni;
// struct ieee80211_rssdesc id;
};
@@ -112,6 +114,9 @@ struct malo_tx_desc {
/* firmware commands as found in a document describing the Libertas FW */
#define MALO_CMD_GET_HW_SPEC 0x0003
#define MALO_CMD_RESPONSE 0x8000
+#define MALO_CMD_SET_PRESCAN 0x0107
+#define MALO_CMD_SET_POSTSCAN 0x0108
+#define MALO_CMD_SET_CHANNEL 0x010a
struct malo_cmdheader {
uint16_t cmd;
@@ -182,11 +187,23 @@ void malo_newassoc(struct ieee80211com *ic, struct ieee80211_node *ni,
int isnew);
struct ieee80211_node *
malo_node_alloc(struct ieee80211com *ic);
+int malo_media_change(struct ifnet *ifp);
+int malo_reset(struct ifnet *ifp);
+void malo_next_scan(void *arg);
+void malo_tx_intr(struct malo_softc *sc);
+int malo_tx_mgt(struct malo_softc *sc, struct mbuf *m0,
+ struct ieee80211_node *ni);
+void malo_tx_setup_desc(struct malo_softc *sc, struct malo_tx_desc *desc,
+ uint32_t flags, uint16_t xflags, int len, int rate,
+ const bus_dma_segment_t *segs, int nsegs, int ac);
void malo_rx_intr(struct malo_softc *sc);
int malo_load_bootimg(struct malo_softc *sc);
int malo_load_firmware(struct malo_softc *sc);
int malo_cmd_get_spec(struct malo_softc *sc);
int malo_cmd_reset(struct malo_softc *sc);
+int malo_cmd_set_prescan(struct malo_softc *sc);
+int malo_cmd_set_postscan(struct malo_softc *sc);
+int malo_cmd_set_channel(struct malo_softc *sc, uint8_t channel);
/* supported rates */
const struct ieee80211_rateset malo_rates_11b =
@@ -205,8 +222,6 @@ malo_intr(void *arg)
/* not for us */
return (0);
- DPRINTF(("%s: INTERRUPT %08x\n", sc->sc_dev.dv_xname, status));
-
if (status & 0x4) {
#ifdef MALO_DEBUG
struct malo_cmdheader *hdr = sc->sc_cmd_mem;
@@ -226,6 +241,9 @@ malo_intr(void *arg)
wakeup(sc);
}
+ if (status & 0x1)
+ malo_tx_intr(sc);
+
if (status & 0x2)
malo_rx_intr(sc);
@@ -241,6 +259,10 @@ malo_attach(struct malo_softc *sc)
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &sc->sc_ic.ic_if;
int i;
+
+ /* initialize channel scanning timer */
+ timeout_set(&sc->sc_scan_to, malo_next_scan, sc);
+
#if 0
/* ???, what is this for, seems unnecessary */
/* malo_ctl_write4(sc, 0x0c38, 0x1f); */
@@ -297,8 +319,7 @@ malo_attach(struct malo_softc *sc)
ic->ic_newassoc = malo_newassoc;
ic->ic_node_alloc = malo_node_alloc;
- ieee80211_media_init(ifp, ieee80211_media_change,
- ieee80211_media_status);
+ ieee80211_media_init(ifp, malo_media_change, ieee80211_media_status);
#if NBPFILTER > 0
bpfattach(&sc->sc_drvbpf, ifp, DLT_IEEE802_11_RADIO,
@@ -323,6 +344,9 @@ malo_detach(void *arg)
struct ieee80211com *ic = &sc->sc_ic;
struct ifnet *ifp = &ic->ic_if;
+ /* remove channel scanning timer */
+ timeout_del(&sc->sc_scan_to);
+
malo_stop(sc);
ieee80211_ifdetach(ifp);
if_detach(ifp);
@@ -770,7 +794,58 @@ malo_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
void
malo_start(struct ifnet *ifp)
{
+ struct malo_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct mbuf *m0;
+ struct ieee80211_node *ni;
+
+ DPRINTF(("%s: %s\n", sc->sc_dev.dv_xname, __func__));
+
+ if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
+ return;
+
+ for (;;) {
+ IF_POLL(&ic->ic_mgtq, m0);
+ if (m0 != NULL) {
+ if (sc->sc_txring.queued >= MALO_TX_RING_COUNT) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+ IF_DEQUEUE(&ic->ic_mgtq, m0);
+ ni = (struct ieee80211_node *)m0->m_pkthdr.rcvif;
+ m0->m_pkthdr.rcvif = NULL;
+#if NBPFILTER > 0
+ if (ic->ic_rawbpf != NULL)
+ bpf_mtap(ic->ic_rawbpf, m0, BPF_DIRECTION_OUT);
+#endif
+ if (malo_tx_mgt(sc, m0, ni) != 0)
+ break;
+ } else {
+ if (ic->ic_state != IEEE80211_S_RUN)
+ break;
+ IFQ_POLL(&ifp->if_snd, m0);
+ if (m0 == NULL)
+ break;
+ if (sc->sc_txring.queued >= MALO_TX_RING_COUNT - 1) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+ IFQ_DEQUEUE(&ifp->if_snd, m0);
+#if NBPFILTER > 0
+ if (ifp->if_bpf != NULL)
+ bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
+#endif
+ m0 = ieee80211_encap(ifp, m0, &ni);
+ if (m0 == NULL)
+ continue;
+#if NBPFILTER > 0
+ if (ic->ic_rawbpf != NULL)
+ bpf_mtap(ic->ic_rawbpf, m0, BPF_DIRECTION_OUT);
+#endif
+ /* TODO malo_tx_data() */
+ }
+ }
}
int
@@ -785,6 +860,8 @@ malo_stop(struct malo_softc *sc)
ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
+ ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
+
malo_reset_rx_ring(sc, &sc->sc_rxring);
DPRINTF(("%s: malo_stop\n", ifp->if_xname));
@@ -803,7 +880,47 @@ malo_watchdog(struct ifnet *ifp)
int
malo_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg)
{
- return (0);
+ struct malo_softc *sc = ic->ic_if.if_softc;
+ enum ieee80211_state ostate;
+ uint8_t chan;
+
+ DPRINTF(("%s: %s\n", sc->sc_dev.dv_xname, __func__));
+
+ ostate = ic->ic_state;
+ timeout_del(&sc->sc_scan_to);
+
+ switch (nstate) {
+ case IEEE80211_S_INIT:
+ if (ostate == IEEE80211_S_SCAN) {
+ if (malo_cmd_set_postscan(sc) != 0)
+ DPRINTF(("%s: can't set postscan\n",
+ sc->sc_dev.dv_xname));
+ else
+ DPRINTF(("%s: postscan done\n",
+ sc->sc_dev.dv_xname));
+ }
+ break;
+ case IEEE80211_S_SCAN:
+ if (ostate == IEEE80211_S_INIT) {
+ if (malo_cmd_set_prescan(sc) != 0)
+ DPRINTF(("%s: can't set prescan\n",
+ sc->sc_dev.dv_xname));
+ else
+ DPRINTF(("%s: prescan done\n",
+ sc->sc_dev.dv_xname));
+ }
+
+ chan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
+
+ malo_cmd_set_channel(sc, chan);
+
+ timeout_add(&sc->sc_scan_to, hz / 2);
+ break;
+ default:
+ break;
+ }
+
+ return (sc->sc_newstate(ic, nstate, arg));
}
void
@@ -826,6 +943,164 @@ malo_node_alloc(struct ieee80211com *ic)
return ((struct ieee80211_node *)wn);
}
+int
+malo_media_change(struct ifnet *ifp)
+{
+ int error;
+
+ DPRINTF(("%s: %s\n", ifp->if_xname, __func__));
+
+ error = ieee80211_media_change(ifp);
+ if (error != ENETRESET)
+ return (error);
+
+ if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING))
+ malo_reset(ifp);
+
+ return (0);
+}
+
+int
+malo_reset(struct ifnet *ifp)
+{
+ struct malo_softc *sc = ifp->if_softc;
+ struct ieee80211com *ic = &sc->sc_ic;
+ int chan;
+
+ DPRINTF(("%s: %s\n", sc->sc_dev.dv_xname, __func__));
+
+ /* set channel */
+ chan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
+ if (malo_cmd_set_channel(sc, chan) == 0)
+ DPRINTF(("%s: setting channel to %d\n", chan));
+ else
+ DPRINTF(("%s: setting channel to %d failed!\n", chan));
+
+ return (0);
+}
+
+void
+malo_next_scan(void *arg)
+{
+ struct malo_softc *sc = arg;
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+
+ DPRINTF(("%s: %s\n", ifp->if_xname, __func__));
+
+ if (ic->ic_state == IEEE80211_S_SCAN)
+ ieee80211_next_scan(ifp);
+}
+
+void
+malo_tx_intr(struct malo_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+
+ DPRINTF(("%s: %s\n", sc->sc_dev.dv_xname, __func__));
+
+ malo_start(ifp);
+}
+
+int
+malo_tx_mgt(struct malo_softc *sc, struct mbuf *m0, struct ieee80211_node *ni)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ struct ifnet *ifp = &ic->ic_if;
+ struct malo_tx_desc *desc;
+ struct malo_tx_data *data;
+ struct ieee80211_frame *wh;
+ uint32_t flags = 0;
+ int rate, error;
+
+ DPRINTF(("%s: %s\n", sc->sc_dev.dv_xname, __func__));
+
+ desc = &sc->sc_txring.desc[sc->sc_txring.cur];
+ data = &sc->sc_txring.data[sc->sc_txring.cur];
+
+ if (data->softstat & 0x80)
+ return (EAGAIN);
+
+ /* send mgt frames at the lowest available rate */
+ rate = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ? 12 : 2;
+
+ wh = mtod(m0, struct ieee80211_frame *);
+
+ if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
+ m0 = ieee80211_wep_crypt(ifp, m0, 1);
+ if (m0 == NULL)
+ return (ENOBUFS);
+
+ wh = mtod(m0, struct ieee80211_frame *);
+ }
+
+ error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0,
+ BUS_DMA_NOWAIT);
+ if (error != 0) {
+ printf("%s: could not map mbuf (error %d)\n",
+ sc->sc_dev.dv_xname, error);
+ m_freem(m0);
+ return (error);
+ }
+
+#if NBPFILTER > 0
+ if (sc->sc_drvbpf != NULL) {
+ struct mbuf mb;
+ struct malo_tx_radiotap_hdr *tap = &sc->sc_txtap;
+
+ tap->wt_flags = 0;
+ tap->wt_rate = rate;
+ tap->wt_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq);
+ tap->wt_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags);
+
+ M_DUP_PKTHDR(&mb, m0);
+ mb.m_data = (caddr_t)tap;
+ mb.m_len = sc->sc_txtap_len;
+ mb.m_next = m0;
+ mb.m_pkthdr.len += mb.m_len;
+ bpf_mtap(sc->sc_drvbpf, &mb, BPF_DIRECTION_OUT);
+ }
+#endif
+
+ data->m = m0;
+ data->ni = ni;
+ data->softstat |= 0x80;
+
+ malo_tx_setup_desc(sc, desc, flags, 0, m0->m_pkthdr.len, rate,
+ data->map->dm_segs, data->map->dm_nsegs, 0);
+
+ bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize,
+ BUS_DMASYNC_PREWRITE);
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_txring.map,
+ sc->sc_txring.cur * sizeof(struct malo_tx_desc),
+ sizeof(struct malo_tx_desc), BUS_DMASYNC_PREWRITE);
+
+ DPRINTF(("%s: sending mgmt frame, len=%u idx=%u rate=%u\n",
+ sc->sc_dev.dv_xname, m0->m_pkthdr.len, sc->sc_txring.cur, rate));
+
+ sc->sc_txring.queued++;
+ sc->sc_txring.cur = (sc->sc_txring.cur + 1) %
+ sizeof(struct malo_tx_desc);
+
+ /* kick mgmt TX */
+ malo_ctl_write4(sc, 0x0c18, 1);
+ malo_ctl_read4(sc, 0x0c14);
+
+ return (0);
+}
+
+void
+malo_tx_setup_desc(struct malo_softc *sc, struct malo_tx_desc *desc,
+ uint32_t flags, uint16_t xflags, int len, int rate,
+ const bus_dma_segment_t *segs, int nsegs, int ac)
+{
+ desc->len = htole16(segs[0].ds_len);
+ desc->datarate = rate;
+ desc->physdata = htole32(segs[0].ds_addr);
+ desc->status = htole32(0x00000001 | 0x80000000);
+}
+
void
malo_rx_intr(struct malo_softc *sc)
{
@@ -850,7 +1125,7 @@ malo_rx_intr(struct malo_softc *sc)
bus_dmamap_sync(sc->sc_dmat, sc->sc_rxring.map,
sc->sc_rxring.cur * sizeof(struct malo_rx_desc),
sizeof(struct malo_rx_desc), BUS_DMASYNC_POSTREAD);
-
+#if 0
DPRINTF(("rx intr idx=%d, rxctrl=0x%02x, rssi=%d, "
"status=0x%02x, channel=%d, len=%d, res1=%02x, rate=%d, "
"physdata=0x%04x, physnext=0x%04x, qosctrl=%02x, res2=%d\n",
@@ -858,7 +1133,7 @@ malo_rx_intr(struct malo_softc *sc)
desc->channel, letoh16(desc->len), desc->reserved1,
desc->datarate, desc->physdata, desc->physnext,
desc->qosctrl, desc->reserved2));
-
+#endif
if ((letoh32(desc->rxctrl) & 0x80) == 0)
break;
@@ -926,7 +1201,7 @@ malo_rx_intr(struct malo_softc *sc)
htole16(ic->ic_bss->ni_chan->ic_flags);
*/
tap->wr_rssi = desc->rssi;
- tap->wr_max_rssi = 100; /* XXX find out correct max */
+ tap->wr_max_rssi = 75;
M_DUP_PKTHDR(&mb, m);
mb.m_data = (caddr_t)tap;
@@ -1161,3 +1436,80 @@ malo_cmd_reset(struct malo_softc *sc)
else
return (ETIMEDOUT);
}
+
+int
+malo_cmd_set_prescan(struct malo_softc *sc)
+{
+ struct malo_cmdheader *hdr = sc->sc_cmd_mem;
+
+ hdr->cmd = MALO_CMD_SET_PRESCAN;
+ hdr->size = htole16(sizeof(*hdr));
+ hdr->seqnum = 1;
+ hdr->result = 0;
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE,
+ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+ malo_send_cmd(sc, sc->sc_cmd_dmaaddr, 0);
+ tsleep(sc, 0, "malosca", hz);
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE,
+ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+
+ if (hdr->cmd & MALO_CMD_RESPONSE)
+ return (0);
+ else
+ return (ETIMEDOUT);
+}
+
+int
+malo_cmd_set_postscan(struct malo_softc *sc)
+{
+ struct malo_cmdheader *hdr = sc->sc_cmd_mem;
+
+ hdr->cmd = MALO_CMD_SET_POSTSCAN;
+ hdr->size = htole16(sizeof(*hdr));
+ hdr->seqnum = 1;
+ hdr->result = 0;
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE,
+ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+ malo_send_cmd(sc, sc->sc_cmd_dmaaddr, 0);
+ tsleep(sc, 0, "malosca", hz);
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE,
+ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+
+ if (hdr->cmd & MALO_CMD_RESPONSE)
+ return (0);
+ else
+ return (ETIMEDOUT);
+}
+
+int
+malo_cmd_set_channel(struct malo_softc *sc, uint8_t channel)
+{
+ struct malo_cmdheader *hdr = sc->sc_cmd_mem;
+
+ hdr->cmd = htole16(MALO_CMD_SET_CHANNEL);
+ hdr->size = htole16(sizeof(*hdr) + sizeof(channel));
+ hdr->seqnum = 1;
+ hdr->result = 0;
+
+ bcopy(&channel, (void *)hdr + 1, sizeof(channel));
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE,
+ BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+ malo_send_cmd(sc, sc->sc_cmd_dmaaddr, 0);
+ //tsleep(sc, 0, "malochn", hz);
+
+ bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE,
+ BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+
+ if (hdr->cmd & MALO_CMD_RESPONSE)
+ return (0);
+ else
+ return (ETIMEDOUT);
+}
diff --git a/sys/dev/ic/malo.h b/sys/dev/ic/malo.h
index 5bbea597e3e..8c812303c43 100644
--- a/sys/dev/ic/malo.h
+++ b/sys/dev/ic/malo.h
@@ -1,7 +1,8 @@
-/* $OpenBSD: malo.h,v 1.6 2006/10/24 19:20:01 mglocker Exp $ */
+/* $OpenBSD: malo.h,v 1.7 2006/10/29 11:41:34 mglocker Exp $ */
/*
* Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2006 Marcus Glocker <mglocker@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -102,6 +103,8 @@ struct malo_softc {
int (*sc_enable)(struct malo_softc *);
void (*sc_disable)(struct malo_softc *);
+ struct timeout sc_scan_to;
+
#if NBPFILTER > 0
caddr_t sc_drvbpf;