Remove SIOC[GS]IFMEDIA because ieee80211_ioctl() does the same thing.diff -r1.98 -r1.99 src/sys/dev/ic/awi.c
(msaitoh)
--- src/sys/dev/ic/awi.c 2019/05/28 07:41:48 1.98
+++ src/sys/dev/ic/awi.c 2019/12/05 03:11:40 1.99
@@ -1,1863 +1,1858 @@ | @@ -1,1863 +1,1858 @@ | |||
1 | /* $NetBSD: awi.c,v 1.98 2019/05/28 07:41:48 msaitoh Exp $ */ | 1 | /* $NetBSD: awi.c,v 1.99 2019/12/05 03:11:40 msaitoh Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 1999,2000,2001 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 1999,2000,2001 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Bill Sommerfeld | 8 | * by Bill Sommerfeld | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | /* | 31 | /* | |
32 | * Driver for AMD 802.11 firmware. | 32 | * Driver for AMD 802.11 firmware. | |
33 | * Uses am79c930 chip driver to talk to firmware running on the am79c930. | 33 | * Uses am79c930 chip driver to talk to firmware running on the am79c930. | |
34 | * | 34 | * | |
35 | * More-or-less a generic ethernet-like if driver, with 802.11 gorp added. | 35 | * More-or-less a generic ethernet-like if driver, with 802.11 gorp added. | |
36 | */ | 36 | */ | |
37 | 37 | |||
38 | /* | 38 | /* | |
39 | * todo: | 39 | * todo: | |
40 | * - flush tx queue on resynch. | 40 | * - flush tx queue on resynch. | |
41 | * - clear oactive on "down". | 41 | * - clear oactive on "down". | |
42 | * - rewrite copy-into-mbuf code | 42 | * - rewrite copy-into-mbuf code | |
43 | * - mgmt state machine gets stuck retransmitting assoc requests. | 43 | * - mgmt state machine gets stuck retransmitting assoc requests. | |
44 | * - multicast filter. | 44 | * - multicast filter. | |
45 | * - fix device reset so it's more likely to work | 45 | * - fix device reset so it's more likely to work | |
46 | * - show status goo through ifmedia. | 46 | * - show status goo through ifmedia. | |
47 | * | 47 | * | |
48 | * more todo: | 48 | * more todo: | |
49 | * - deal with more 802.11 frames. | 49 | * - deal with more 802.11 frames. | |
50 | * - send reassoc request | 50 | * - send reassoc request | |
51 | * - deal with reassoc response | 51 | * - deal with reassoc response | |
52 | * - send/deal with disassociation | 52 | * - send/deal with disassociation | |
53 | * - deal with "full" access points (no room for me). | 53 | * - deal with "full" access points (no room for me). | |
54 | * - power save mode | 54 | * - power save mode | |
55 | * | 55 | * | |
56 | * later: | 56 | * later: | |
57 | * - SSID preferences | 57 | * - SSID preferences | |
58 | * - need ioctls for poking at the MIBs | 58 | * - need ioctls for poking at the MIBs | |
59 | * - implement ad-hoc mode (including bss creation). | 59 | * - implement ad-hoc mode (including bss creation). | |
60 | * - decide when to do "ad hoc" vs. infrastructure mode (IFF_LINK flags?) | 60 | * - decide when to do "ad hoc" vs. infrastructure mode (IFF_LINK flags?) | |
61 | * (focus on inf. mode since that will be needed for ietf) | 61 | * (focus on inf. mode since that will be needed for ietf) | |
62 | * - deal with DH vs. FH versions of the card | 62 | * - deal with DH vs. FH versions of the card | |
63 | * - deal with faster cards (2mb/s) | 63 | * - deal with faster cards (2mb/s) | |
64 | * - ?WEP goo (mmm, rc4) (it looks not particularly useful). | 64 | * - ?WEP goo (mmm, rc4) (it looks not particularly useful). | |
65 | * - ifmedia revision. | 65 | * - ifmedia revision. | |
66 | * - common 802.11 mibish things. | 66 | * - common 802.11 mibish things. | |
67 | * - common 802.11 media layer. | 67 | * - common 802.11 media layer. | |
68 | */ | 68 | */ | |
69 | 69 | |||
70 | /* | 70 | /* | |
71 | * Driver for AMD 802.11 PCnetMobile firmware. | 71 | * Driver for AMD 802.11 PCnetMobile firmware. | |
72 | * Uses am79c930 chip driver to talk to firmware running on the am79c930. | 72 | * Uses am79c930 chip driver to talk to firmware running on the am79c930. | |
73 | * | 73 | * | |
74 | * The initial version of the driver was written by | 74 | * The initial version of the driver was written by | |
75 | * Bill Sommerfeld <sommerfeld@NetBSD.org>. | 75 | * Bill Sommerfeld <sommerfeld@NetBSD.org>. | |
76 | * Then the driver module completely rewritten to support cards with DS phy | 76 | * Then the driver module completely rewritten to support cards with DS phy | |
77 | * and to support adhoc mode by Atsushi Onoe <onoe@NetBSD.org> | 77 | * and to support adhoc mode by Atsushi Onoe <onoe@NetBSD.org> | |
78 | */ | 78 | */ | |
79 | 79 | |||
80 | #include <sys/cdefs.h> | 80 | #include <sys/cdefs.h> | |
81 | __KERNEL_RCSID(0, "$NetBSD: awi.c,v 1.98 2019/05/28 07:41:48 msaitoh Exp $"); | 81 | __KERNEL_RCSID(0, "$NetBSD: awi.c,v 1.99 2019/12/05 03:11:40 msaitoh Exp $"); | |
82 | 82 | |||
83 | #include "opt_inet.h" | 83 | #include "opt_inet.h" | |
84 | 84 | |||
85 | #include <sys/param.h> | 85 | #include <sys/param.h> | |
86 | #include <sys/systm.h> | 86 | #include <sys/systm.h> | |
87 | #include <sys/kernel.h> | 87 | #include <sys/kernel.h> | |
88 | #include <sys/mbuf.h> | 88 | #include <sys/mbuf.h> | |
89 | #include <sys/malloc.h> | 89 | #include <sys/malloc.h> | |
90 | #include <sys/proc.h> | 90 | #include <sys/proc.h> | |
91 | #include <sys/socket.h> | 91 | #include <sys/socket.h> | |
92 | #include <sys/sockio.h> | 92 | #include <sys/sockio.h> | |
93 | #include <sys/errno.h> | 93 | #include <sys/errno.h> | |
94 | #include <sys/endian.h> | 94 | #include <sys/endian.h> | |
95 | #include <sys/device.h> | 95 | #include <sys/device.h> | |
96 | #include <sys/cpu.h> | 96 | #include <sys/cpu.h> | |
97 | #include <sys/bus.h> | 97 | #include <sys/bus.h> | |
98 | 98 | |||
99 | #include <net/if.h> | 99 | #include <net/if.h> | |
100 | #include <net/if_dl.h> | 100 | #include <net/if_dl.h> | |
101 | #include <net/if_ether.h> | 101 | #include <net/if_ether.h> | |
102 | #include <net/if_media.h> | 102 | #include <net/if_media.h> | |
103 | #include <net/if_llc.h> | 103 | #include <net/if_llc.h> | |
104 | #include <net/bpf.h> | 104 | #include <net/bpf.h> | |
105 | 105 | |||
106 | #include <net80211/ieee80211_netbsd.h> | 106 | #include <net80211/ieee80211_netbsd.h> | |
107 | #include <net80211/ieee80211_var.h> | 107 | #include <net80211/ieee80211_var.h> | |
108 | 108 | |||
109 | #include <dev/ic/am79c930reg.h> | 109 | #include <dev/ic/am79c930reg.h> | |
110 | #include <dev/ic/am79c930var.h> | 110 | #include <dev/ic/am79c930var.h> | |
111 | #include <dev/ic/awireg.h> | 111 | #include <dev/ic/awireg.h> | |
112 | #include <dev/ic/awivar.h> | 112 | #include <dev/ic/awivar.h> | |
113 | 113 | |||
114 | static void awi_softintr(void *); | 114 | static void awi_softintr(void *); | |
115 | static int awi_init(struct ifnet *); | 115 | static int awi_init(struct ifnet *); | |
116 | static void awi_stop(struct ifnet *, int); | 116 | static void awi_stop(struct ifnet *, int); | |
117 | static void awi_start(struct ifnet *); | 117 | static void awi_start(struct ifnet *); | |
118 | static void awi_watchdog(struct ifnet *); | 118 | static void awi_watchdog(struct ifnet *); | |
119 | static int awi_ioctl(struct ifnet *, u_long, void *); | 119 | static int awi_ioctl(struct ifnet *, u_long, void *); | |
120 | static int awi_media_change(struct ifnet *); | 120 | static int awi_media_change(struct ifnet *); | |
121 | static void awi_media_status(struct ifnet *, struct ifmediareq *); | 121 | static void awi_media_status(struct ifnet *, struct ifmediareq *); | |
122 | static int awi_mode_init(struct awi_softc *); | 122 | static int awi_mode_init(struct awi_softc *); | |
123 | static void awi_rx_int(struct awi_softc *); | 123 | static void awi_rx_int(struct awi_softc *); | |
124 | static void awi_tx_int(struct awi_softc *); | 124 | static void awi_tx_int(struct awi_softc *); | |
125 | static struct mbuf *awi_devget(struct awi_softc *, uint32_t, uint16_t); | 125 | static struct mbuf *awi_devget(struct awi_softc *, uint32_t, uint16_t); | |
126 | static int awi_hw_init(struct awi_softc *); | 126 | static int awi_hw_init(struct awi_softc *); | |
127 | static int awi_init_mibs(struct awi_softc *); | 127 | static int awi_init_mibs(struct awi_softc *); | |
128 | static int awi_mib(struct awi_softc *, uint8_t, uint8_t, int); | 128 | static int awi_mib(struct awi_softc *, uint8_t, uint8_t, int); | |
129 | static int awi_cmd(struct awi_softc *, uint8_t, int); | 129 | static int awi_cmd(struct awi_softc *, uint8_t, int); | |
130 | static int awi_cmd_wait(struct awi_softc *); | 130 | static int awi_cmd_wait(struct awi_softc *); | |
131 | static void awi_cmd_done(struct awi_softc *); | 131 | static void awi_cmd_done(struct awi_softc *); | |
132 | static int awi_next_txd(struct awi_softc *, int, uint32_t *, uint32_t *); | 132 | static int awi_next_txd(struct awi_softc *, int, uint32_t *, uint32_t *); | |
133 | static int awi_lock(struct awi_softc *); | 133 | static int awi_lock(struct awi_softc *); | |
134 | static void awi_unlock(struct awi_softc *); | 134 | static void awi_unlock(struct awi_softc *); | |
135 | static int awi_intr_lock(struct awi_softc *); | 135 | static int awi_intr_lock(struct awi_softc *); | |
136 | static void awi_intr_unlock(struct awi_softc *); | 136 | static void awi_intr_unlock(struct awi_softc *); | |
137 | static int awi_newstate(struct ieee80211com *, enum ieee80211_state, int); | 137 | static int awi_newstate(struct ieee80211com *, enum ieee80211_state, int); | |
138 | static void awi_recv_mgmt(struct ieee80211com *, struct mbuf *, | 138 | static void awi_recv_mgmt(struct ieee80211com *, struct mbuf *, | |
139 | struct ieee80211_node *, int, int, uint32_t); | 139 | struct ieee80211_node *, int, int, uint32_t); | |
140 | static int awi_send_mgmt(struct ieee80211com *, struct ieee80211_node *, int, | 140 | static int awi_send_mgmt(struct ieee80211com *, struct ieee80211_node *, int, | |
141 | int); | 141 | int); | |
142 | static struct mbuf *awi_ether_encap(struct awi_softc *, struct mbuf *); | 142 | static struct mbuf *awi_ether_encap(struct awi_softc *, struct mbuf *); | |
143 | static struct mbuf *awi_ether_modcap(struct awi_softc *, struct mbuf *); | 143 | static struct mbuf *awi_ether_modcap(struct awi_softc *, struct mbuf *); | |
144 | 144 | |||
145 | /* Unaligned little endian access */ | 145 | /* Unaligned little endian access */ | |
146 | #define LE_READ_2(p) \ | 146 | #define LE_READ_2(p) \ | |
147 | ((((uint8_t *)(p))[0] ) | (((uint8_t *)(p))[1] << 8)) | 147 | ((((uint8_t *)(p))[0] ) | (((uint8_t *)(p))[1] << 8)) | |
148 | #define LE_READ_4(p) \ | 148 | #define LE_READ_4(p) \ | |
149 | ((((uint8_t *)(p))[0] ) | (((uint8_t *)(p))[1] << 8) | \ | 149 | ((((uint8_t *)(p))[0] ) | (((uint8_t *)(p))[1] << 8) | \ | |
150 | (((uint8_t *)(p))[2] << 16) | (((uint8_t *)(p))[3] << 24)) | 150 | (((uint8_t *)(p))[2] << 16) | (((uint8_t *)(p))[3] << 24)) | |
151 | #define LE_WRITE_2(p, v) \ | 151 | #define LE_WRITE_2(p, v) \ | |
152 | ((((uint8_t *)(p))[0] = (((uint32_t)(v) ) & 0xff)), \ | 152 | ((((uint8_t *)(p))[0] = (((uint32_t)(v) ) & 0xff)), \ | |
153 | (((uint8_t *)(p))[1] = (((uint32_t)(v) >> 8) & 0xff))) | 153 | (((uint8_t *)(p))[1] = (((uint32_t)(v) >> 8) & 0xff))) | |
154 | #define LE_WRITE_4(p, v) \ | 154 | #define LE_WRITE_4(p, v) \ | |
155 | ((((uint8_t *)(p))[0] = (((uint32_t)(v) ) & 0xff)), \ | 155 | ((((uint8_t *)(p))[0] = (((uint32_t)(v) ) & 0xff)), \ | |
156 | (((uint8_t *)(p))[1] = (((uint32_t)(v) >> 8) & 0xff)), \ | 156 | (((uint8_t *)(p))[1] = (((uint32_t)(v) >> 8) & 0xff)), \ | |
157 | (((uint8_t *)(p))[2] = (((uint32_t)(v) >> 16) & 0xff)), \ | 157 | (((uint8_t *)(p))[2] = (((uint32_t)(v) >> 16) & 0xff)), \ | |
158 | (((uint8_t *)(p))[3] = (((uint32_t)(v) >> 24) & 0xff))) | 158 | (((uint8_t *)(p))[3] = (((uint32_t)(v) >> 24) & 0xff))) | |
159 | 159 | |||
160 | static const struct awi_chanset awi_chanset[] = { | 160 | static const struct awi_chanset awi_chanset[] = { | |
161 | /* PHY type domain min max def */ | 161 | /* PHY type domain min max def */ | |
162 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_JP, 6, 17, 6 }, | 162 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_JP, 6, 17, 6 }, | |
163 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_ES, 0, 26, 1 }, | 163 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_ES, 0, 26, 1 }, | |
164 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_FR, 0, 32, 1 }, | 164 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_FR, 0, 32, 1 }, | |
165 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_US, 0, 77, 1 }, | 165 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_US, 0, 77, 1 }, | |
166 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_CA, 0, 77, 1 }, | 166 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_CA, 0, 77, 1 }, | |
167 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_EU, 0, 77, 1 }, | 167 | { AWI_PHY_TYPE_FH, AWI_REG_DOMAIN_EU, 0, 77, 1 }, | |
168 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_JP, 14, 14, 14 }, | 168 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_JP, 14, 14, 14 }, | |
169 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_ES, 10, 11, 10 }, | 169 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_ES, 10, 11, 10 }, | |
170 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_FR, 10, 13, 10 }, | 170 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_FR, 10, 13, 10 }, | |
171 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_US, 1, 11, 3 }, | 171 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_US, 1, 11, 3 }, | |
172 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_CA, 1, 11, 3 }, | 172 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_CA, 1, 11, 3 }, | |
173 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_EU, 1, 13, 3 }, | 173 | { AWI_PHY_TYPE_DS, AWI_REG_DOMAIN_EU, 1, 13, 3 }, | |
174 | { 0, 0, 0, 0, 0 } | 174 | { 0, 0, 0, 0, 0 } | |
175 | }; | 175 | }; | |
176 | 176 | |||
177 | #ifdef AWI_DEBUG | 177 | #ifdef AWI_DEBUG | |
178 | int awi_debug = 0; | 178 | int awi_debug = 0; | |
179 | 179 | |||
180 | #define DPRINTF(X) if (awi_debug) printf X | 180 | #define DPRINTF(X) if (awi_debug) printf X | |
181 | #define DPRINTF2(X) if (awi_debug > 1) printf X | 181 | #define DPRINTF2(X) if (awi_debug > 1) printf X | |
182 | #else | 182 | #else | |
183 | #define DPRINTF(X) | 183 | #define DPRINTF(X) | |
184 | #define DPRINTF2(X) | 184 | #define DPRINTF2(X) | |
185 | #endif | 185 | #endif | |
186 | 186 | |||
187 | int | 187 | int | |
188 | awi_attach(struct awi_softc *sc) | 188 | awi_attach(struct awi_softc *sc) | |
189 | { | 189 | { | |
190 | struct ieee80211com *ic = &sc->sc_ic; | 190 | struct ieee80211com *ic = &sc->sc_ic; | |
191 | struct ifnet *ifp = &sc->sc_if; | 191 | struct ifnet *ifp = &sc->sc_if; | |
192 | int s, i, error, nrate; | 192 | int s, i, error, nrate; | |
193 | int mword; | 193 | int mword; | |
194 | enum ieee80211_phymode mode; | 194 | enum ieee80211_phymode mode; | |
195 | 195 | |||
196 | s = splnet(); | 196 | s = splnet(); | |
197 | sc->sc_busy = 1; | 197 | sc->sc_busy = 1; | |
198 | sc->sc_attached = 0; | 198 | sc->sc_attached = 0; | |
199 | sc->sc_substate = AWI_ST_NONE; | 199 | sc->sc_substate = AWI_ST_NONE; | |
200 | sc->sc_soft_ih = softint_establish(SOFTINT_NET, awi_softintr, sc); | 200 | sc->sc_soft_ih = softint_establish(SOFTINT_NET, awi_softintr, sc); | |
201 | if (sc->sc_soft_ih == NULL) { | 201 | if (sc->sc_soft_ih == NULL) { | |
202 | config_deactivate(sc->sc_dev); | 202 | config_deactivate(sc->sc_dev); | |
203 | splx(s); | 203 | splx(s); | |
204 | return ENOMEM; | 204 | return ENOMEM; | |
205 | } | 205 | } | |
206 | if ((error = awi_hw_init(sc)) != 0) { | 206 | if ((error = awi_hw_init(sc)) != 0) { | |
207 | config_deactivate(sc->sc_dev); | 207 | config_deactivate(sc->sc_dev); | |
208 | splx(s); | 208 | splx(s); | |
209 | return error; | 209 | return error; | |
210 | } | 210 | } | |
211 | error = awi_init_mibs(sc); | 211 | error = awi_init_mibs(sc); | |
212 | if (error != 0) { | 212 | if (error != 0) { | |
213 | config_deactivate(sc->sc_dev); | 213 | config_deactivate(sc->sc_dev); | |
214 | splx(s); | 214 | splx(s); | |
215 | return error; | 215 | return error; | |
216 | } | 216 | } | |
217 | ifp->if_softc = sc; | 217 | ifp->if_softc = sc; | |
218 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | 218 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | |
219 | ifp->if_ioctl = awi_ioctl; | 219 | ifp->if_ioctl = awi_ioctl; | |
220 | ifp->if_start = awi_start; | 220 | ifp->if_start = awi_start; | |
221 | ifp->if_watchdog = awi_watchdog; | 221 | ifp->if_watchdog = awi_watchdog; | |
222 | ifp->if_init = awi_init; | 222 | ifp->if_init = awi_init; | |
223 | ifp->if_stop = awi_stop; | 223 | ifp->if_stop = awi_stop; | |
224 | IFQ_SET_READY(&ifp->if_snd); | 224 | IFQ_SET_READY(&ifp->if_snd); | |
225 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | 225 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | |
226 | 226 | |||
227 | ic->ic_ifp = ifp; | 227 | ic->ic_ifp = ifp; | |
228 | ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_IBSS | IEEE80211_C_HOSTAP; | 228 | ic->ic_caps = IEEE80211_C_WEP | IEEE80211_C_IBSS | IEEE80211_C_HOSTAP; | |
229 | if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { | 229 | if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { | |
230 | ic->ic_phytype = IEEE80211_T_FH; | 230 | ic->ic_phytype = IEEE80211_T_FH; | |
231 | mode = IEEE80211_MODE_FH; | 231 | mode = IEEE80211_MODE_FH; | |
232 | } else { | 232 | } else { | |
233 | ic->ic_phytype = IEEE80211_T_DS; | 233 | ic->ic_phytype = IEEE80211_T_DS; | |
234 | ic->ic_caps |= IEEE80211_C_AHDEMO; | 234 | ic->ic_caps |= IEEE80211_C_AHDEMO; | |
235 | mode = IEEE80211_MODE_11B; | 235 | mode = IEEE80211_MODE_11B; | |
236 | } | 236 | } | |
237 | ic->ic_opmode = IEEE80211_M_STA; | 237 | ic->ic_opmode = IEEE80211_M_STA; | |
238 | nrate = sc->sc_mib_phy.aSuprt_Data_Rates[1]; | 238 | nrate = sc->sc_mib_phy.aSuprt_Data_Rates[1]; | |
239 | memcpy(ic->ic_sup_rates[mode].rs_rates, | 239 | memcpy(ic->ic_sup_rates[mode].rs_rates, | |
240 | sc->sc_mib_phy.aSuprt_Data_Rates + 2, nrate); | 240 | sc->sc_mib_phy.aSuprt_Data_Rates + 2, nrate); | |
241 | ic->ic_sup_rates[mode].rs_nrates = nrate; | 241 | ic->ic_sup_rates[mode].rs_nrates = nrate; | |
242 | IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_mib_addr.aMAC_Address); | 242 | IEEE80211_ADDR_COPY(ic->ic_myaddr, sc->sc_mib_addr.aMAC_Address); | |
243 | 243 | |||
244 | printf("%s: IEEE802.11 %s (firmware %s)\n", ifp->if_xname, | 244 | printf("%s: IEEE802.11 %s (firmware %s)\n", ifp->if_xname, | |
245 | (ic->ic_phytype == IEEE80211_T_FH) ? "FH" : "DS", sc->sc_banner); | 245 | (ic->ic_phytype == IEEE80211_T_FH) ? "FH" : "DS", sc->sc_banner); | |
246 | printf("%s: 802.11 address: %s\n", ifp->if_xname, | 246 | printf("%s: 802.11 address: %s\n", ifp->if_xname, | |
247 | ether_sprintf(ic->ic_myaddr)); | 247 | ether_sprintf(ic->ic_myaddr)); | |
248 | 248 | |||
249 | if_attach(ifp); | 249 | if_attach(ifp); | |
250 | ieee80211_ifattach(ic); | 250 | ieee80211_ifattach(ic); | |
251 | 251 | |||
252 | sc->sc_newstate = ic->ic_newstate; | 252 | sc->sc_newstate = ic->ic_newstate; | |
253 | ic->ic_newstate = awi_newstate; | 253 | ic->ic_newstate = awi_newstate; | |
254 | 254 | |||
255 | sc->sc_recv_mgmt = ic->ic_recv_mgmt; | 255 | sc->sc_recv_mgmt = ic->ic_recv_mgmt; | |
256 | ic->ic_recv_mgmt = awi_recv_mgmt; | 256 | ic->ic_recv_mgmt = awi_recv_mgmt; | |
257 | 257 | |||
258 | sc->sc_send_mgmt = ic->ic_send_mgmt; | 258 | sc->sc_send_mgmt = ic->ic_send_mgmt; | |
259 | ic->ic_send_mgmt = awi_send_mgmt; | 259 | ic->ic_send_mgmt = awi_send_mgmt; | |
260 | 260 | |||
261 | ieee80211_media_init(ic, awi_media_change, awi_media_status); | 261 | ieee80211_media_init(ic, awi_media_change, awi_media_status); | |
262 | 262 | |||
263 | /* Melco compatibility mode. */ | 263 | /* Melco compatibility mode. */ | |
264 | #define ADD(s, o) ifmedia_add(&ic->ic_media, \ | 264 | #define ADD(s, o) ifmedia_add(&ic->ic_media, \ | |
265 | IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL) | 265 | IFM_MAKEWORD(IFM_IEEE80211, (s), (o), 0), 0, NULL) | |
266 | ADD(IFM_AUTO, IFM_FLAG0); | 266 | ADD(IFM_AUTO, IFM_FLAG0); | |
267 | 267 | |||
268 | for (i = 0; i < nrate; i++) { | 268 | for (i = 0; i < nrate; i++) { | |
269 | mword = ieee80211_rate2media(ic, | 269 | mword = ieee80211_rate2media(ic, | |
270 | ic->ic_sup_rates[mode].rs_rates[i], mode); | 270 | ic->ic_sup_rates[mode].rs_rates[i], mode); | |
271 | if (mword == 0) | 271 | if (mword == 0) | |
272 | continue; | 272 | continue; | |
273 | ADD(mword, IFM_FLAG0); | 273 | ADD(mword, IFM_FLAG0); | |
274 | } | 274 | } | |
275 | #undef ADD | 275 | #undef ADD | |
276 | 276 | |||
277 | if ((sc->sc_sdhook = shutdownhook_establish(awi_shutdown, sc)) == NULL) | 277 | if ((sc->sc_sdhook = shutdownhook_establish(awi_shutdown, sc)) == NULL) | |
278 | printf("%s: WARNING: unable to establish shutdown hook\n", | 278 | printf("%s: WARNING: unable to establish shutdown hook\n", | |
279 | ifp->if_xname); | 279 | ifp->if_xname); | |
280 | if ((sc->sc_powerhook = | 280 | if ((sc->sc_powerhook = | |
281 | powerhook_establish(ifp->if_xname, awi_power, sc)) == NULL) | 281 | powerhook_establish(ifp->if_xname, awi_power, sc)) == NULL) | |
282 | printf("%s: WARNING: unable to establish power hook\n", | 282 | printf("%s: WARNING: unable to establish power hook\n", | |
283 | ifp->if_xname); | 283 | ifp->if_xname); | |
284 | sc->sc_attached = 1; | 284 | sc->sc_attached = 1; | |
285 | splx(s); | 285 | splx(s); | |
286 | 286 | |||
287 | /* Ready to accept ioctl */ | 287 | /* Ready to accept ioctl */ | |
288 | awi_unlock(sc); | 288 | awi_unlock(sc); | |
289 | 289 | |||
290 | return 0; | 290 | return 0; | |
291 | } | 291 | } | |
292 | 292 | |||
293 | int | 293 | int | |
294 | awi_detach(struct awi_softc *sc) | 294 | awi_detach(struct awi_softc *sc) | |
295 | { | 295 | { | |
296 | struct ieee80211com *ic = &sc->sc_ic; | 296 | struct ieee80211com *ic = &sc->sc_ic; | |
297 | struct ifnet *ifp = &sc->sc_if; | 297 | struct ifnet *ifp = &sc->sc_if; | |
298 | int s; | 298 | int s; | |
299 | 299 | |||
300 | if (!sc->sc_attached) | 300 | if (!sc->sc_attached) | |
301 | return 0; | 301 | return 0; | |
302 | 302 | |||
303 | s = splnet(); | 303 | s = splnet(); | |
304 | awi_stop(ifp, 1); | 304 | awi_stop(ifp, 1); | |
305 | 305 | |||
306 | while (sc->sc_sleep_cnt > 0) { | 306 | while (sc->sc_sleep_cnt > 0) { | |
307 | wakeup(sc); | 307 | wakeup(sc); | |
308 | (void)tsleep(sc, PWAIT, "awidet", 1); | 308 | (void)tsleep(sc, PWAIT, "awidet", 1); | |
309 | } | 309 | } | |
310 | sc->sc_attached = 0; | 310 | sc->sc_attached = 0; | |
311 | ieee80211_ifdetach(ic); | 311 | ieee80211_ifdetach(ic); | |
312 | if_detach(ifp); | 312 | if_detach(ifp); | |
313 | shutdownhook_disestablish(sc->sc_sdhook); | 313 | shutdownhook_disestablish(sc->sc_sdhook); | |
314 | powerhook_disestablish(sc->sc_powerhook); | 314 | powerhook_disestablish(sc->sc_powerhook); | |
315 | softint_disestablish(sc->sc_soft_ih); | 315 | softint_disestablish(sc->sc_soft_ih); | |
316 | splx(s); | 316 | splx(s); | |
317 | return 0; | 317 | return 0; | |
318 | } | 318 | } | |
319 | 319 | |||
320 | int | 320 | int | |
321 | awi_activate(device_t self, enum devact act) | 321 | awi_activate(device_t self, enum devact act) | |
322 | { | 322 | { | |
323 | struct awi_softc *sc = device_private(self); | 323 | struct awi_softc *sc = device_private(self); | |
324 | 324 | |||
325 | switch (act) { | 325 | switch (act) { | |
326 | case DVACT_DEACTIVATE: | 326 | case DVACT_DEACTIVATE: | |
327 | if_deactivate(&sc->sc_if); | 327 | if_deactivate(&sc->sc_if); | |
328 | return 0; | 328 | return 0; | |
329 | default: | 329 | default: | |
330 | return EOPNOTSUPP; | 330 | return EOPNOTSUPP; | |
331 | } | 331 | } | |
332 | } | 332 | } | |
333 | 333 | |||
334 | void | 334 | void | |
335 | awi_power(int why, void *arg) | 335 | awi_power(int why, void *arg) | |
336 | { | 336 | { | |
337 | struct awi_softc *sc = arg; | 337 | struct awi_softc *sc = arg; | |
338 | struct ifnet *ifp = &sc->sc_if; | 338 | struct ifnet *ifp = &sc->sc_if; | |
339 | int s; | 339 | int s; | |
340 | int ocansleep; | 340 | int ocansleep; | |
341 | 341 | |||
342 | DPRINTF(("awi_power: %d\n", why)); | 342 | DPRINTF(("awi_power: %d\n", why)); | |
343 | s = splnet(); | 343 | s = splnet(); | |
344 | ocansleep = sc->sc_cansleep; | 344 | ocansleep = sc->sc_cansleep; | |
345 | sc->sc_cansleep = 0; | 345 | sc->sc_cansleep = 0; | |
346 | switch (why) { | 346 | switch (why) { | |
347 | case PWR_SUSPEND: | 347 | case PWR_SUSPEND: | |
348 | case PWR_STANDBY: | 348 | case PWR_STANDBY: | |
349 | awi_stop(ifp, 1); | 349 | awi_stop(ifp, 1); | |
350 | break; | 350 | break; | |
351 | case PWR_RESUME: | 351 | case PWR_RESUME: | |
352 | if (ifp->if_flags & IFF_UP) { | 352 | if (ifp->if_flags & IFF_UP) { | |
353 | awi_init(ifp); | 353 | awi_init(ifp); | |
354 | awi_softintr(sc); /* make sure */ | 354 | awi_softintr(sc); /* make sure */ | |
355 | } | 355 | } | |
356 | break; | 356 | break; | |
357 | case PWR_SOFTSUSPEND: | 357 | case PWR_SOFTSUSPEND: | |
358 | case PWR_SOFTSTANDBY: | 358 | case PWR_SOFTSTANDBY: | |
359 | case PWR_SOFTRESUME: | 359 | case PWR_SOFTRESUME: | |
360 | break; | 360 | break; | |
361 | } | 361 | } | |
362 | sc->sc_cansleep = ocansleep; | 362 | sc->sc_cansleep = ocansleep; | |
363 | splx(s); | 363 | splx(s); | |
364 | } | 364 | } | |
365 | 365 | |||
366 | void | 366 | void | |
367 | awi_shutdown(void *arg) | 367 | awi_shutdown(void *arg) | |
368 | { | 368 | { | |
369 | struct awi_softc *sc = arg; | 369 | struct awi_softc *sc = arg; | |
370 | struct ifnet *ifp = &sc->sc_if; | 370 | struct ifnet *ifp = &sc->sc_if; | |
371 | 371 | |||
372 | if (sc->sc_attached) | 372 | if (sc->sc_attached) | |
373 | awi_stop(ifp, 1); | 373 | awi_stop(ifp, 1); | |
374 | } | 374 | } | |
375 | 375 | |||
376 | int | 376 | int | |
377 | awi_intr(void *arg) | 377 | awi_intr(void *arg) | |
378 | { | 378 | { | |
379 | struct awi_softc *sc = arg; | 379 | struct awi_softc *sc = arg; | |
380 | 380 | |||
381 | if (!sc->sc_enabled || !sc->sc_enab_intr || | 381 | if (!sc->sc_enabled || !sc->sc_enab_intr || | |
382 | !device_is_active(sc->sc_dev)) { | 382 | !device_is_active(sc->sc_dev)) { | |
383 | DPRINTF(("awi_intr: stray interrupt: " | 383 | DPRINTF(("awi_intr: stray interrupt: " | |
384 | "enabled %d enab_intr %d invalid %d\n", | 384 | "enabled %d enab_intr %d invalid %d\n", | |
385 | sc->sc_enabled, sc->sc_enab_intr, | 385 | sc->sc_enabled, sc->sc_enab_intr, | |
386 | !device_is_active(sc->sc_dev))); | 386 | !device_is_active(sc->sc_dev))); | |
387 | return 0; | 387 | return 0; | |
388 | } | 388 | } | |
389 | 389 | |||
390 | softint_schedule(sc->sc_soft_ih); | 390 | softint_schedule(sc->sc_soft_ih); | |
391 | return 1; | 391 | return 1; | |
392 | } | 392 | } | |
393 | 393 | |||
394 | static void | 394 | static void | |
395 | awi_softintr(void *arg) | 395 | awi_softintr(void *arg) | |
396 | { | 396 | { | |
397 | struct awi_softc *sc = arg; | 397 | struct awi_softc *sc = arg; | |
398 | uint16_t status; | 398 | uint16_t status; | |
399 | int ocansleep; | 399 | int ocansleep; | |
400 | int s; | 400 | int s; | |
401 | #ifdef AWI_DEBUG | 401 | #ifdef AWI_DEBUG | |
402 | static const char *intname[] = { | 402 | static const char *intname[] = { | |
403 | "CMD", "RX", "TX", "SCAN_CMPLT", | 403 | "CMD", "RX", "TX", "SCAN_CMPLT", | |
404 | "CFP_START", "DTIM", "CFP_ENDING", "GROGGY", | 404 | "CFP_START", "DTIM", "CFP_ENDING", "GROGGY", | |
405 | "TXDATA", "TXBCAST", "TXPS", "TXCF", | 405 | "TXDATA", "TXBCAST", "TXPS", "TXCF", | |
406 | "TXMGT", "#13", "RXDATA", "RXMGT" | 406 | "TXMGT", "#13", "RXDATA", "RXMGT" | |
407 | }; | 407 | }; | |
408 | #endif | 408 | #endif | |
409 | 409 | |||
410 | s = splnet(); | 410 | s = splnet(); | |
411 | am79c930_gcr_setbits(&sc->sc_chip, | 411 | am79c930_gcr_setbits(&sc->sc_chip, | |
412 | AM79C930_GCR_DISPWDN | AM79C930_GCR_ECINT); | 412 | AM79C930_GCR_DISPWDN | AM79C930_GCR_ECINT); | |
413 | awi_write_1(sc, AWI_DIS_PWRDN, 1); | 413 | awi_write_1(sc, AWI_DIS_PWRDN, 1); | |
414 | ocansleep = sc->sc_cansleep; | 414 | ocansleep = sc->sc_cansleep; | |
415 | sc->sc_cansleep = 0; | 415 | sc->sc_cansleep = 0; | |
416 | 416 | |||
417 | for (;;) { | 417 | for (;;) { | |
418 | if (awi_intr_lock(sc) != 0) | 418 | if (awi_intr_lock(sc) != 0) | |
419 | break; | 419 | break; | |
420 | status = awi_read_1(sc, AWI_INTSTAT); | 420 | status = awi_read_1(sc, AWI_INTSTAT); | |
421 | awi_write_1(sc, AWI_INTSTAT, 0); | 421 | awi_write_1(sc, AWI_INTSTAT, 0); | |
422 | awi_write_1(sc, AWI_INTSTAT, 0); | 422 | awi_write_1(sc, AWI_INTSTAT, 0); | |
423 | status |= awi_read_1(sc, AWI_INTSTAT2) << 8; | 423 | status |= awi_read_1(sc, AWI_INTSTAT2) << 8; | |
424 | awi_write_1(sc, AWI_INTSTAT2, 0); | 424 | awi_write_1(sc, AWI_INTSTAT2, 0); | |
425 | DELAY(10); | 425 | DELAY(10); | |
426 | awi_intr_unlock(sc); | 426 | awi_intr_unlock(sc); | |
427 | if (!sc->sc_cmd_inprog) | 427 | if (!sc->sc_cmd_inprog) | |
428 | status &= ~AWI_INT_CMD; /* make sure */ | 428 | status &= ~AWI_INT_CMD; /* make sure */ | |
429 | if (status == 0) | 429 | if (status == 0) | |
430 | break; | 430 | break; | |
431 | #ifdef AWI_DEBUG | 431 | #ifdef AWI_DEBUG | |
432 | if (awi_debug > 1) { | 432 | if (awi_debug > 1) { | |
433 | int i; | 433 | int i; | |
434 | 434 | |||
435 | printf("awi_intr: status 0x%04x", status); | 435 | printf("awi_intr: status 0x%04x", status); | |
436 | for (i = 0; i < sizeof(intname)/sizeof(intname[0]); | 436 | for (i = 0; i < sizeof(intname)/sizeof(intname[0]); | |
437 | i++) { | 437 | i++) { | |
438 | if (status & (1 << i)) | 438 | if (status & (1 << i)) | |
439 | printf(" %s", intname[i]); | 439 | printf(" %s", intname[i]); | |
440 | } | 440 | } | |
441 | printf("\n"); | 441 | printf("\n"); | |
442 | } | 442 | } | |
443 | #endif | 443 | #endif | |
444 | if (status & AWI_INT_RX) | 444 | if (status & AWI_INT_RX) | |
445 | awi_rx_int(sc); | 445 | awi_rx_int(sc); | |
446 | if (status & AWI_INT_TX) | 446 | if (status & AWI_INT_TX) | |
447 | awi_tx_int(sc); | 447 | awi_tx_int(sc); | |
448 | if (status & AWI_INT_CMD) | 448 | if (status & AWI_INT_CMD) | |
449 | awi_cmd_done(sc); | 449 | awi_cmd_done(sc); | |
450 | if (status & AWI_INT_SCAN_CMPLT) { | 450 | if (status & AWI_INT_SCAN_CMPLT) { | |
451 | if (sc->sc_ic.ic_state == IEEE80211_S_SCAN && | 451 | if (sc->sc_ic.ic_state == IEEE80211_S_SCAN && | |
452 | sc->sc_substate == AWI_ST_NONE) | 452 | sc->sc_substate == AWI_ST_NONE) | |
453 | ieee80211_next_scan(&sc->sc_ic); | 453 | ieee80211_next_scan(&sc->sc_ic); | |
454 | } | 454 | } | |
455 | } | 455 | } | |
456 | 456 | |||
457 | sc->sc_cansleep = ocansleep; | 457 | sc->sc_cansleep = ocansleep; | |
458 | am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_DISPWDN); | 458 | am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_DISPWDN); | |
459 | awi_write_1(sc, AWI_DIS_PWRDN, 0); | 459 | awi_write_1(sc, AWI_DIS_PWRDN, 0); | |
460 | splx(s); | 460 | splx(s); | |
461 | } | 461 | } | |
462 | 462 | |||
463 | 463 | |||
464 | static int | 464 | static int | |
465 | awi_init(struct ifnet *ifp) | 465 | awi_init(struct ifnet *ifp) | |
466 | { | 466 | { | |
467 | struct awi_softc *sc = ifp->if_softc; | 467 | struct awi_softc *sc = ifp->if_softc; | |
468 | struct ieee80211com *ic = &sc->sc_ic; | 468 | struct ieee80211com *ic = &sc->sc_ic; | |
469 | struct ieee80211_node *ni = ic->ic_bss; | 469 | struct ieee80211_node *ni = ic->ic_bss; | |
470 | struct ieee80211_rateset *rs; | 470 | struct ieee80211_rateset *rs; | |
471 | int error, rate, i; | 471 | int error, rate, i; | |
472 | 472 | |||
473 | DPRINTF(("awi_init: enabled=%d\n", sc->sc_enabled)); | 473 | DPRINTF(("awi_init: enabled=%d\n", sc->sc_enabled)); | |
474 | if (sc->sc_enabled) { | 474 | if (sc->sc_enabled) { | |
475 | awi_stop(ifp, 0); | 475 | awi_stop(ifp, 0); | |
476 | } else { | 476 | } else { | |
477 | if (sc->sc_enable) | 477 | if (sc->sc_enable) | |
478 | (*sc->sc_enable)(sc); | 478 | (*sc->sc_enable)(sc); | |
479 | sc->sc_enabled = 1; | 479 | sc->sc_enabled = 1; | |
480 | if ((error = awi_hw_init(sc)) != 0) { | 480 | if ((error = awi_hw_init(sc)) != 0) { | |
481 | if (sc->sc_disable) | 481 | if (sc->sc_disable) | |
482 | (*sc->sc_disable)(sc); | 482 | (*sc->sc_disable)(sc); | |
483 | sc->sc_enabled = 0; | 483 | sc->sc_enabled = 0; | |
484 | return error; | 484 | return error; | |
485 | } | 485 | } | |
486 | } | 486 | } | |
487 | ic->ic_state = IEEE80211_S_INIT; | 487 | ic->ic_state = IEEE80211_S_INIT; | |
488 | 488 | |||
489 | ic->ic_flags &= ~IEEE80211_F_IBSSON; | 489 | ic->ic_flags &= ~IEEE80211_F_IBSSON; | |
490 | switch (ic->ic_opmode) { | 490 | switch (ic->ic_opmode) { | |
491 | case IEEE80211_M_STA: | 491 | case IEEE80211_M_STA: | |
492 | sc->sc_mib_local.Network_Mode = 1; | 492 | sc->sc_mib_local.Network_Mode = 1; | |
493 | sc->sc_mib_local.Acting_as_AP = 0; | 493 | sc->sc_mib_local.Acting_as_AP = 0; | |
494 | break; | 494 | break; | |
495 | case IEEE80211_M_IBSS: | 495 | case IEEE80211_M_IBSS: | |
496 | ic->ic_flags |= IEEE80211_F_IBSSON; | 496 | ic->ic_flags |= IEEE80211_F_IBSSON; | |
497 | /* FALLTHRU */ | 497 | /* FALLTHRU */ | |
498 | case IEEE80211_M_AHDEMO: | 498 | case IEEE80211_M_AHDEMO: | |
499 | sc->sc_mib_local.Network_Mode = 0; | 499 | sc->sc_mib_local.Network_Mode = 0; | |
500 | sc->sc_mib_local.Acting_as_AP = 0; | 500 | sc->sc_mib_local.Acting_as_AP = 0; | |
501 | break; | 501 | break; | |
502 | case IEEE80211_M_HOSTAP: | 502 | case IEEE80211_M_HOSTAP: | |
503 | sc->sc_mib_local.Network_Mode = 1; | 503 | sc->sc_mib_local.Network_Mode = 1; | |
504 | sc->sc_mib_local.Acting_as_AP = 1; | 504 | sc->sc_mib_local.Acting_as_AP = 1; | |
505 | break; | 505 | break; | |
506 | case IEEE80211_M_MONITOR: | 506 | case IEEE80211_M_MONITOR: | |
507 | return ENODEV; | 507 | return ENODEV; | |
508 | } | 508 | } | |
509 | #if 0 | 509 | #if 0 | |
510 | IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl)); | 510 | IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl)); | |
511 | #endif | 511 | #endif | |
512 | memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE); | 512 | memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE); | |
513 | sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID; | 513 | sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID; | |
514 | sc->sc_mib_mac.aDesired_ESS_ID[1] = ic->ic_des_esslen; | 514 | sc->sc_mib_mac.aDesired_ESS_ID[1] = ic->ic_des_esslen; | |
515 | memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], ic->ic_des_essid, | 515 | memcpy(&sc->sc_mib_mac.aDesired_ESS_ID[2], ic->ic_des_essid, | |
516 | ic->ic_des_esslen); | 516 | ic->ic_des_esslen); | |
517 | 517 | |||
518 | /* Configure basic rate */ | 518 | /* Configure basic rate */ | |
519 | if (ic->ic_phytype == IEEE80211_T_FH) | 519 | if (ic->ic_phytype == IEEE80211_T_FH) | |
520 | rs = &ic->ic_sup_rates[IEEE80211_MODE_FH]; | 520 | rs = &ic->ic_sup_rates[IEEE80211_MODE_FH]; | |
521 | else | 521 | else | |
522 | rs = &ic->ic_sup_rates[IEEE80211_MODE_11B]; | 522 | rs = &ic->ic_sup_rates[IEEE80211_MODE_11B]; | |
523 | if (ic->ic_fixed_rate != -1) { | 523 | if (ic->ic_fixed_rate != -1) { | |
524 | rate = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; | 524 | rate = rs->rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; | |
525 | } else { | 525 | } else { | |
526 | rate = 0; | 526 | rate = 0; | |
527 | for (i = 0; i < rs->rs_nrates; i++) { | 527 | for (i = 0; i < rs->rs_nrates; i++) { | |
528 | if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) && | 528 | if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) && | |
529 | rate < (rs->rs_rates[i] & IEEE80211_RATE_VAL)) | 529 | rate < (rs->rs_rates[i] & IEEE80211_RATE_VAL)) | |
530 | rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; | 530 | rate = rs->rs_rates[i] & IEEE80211_RATE_VAL; | |
531 | } | 531 | } | |
532 | } | 532 | } | |
533 | rate *= 5; | 533 | rate *= 5; | |
534 | LE_WRITE_2(&sc->sc_mib_mac.aStation_Basic_Rate, rate); | 534 | LE_WRITE_2(&sc->sc_mib_mac.aStation_Basic_Rate, rate); | |
535 | 535 | |||
536 | if ((error = awi_mode_init(sc)) != 0) { | 536 | if ((error = awi_mode_init(sc)) != 0) { | |
537 | DPRINTF(("awi_init: awi_mode_init failed %d\n", error)); | 537 | DPRINTF(("awi_init: awi_mode_init failed %d\n", error)); | |
538 | awi_stop(ifp, 1); | 538 | awi_stop(ifp, 1); | |
539 | return error; | 539 | return error; | |
540 | } | 540 | } | |
541 | 541 | |||
542 | /* Start transmitter */ | 542 | /* Start transmitter */ | |
543 | sc->sc_txdone = sc->sc_txnext = sc->sc_txbase; | 543 | sc->sc_txdone = sc->sc_txnext = sc->sc_txbase; | |
544 | awi_write_4(sc, sc->sc_txbase + AWI_TXD_START, 0); | 544 | awi_write_4(sc, sc->sc_txbase + AWI_TXD_START, 0); | |
545 | awi_write_4(sc, sc->sc_txbase + AWI_TXD_NEXT, 0); | 545 | awi_write_4(sc, sc->sc_txbase + AWI_TXD_NEXT, 0); | |
546 | awi_write_4(sc, sc->sc_txbase + AWI_TXD_LENGTH, 0); | 546 | awi_write_4(sc, sc->sc_txbase + AWI_TXD_LENGTH, 0); | |
547 | awi_write_1(sc, sc->sc_txbase + AWI_TXD_RATE, 0); | 547 | awi_write_1(sc, sc->sc_txbase + AWI_TXD_RATE, 0); | |
548 | awi_write_4(sc, sc->sc_txbase + AWI_TXD_NDA, 0); | 548 | awi_write_4(sc, sc->sc_txbase + AWI_TXD_NDA, 0); | |
549 | awi_write_4(sc, sc->sc_txbase + AWI_TXD_NRA, 0); | 549 | awi_write_4(sc, sc->sc_txbase + AWI_TXD_NRA, 0); | |
550 | awi_write_1(sc, sc->sc_txbase + AWI_TXD_STATE, 0); | 550 | awi_write_1(sc, sc->sc_txbase + AWI_TXD_STATE, 0); | |
551 | awi_write_4(sc, AWI_CA_TX_DATA, sc->sc_txbase); | 551 | awi_write_4(sc, AWI_CA_TX_DATA, sc->sc_txbase); | |
552 | awi_write_4(sc, AWI_CA_TX_MGT, 0); | 552 | awi_write_4(sc, AWI_CA_TX_MGT, 0); | |
553 | awi_write_4(sc, AWI_CA_TX_BCAST, 0); | 553 | awi_write_4(sc, AWI_CA_TX_BCAST, 0); | |
554 | awi_write_4(sc, AWI_CA_TX_PS, 0); | 554 | awi_write_4(sc, AWI_CA_TX_PS, 0); | |
555 | awi_write_4(sc, AWI_CA_TX_CF, 0); | 555 | awi_write_4(sc, AWI_CA_TX_CF, 0); | |
556 | if ((error = awi_cmd(sc, AWI_CMD_INIT_TX, AWI_WAIT)) != 0) { | 556 | if ((error = awi_cmd(sc, AWI_CMD_INIT_TX, AWI_WAIT)) != 0) { | |
557 | DPRINTF(("awi_init: failed to start transmitter: %d\n", error)); | 557 | DPRINTF(("awi_init: failed to start transmitter: %d\n", error)); | |
558 | awi_stop(ifp, 1); | 558 | awi_stop(ifp, 1); | |
559 | return error; | 559 | return error; | |
560 | } | 560 | } | |
561 | 561 | |||
562 | /* Start receiver */ | 562 | /* Start receiver */ | |
563 | if ((error = awi_cmd(sc, AWI_CMD_INIT_RX, AWI_WAIT)) != 0) { | 563 | if ((error = awi_cmd(sc, AWI_CMD_INIT_RX, AWI_WAIT)) != 0) { | |
564 | DPRINTF(("awi_init: failed to start receiver: %d\n", error)); | 564 | DPRINTF(("awi_init: failed to start receiver: %d\n", error)); | |
565 | awi_stop(ifp, 1); | 565 | awi_stop(ifp, 1); | |
566 | return error; | 566 | return error; | |
567 | } | 567 | } | |
568 | sc->sc_rxdoff = awi_read_4(sc, AWI_CA_IRX_DATA_DESC); | 568 | sc->sc_rxdoff = awi_read_4(sc, AWI_CA_IRX_DATA_DESC); | |
569 | sc->sc_rxmoff = awi_read_4(sc, AWI_CA_IRX_PS_DESC); | 569 | sc->sc_rxmoff = awi_read_4(sc, AWI_CA_IRX_PS_DESC); | |
570 | 570 | |||
571 | ifp->if_flags |= IFF_RUNNING; | 571 | ifp->if_flags |= IFF_RUNNING; | |
572 | ifp->if_flags &= ~IFF_OACTIVE; | 572 | ifp->if_flags &= ~IFF_OACTIVE; | |
573 | ic->ic_state = IEEE80211_S_INIT; | 573 | ic->ic_state = IEEE80211_S_INIT; | |
574 | 574 | |||
575 | if (ic->ic_opmode == IEEE80211_M_AHDEMO || | 575 | if (ic->ic_opmode == IEEE80211_M_AHDEMO || | |
576 | ic->ic_opmode == IEEE80211_M_HOSTAP) { | 576 | ic->ic_opmode == IEEE80211_M_HOSTAP) { | |
577 | ni->ni_chan = ic->ic_ibss_chan; | 577 | ni->ni_chan = ic->ic_ibss_chan; | |
578 | ni->ni_intval = ic->ic_lintval; | 578 | ni->ni_intval = ic->ic_lintval; | |
579 | ni->ni_rssi = 0; | 579 | ni->ni_rssi = 0; | |
580 | ni->ni_rstamp = 0; | 580 | ni->ni_rstamp = 0; | |
581 | memset(&ni->ni_tstamp, 0, sizeof(ni->ni_tstamp)); | 581 | memset(&ni->ni_tstamp, 0, sizeof(ni->ni_tstamp)); | |
582 | ni->ni_rates = | 582 | ni->ni_rates = | |
583 | ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; | 583 | ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)]; | |
584 | IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr); | 584 | IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr); | |
585 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) { | 585 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) { | |
586 | IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr); | 586 | IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr); | |
587 | ni->ni_esslen = ic->ic_des_esslen; | 587 | ni->ni_esslen = ic->ic_des_esslen; | |
588 | memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen); | 588 | memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen); | |
589 | ni->ni_capinfo = IEEE80211_CAPINFO_ESS; | 589 | ni->ni_capinfo = IEEE80211_CAPINFO_ESS; | |
590 | if (ic->ic_phytype == IEEE80211_T_FH) { | 590 | if (ic->ic_phytype == IEEE80211_T_FH) { | |
591 | ni->ni_fhdwell = 200; /* XXX */ | 591 | ni->ni_fhdwell = 200; /* XXX */ | |
592 | ni->ni_fhindex = 1; | 592 | ni->ni_fhindex = 1; | |
593 | } | 593 | } | |
594 | } else { | 594 | } else { | |
595 | ni->ni_capinfo = IEEE80211_CAPINFO_IBSS; | 595 | ni->ni_capinfo = IEEE80211_CAPINFO_IBSS; | |
596 | memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN); | 596 | memset(ni->ni_bssid, 0, IEEE80211_ADDR_LEN); | |
597 | ni->ni_esslen = 0; | 597 | ni->ni_esslen = 0; | |
598 | } | 598 | } | |
599 | if (ic->ic_flags & IEEE80211_F_PRIVACY) | 599 | if (ic->ic_flags & IEEE80211_F_PRIVACY) | |
600 | ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; | 600 | ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY; | |
601 | if (ic->ic_opmode != IEEE80211_M_AHDEMO) | 601 | if (ic->ic_opmode != IEEE80211_M_AHDEMO) | |
602 | ic->ic_flags |= IEEE80211_F_SIBSS; | 602 | ic->ic_flags |= IEEE80211_F_SIBSS; | |
603 | ic->ic_state = IEEE80211_S_SCAN; /*XXX*/ | 603 | ic->ic_state = IEEE80211_S_SCAN; /*XXX*/ | |
604 | sc->sc_substate = AWI_ST_NONE; | 604 | sc->sc_substate = AWI_ST_NONE; | |
605 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1); | 605 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1); | |
606 | } else { | 606 | } else { | |
607 | /* XXX check sc->sc_cur_chan */ | 607 | /* XXX check sc->sc_cur_chan */ | |
608 | ni->ni_chan = &ic->ic_channels[sc->sc_cur_chan]; | 608 | ni->ni_chan = &ic->ic_channels[sc->sc_cur_chan]; | |
609 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | 609 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | |
610 | } | 610 | } | |
611 | return 0; | 611 | return 0; | |
612 | } | 612 | } | |
613 | 613 | |||
614 | static void | 614 | static void | |
615 | awi_stop(struct ifnet *ifp, int disable) | 615 | awi_stop(struct ifnet *ifp, int disable) | |
616 | { | 616 | { | |
617 | struct awi_softc *sc = ifp->if_softc; | 617 | struct awi_softc *sc = ifp->if_softc; | |
618 | 618 | |||
619 | if (!sc->sc_enabled) | 619 | if (!sc->sc_enabled) | |
620 | return; | 620 | return; | |
621 | 621 | |||
622 | DPRINTF(("awi_stop(%d)\n", disable)); | 622 | DPRINTF(("awi_stop(%d)\n", disable)); | |
623 | 623 | |||
624 | ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1); | 624 | ieee80211_new_state(&sc->sc_ic, IEEE80211_S_INIT, -1); | |
625 | 625 | |||
626 | if (device_is_active(sc->sc_dev)) { | 626 | if (device_is_active(sc->sc_dev)) { | |
627 | if (sc->sc_cmd_inprog) | 627 | if (sc->sc_cmd_inprog) | |
628 | (void)awi_cmd_wait(sc); | 628 | (void)awi_cmd_wait(sc); | |
629 | (void)awi_cmd(sc, AWI_CMD_KILL_RX, AWI_WAIT); | 629 | (void)awi_cmd(sc, AWI_CMD_KILL_RX, AWI_WAIT); | |
630 | sc->sc_cmd_inprog = AWI_CMD_FLUSH_TX; | 630 | sc->sc_cmd_inprog = AWI_CMD_FLUSH_TX; | |
631 | awi_write_1(sc, AWI_CA_FTX_DATA, 1); | 631 | awi_write_1(sc, AWI_CA_FTX_DATA, 1); | |
632 | awi_write_1(sc, AWI_CA_FTX_MGT, 0); | 632 | awi_write_1(sc, AWI_CA_FTX_MGT, 0); | |
633 | awi_write_1(sc, AWI_CA_FTX_BCAST, 0); | 633 | awi_write_1(sc, AWI_CA_FTX_BCAST, 0); | |
634 | awi_write_1(sc, AWI_CA_FTX_PS, 0); | 634 | awi_write_1(sc, AWI_CA_FTX_PS, 0); | |
635 | awi_write_1(sc, AWI_CA_FTX_CF, 0); | 635 | awi_write_1(sc, AWI_CA_FTX_CF, 0); | |
636 | (void)awi_cmd(sc, AWI_CMD_FLUSH_TX, AWI_WAIT); | 636 | (void)awi_cmd(sc, AWI_CMD_FLUSH_TX, AWI_WAIT); | |
637 | } | 637 | } | |
638 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | 638 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | |
639 | ifp->if_timer = 0; | 639 | ifp->if_timer = 0; | |
640 | sc->sc_tx_timer = sc->sc_rx_timer = 0; | 640 | sc->sc_tx_timer = sc->sc_rx_timer = 0; | |
641 | if (sc->sc_rxpend != NULL) { | 641 | if (sc->sc_rxpend != NULL) { | |
642 | m_freem(sc->sc_rxpend); | 642 | m_freem(sc->sc_rxpend); | |
643 | sc->sc_rxpend = NULL; | 643 | sc->sc_rxpend = NULL; | |
644 | } | 644 | } | |
645 | IFQ_PURGE(&ifp->if_snd); | 645 | IFQ_PURGE(&ifp->if_snd); | |
646 | 646 | |||
647 | if (disable) { | 647 | if (disable) { | |
648 | if (device_is_active(sc->sc_dev)) | 648 | if (device_is_active(sc->sc_dev)) | |
649 | am79c930_gcr_setbits(&sc->sc_chip, | 649 | am79c930_gcr_setbits(&sc->sc_chip, | |
650 | AM79C930_GCR_CORESET); | 650 | AM79C930_GCR_CORESET); | |
651 | if (sc->sc_disable) | 651 | if (sc->sc_disable) | |
652 | (*sc->sc_disable)(sc); | 652 | (*sc->sc_disable)(sc); | |
653 | sc->sc_enabled = 0; | 653 | sc->sc_enabled = 0; | |
654 | } | 654 | } | |
655 | } | 655 | } | |
656 | 656 | |||
657 | static void | 657 | static void | |
658 | awi_start(struct ifnet *ifp) | 658 | awi_start(struct ifnet *ifp) | |
659 | { | 659 | { | |
660 | struct awi_softc *sc = ifp->if_softc; | 660 | struct awi_softc *sc = ifp->if_softc; | |
661 | struct ieee80211com *ic = &sc->sc_ic; | 661 | struct ieee80211com *ic = &sc->sc_ic; | |
662 | struct ether_header *eh; | 662 | struct ether_header *eh; | |
663 | struct ieee80211_node *ni; | 663 | struct ieee80211_node *ni; | |
664 | struct ieee80211_frame *wh; | 664 | struct ieee80211_frame *wh; | |
665 | struct mbuf *m, *m0; | 665 | struct mbuf *m, *m0; | |
666 | int len, dowep; | 666 | int len, dowep; | |
667 | uint32_t txd, frame, ntxd; | 667 | uint32_t txd, frame, ntxd; | |
668 | uint8_t rate; | 668 | uint8_t rate; | |
669 | 669 | |||
670 | if (!sc->sc_enabled || !device_is_active(sc->sc_dev)) | 670 | if (!sc->sc_enabled || !device_is_active(sc->sc_dev)) | |
671 | return; | 671 | return; | |
672 | 672 | |||
673 | for (;;) { | 673 | for (;;) { | |
674 | txd = sc->sc_txnext; | 674 | txd = sc->sc_txnext; | |
675 | IF_POLL(&ic->ic_mgtq, m0); | 675 | IF_POLL(&ic->ic_mgtq, m0); | |
676 | dowep = 0; | 676 | dowep = 0; | |
677 | if (m0 != NULL) { | 677 | if (m0 != NULL) { | |
678 | len = m0->m_pkthdr.len; | 678 | len = m0->m_pkthdr.len; | |
679 | if (awi_next_txd(sc, len, &frame, &ntxd)) { | 679 | if (awi_next_txd(sc, len, &frame, &ntxd)) { | |
680 | ifp->if_flags |= IFF_OACTIVE; | 680 | ifp->if_flags |= IFF_OACTIVE; | |
681 | break; | 681 | break; | |
682 | } | 682 | } | |
683 | IF_DEQUEUE(&ic->ic_mgtq, m0); | 683 | IF_DEQUEUE(&ic->ic_mgtq, m0); | |
684 | ni = M_GETCTX(m0, struct ieee80211_node *); | 684 | ni = M_GETCTX(m0, struct ieee80211_node *); | |
685 | } else { | 685 | } else { | |
686 | if (ic->ic_state != IEEE80211_S_RUN) | 686 | if (ic->ic_state != IEEE80211_S_RUN) | |
687 | break; | 687 | break; | |
688 | IFQ_POLL(&ifp->if_snd, m0); | 688 | IFQ_POLL(&ifp->if_snd, m0); | |
689 | if (m0 == NULL) | 689 | if (m0 == NULL) | |
690 | break; | 690 | break; | |
691 | /* | 691 | /* | |
692 | * Need to calculate the real length to determine | 692 | * Need to calculate the real length to determine | |
693 | * if the transmit buffer has a room for the packet. | 693 | * if the transmit buffer has a room for the packet. | |
694 | */ | 694 | */ | |
695 | len = m0->m_pkthdr.len + sizeof(struct ieee80211_frame); | 695 | len = m0->m_pkthdr.len + sizeof(struct ieee80211_frame); | |
696 | if (!(ifp->if_flags & IFF_LINK0) && !sc->sc_adhoc_ap) | 696 | if (!(ifp->if_flags & IFF_LINK0) && !sc->sc_adhoc_ap) | |
697 | len += sizeof(struct llc) - | 697 | len += sizeof(struct llc) - | |
698 | sizeof(struct ether_header); | 698 | sizeof(struct ether_header); | |
699 | if (ic->ic_flags & IEEE80211_F_PRIVACY) { | 699 | if (ic->ic_flags & IEEE80211_F_PRIVACY) { | |
700 | dowep = 1; | 700 | dowep = 1; | |
701 | len += IEEE80211_WEP_IVLEN + | 701 | len += IEEE80211_WEP_IVLEN + | |
702 | IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; | 702 | IEEE80211_WEP_KIDLEN + IEEE80211_WEP_CRCLEN; | |
703 | } | 703 | } | |
704 | if (awi_next_txd(sc, len, &frame, &ntxd)) { | 704 | if (awi_next_txd(sc, len, &frame, &ntxd)) { | |
705 | ifp->if_flags |= IFF_OACTIVE; | 705 | ifp->if_flags |= IFF_OACTIVE; | |
706 | break; | 706 | break; | |
707 | } | 707 | } | |
708 | IFQ_DEQUEUE(&ifp->if_snd, m0); | 708 | IFQ_DEQUEUE(&ifp->if_snd, m0); | |
709 | ifp->if_opackets++; | 709 | ifp->if_opackets++; | |
710 | bpf_mtap(ifp, m0, BPF_D_OUT); | 710 | bpf_mtap(ifp, m0, BPF_D_OUT); | |
711 | eh = mtod(m0, struct ether_header *); | 711 | eh = mtod(m0, struct ether_header *); | |
712 | ni = ieee80211_find_txnode(ic, eh->ether_dhost); | 712 | ni = ieee80211_find_txnode(ic, eh->ether_dhost); | |
713 | if (ni == NULL) { | 713 | if (ni == NULL) { | |
714 | ifp->if_oerrors++; | 714 | ifp->if_oerrors++; | |
715 | continue; | 715 | continue; | |
716 | } | 716 | } | |
717 | if ((ifp->if_flags & IFF_LINK0) || sc->sc_adhoc_ap) | 717 | if ((ifp->if_flags & IFF_LINK0) || sc->sc_adhoc_ap) | |
718 | m0 = awi_ether_encap(sc, m0); | 718 | m0 = awi_ether_encap(sc, m0); | |
719 | else { | 719 | else { | |
720 | m0 = ieee80211_encap(ic, m0, ni); | 720 | m0 = ieee80211_encap(ic, m0, ni); | |
721 | } | 721 | } | |
722 | if (m0 == NULL) { | 722 | if (m0 == NULL) { | |
723 | ieee80211_free_node(ni); | 723 | ieee80211_free_node(ni); | |
724 | ifp->if_oerrors++; | 724 | ifp->if_oerrors++; | |
725 | continue; | 725 | continue; | |
726 | } | 726 | } | |
727 | wh = mtod(m0, struct ieee80211_frame *); | 727 | wh = mtod(m0, struct ieee80211_frame *); | |
728 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && | 728 | if (!IEEE80211_IS_MULTICAST(wh->i_addr1) && | |
729 | (ic->ic_opmode == IEEE80211_M_HOSTAP || | 729 | (ic->ic_opmode == IEEE80211_M_HOSTAP || | |
730 | ic->ic_opmode == IEEE80211_M_IBSS) && | 730 | ic->ic_opmode == IEEE80211_M_IBSS) && | |
731 | sc->sc_adhoc_ap == 0 && | 731 | sc->sc_adhoc_ap == 0 && | |
732 | (ifp->if_flags & IFF_LINK0) == 0 && | 732 | (ifp->if_flags & IFF_LINK0) == 0 && | |
733 | (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == | 733 | (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == | |
734 | IEEE80211_FC0_TYPE_DATA) { | 734 | IEEE80211_FC0_TYPE_DATA) { | |
735 | m_freem(m0); | 735 | m_freem(m0); | |
736 | ieee80211_free_node(ni); | 736 | ieee80211_free_node(ni); | |
737 | ifp->if_oerrors++; | 737 | ifp->if_oerrors++; | |
738 | continue; | 738 | continue; | |
739 | } | 739 | } | |
740 | } | 740 | } | |
741 | bpf_mtap3(ic->ic_rawbpf, m0, BPF_D_OUT); | 741 | bpf_mtap3(ic->ic_rawbpf, m0, BPF_D_OUT); | |
742 | if (dowep) { | 742 | if (dowep) { | |
743 | if ((ieee80211_crypto_encap(ic, ni, m0)) == NULL) { | 743 | if ((ieee80211_crypto_encap(ic, ni, m0)) == NULL) { | |
744 | m_freem(m0); | 744 | m_freem(m0); | |
745 | ieee80211_free_node(ni); | 745 | ieee80211_free_node(ni); | |
746 | ifp->if_oerrors++; | 746 | ifp->if_oerrors++; | |
747 | continue; | 747 | continue; | |
748 | } | 748 | } | |
749 | } | 749 | } | |
750 | ieee80211_free_node(ni); | 750 | ieee80211_free_node(ni); | |
751 | #ifdef DIAGNOSTIC | 751 | #ifdef DIAGNOSTIC | |
752 | if (m0->m_pkthdr.len != len) { | 752 | if (m0->m_pkthdr.len != len) { | |
753 | printf("%s: length %d should be %d\n", | 753 | printf("%s: length %d should be %d\n", | |
754 | sc->sc_if.if_xname, m0->m_pkthdr.len, len); | 754 | sc->sc_if.if_xname, m0->m_pkthdr.len, len); | |
755 | m_freem(m0); | 755 | m_freem(m0); | |
756 | ifp->if_oerrors++; | 756 | ifp->if_oerrors++; | |
757 | continue; | 757 | continue; | |
758 | } | 758 | } | |
759 | #endif | 759 | #endif | |
760 | 760 | |||
761 | if ((ifp->if_flags & IFF_DEBUG) && (ifp->if_flags & IFF_LINK2)) | 761 | if ((ifp->if_flags & IFF_DEBUG) && (ifp->if_flags & IFF_LINK2)) | |
762 | ieee80211_dump_pkt(m0->m_data, m0->m_len, | 762 | ieee80211_dump_pkt(m0->m_data, m0->m_len, | |
763 | ic->ic_bss->ni_rates. | 763 | ic->ic_bss->ni_rates. | |
764 | rs_rates[ic->ic_bss->ni_txrate] & | 764 | rs_rates[ic->ic_bss->ni_txrate] & | |
765 | IEEE80211_RATE_VAL, -1); | 765 | IEEE80211_RATE_VAL, -1); | |
766 | 766 | |||
767 | for (m = m0, len = 0; m != NULL; m = m->m_next) { | 767 | for (m = m0, len = 0; m != NULL; m = m->m_next) { | |
768 | awi_write_bytes(sc, frame + len, mtod(m, uint8_t *), | 768 | awi_write_bytes(sc, frame + len, mtod(m, uint8_t *), | |
769 | m->m_len); | 769 | m->m_len); | |
770 | len += m->m_len; | 770 | len += m->m_len; | |
771 | } | 771 | } | |
772 | m_freem(m0); | 772 | m_freem(m0); | |
773 | rate = (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] & | 773 | rate = (ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] & | |
774 | IEEE80211_RATE_VAL) * 5; | 774 | IEEE80211_RATE_VAL) * 5; | |
775 | awi_write_1(sc, ntxd + AWI_TXD_STATE, 0); | 775 | awi_write_1(sc, ntxd + AWI_TXD_STATE, 0); | |
776 | awi_write_4(sc, txd + AWI_TXD_START, frame); | 776 | awi_write_4(sc, txd + AWI_TXD_START, frame); | |
777 | awi_write_4(sc, txd + AWI_TXD_NEXT, ntxd); | 777 | awi_write_4(sc, txd + AWI_TXD_NEXT, ntxd); | |
778 | awi_write_4(sc, txd + AWI_TXD_LENGTH, len); | 778 | awi_write_4(sc, txd + AWI_TXD_LENGTH, len); | |
779 | awi_write_1(sc, txd + AWI_TXD_RATE, rate); | 779 | awi_write_1(sc, txd + AWI_TXD_RATE, rate); | |
780 | awi_write_4(sc, txd + AWI_TXD_NDA, 0); | 780 | awi_write_4(sc, txd + AWI_TXD_NDA, 0); | |
781 | awi_write_4(sc, txd + AWI_TXD_NRA, 0); | 781 | awi_write_4(sc, txd + AWI_TXD_NRA, 0); | |
782 | awi_write_1(sc, txd + AWI_TXD_STATE, AWI_TXD_ST_OWN); | 782 | awi_write_1(sc, txd + AWI_TXD_STATE, AWI_TXD_ST_OWN); | |
783 | sc->sc_txnext = ntxd; | 783 | sc->sc_txnext = ntxd; | |
784 | 784 | |||
785 | sc->sc_tx_timer = 5; | 785 | sc->sc_tx_timer = 5; | |
786 | ifp->if_timer = 1; | 786 | ifp->if_timer = 1; | |
787 | } | 787 | } | |
788 | } | 788 | } | |
789 | 789 | |||
790 | static void | 790 | static void | |
791 | awi_watchdog(struct ifnet *ifp) | 791 | awi_watchdog(struct ifnet *ifp) | |
792 | { | 792 | { | |
793 | struct awi_softc *sc = ifp->if_softc; | 793 | struct awi_softc *sc = ifp->if_softc; | |
794 | uint32_t prevdone; | 794 | uint32_t prevdone; | |
795 | int ocansleep; | 795 | int ocansleep; | |
796 | 796 | |||
797 | ifp->if_timer = 0; | 797 | ifp->if_timer = 0; | |
798 | if (!sc->sc_enabled || !device_is_active(sc->sc_dev)) | 798 | if (!sc->sc_enabled || !device_is_active(sc->sc_dev)) | |
799 | return; | 799 | return; | |
800 | 800 | |||
801 | ocansleep = sc->sc_cansleep; | 801 | ocansleep = sc->sc_cansleep; | |
802 | sc->sc_cansleep = 0; | 802 | sc->sc_cansleep = 0; | |
803 | if (sc->sc_tx_timer) { | 803 | if (sc->sc_tx_timer) { | |
804 | if (--sc->sc_tx_timer == 0) { | 804 | if (--sc->sc_tx_timer == 0) { | |
805 | printf("%s: device timeout\n", ifp->if_xname); | 805 | printf("%s: device timeout\n", ifp->if_xname); | |
806 | prevdone = sc->sc_txdone; | 806 | prevdone = sc->sc_txdone; | |
807 | awi_tx_int(sc); | 807 | awi_tx_int(sc); | |
808 | if (sc->sc_txdone == prevdone) { | 808 | if (sc->sc_txdone == prevdone) { | |
809 | ifp->if_oerrors++; | 809 | ifp->if_oerrors++; | |
810 | awi_init(ifp); | 810 | awi_init(ifp); | |
811 | goto out; | 811 | goto out; | |
812 | } | 812 | } | |
813 | } | 813 | } | |
814 | ifp->if_timer = 1; | 814 | ifp->if_timer = 1; | |
815 | } | 815 | } | |
816 | if (sc->sc_rx_timer) { | 816 | if (sc->sc_rx_timer) { | |
817 | if (--sc->sc_rx_timer == 0) { | 817 | if (--sc->sc_rx_timer == 0) { | |
818 | if (sc->sc_ic.ic_state == IEEE80211_S_RUN) { | 818 | if (sc->sc_ic.ic_state == IEEE80211_S_RUN) { | |
819 | ieee80211_new_state(&sc->sc_ic, | 819 | ieee80211_new_state(&sc->sc_ic, | |
820 | IEEE80211_S_SCAN, -1); | 820 | IEEE80211_S_SCAN, -1); | |
821 | goto out; | 821 | goto out; | |
822 | } | 822 | } | |
823 | } else | 823 | } else | |
824 | ifp->if_timer = 1; | 824 | ifp->if_timer = 1; | |
825 | } | 825 | } | |
826 | /* TODO: rate control */ | 826 | /* TODO: rate control */ | |
827 | ieee80211_watchdog(&sc->sc_ic); | 827 | ieee80211_watchdog(&sc->sc_ic); | |
828 | out: | 828 | out: | |
829 | sc->sc_cansleep = ocansleep; | 829 | sc->sc_cansleep = ocansleep; | |
830 | } | 830 | } | |
831 | 831 | |||
832 | static int | 832 | static int | |
833 | awi_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 833 | awi_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
834 | { | 834 | { | |
835 | struct awi_softc *sc = ifp->if_softc; | 835 | struct awi_softc *sc = ifp->if_softc; | |
836 | struct ifreq *ifr = (struct ifreq *)data; | |||
837 | int s, error; | 836 | int s, error; | |
838 | 837 | |||
839 | s = splnet(); | 838 | s = splnet(); | |
840 | /* Serialize ioctl, since we may sleep */ | 839 | /* Serialize ioctl, since we may sleep */ | |
841 | if ((error = awi_lock(sc)) != 0) | 840 | if ((error = awi_lock(sc)) != 0) | |
842 | goto cantlock; | 841 | goto cantlock; | |
843 | 842 | |||
844 | switch (cmd) { | 843 | switch (cmd) { | |
845 | case SIOCSIFFLAGS: | 844 | case SIOCSIFFLAGS: | |
846 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | 845 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | |
847 | break; | 846 | break; | |
848 | if (ifp->if_flags & IFF_UP) { | 847 | if (ifp->if_flags & IFF_UP) { | |
849 | if (sc->sc_enabled) { | 848 | if (sc->sc_enabled) { | |
850 | /* | 849 | /* | |
851 | * To avoid rescanning another access point, | 850 | * To avoid rescanning another access point, | |
852 | * do not call awi_init() here. Instead, | 851 | * do not call awi_init() here. Instead, | |
853 | * only reflect promisc mode settings. | 852 | * only reflect promisc mode settings. | |
854 | */ | 853 | */ | |
855 | error = awi_mode_init(sc); | 854 | error = awi_mode_init(sc); | |
856 | } else | 855 | } else | |
857 | error = awi_init(ifp); | 856 | error = awi_init(ifp); | |
858 | } else if (sc->sc_enabled) | 857 | } else if (sc->sc_enabled) | |
859 | awi_stop(ifp, 1); | 858 | awi_stop(ifp, 1); | |
860 | break; | 859 | break; | |
861 | case SIOCSIFMEDIA: | |||
862 | case SIOCGIFMEDIA: | |||
863 | error = ifmedia_ioctl(ifp, ifr, &sc->sc_ic.ic_media, cmd); | |||
864 | break; | |||
865 | case SIOCADDMULTI: | 860 | case SIOCADDMULTI: | |
866 | case SIOCDELMULTI: | 861 | case SIOCDELMULTI: | |
867 | error = ether_ioctl(ifp, cmd, data); | 862 | error = ether_ioctl(ifp, cmd, data); | |
868 | if (error == ENETRESET) { | 863 | if (error == ENETRESET) { | |
869 | /* Do not rescan */ | 864 | /* Do not rescan */ | |
870 | if (ifp->if_flags & IFF_RUNNING) | 865 | if (ifp->if_flags & IFF_RUNNING) | |
871 | error = awi_mode_init(sc); | 866 | error = awi_mode_init(sc); | |
872 | else | 867 | else | |
873 | error = 0; | 868 | error = 0; | |
874 | } | 869 | } | |
875 | break; | 870 | break; | |
876 | default: | 871 | default: | |
877 | error = ieee80211_ioctl(&sc->sc_ic, cmd, data); | 872 | error = ieee80211_ioctl(&sc->sc_ic, cmd, data); | |
878 | if (error == ENETRESET) { | 873 | if (error == ENETRESET) { | |
879 | if (sc->sc_enabled) | 874 | if (sc->sc_enabled) | |
880 | error = awi_init(ifp); | 875 | error = awi_init(ifp); | |
881 | else | 876 | else | |
882 | error = 0; | 877 | error = 0; | |
883 | } | 878 | } | |
884 | break; | 879 | break; | |
885 | } | 880 | } | |
886 | awi_unlock(sc); | 881 | awi_unlock(sc); | |
887 | cantlock: | 882 | cantlock: | |
888 | splx(s); | 883 | splx(s); | |
889 | return error; | 884 | return error; | |
890 | } | 885 | } | |
891 | 886 | |||
892 | /* | 887 | /* | |
893 | * Called from ifmedia_ioctl via awi_ioctl with lock obtained. | 888 | * Called from ifmedia_ioctl via awi_ioctl with lock obtained. | |
894 | * | 889 | * | |
895 | * TBD factor with ieee80211_media_change | 890 | * TBD factor with ieee80211_media_change | |
896 | */ | 891 | */ | |
897 | static int | 892 | static int | |
898 | awi_media_change(struct ifnet *ifp) | 893 | awi_media_change(struct ifnet *ifp) | |
899 | { | 894 | { | |
900 | struct awi_softc *sc = ifp->if_softc; | 895 | struct awi_softc *sc = ifp->if_softc; | |
901 | struct ieee80211com *ic = &sc->sc_ic; | 896 | struct ieee80211com *ic = &sc->sc_ic; | |
902 | struct ifmedia_entry *ime; | 897 | struct ifmedia_entry *ime; | |
903 | enum ieee80211_opmode newmode; | 898 | enum ieee80211_opmode newmode; | |
904 | int i, rate, newadhoc_ap, error = 0; | 899 | int i, rate, newadhoc_ap, error = 0; | |
905 | 900 | |||
906 | ime = ic->ic_media.ifm_cur; | 901 | ime = ic->ic_media.ifm_cur; | |
907 | if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) { | 902 | if (IFM_SUBTYPE(ime->ifm_media) == IFM_AUTO) { | |
908 | i = -1; | 903 | i = -1; | |
909 | } else { | 904 | } else { | |
910 | struct ieee80211_rateset *rs = | 905 | struct ieee80211_rateset *rs = | |
911 | &ic->ic_sup_rates[(ic->ic_phytype == IEEE80211_T_FH) | 906 | &ic->ic_sup_rates[(ic->ic_phytype == IEEE80211_T_FH) | |
912 | ? IEEE80211_MODE_FH : IEEE80211_MODE_11B]; | 907 | ? IEEE80211_MODE_FH : IEEE80211_MODE_11B]; | |
913 | rate = ieee80211_media2rate(ime->ifm_media); | 908 | rate = ieee80211_media2rate(ime->ifm_media); | |
914 | if (rate == 0) | 909 | if (rate == 0) | |
915 | return EINVAL; | 910 | return EINVAL; | |
916 | for (i = 0; i < rs->rs_nrates; i++) { | 911 | for (i = 0; i < rs->rs_nrates; i++) { | |
917 | if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate) | 912 | if ((rs->rs_rates[i] & IEEE80211_RATE_VAL) == rate) | |
918 | break; | 913 | break; | |
919 | } | 914 | } | |
920 | if (i == rs->rs_nrates) | 915 | if (i == rs->rs_nrates) | |
921 | return EINVAL; | 916 | return EINVAL; | |
922 | } | 917 | } | |
923 | if (ic->ic_fixed_rate != i) { | 918 | if (ic->ic_fixed_rate != i) { | |
924 | ic->ic_fixed_rate = i; | 919 | ic->ic_fixed_rate = i; | |
925 | error = ENETRESET; | 920 | error = ENETRESET; | |
926 | } | 921 | } | |
927 | 922 | |||
928 | /* | 923 | /* | |
929 | * Combination of mediaopt | 924 | * Combination of mediaopt | |
930 | * | 925 | * | |
931 | * hostap adhoc flag0 opmode adhoc_ap comment | 926 | * hostap adhoc flag0 opmode adhoc_ap comment | |
932 | * + - - HOSTAP 0 HostAP | 927 | * + - - HOSTAP 0 HostAP | |
933 | * - + - IBSS 0 IBSS | 928 | * - + - IBSS 0 IBSS | |
934 | * - + + AHDEMO 0 WaveLAN adhoc | 929 | * - + + AHDEMO 0 WaveLAN adhoc | |
935 | * - - + IBSS 1 Melco old Sta | 930 | * - - + IBSS 1 Melco old Sta | |
936 | * also LINK0 | 931 | * also LINK0 | |
937 | * - - - STA 0 Infra Station | 932 | * - - - STA 0 Infra Station | |
938 | */ | 933 | */ | |
939 | newadhoc_ap = 0; | 934 | newadhoc_ap = 0; | |
940 | if (ime->ifm_media & IFM_IEEE80211_HOSTAP) | 935 | if (ime->ifm_media & IFM_IEEE80211_HOSTAP) | |
941 | newmode = IEEE80211_M_HOSTAP; | 936 | newmode = IEEE80211_M_HOSTAP; | |
942 | else if (ime->ifm_media & IFM_IEEE80211_ADHOC) { | 937 | else if (ime->ifm_media & IFM_IEEE80211_ADHOC) { | |
943 | if (ic->ic_phytype == IEEE80211_T_DS && | 938 | if (ic->ic_phytype == IEEE80211_T_DS && | |
944 | (ime->ifm_media & IFM_FLAG0)) | 939 | (ime->ifm_media & IFM_FLAG0)) | |
945 | newmode = IEEE80211_M_AHDEMO; | 940 | newmode = IEEE80211_M_AHDEMO; | |
946 | else | 941 | else | |
947 | newmode = IEEE80211_M_IBSS; | 942 | newmode = IEEE80211_M_IBSS; | |
948 | } else if (ime->ifm_media & IFM_FLAG0) { | 943 | } else if (ime->ifm_media & IFM_FLAG0) { | |
949 | newmode = IEEE80211_M_IBSS; | 944 | newmode = IEEE80211_M_IBSS; | |
950 | newadhoc_ap = 1; | 945 | newadhoc_ap = 1; | |
951 | } else | 946 | } else | |
952 | newmode = IEEE80211_M_STA; | 947 | newmode = IEEE80211_M_STA; | |
953 | if (ic->ic_opmode != newmode || sc->sc_adhoc_ap != newadhoc_ap) { | 948 | if (ic->ic_opmode != newmode || sc->sc_adhoc_ap != newadhoc_ap) { | |
954 | ic->ic_opmode = newmode; | 949 | ic->ic_opmode = newmode; | |
955 | sc->sc_adhoc_ap = newadhoc_ap; | 950 | sc->sc_adhoc_ap = newadhoc_ap; | |
956 | error = ENETRESET; | 951 | error = ENETRESET; | |
957 | } | 952 | } | |
958 | 953 | |||
959 | if (error == ENETRESET) { | 954 | if (error == ENETRESET) { | |
960 | if (sc->sc_enabled) | 955 | if (sc->sc_enabled) | |
961 | error = awi_init(ifp); | 956 | error = awi_init(ifp); | |
962 | else | 957 | else | |
963 | error = 0; | 958 | error = 0; | |
964 | } | 959 | } | |
965 | return error; | 960 | return error; | |
966 | } | 961 | } | |
967 | 962 | |||
968 | static void | 963 | static void | |
969 | awi_media_status(struct ifnet *ifp, struct ifmediareq *imr) | 964 | awi_media_status(struct ifnet *ifp, struct ifmediareq *imr) | |
970 | { | 965 | { | |
971 | struct awi_softc *sc = ifp->if_softc; | 966 | struct awi_softc *sc = ifp->if_softc; | |
972 | struct ieee80211com *ic = &sc->sc_ic; | 967 | struct ieee80211com *ic = &sc->sc_ic; | |
973 | int rate; | 968 | int rate; | |
974 | enum ieee80211_phymode mode; | 969 | enum ieee80211_phymode mode; | |
975 | 970 | |||
976 | imr->ifm_status = IFM_AVALID; | 971 | imr->ifm_status = IFM_AVALID; | |
977 | if (ic->ic_state == IEEE80211_S_RUN) | 972 | if (ic->ic_state == IEEE80211_S_RUN) | |
978 | imr->ifm_status |= IFM_ACTIVE; | 973 | imr->ifm_status |= IFM_ACTIVE; | |
979 | imr->ifm_active = IFM_IEEE80211; | 974 | imr->ifm_active = IFM_IEEE80211; | |
980 | if (ic->ic_phytype == IEEE80211_T_FH) | 975 | if (ic->ic_phytype == IEEE80211_T_FH) | |
981 | mode = IEEE80211_MODE_FH; | 976 | mode = IEEE80211_MODE_FH; | |
982 | else | 977 | else | |
983 | mode = IEEE80211_MODE_11B; | 978 | mode = IEEE80211_MODE_11B; | |
984 | if (ic->ic_state == IEEE80211_S_RUN) { | 979 | if (ic->ic_state == IEEE80211_S_RUN) { | |
985 | rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] & | 980 | rate = ic->ic_bss->ni_rates.rs_rates[ic->ic_bss->ni_txrate] & | |
986 | IEEE80211_RATE_VAL; | 981 | IEEE80211_RATE_VAL; | |
987 | } else { | 982 | } else { | |
988 | if (ic->ic_fixed_rate == -1) | 983 | if (ic->ic_fixed_rate == -1) | |
989 | rate = 0; | 984 | rate = 0; | |
990 | else | 985 | else | |
991 | rate = ic->ic_sup_rates[mode]. | 986 | rate = ic->ic_sup_rates[mode]. | |
992 | rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; | 987 | rs_rates[ic->ic_fixed_rate] & IEEE80211_RATE_VAL; | |
993 | } | 988 | } | |
994 | imr->ifm_active |= ieee80211_rate2media(ic, rate, mode); | 989 | imr->ifm_active |= ieee80211_rate2media(ic, rate, mode); | |
995 | switch (ic->ic_opmode) { | 990 | switch (ic->ic_opmode) { | |
996 | case IEEE80211_M_MONITOR: /* We should never reach here */ | 991 | case IEEE80211_M_MONITOR: /* We should never reach here */ | |
997 | break; | 992 | break; | |
998 | case IEEE80211_M_STA: | 993 | case IEEE80211_M_STA: | |
999 | break; | 994 | break; | |
1000 | case IEEE80211_M_IBSS: | 995 | case IEEE80211_M_IBSS: | |
1001 | if (sc->sc_adhoc_ap) | 996 | if (sc->sc_adhoc_ap) | |
1002 | imr->ifm_active |= IFM_FLAG0; | 997 | imr->ifm_active |= IFM_FLAG0; | |
1003 | else | 998 | else | |
1004 | imr->ifm_active |= IFM_IEEE80211_ADHOC; | 999 | imr->ifm_active |= IFM_IEEE80211_ADHOC; | |
1005 | break; | 1000 | break; | |
1006 | case IEEE80211_M_AHDEMO: | 1001 | case IEEE80211_M_AHDEMO: | |
1007 | imr->ifm_active |= IFM_IEEE80211_ADHOC | IFM_FLAG0; | 1002 | imr->ifm_active |= IFM_IEEE80211_ADHOC | IFM_FLAG0; | |
1008 | break; | 1003 | break; | |
1009 | case IEEE80211_M_HOSTAP: | 1004 | case IEEE80211_M_HOSTAP: | |
1010 | imr->ifm_active |= IFM_IEEE80211_HOSTAP; | 1005 | imr->ifm_active |= IFM_IEEE80211_HOSTAP; | |
1011 | break; | 1006 | break; | |
1012 | } | 1007 | } | |
1013 | } | 1008 | } | |
1014 | 1009 | |||
1015 | static int | 1010 | static int | |
1016 | awi_mode_init(struct awi_softc *sc) | 1011 | awi_mode_init(struct awi_softc *sc) | |
1017 | { | 1012 | { | |
1018 | struct ethercom *ec = &sc->sc_ec; | 1013 | struct ethercom *ec = &sc->sc_ec; | |
1019 | struct ifnet *ifp = &sc->sc_if; | 1014 | struct ifnet *ifp = &sc->sc_if; | |
1020 | int n, error; | 1015 | int n, error; | |
1021 | struct ether_multi *enm; | 1016 | struct ether_multi *enm; | |
1022 | struct ether_multistep step; | 1017 | struct ether_multistep step; | |
1023 | 1018 | |||
1024 | /* Reinitialize muticast filter */ | 1019 | /* Reinitialize muticast filter */ | |
1025 | n = 0; | 1020 | n = 0; | |
1026 | sc->sc_mib_local.Accept_All_Multicast_Dis = 0; | 1021 | sc->sc_mib_local.Accept_All_Multicast_Dis = 0; | |
1027 | if (sc->sc_ic.ic_opmode != IEEE80211_M_HOSTAP && | 1022 | if (sc->sc_ic.ic_opmode != IEEE80211_M_HOSTAP && | |
1028 | (ifp->if_flags & IFF_PROMISC)) { | 1023 | (ifp->if_flags & IFF_PROMISC)) { | |
1029 | sc->sc_mib_mac.aPromiscuous_Enable = 1; | 1024 | sc->sc_mib_mac.aPromiscuous_Enable = 1; | |
1030 | goto set_mib; | 1025 | goto set_mib; | |
1031 | } | 1026 | } | |
1032 | sc->sc_mib_mac.aPromiscuous_Enable = 0; | 1027 | sc->sc_mib_mac.aPromiscuous_Enable = 0; | |
1033 | ETHER_LOCK(ec); | 1028 | ETHER_LOCK(ec); | |
1034 | ETHER_FIRST_MULTI(step, ec, enm); | 1029 | ETHER_FIRST_MULTI(step, ec, enm); | |
1035 | while (enm != NULL) { | 1030 | while (enm != NULL) { | |
1036 | if (n == AWI_GROUP_ADDR_SIZE || | 1031 | if (n == AWI_GROUP_ADDR_SIZE || | |
1037 | !IEEE80211_ADDR_EQ(enm->enm_addrlo, enm->enm_addrhi)) { | 1032 | !IEEE80211_ADDR_EQ(enm->enm_addrlo, enm->enm_addrhi)) { | |
1038 | ETHER_UNLOCK(ec); | 1033 | ETHER_UNLOCK(ec); | |
1039 | goto set_mib; | 1034 | goto set_mib; | |
1040 | } | 1035 | } | |
1041 | IEEE80211_ADDR_COPY(sc->sc_mib_addr.aGroup_Addresses[n], | 1036 | IEEE80211_ADDR_COPY(sc->sc_mib_addr.aGroup_Addresses[n], | |
1042 | enm->enm_addrlo); | 1037 | enm->enm_addrlo); | |
1043 | n++; | 1038 | n++; | |
1044 | ETHER_NEXT_MULTI(step, enm); | 1039 | ETHER_NEXT_MULTI(step, enm); | |
1045 | } | 1040 | } | |
1046 | ETHER_UNLOCK(ec); | 1041 | ETHER_UNLOCK(ec); | |
1047 | for (; n < AWI_GROUP_ADDR_SIZE; n++) | 1042 | for (; n < AWI_GROUP_ADDR_SIZE; n++) | |
1048 | memset(sc->sc_mib_addr.aGroup_Addresses[n], 0, | 1043 | memset(sc->sc_mib_addr.aGroup_Addresses[n], 0, | |
1049 | IEEE80211_ADDR_LEN); | 1044 | IEEE80211_ADDR_LEN); | |
1050 | sc->sc_mib_local.Accept_All_Multicast_Dis = 1; | 1045 | sc->sc_mib_local.Accept_All_Multicast_Dis = 1; | |
1051 | 1046 | |||
1052 | set_mib: | 1047 | set_mib: | |
1053 | if (sc->sc_mib_local.Accept_All_Multicast_Dis) | 1048 | if (sc->sc_mib_local.Accept_All_Multicast_Dis) | |
1054 | ifp->if_flags &= ~IFF_ALLMULTI; | 1049 | ifp->if_flags &= ~IFF_ALLMULTI; | |
1055 | else | 1050 | else | |
1056 | ifp->if_flags |= IFF_ALLMULTI; | 1051 | ifp->if_flags |= IFF_ALLMULTI; | |
1057 | sc->sc_mib_mgt.Wep_Required = | 1052 | sc->sc_mib_mgt.Wep_Required = | |
1058 | (sc->sc_ic.ic_flags & IEEE80211_F_PRIVACY) ? AWI_WEP_ON : AWI_WEP_OFF; | 1053 | (sc->sc_ic.ic_flags & IEEE80211_F_PRIVACY) ? AWI_WEP_ON : AWI_WEP_OFF; | |
1059 | 1054 | |||
1060 | if ((error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_LOCAL, AWI_WAIT)) || | 1055 | if ((error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_LOCAL, AWI_WAIT)) || | |
1061 | (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_ADDR, AWI_WAIT)) || | 1056 | (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_ADDR, AWI_WAIT)) || | |
1062 | (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MAC, AWI_WAIT)) || | 1057 | (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MAC, AWI_WAIT)) || | |
1063 | (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT, AWI_WAIT)) || | 1058 | (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_MGT, AWI_WAIT)) || | |
1064 | (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_PHY, AWI_WAIT))) { | 1059 | (error = awi_mib(sc, AWI_CMD_SET_MIB, AWI_MIB_PHY, AWI_WAIT))) { | |
1065 | DPRINTF(("awi_mode_init: MIB set failed: %d\n", error)); | 1060 | DPRINTF(("awi_mode_init: MIB set failed: %d\n", error)); | |
1066 | return error; | 1061 | return error; | |
1067 | } | 1062 | } | |
1068 | return 0; | 1063 | return 0; | |
1069 | } | 1064 | } | |
1070 | 1065 | |||
1071 | static void | 1066 | static void | |
1072 | awi_rx_int(struct awi_softc *sc) | 1067 | awi_rx_int(struct awi_softc *sc) | |
1073 | { | 1068 | { | |
1074 | struct ieee80211com *ic = &sc->sc_ic; | 1069 | struct ieee80211com *ic = &sc->sc_ic; | |
1075 | struct ifnet *ifp = &sc->sc_if; | 1070 | struct ifnet *ifp = &sc->sc_if; | |
1076 | struct ieee80211_frame_min *wh; | 1071 | struct ieee80211_frame_min *wh; | |
1077 | struct ieee80211_node *ni; | 1072 | struct ieee80211_node *ni; | |
1078 | uint8_t state, rate, rssi; | 1073 | uint8_t state, rate, rssi; | |
1079 | uint16_t len; | 1074 | uint16_t len; | |
1080 | uint32_t frame, next, rstamp, rxoff; | 1075 | uint32_t frame, next, rstamp, rxoff; | |
1081 | struct mbuf *m; | 1076 | struct mbuf *m; | |
1082 | 1077 | |||
1083 | rxoff = sc->sc_rxdoff; | 1078 | rxoff = sc->sc_rxdoff; | |
1084 | for (;;) { | 1079 | for (;;) { | |
1085 | state = awi_read_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE); | 1080 | state = awi_read_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE); | |
1086 | if (state & AWI_RXD_ST_OWN) | 1081 | if (state & AWI_RXD_ST_OWN) | |
1087 | break; | 1082 | break; | |
1088 | if (!(state & AWI_RXD_ST_CONSUMED)) { | 1083 | if (!(state & AWI_RXD_ST_CONSUMED)) { | |
1089 | if (sc->sc_substate != AWI_ST_NONE) | 1084 | if (sc->sc_substate != AWI_ST_NONE) | |
1090 | goto rx_next; | 1085 | goto rx_next; | |
1091 | if (state & AWI_RXD_ST_RXERROR) { | 1086 | if (state & AWI_RXD_ST_RXERROR) { | |
1092 | ifp->if_ierrors++; | 1087 | ifp->if_ierrors++; | |
1093 | goto rx_next; | 1088 | goto rx_next; | |
1094 | } | 1089 | } | |
1095 | len = awi_read_2(sc, rxoff + AWI_RXD_LEN); | 1090 | len = awi_read_2(sc, rxoff + AWI_RXD_LEN); | |
1096 | rate = awi_read_1(sc, rxoff + AWI_RXD_RATE); | 1091 | rate = awi_read_1(sc, rxoff + AWI_RXD_RATE); | |
1097 | rssi = awi_read_1(sc, rxoff + AWI_RXD_RSSI); | 1092 | rssi = awi_read_1(sc, rxoff + AWI_RXD_RSSI); | |
1098 | frame = awi_read_4(sc, rxoff + AWI_RXD_START_FRAME) & | 1093 | frame = awi_read_4(sc, rxoff + AWI_RXD_START_FRAME) & | |
1099 | 0x7fff; | 1094 | 0x7fff; | |
1100 | rstamp = awi_read_4(sc, rxoff + AWI_RXD_LOCALTIME); | 1095 | rstamp = awi_read_4(sc, rxoff + AWI_RXD_LOCALTIME); | |
1101 | m = awi_devget(sc, frame, len); | 1096 | m = awi_devget(sc, frame, len); | |
1102 | if (m == NULL) { | 1097 | if (m == NULL) { | |
1103 | ifp->if_ierrors++; | 1098 | ifp->if_ierrors++; | |
1104 | goto rx_next; | 1099 | goto rx_next; | |
1105 | } | 1100 | } | |
1106 | if (state & AWI_RXD_ST_LF) { | 1101 | if (state & AWI_RXD_ST_LF) { | |
1107 | /* TODO check my bss */ | 1102 | /* TODO check my bss */ | |
1108 | if (!(sc->sc_ic.ic_flags & IEEE80211_F_SIBSS) && | 1103 | if (!(sc->sc_ic.ic_flags & IEEE80211_F_SIBSS) && | |
1109 | sc->sc_ic.ic_state == IEEE80211_S_RUN) { | 1104 | sc->sc_ic.ic_state == IEEE80211_S_RUN) { | |
1110 | sc->sc_rx_timer = 10; | 1105 | sc->sc_rx_timer = 10; | |
1111 | ifp->if_timer = 1; | 1106 | ifp->if_timer = 1; | |
1112 | } | 1107 | } | |
1113 | if ((ifp->if_flags & IFF_DEBUG) && | 1108 | if ((ifp->if_flags & IFF_DEBUG) && | |
1114 | (ifp->if_flags & IFF_LINK2)) | 1109 | (ifp->if_flags & IFF_LINK2)) | |
1115 | ieee80211_dump_pkt(m->m_data, m->m_len, | 1110 | ieee80211_dump_pkt(m->m_data, m->m_len, | |
1116 | rate / 5, rssi); | 1111 | rate / 5, rssi); | |
1117 | if ((ifp->if_flags & IFF_LINK0) || | 1112 | if ((ifp->if_flags & IFF_LINK0) || | |
1118 | sc->sc_adhoc_ap) | 1113 | sc->sc_adhoc_ap) | |
1119 | m = awi_ether_modcap(sc, m); | 1114 | m = awi_ether_modcap(sc, m); | |
1120 | else | 1115 | else | |
1121 | m = m_pullup(m, sizeof(*wh)); | 1116 | m = m_pullup(m, sizeof(*wh)); | |
1122 | if (m == NULL) { | 1117 | if (m == NULL) { | |
1123 | ifp->if_ierrors++; | 1118 | ifp->if_ierrors++; | |
1124 | goto rx_next; | 1119 | goto rx_next; | |
1125 | } | 1120 | } | |
1126 | wh = mtod(m, struct ieee80211_frame_min *); | 1121 | wh = mtod(m, struct ieee80211_frame_min *); | |
1127 | ni = ieee80211_find_rxnode(ic, wh); | 1122 | ni = ieee80211_find_rxnode(ic, wh); | |
1128 | ieee80211_input(ic, m, ni, rssi, rstamp); | 1123 | ieee80211_input(ic, m, ni, rssi, rstamp); | |
1129 | /* | 1124 | /* | |
1130 | * The frame may have caused the | 1125 | * The frame may have caused the | |
1131 | * node to be marked for reclamation | 1126 | * node to be marked for reclamation | |
1132 | * (e.g. in response to a DEAUTH | 1127 | * (e.g. in response to a DEAUTH | |
1133 | * message) so use release_node here | 1128 | * message) so use release_node here | |
1134 | * instead of unref_node. | 1129 | * instead of unref_node. | |
1135 | */ | 1130 | */ | |
1136 | ieee80211_free_node(ni); | 1131 | ieee80211_free_node(ni); | |
1137 | } else | 1132 | } else | |
1138 | sc->sc_rxpend = m; | 1133 | sc->sc_rxpend = m; | |
1139 | rx_next: | 1134 | rx_next: | |
1140 | state |= AWI_RXD_ST_CONSUMED; | 1135 | state |= AWI_RXD_ST_CONSUMED; | |
1141 | awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state); | 1136 | awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state); | |
1142 | } | 1137 | } | |
1143 | next = awi_read_4(sc, rxoff + AWI_RXD_NEXT); | 1138 | next = awi_read_4(sc, rxoff + AWI_RXD_NEXT); | |
1144 | if (next & AWI_RXD_NEXT_LAST) | 1139 | if (next & AWI_RXD_NEXT_LAST) | |
1145 | break; | 1140 | break; | |
1146 | /* Make sure the next pointer is correct */ | 1141 | /* Make sure the next pointer is correct */ | |
1147 | if (next != awi_read_4(sc, rxoff + AWI_RXD_NEXT)) | 1142 | if (next != awi_read_4(sc, rxoff + AWI_RXD_NEXT)) | |
1148 | break; | 1143 | break; | |
1149 | state |= AWI_RXD_ST_OWN; | 1144 | state |= AWI_RXD_ST_OWN; | |
1150 | awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state); | 1145 | awi_write_1(sc, rxoff + AWI_RXD_HOST_DESC_STATE, state); | |
1151 | rxoff = next & 0x7fff; | 1146 | rxoff = next & 0x7fff; | |
1152 | } | 1147 | } | |
1153 | sc->sc_rxdoff = rxoff; | 1148 | sc->sc_rxdoff = rxoff; | |
1154 | } | 1149 | } | |
1155 | 1150 | |||
1156 | static void | 1151 | static void | |
1157 | awi_tx_int(struct awi_softc *sc) | 1152 | awi_tx_int(struct awi_softc *sc) | |
1158 | { | 1153 | { | |
1159 | struct ifnet *ifp = &sc->sc_if; | 1154 | struct ifnet *ifp = &sc->sc_if; | |
1160 | uint8_t flags; | 1155 | uint8_t flags; | |
1161 | 1156 | |||
1162 | while (sc->sc_txdone != sc->sc_txnext) { | 1157 | while (sc->sc_txdone != sc->sc_txnext) { | |
1163 | flags = awi_read_1(sc, sc->sc_txdone + AWI_TXD_STATE); | 1158 | flags = awi_read_1(sc, sc->sc_txdone + AWI_TXD_STATE); | |
1164 | if ((flags & AWI_TXD_ST_OWN) || !(flags & AWI_TXD_ST_DONE)) | 1159 | if ((flags & AWI_TXD_ST_OWN) || !(flags & AWI_TXD_ST_DONE)) | |
1165 | break; | 1160 | break; | |
1166 | if (flags & AWI_TXD_ST_ERROR) | 1161 | if (flags & AWI_TXD_ST_ERROR) | |
1167 | ifp->if_oerrors++; | 1162 | ifp->if_oerrors++; | |
1168 | sc->sc_txdone = awi_read_4(sc, sc->sc_txdone + AWI_TXD_NEXT) & | 1163 | sc->sc_txdone = awi_read_4(sc, sc->sc_txdone + AWI_TXD_NEXT) & | |
1169 | 0x7fff; | 1164 | 0x7fff; | |
1170 | } | 1165 | } | |
1171 | DPRINTF2(("awi_txint: txdone %d txnext %d txbase %d txend %d\n", | 1166 | DPRINTF2(("awi_txint: txdone %d txnext %d txbase %d txend %d\n", | |
1172 | sc->sc_txdone, sc->sc_txnext, sc->sc_txbase, sc->sc_txend)); | 1167 | sc->sc_txdone, sc->sc_txnext, sc->sc_txbase, sc->sc_txend)); | |
1173 | sc->sc_tx_timer = 0; | 1168 | sc->sc_tx_timer = 0; | |
1174 | ifp->if_flags &= ~IFF_OACTIVE; | 1169 | ifp->if_flags &= ~IFF_OACTIVE; | |
1175 | awi_start(ifp); /* in softint */ | 1170 | awi_start(ifp); /* in softint */ | |
1176 | } | 1171 | } | |
1177 | 1172 | |||
1178 | static struct mbuf * | 1173 | static struct mbuf * | |
1179 | awi_devget(struct awi_softc *sc, uint32_t off, uint16_t len) | 1174 | awi_devget(struct awi_softc *sc, uint32_t off, uint16_t len) | |
1180 | { | 1175 | { | |
1181 | struct ifnet *ifp = &sc->sc_if; | 1176 | struct ifnet *ifp = &sc->sc_if; | |
1182 | struct mbuf *m; | 1177 | struct mbuf *m; | |
1183 | struct mbuf *top, **mp; | 1178 | struct mbuf *top, **mp; | |
1184 | u_int tlen; | 1179 | u_int tlen; | |
1185 | 1180 | |||
1186 | top = sc->sc_rxpend; | 1181 | top = sc->sc_rxpend; | |
1187 | mp = ⊤ | 1182 | mp = ⊤ | |
1188 | if (top != NULL) { | 1183 | if (top != NULL) { | |
1189 | sc->sc_rxpend = NULL; | 1184 | sc->sc_rxpend = NULL; | |
1190 | top->m_pkthdr.len += len; | 1185 | top->m_pkthdr.len += len; | |
1191 | m = top; | 1186 | m = top; | |
1192 | while (*mp != NULL) { | 1187 | while (*mp != NULL) { | |
1193 | m = *mp; | 1188 | m = *mp; | |
1194 | mp = &m->m_next; | 1189 | mp = &m->m_next; | |
1195 | } | 1190 | } | |
1196 | if (m->m_flags & M_EXT) | 1191 | if (m->m_flags & M_EXT) | |
1197 | tlen = m->m_ext.ext_size; | 1192 | tlen = m->m_ext.ext_size; | |
1198 | else if (m->m_flags & M_PKTHDR) | 1193 | else if (m->m_flags & M_PKTHDR) | |
1199 | tlen = MHLEN; | 1194 | tlen = MHLEN; | |
1200 | else | 1195 | else | |
1201 | tlen = MLEN; | 1196 | tlen = MLEN; | |
1202 | tlen -= m->m_len; | 1197 | tlen -= m->m_len; | |
1203 | if (tlen > len) | 1198 | if (tlen > len) | |
1204 | tlen = len; | 1199 | tlen = len; | |
1205 | awi_read_bytes(sc, off, mtod(m, uint8_t *) + m->m_len, tlen); | 1200 | awi_read_bytes(sc, off, mtod(m, uint8_t *) + m->m_len, tlen); | |
1206 | off += tlen; | 1201 | off += tlen; | |
1207 | len -= tlen; | 1202 | len -= tlen; | |
1208 | } | 1203 | } | |
1209 | 1204 | |||
1210 | while (len > 0) { | 1205 | while (len > 0) { | |
1211 | if (top == NULL) { | 1206 | if (top == NULL) { | |
1212 | MGETHDR(m, M_DONTWAIT, MT_DATA); | 1207 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
1213 | if (m == NULL) | 1208 | if (m == NULL) | |
1214 | return NULL; | 1209 | return NULL; | |
1215 | m_set_rcvif(m, ifp); | 1210 | m_set_rcvif(m, ifp); | |
1216 | m->m_pkthdr.len = len; | 1211 | m->m_pkthdr.len = len; | |
1217 | m->m_len = MHLEN; | 1212 | m->m_len = MHLEN; | |
1218 | m->m_flags |= M_HASFCS; | 1213 | m->m_flags |= M_HASFCS; | |
1219 | } else { | 1214 | } else { | |
1220 | MGET(m, M_DONTWAIT, MT_DATA); | 1215 | MGET(m, M_DONTWAIT, MT_DATA); | |
1221 | if (m == NULL) { | 1216 | if (m == NULL) { | |
1222 | m_freem(top); | 1217 | m_freem(top); | |
1223 | return NULL; | 1218 | return NULL; | |
1224 | } | 1219 | } | |
1225 | m->m_len = MLEN; | 1220 | m->m_len = MLEN; | |
1226 | } | 1221 | } | |
1227 | if (len >= MINCLSIZE) { | 1222 | if (len >= MINCLSIZE) { | |
1228 | MCLGET(m, M_DONTWAIT); | 1223 | MCLGET(m, M_DONTWAIT); | |
1229 | if (m->m_flags & M_EXT) | 1224 | if (m->m_flags & M_EXT) | |
1230 | m->m_len = m->m_ext.ext_size; | 1225 | m->m_len = m->m_ext.ext_size; | |
1231 | } | 1226 | } | |
1232 | if (top == NULL) { | 1227 | if (top == NULL) { | |
1233 | int hdrlen = sizeof(struct ieee80211_frame) + | 1228 | int hdrlen = sizeof(struct ieee80211_frame) + | |
1234 | sizeof(struct llc); | 1229 | sizeof(struct llc); | |
1235 | char *newdata = (char *) | 1230 | char *newdata = (char *) | |
1236 | ALIGN(m->m_data + hdrlen) - hdrlen; | 1231 | ALIGN(m->m_data + hdrlen) - hdrlen; | |
1237 | m->m_len -= newdata - m->m_data; | 1232 | m->m_len -= newdata - m->m_data; | |
1238 | m->m_data = newdata; | 1233 | m->m_data = newdata; | |
1239 | } | 1234 | } | |
1240 | if (m->m_len > len) | 1235 | if (m->m_len > len) | |
1241 | m->m_len = len; | 1236 | m->m_len = len; | |
1242 | awi_read_bytes(sc, off, mtod(m, uint8_t *), m->m_len); | 1237 | awi_read_bytes(sc, off, mtod(m, uint8_t *), m->m_len); | |
1243 | off += m->m_len; | 1238 | off += m->m_len; | |
1244 | len -= m->m_len; | 1239 | len -= m->m_len; | |
1245 | *mp = m; | 1240 | *mp = m; | |
1246 | mp = &m->m_next; | 1241 | mp = &m->m_next; | |
1247 | } | 1242 | } | |
1248 | return top; | 1243 | return top; | |
1249 | } | 1244 | } | |
1250 | 1245 | |||
1251 | /* | 1246 | /* | |
1252 | * Initialize hardware and start firmware to accept commands. | 1247 | * Initialize hardware and start firmware to accept commands. | |
1253 | * Called everytime after power on firmware. | 1248 | * Called everytime after power on firmware. | |
1254 | */ | 1249 | */ | |
1255 | 1250 | |||
1256 | static int | 1251 | static int | |
1257 | awi_hw_init(struct awi_softc *sc) | 1252 | awi_hw_init(struct awi_softc *sc) | |
1258 | { | 1253 | { | |
1259 | uint8_t status; | 1254 | uint8_t status; | |
1260 | uint16_t intmask; | 1255 | uint16_t intmask; | |
1261 | int i, error; | 1256 | int i, error; | |
1262 | 1257 | |||
1263 | sc->sc_enab_intr = 0; | 1258 | sc->sc_enab_intr = 0; | |
1264 | awi_drvstate(sc, AWI_DRV_RESET); | 1259 | awi_drvstate(sc, AWI_DRV_RESET); | |
1265 | 1260 | |||
1266 | /* Reset firmware */ | 1261 | /* Reset firmware */ | |
1267 | am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_CORESET); | 1262 | am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_CORESET); | |
1268 | DELAY(100); | 1263 | DELAY(100); | |
1269 | awi_write_1(sc, AWI_SELFTEST, 0); | 1264 | awi_write_1(sc, AWI_SELFTEST, 0); | |
1270 | awi_write_1(sc, AWI_CMD, 0); | 1265 | awi_write_1(sc, AWI_CMD, 0); | |
1271 | awi_write_1(sc, AWI_BANNER, 0); | 1266 | awi_write_1(sc, AWI_BANNER, 0); | |
1272 | am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_CORESET); | 1267 | am79c930_gcr_clearbits(&sc->sc_chip, AM79C930_GCR_CORESET); | |
1273 | DELAY(100); | 1268 | DELAY(100); | |
1274 | 1269 | |||
1275 | /* Wait for selftest completion */ | 1270 | /* Wait for selftest completion */ | |
1276 | for (i = 0; ; i++) { | 1271 | for (i = 0; ; i++) { | |
1277 | if (!device_is_active(sc->sc_dev)) | 1272 | if (!device_is_active(sc->sc_dev)) | |
1278 | return ENXIO; | 1273 | return ENXIO; | |
1279 | if (i >= AWI_SELFTEST_TIMEOUT*hz/1000) { | 1274 | if (i >= AWI_SELFTEST_TIMEOUT*hz/1000) { | |
1280 | printf("%s: failed to complete selftest (timeout)\n", | 1275 | printf("%s: failed to complete selftest (timeout)\n", | |
1281 | sc->sc_if.if_xname); | 1276 | sc->sc_if.if_xname); | |
1282 | return ENXIO; | 1277 | return ENXIO; | |
1283 | } | 1278 | } | |
1284 | status = awi_read_1(sc, AWI_SELFTEST); | 1279 | status = awi_read_1(sc, AWI_SELFTEST); | |
1285 | if ((status & 0xf0) == 0xf0) | 1280 | if ((status & 0xf0) == 0xf0) | |
1286 | break; | 1281 | break; | |
1287 | if (sc->sc_cansleep) { | 1282 | if (sc->sc_cansleep) { | |
1288 | sc->sc_sleep_cnt++; | 1283 | sc->sc_sleep_cnt++; | |
1289 | (void)tsleep(sc, PWAIT, "awitst", 1); | 1284 | (void)tsleep(sc, PWAIT, "awitst", 1); | |
1290 | sc->sc_sleep_cnt--; | 1285 | sc->sc_sleep_cnt--; | |
1291 | } else { | 1286 | } else { | |
1292 | DELAY(1000*1000/hz); | 1287 | DELAY(1000*1000/hz); | |
1293 | } | 1288 | } | |
1294 | } | 1289 | } | |
1295 | if (status != AWI_SELFTEST_PASSED) { | 1290 | if (status != AWI_SELFTEST_PASSED) { | |
1296 | printf("%s: failed to complete selftest (code %x)\n", | 1291 | printf("%s: failed to complete selftest (code %x)\n", | |
1297 | sc->sc_if.if_xname, status); | 1292 | sc->sc_if.if_xname, status); | |
1298 | return ENXIO; | 1293 | return ENXIO; | |
1299 | } | 1294 | } | |
1300 | 1295 | |||
1301 | /* Check banner to confirm firmware write it */ | 1296 | /* Check banner to confirm firmware write it */ | |
1302 | awi_read_bytes(sc, AWI_BANNER, sc->sc_banner, AWI_BANNER_LEN); | 1297 | awi_read_bytes(sc, AWI_BANNER, sc->sc_banner, AWI_BANNER_LEN); | |
1303 | if (memcmp(sc->sc_banner, "PCnetMobile:", 12) != 0) { | 1298 | if (memcmp(sc->sc_banner, "PCnetMobile:", 12) != 0) { | |
1304 | printf("%s: failed to complete selftest (bad banner)\n", | 1299 | printf("%s: failed to complete selftest (bad banner)\n", | |
1305 | sc->sc_if.if_xname); | 1300 | sc->sc_if.if_xname); | |
1306 | for (i = 0; i < AWI_BANNER_LEN; i++) | 1301 | for (i = 0; i < AWI_BANNER_LEN; i++) | |
1307 | printf("%s%02x", i ? ":" : "\t", sc->sc_banner[i]); | 1302 | printf("%s%02x", i ? ":" : "\t", sc->sc_banner[i]); | |
1308 | printf("\n"); | 1303 | printf("\n"); | |
1309 | return ENXIO; | 1304 | return ENXIO; | |
1310 | } | 1305 | } | |
1311 | 1306 | |||
1312 | /* Initializing interrupt */ | 1307 | /* Initializing interrupt */ | |
1313 | sc->sc_enab_intr = 1; | 1308 | sc->sc_enab_intr = 1; | |
1314 | error = awi_intr_lock(sc); | 1309 | error = awi_intr_lock(sc); | |
1315 | if (error) | 1310 | if (error) | |
1316 | return error; | 1311 | return error; | |
1317 | intmask = AWI_INT_GROGGY | AWI_INT_SCAN_CMPLT | | 1312 | intmask = AWI_INT_GROGGY | AWI_INT_SCAN_CMPLT | | |
1318 | AWI_INT_TX | AWI_INT_RX | AWI_INT_CMD; | 1313 | AWI_INT_TX | AWI_INT_RX | AWI_INT_CMD; | |
1319 | awi_write_1(sc, AWI_INTMASK, ~intmask & 0xff); | 1314 | awi_write_1(sc, AWI_INTMASK, ~intmask & 0xff); | |
1320 | awi_write_1(sc, AWI_INTMASK2, 0); | 1315 | awi_write_1(sc, AWI_INTMASK2, 0); | |
1321 | awi_write_1(sc, AWI_INTSTAT, 0); | 1316 | awi_write_1(sc, AWI_INTSTAT, 0); | |
1322 | awi_write_1(sc, AWI_INTSTAT2, 0); | 1317 | awi_write_1(sc, AWI_INTSTAT2, 0); | |
1323 | awi_intr_unlock(sc); | 1318 | awi_intr_unlock(sc); | |
1324 | am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_ENECINT); | 1319 | am79c930_gcr_setbits(&sc->sc_chip, AM79C930_GCR_ENECINT); | |
1325 | 1320 | |||
1326 | /* Issuing interface test command */ | 1321 | /* Issuing interface test command */ | |
1327 | error = awi_cmd(sc, AWI_CMD_NOP, AWI_WAIT); | 1322 | error = awi_cmd(sc, AWI_CMD_NOP, AWI_WAIT); | |
1328 | if (error) { | 1323 | if (error) { | |
1329 | printf("%s: failed to complete selftest", | 1324 | printf("%s: failed to complete selftest", | |
1330 | sc->sc_if.if_xname); | 1325 | sc->sc_if.if_xname); | |
1331 | if (error == ENXIO) | 1326 | if (error == ENXIO) | |
1332 | printf(" (no hardware)\n"); | 1327 | printf(" (no hardware)\n"); | |
1333 | else if (error != EWOULDBLOCK) | 1328 | else if (error != EWOULDBLOCK) | |
1334 | printf(" (error %d)\n", error); | 1329 | printf(" (error %d)\n", error); | |
1335 | else if (sc->sc_cansleep) | 1330 | else if (sc->sc_cansleep) | |
1336 | printf(" (lost interrupt)\n"); | 1331 | printf(" (lost interrupt)\n"); | |
1337 | else | 1332 | else | |
1338 | printf(" (command timeout)\n"); | 1333 | printf(" (command timeout)\n"); | |
1339 | return error; | 1334 | return error; | |
1340 | } | 1335 | } | |
1341 | 1336 | |||
1342 | /* Initialize VBM */ | 1337 | /* Initialize VBM */ | |
1343 | awi_write_1(sc, AWI_VBM_OFFSET, 0); | 1338 | awi_write_1(sc, AWI_VBM_OFFSET, 0); | |
1344 | awi_write_1(sc, AWI_VBM_LENGTH, 1); | 1339 | awi_write_1(sc, AWI_VBM_LENGTH, 1); | |
1345 | awi_write_1(sc, AWI_VBM_BITMAP, 0); | 1340 | awi_write_1(sc, AWI_VBM_BITMAP, 0); | |
1346 | return 0; | 1341 | return 0; | |
1347 | } | 1342 | } | |
1348 | 1343 | |||
1349 | /* | 1344 | /* | |
1350 | * Extract the factory default MIB value from firmware and assign the driver | 1345 | * Extract the factory default MIB value from firmware and assign the driver | |
1351 | * default value. | 1346 | * default value. | |
1352 | * Called once at attaching the interface. | 1347 | * Called once at attaching the interface. | |
1353 | */ | 1348 | */ | |
1354 | 1349 | |||
1355 | static int | 1350 | static int | |
1356 | awi_init_mibs(struct awi_softc *sc) | 1351 | awi_init_mibs(struct awi_softc *sc) | |
1357 | { | 1352 | { | |
1358 | int chan, i, error; | 1353 | int chan, i, error; | |
1359 | struct ieee80211com *ic = &sc->sc_ic; | 1354 | struct ieee80211com *ic = &sc->sc_ic; | |
1360 | const struct awi_chanset *cs; | 1355 | const struct awi_chanset *cs; | |
1361 | 1356 | |||
1362 | if ((error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_LOCAL, AWI_WAIT)) || | 1357 | if ((error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_LOCAL, AWI_WAIT)) || | |
1363 | (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_ADDR, AWI_WAIT)) || | 1358 | (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_ADDR, AWI_WAIT)) || | |
1364 | (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MAC, AWI_WAIT)) || | 1359 | (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MAC, AWI_WAIT)) || | |
1365 | (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MGT, AWI_WAIT)) || | 1360 | (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_MGT, AWI_WAIT)) || | |
1366 | (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_PHY, AWI_WAIT))) { | 1361 | (error = awi_mib(sc, AWI_CMD_GET_MIB, AWI_MIB_PHY, AWI_WAIT))) { | |
1367 | printf("%s: failed to get default mib value (error %d)\n", | 1362 | printf("%s: failed to get default mib value (error %d)\n", | |
1368 | sc->sc_if.if_xname, error); | 1363 | sc->sc_if.if_xname, error); | |
1369 | return error; | 1364 | return error; | |
1370 | } | 1365 | } | |
1371 | 1366 | |||
1372 | memset(&sc->sc_ic.ic_chan_avail, 0, sizeof(sc->sc_ic.ic_chan_avail)); | 1367 | memset(&sc->sc_ic.ic_chan_avail, 0, sizeof(sc->sc_ic.ic_chan_avail)); | |
1373 | for (cs = awi_chanset; ; cs++) { | 1368 | for (cs = awi_chanset; ; cs++) { | |
1374 | if (cs->cs_type == 0) { | 1369 | if (cs->cs_type == 0) { | |
1375 | printf("%s: failed to set available channel\n", | 1370 | printf("%s: failed to set available channel\n", | |
1376 | sc->sc_if.if_xname); | 1371 | sc->sc_if.if_xname); | |
1377 | return ENXIO; | 1372 | return ENXIO; | |
1378 | } | 1373 | } | |
1379 | if (cs->cs_type == sc->sc_mib_phy.IEEE_PHY_Type && | 1374 | if (cs->cs_type == sc->sc_mib_phy.IEEE_PHY_Type && | |
1380 | cs->cs_region == sc->sc_mib_phy.aCurrent_Reg_Domain) | 1375 | cs->cs_region == sc->sc_mib_phy.aCurrent_Reg_Domain) | |
1381 | break; | 1376 | break; | |
1382 | } | 1377 | } | |
1383 | if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { | 1378 | if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { | |
1384 | for (i = cs->cs_min; i <= cs->cs_max; i++) { | 1379 | for (i = cs->cs_min; i <= cs->cs_max; i++) { | |
1385 | chan = IEEE80211_FH_CHAN(i % 3 + 1, i); | 1380 | chan = IEEE80211_FH_CHAN(i % 3 + 1, i); | |
1386 | setbit(sc->sc_ic.ic_chan_avail, chan); | 1381 | setbit(sc->sc_ic.ic_chan_avail, chan); | |
1387 | /* XXX for FHSS, does frequency matter? */ | 1382 | /* XXX for FHSS, does frequency matter? */ | |
1388 | ic->ic_channels[chan].ic_freq = 0; | 1383 | ic->ic_channels[chan].ic_freq = 0; | |
1389 | ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_FHSS; | 1384 | ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_FHSS; | |
1390 | /* | 1385 | /* | |
1391 | * According to the IEEE 802.11 specification, | 1386 | * According to the IEEE 802.11 specification, | |
1392 | * hop pattern parameter for FH phy should be | 1387 | * hop pattern parameter for FH phy should be | |
1393 | * incremented by 3 for given hop chanset, i.e., | 1388 | * incremented by 3 for given hop chanset, i.e., | |
1394 | * the chanset parameter is calculated for given | 1389 | * the chanset parameter is calculated for given | |
1395 | * hop patter. However, BayStack 650 Access Points | 1390 | * hop patter. However, BayStack 650 Access Points | |
1396 | * apparently use fixed hop chanset parameter value | 1391 | * apparently use fixed hop chanset parameter value | |
1397 | * 1 for any hop pattern. So we also try this | 1392 | * 1 for any hop pattern. So we also try this | |
1398 | * combination of hop chanset and pattern. | 1393 | * combination of hop chanset and pattern. | |
1399 | */ | 1394 | */ | |
1400 | chan = IEEE80211_FH_CHAN(1, i); | 1395 | chan = IEEE80211_FH_CHAN(1, i); | |
1401 | setbit(sc->sc_ic.ic_chan_avail, chan); | 1396 | setbit(sc->sc_ic.ic_chan_avail, chan); | |
1402 | ic->ic_channels[chan].ic_freq = 0; /* XXX */ | 1397 | ic->ic_channels[chan].ic_freq = 0; /* XXX */ | |
1403 | ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_FHSS; | 1398 | ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_FHSS; | |
1404 | } | 1399 | } | |
1405 | } else { | 1400 | } else { | |
1406 | for (i = cs->cs_min; i <= cs->cs_max; i++) { | 1401 | for (i = cs->cs_min; i <= cs->cs_max; i++) { | |
1407 | setbit(sc->sc_ic.ic_chan_avail, i); | 1402 | setbit(sc->sc_ic.ic_chan_avail, i); | |
1408 | ic->ic_channels[i].ic_freq = | 1403 | ic->ic_channels[i].ic_freq = | |
1409 | ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); | 1404 | ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); | |
1410 | ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B; | 1405 | ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B; | |
1411 | } | 1406 | } | |
1412 | } | 1407 | } | |
1413 | sc->sc_cur_chan = cs->cs_def; | 1408 | sc->sc_cur_chan = cs->cs_def; | |
1414 | ic->ic_ibss_chan = &ic->ic_channels[cs->cs_def]; | 1409 | ic->ic_ibss_chan = &ic->ic_channels[cs->cs_def]; | |
1415 | 1410 | |||
1416 | sc->sc_mib_local.Fragmentation_Dis = 1; | 1411 | sc->sc_mib_local.Fragmentation_Dis = 1; | |
1417 | sc->sc_mib_local.Add_PLCP_Dis = 0; | 1412 | sc->sc_mib_local.Add_PLCP_Dis = 0; | |
1418 | sc->sc_mib_local.MAC_Hdr_Prsv = 0; | 1413 | sc->sc_mib_local.MAC_Hdr_Prsv = 0; | |
1419 | sc->sc_mib_local.Rx_Mgmt_Que_En = 0; | 1414 | sc->sc_mib_local.Rx_Mgmt_Que_En = 0; | |
1420 | sc->sc_mib_local.Re_Assembly_Dis = 1; | 1415 | sc->sc_mib_local.Re_Assembly_Dis = 1; | |
1421 | sc->sc_mib_local.Strip_PLCP_Dis = 0; | 1416 | sc->sc_mib_local.Strip_PLCP_Dis = 0; | |
1422 | sc->sc_mib_local.Power_Saving_Mode_Dis = 1; | 1417 | sc->sc_mib_local.Power_Saving_Mode_Dis = 1; | |
1423 | sc->sc_mib_local.Accept_All_Multicast_Dis = 1; | 1418 | sc->sc_mib_local.Accept_All_Multicast_Dis = 1; | |
1424 | sc->sc_mib_local.Check_Seq_Cntl_Dis = 0; | 1419 | sc->sc_mib_local.Check_Seq_Cntl_Dis = 0; | |
1425 | sc->sc_mib_local.Flush_CFP_Queue_On_CF_End = 0; | 1420 | sc->sc_mib_local.Flush_CFP_Queue_On_CF_End = 0; | |
1426 | sc->sc_mib_local.Network_Mode = 1; | 1421 | sc->sc_mib_local.Network_Mode = 1; | |
1427 | sc->sc_mib_local.PWD_Lvl = 0; | 1422 | sc->sc_mib_local.PWD_Lvl = 0; | |
1428 | sc->sc_mib_local.CFP_Mode = 0; | 1423 | sc->sc_mib_local.CFP_Mode = 0; | |
1429 | 1424 | |||
1430 | /* Allocate buffers */ | 1425 | /* Allocate buffers */ | |
1431 | sc->sc_txbase = AWI_BUFFERS; | 1426 | sc->sc_txbase = AWI_BUFFERS; | |
1432 | sc->sc_txend = sc->sc_txbase + | 1427 | sc->sc_txend = sc->sc_txbase + | |
1433 | (AWI_TXD_SIZE + sizeof(struct ieee80211_frame) + | 1428 | (AWI_TXD_SIZE + sizeof(struct ieee80211_frame) + | |
1434 | sizeof(struct ether_header) + ETHERMTU) * AWI_NTXBUFS; | 1429 | sizeof(struct ether_header) + ETHERMTU) * AWI_NTXBUFS; | |
1435 | LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Offset, sc->sc_txbase); | 1430 | LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Offset, sc->sc_txbase); | |
1436 | LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Size, | 1431 | LE_WRITE_4(&sc->sc_mib_local.Tx_Buffer_Size, | |
1437 | sc->sc_txend - sc->sc_txbase); | 1432 | sc->sc_txend - sc->sc_txbase); | |
1438 | LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Offset, sc->sc_txend); | 1433 | LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Offset, sc->sc_txend); | |
1439 | LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Size, | 1434 | LE_WRITE_4(&sc->sc_mib_local.Rx_Buffer_Size, | |
1440 | AWI_BUFFERS_END - sc->sc_txend); | 1435 | AWI_BUFFERS_END - sc->sc_txend); | |
1441 | sc->sc_mib_local.Acting_as_AP = 0; | 1436 | sc->sc_mib_local.Acting_as_AP = 0; | |
1442 | sc->sc_mib_local.Fill_CFP = 0; | 1437 | sc->sc_mib_local.Fill_CFP = 0; | |
1443 | 1438 | |||
1444 | memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE); | 1439 | memset(&sc->sc_mib_mac.aDesired_ESS_ID, 0, AWI_ESS_ID_SIZE); | |
1445 | sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID; | 1440 | sc->sc_mib_mac.aDesired_ESS_ID[0] = IEEE80211_ELEMID_SSID; | |
1446 | 1441 | |||
1447 | sc->sc_mib_mgt.aPower_Mgt_Mode = 0; | 1442 | sc->sc_mib_mgt.aPower_Mgt_Mode = 0; | |
1448 | sc->sc_mib_mgt.aDTIM_Period = 1; | 1443 | sc->sc_mib_mgt.aDTIM_Period = 1; | |
1449 | LE_WRITE_2(&sc->sc_mib_mgt.aATIM_Window, 0); | 1444 | LE_WRITE_2(&sc->sc_mib_mgt.aATIM_Window, 0); | |
1450 | return 0; | 1445 | return 0; | |
1451 | } | 1446 | } | |
1452 | 1447 | |||
1453 | static int | 1448 | static int | |
1454 | awi_mib(struct awi_softc *sc, uint8_t cmd, uint8_t mib, int wflag) | 1449 | awi_mib(struct awi_softc *sc, uint8_t cmd, uint8_t mib, int wflag) | |
1455 | { | 1450 | { | |
1456 | int error; | 1451 | int error; | |
1457 | uint8_t size, *ptr; | 1452 | uint8_t size, *ptr; | |
1458 | 1453 | |||
1459 | switch (mib) { | 1454 | switch (mib) { | |
1460 | case AWI_MIB_LOCAL: | 1455 | case AWI_MIB_LOCAL: | |
1461 | ptr = (uint8_t *)&sc->sc_mib_local; | 1456 | ptr = (uint8_t *)&sc->sc_mib_local; | |
1462 | size = sizeof(sc->sc_mib_local); | 1457 | size = sizeof(sc->sc_mib_local); | |
1463 | break; | 1458 | break; | |
1464 | case AWI_MIB_ADDR: | 1459 | case AWI_MIB_ADDR: | |
1465 | ptr = (uint8_t *)&sc->sc_mib_addr; | 1460 | ptr = (uint8_t *)&sc->sc_mib_addr; | |
1466 | size = sizeof(sc->sc_mib_addr); | 1461 | size = sizeof(sc->sc_mib_addr); | |
1467 | break; | 1462 | break; | |
1468 | case AWI_MIB_MAC: | 1463 | case AWI_MIB_MAC: | |
1469 | ptr = (uint8_t *)&sc->sc_mib_mac; | 1464 | ptr = (uint8_t *)&sc->sc_mib_mac; | |
1470 | size = sizeof(sc->sc_mib_mac); | 1465 | size = sizeof(sc->sc_mib_mac); | |
1471 | break; | 1466 | break; | |
1472 | case AWI_MIB_STAT: | 1467 | case AWI_MIB_STAT: | |
1473 | ptr = (uint8_t *)&sc->sc_mib_stat; | 1468 | ptr = (uint8_t *)&sc->sc_mib_stat; | |
1474 | size = sizeof(sc->sc_mib_stat); | 1469 | size = sizeof(sc->sc_mib_stat); | |
1475 | break; | 1470 | break; | |
1476 | case AWI_MIB_MGT: | 1471 | case AWI_MIB_MGT: | |
1477 | ptr = (uint8_t *)&sc->sc_mib_mgt; | 1472 | ptr = (uint8_t *)&sc->sc_mib_mgt; | |
1478 | size = sizeof(sc->sc_mib_mgt); | 1473 | size = sizeof(sc->sc_mib_mgt); | |
1479 | break; | 1474 | break; | |
1480 | case AWI_MIB_PHY: | 1475 | case AWI_MIB_PHY: | |
1481 | ptr = (uint8_t *)&sc->sc_mib_phy; | 1476 | ptr = (uint8_t *)&sc->sc_mib_phy; | |
1482 | size = sizeof(sc->sc_mib_phy); | 1477 | size = sizeof(sc->sc_mib_phy); | |
1483 | break; | 1478 | break; | |
1484 | default: | 1479 | default: | |
1485 | return EINVAL; | 1480 | return EINVAL; | |
1486 | } | 1481 | } | |
1487 | if (sc->sc_cmd_inprog) { | 1482 | if (sc->sc_cmd_inprog) { | |
1488 | if ((error = awi_cmd_wait(sc)) != 0) { | 1483 | if ((error = awi_cmd_wait(sc)) != 0) { | |
1489 | if (error == EWOULDBLOCK) { | 1484 | if (error == EWOULDBLOCK) { | |
1490 | DPRINTF(("awi_mib: cmd %d inprog", | 1485 | DPRINTF(("awi_mib: cmd %d inprog", | |
1491 | sc->sc_cmd_inprog)); | 1486 | sc->sc_cmd_inprog)); | |
1492 | } | 1487 | } | |
1493 | return error; | 1488 | return error; | |
1494 | } | 1489 | } | |
1495 | } | 1490 | } | |
1496 | sc->sc_cmd_inprog = cmd; | 1491 | sc->sc_cmd_inprog = cmd; | |
1497 | if (cmd == AWI_CMD_SET_MIB) | 1492 | if (cmd == AWI_CMD_SET_MIB) | |
1498 | awi_write_bytes(sc, AWI_CA_MIB_DATA, ptr, size); | 1493 | awi_write_bytes(sc, AWI_CA_MIB_DATA, ptr, size); | |
1499 | awi_write_1(sc, AWI_CA_MIB_TYPE, mib); | 1494 | awi_write_1(sc, AWI_CA_MIB_TYPE, mib); | |
1500 | awi_write_1(sc, AWI_CA_MIB_SIZE, size); | 1495 | awi_write_1(sc, AWI_CA_MIB_SIZE, size); | |
1501 | awi_write_1(sc, AWI_CA_MIB_INDEX, 0); | 1496 | awi_write_1(sc, AWI_CA_MIB_INDEX, 0); | |
1502 | if ((error = awi_cmd(sc, cmd, wflag)) != 0) | 1497 | if ((error = awi_cmd(sc, cmd, wflag)) != 0) | |
1503 | return error; | 1498 | return error; | |
1504 | if (cmd == AWI_CMD_GET_MIB) { | 1499 | if (cmd == AWI_CMD_GET_MIB) { | |
1505 | awi_read_bytes(sc, AWI_CA_MIB_DATA, ptr, size); | 1500 | awi_read_bytes(sc, AWI_CA_MIB_DATA, ptr, size); | |
1506 | #ifdef AWI_DEBUG | 1501 | #ifdef AWI_DEBUG | |
1507 | if (awi_debug) { | 1502 | if (awi_debug) { | |
1508 | int i; | 1503 | int i; | |
1509 | 1504 | |||
1510 | printf("awi_mib: #%d:", mib); | 1505 | printf("awi_mib: #%d:", mib); | |
1511 | for (i = 0; i < size; i++) | 1506 | for (i = 0; i < size; i++) | |
1512 | printf(" %02x", ptr[i]); | 1507 | printf(" %02x", ptr[i]); | |
1513 | printf("\n"); | 1508 | printf("\n"); | |
1514 | } | 1509 | } | |
1515 | #endif | 1510 | #endif | |
1516 | } | 1511 | } | |
1517 | return 0; | 1512 | return 0; | |
1518 | } | 1513 | } | |
1519 | 1514 | |||
1520 | static int | 1515 | static int | |
1521 | awi_cmd(struct awi_softc *sc, uint8_t cmd, int wflag) | 1516 | awi_cmd(struct awi_softc *sc, uint8_t cmd, int wflag) | |
1522 | { | 1517 | { | |
1523 | uint8_t status; | 1518 | uint8_t status; | |
1524 | int error = 0; | 1519 | int error = 0; | |
1525 | #ifdef AWI_DEBUG | 1520 | #ifdef AWI_DEBUG | |
1526 | static const char *cmdname[] = { | 1521 | static const char *cmdname[] = { | |
1527 | "IDLE", "NOP", "SET_MIB", "INIT_TX", "FLUSH_TX", "INIT_RX", | 1522 | "IDLE", "NOP", "SET_MIB", "INIT_TX", "FLUSH_TX", "INIT_RX", | |
1528 | "KILL_RX", "SLEEP", "WAKE", "GET_MIB", "SCAN", "SYNC", "RESUME" | 1523 | "KILL_RX", "SLEEP", "WAKE", "GET_MIB", "SCAN", "SYNC", "RESUME" | |
1529 | }; | 1524 | }; | |
1530 | #endif | 1525 | #endif | |
1531 | 1526 | |||
1532 | #ifdef AWI_DEBUG | 1527 | #ifdef AWI_DEBUG | |
1533 | if (awi_debug > 1) { | 1528 | if (awi_debug > 1) { | |
1534 | if (cmd >= sizeof(cmdname)/sizeof(cmdname[0])) | 1529 | if (cmd >= sizeof(cmdname)/sizeof(cmdname[0])) | |
1535 | printf("awi_cmd: #%d", cmd); | 1530 | printf("awi_cmd: #%d", cmd); | |
1536 | else | 1531 | else | |
1537 | printf("awi_cmd: %s", cmdname[cmd]); | 1532 | printf("awi_cmd: %s", cmdname[cmd]); | |
1538 | printf(" %s\n", wflag == AWI_NOWAIT ? "nowait" : "wait"); | 1533 | printf(" %s\n", wflag == AWI_NOWAIT ? "nowait" : "wait"); | |
1539 | } | 1534 | } | |
1540 | #endif | 1535 | #endif | |
1541 | sc->sc_cmd_inprog = cmd; | 1536 | sc->sc_cmd_inprog = cmd; | |
1542 | awi_write_1(sc, AWI_CMD_STATUS, AWI_STAT_IDLE); | 1537 | awi_write_1(sc, AWI_CMD_STATUS, AWI_STAT_IDLE); | |
1543 | awi_write_1(sc, AWI_CMD, cmd); | 1538 | awi_write_1(sc, AWI_CMD, cmd); | |
1544 | if (wflag == AWI_NOWAIT) | 1539 | if (wflag == AWI_NOWAIT) | |
1545 | return EINPROGRESS; | 1540 | return EINPROGRESS; | |
1546 | if ((error = awi_cmd_wait(sc)) != 0) | 1541 | if ((error = awi_cmd_wait(sc)) != 0) | |
1547 | return error; | 1542 | return error; | |
1548 | status = awi_read_1(sc, AWI_CMD_STATUS); | 1543 | status = awi_read_1(sc, AWI_CMD_STATUS); | |
1549 | awi_write_1(sc, AWI_CMD, 0); | 1544 | awi_write_1(sc, AWI_CMD, 0); | |
1550 | switch (status) { | 1545 | switch (status) { | |
1551 | case AWI_STAT_OK: | 1546 | case AWI_STAT_OK: | |
1552 | break; | 1547 | break; | |
1553 | case AWI_STAT_BADPARM: | 1548 | case AWI_STAT_BADPARM: | |
1554 | return EINVAL; | 1549 | return EINVAL; | |
1555 | default: | 1550 | default: | |
1556 | printf("%s: command %d failed %x\n", | 1551 | printf("%s: command %d failed %x\n", | |
1557 | sc->sc_if.if_xname, cmd, status); | 1552 | sc->sc_if.if_xname, cmd, status); | |
1558 | return ENXIO; | 1553 | return ENXIO; | |
1559 | } | 1554 | } | |
1560 | return 0; | 1555 | return 0; | |
1561 | } | 1556 | } | |
1562 | 1557 | |||
1563 | static int | 1558 | static int | |
1564 | awi_cmd_wait(struct awi_softc *sc) | 1559 | awi_cmd_wait(struct awi_softc *sc) | |
1565 | { | 1560 | { | |
1566 | int i, error = 0; | 1561 | int i, error = 0; | |
1567 | 1562 | |||
1568 | i = 0; | 1563 | i = 0; | |
1569 | while (sc->sc_cmd_inprog) { | 1564 | while (sc->sc_cmd_inprog) { | |
1570 | if (!device_is_active(sc->sc_dev)) | 1565 | if (!device_is_active(sc->sc_dev)) | |
1571 | return ENXIO; | 1566 | return ENXIO; | |
1572 | if (awi_read_1(sc, AWI_CMD) != sc->sc_cmd_inprog) { | 1567 | if (awi_read_1(sc, AWI_CMD) != sc->sc_cmd_inprog) { | |
1573 | printf("%s: failed to access hardware\n", | 1568 | printf("%s: failed to access hardware\n", | |
1574 | sc->sc_if.if_xname); | 1569 | sc->sc_if.if_xname); | |
1575 | config_deactivate(sc->sc_dev); | 1570 | config_deactivate(sc->sc_dev); | |
1576 | return ENXIO; | 1571 | return ENXIO; | |
1577 | } | 1572 | } | |
1578 | if (sc->sc_cansleep) { | 1573 | if (sc->sc_cansleep) { | |
1579 | sc->sc_sleep_cnt++; | 1574 | sc->sc_sleep_cnt++; | |
1580 | error = tsleep(sc, PWAIT, "awicmd", | 1575 | error = tsleep(sc, PWAIT, "awicmd", | |
1581 | AWI_CMD_TIMEOUT*hz/1000); | 1576 | AWI_CMD_TIMEOUT*hz/1000); | |
1582 | sc->sc_sleep_cnt--; | 1577 | sc->sc_sleep_cnt--; | |
1583 | } else { | 1578 | } else { | |
1584 | if (awi_read_1(sc, AWI_CMD_STATUS) != AWI_STAT_IDLE) { | 1579 | if (awi_read_1(sc, AWI_CMD_STATUS) != AWI_STAT_IDLE) { | |
1585 | awi_cmd_done(sc); | 1580 | awi_cmd_done(sc); | |
1586 | break; | 1581 | break; | |
1587 | } | 1582 | } | |
1588 | if (i++ >= AWI_CMD_TIMEOUT*1000/10) | 1583 | if (i++ >= AWI_CMD_TIMEOUT*1000/10) | |
1589 | error = EWOULDBLOCK; | 1584 | error = EWOULDBLOCK; | |
1590 | else | 1585 | else | |
1591 | DELAY(10); | 1586 | DELAY(10); | |
1592 | } | 1587 | } | |
1593 | if (error) | 1588 | if (error) | |
1594 | break; | 1589 | break; | |
1595 | } | 1590 | } | |
1596 | if (error) { | 1591 | if (error) { | |
1597 | DPRINTF(("awi_cmd_wait: cmd 0x%x, error %d\n", | 1592 | DPRINTF(("awi_cmd_wait: cmd 0x%x, error %d\n", | |
1598 | sc->sc_cmd_inprog, error)); | 1593 | sc->sc_cmd_inprog, error)); | |
1599 | } | 1594 | } | |
1600 | return error; | 1595 | return error; | |
1601 | } | 1596 | } | |
1602 | 1597 | |||
1603 | static void | 1598 | static void | |
1604 | awi_cmd_done(struct awi_softc *sc) | 1599 | awi_cmd_done(struct awi_softc *sc) | |
1605 | { | 1600 | { | |
1606 | uint8_t cmd, status; | 1601 | uint8_t cmd, status; | |
1607 | 1602 | |||
1608 | status = awi_read_1(sc, AWI_CMD_STATUS); | 1603 | status = awi_read_1(sc, AWI_CMD_STATUS); | |
1609 | if (status == AWI_STAT_IDLE) | 1604 | if (status == AWI_STAT_IDLE) | |
1610 | return; /* stray interrupt */ | 1605 | return; /* stray interrupt */ | |
1611 | 1606 | |||
1612 | cmd = sc->sc_cmd_inprog; | 1607 | cmd = sc->sc_cmd_inprog; | |
1613 | sc->sc_cmd_inprog = 0; | 1608 | sc->sc_cmd_inprog = 0; | |
1614 | wakeup(sc); | 1609 | wakeup(sc); | |
1615 | awi_write_1(sc, AWI_CMD, 0); | 1610 | awi_write_1(sc, AWI_CMD, 0); | |
1616 | 1611 | |||
1617 | if (status != AWI_STAT_OK) { | 1612 | if (status != AWI_STAT_OK) { | |
1618 | printf("%s: command %d failed %x\n", | 1613 | printf("%s: command %d failed %x\n", | |
1619 | sc->sc_if.if_xname, cmd, status); | 1614 | sc->sc_if.if_xname, cmd, status); | |
1620 | sc->sc_substate = AWI_ST_NONE; | 1615 | sc->sc_substate = AWI_ST_NONE; | |
1621 | return; | 1616 | return; | |
1622 | } | 1617 | } | |
1623 | if (sc->sc_substate != AWI_ST_NONE) | 1618 | if (sc->sc_substate != AWI_ST_NONE) | |
1624 | (void)ieee80211_new_state(&sc->sc_ic, sc->sc_nstate, -1); | 1619 | (void)ieee80211_new_state(&sc->sc_ic, sc->sc_nstate, -1); | |
1625 | } | 1620 | } | |
1626 | 1621 | |||
1627 | static int | 1622 | static int | |
1628 | awi_next_txd(struct awi_softc *sc, int len, uint32_t *framep, uint32_t *ntxdp) | 1623 | awi_next_txd(struct awi_softc *sc, int len, uint32_t *framep, uint32_t *ntxdp) | |
1629 | { | 1624 | { | |
1630 | uint32_t txd, ntxd, frame; | 1625 | uint32_t txd, ntxd, frame; | |
1631 | 1626 | |||
1632 | txd = sc->sc_txnext; | 1627 | txd = sc->sc_txnext; | |
1633 | frame = txd + AWI_TXD_SIZE; | 1628 | frame = txd + AWI_TXD_SIZE; | |
1634 | if (frame + len > sc->sc_txend) | 1629 | if (frame + len > sc->sc_txend) | |
1635 | frame = sc->sc_txbase; | 1630 | frame = sc->sc_txbase; | |
1636 | ntxd = frame + len; | 1631 | ntxd = frame + len; | |
1637 | if (ntxd + AWI_TXD_SIZE > sc->sc_txend) | 1632 | if (ntxd + AWI_TXD_SIZE > sc->sc_txend) | |
1638 | ntxd = sc->sc_txbase; | 1633 | ntxd = sc->sc_txbase; | |
1639 | *framep = frame; | 1634 | *framep = frame; | |
1640 | *ntxdp = ntxd; | 1635 | *ntxdp = ntxd; | |
1641 | /* | 1636 | /* | |
1642 | * Determine if there are any room in ring buffer. | 1637 | * Determine if there are any room in ring buffer. | |
1643 | * --- send wait, === new data, +++ conflict (ENOBUFS) | 1638 | * --- send wait, === new data, +++ conflict (ENOBUFS) | |
1644 | * base........................end | 1639 | * base........................end | |
1645 | * done----txd=====ntxd OK | 1640 | * done----txd=====ntxd OK | |
1646 | * --txd=====done++++ntxd-- full | 1641 | * --txd=====done++++ntxd-- full | |
1647 | * --txd=====ntxd done-- OK | 1642 | * --txd=====ntxd done-- OK | |
1648 | * ==ntxd done----txd=== OK | 1643 | * ==ntxd done----txd=== OK | |
1649 | * ==done++++ntxd----txd=== full | 1644 | * ==done++++ntxd----txd=== full | |
1650 | * ++ntxd txd=====done++ full | 1645 | * ++ntxd txd=====done++ full | |
1651 | */ | 1646 | */ | |
1652 | if (txd < ntxd) { | 1647 | if (txd < ntxd) { | |
1653 | if (txd < sc->sc_txdone && ntxd + AWI_TXD_SIZE > sc->sc_txdone) | 1648 | if (txd < sc->sc_txdone && ntxd + AWI_TXD_SIZE > sc->sc_txdone) | |
1654 | return ENOBUFS; | 1649 | return ENOBUFS; | |
1655 | } else { | 1650 | } else { | |
1656 | if (txd < sc->sc_txdone || ntxd + AWI_TXD_SIZE > sc->sc_txdone) | 1651 | if (txd < sc->sc_txdone || ntxd + AWI_TXD_SIZE > sc->sc_txdone) | |
1657 | return ENOBUFS; | 1652 | return ENOBUFS; | |
1658 | } | 1653 | } | |
1659 | return 0; | 1654 | return 0; | |
1660 | } | 1655 | } | |
1661 | 1656 | |||
1662 | static int | 1657 | static int | |
1663 | awi_lock(struct awi_softc *sc) | 1658 | awi_lock(struct awi_softc *sc) | |
1664 | { | 1659 | { | |
1665 | int error = 0; | 1660 | int error = 0; | |
1666 | 1661 | |||
1667 | if (curlwp == NULL) { | 1662 | if (curlwp == NULL) { | |
1668 | /* | 1663 | /* | |
1669 | * XXX | 1664 | * XXX | |
1670 | * Though driver ioctl should be called with context, | 1665 | * Though driver ioctl should be called with context, | |
1671 | * KAME ipv6 stack calls ioctl in interrupt for now. | 1666 | * KAME ipv6 stack calls ioctl in interrupt for now. | |
1672 | * We simply abort the request if there are other | 1667 | * We simply abort the request if there are other | |
1673 | * ioctl requests in progress. | 1668 | * ioctl requests in progress. | |
1674 | */ | 1669 | */ | |
1675 | if (sc->sc_busy) { | 1670 | if (sc->sc_busy) { | |
1676 | if (!device_is_active(sc->sc_dev)) | 1671 | if (!device_is_active(sc->sc_dev)) | |
1677 | return ENXIO; | 1672 | return ENXIO; | |
1678 | return EWOULDBLOCK; | 1673 | return EWOULDBLOCK; | |
1679 | } | 1674 | } | |
1680 | sc->sc_busy = 1; | 1675 | sc->sc_busy = 1; | |
1681 | sc->sc_cansleep = 0; | 1676 | sc->sc_cansleep = 0; | |
1682 | return 0; | 1677 | return 0; | |
1683 | } | 1678 | } | |
1684 | while (sc->sc_busy) { | 1679 | while (sc->sc_busy) { | |
1685 | if (!device_is_active(sc->sc_dev)) | 1680 | if (!device_is_active(sc->sc_dev)) | |
1686 | return ENXIO; | 1681 | return ENXIO; | |
1687 | sc->sc_sleep_cnt++; | 1682 | sc->sc_sleep_cnt++; | |
1688 | error = tsleep(sc, PWAIT | PCATCH, "awilck", 0); | 1683 | error = tsleep(sc, PWAIT | PCATCH, "awilck", 0); | |
1689 | sc->sc_sleep_cnt--; | 1684 | sc->sc_sleep_cnt--; | |
1690 | if (error) | 1685 | if (error) | |
1691 | return error; | 1686 | return error; | |
1692 | } | 1687 | } | |
1693 | sc->sc_busy = 1; | 1688 | sc->sc_busy = 1; | |
1694 | sc->sc_cansleep = 1; | 1689 | sc->sc_cansleep = 1; | |
1695 | return 0; | 1690 | return 0; | |
1696 | } | 1691 | } | |
1697 | 1692 | |||
1698 | static void | 1693 | static void | |
1699 | awi_unlock(struct awi_softc *sc) | 1694 | awi_unlock(struct awi_softc *sc) | |
1700 | { | 1695 | { | |
1701 | sc->sc_busy = 0; | 1696 | sc->sc_busy = 0; | |
1702 | sc->sc_cansleep = 0; | 1697 | sc->sc_cansleep = 0; | |
1703 | if (sc->sc_sleep_cnt) | 1698 | if (sc->sc_sleep_cnt) | |
1704 | wakeup(sc); | 1699 | wakeup(sc); | |
1705 | } | 1700 | } | |
1706 | 1701 | |||
1707 | static int | 1702 | static int | |
1708 | awi_intr_lock(struct awi_softc *sc) | 1703 | awi_intr_lock(struct awi_softc *sc) | |
1709 | { | 1704 | { | |
1710 | uint8_t status; | 1705 | uint8_t status; | |
1711 | int i, retry; | 1706 | int i, retry; | |
1712 | 1707 | |||
1713 | status = 1; | 1708 | status = 1; | |
1714 | for (retry = 0; retry < 10; retry++) { | 1709 | for (retry = 0; retry < 10; retry++) { | |
1715 | for (i = 0; i < AWI_LOCKOUT_TIMEOUT*1000/5; i++) { | 1710 | for (i = 0; i < AWI_LOCKOUT_TIMEOUT*1000/5; i++) { | |
1716 | if ((status = awi_read_1(sc, AWI_LOCKOUT_HOST)) == 0) | 1711 | if ((status = awi_read_1(sc, AWI_LOCKOUT_HOST)) == 0) | |
1717 | break; | 1712 | break; | |
1718 | DELAY(5); | 1713 | DELAY(5); | |
1719 | } | 1714 | } | |
1720 | if (status != 0) | 1715 | if (status != 0) | |
1721 | break; | 1716 | break; | |
1722 | awi_write_1(sc, AWI_LOCKOUT_MAC, 1); | 1717 | awi_write_1(sc, AWI_LOCKOUT_MAC, 1); | |
1723 | if ((status = awi_read_1(sc, AWI_LOCKOUT_HOST)) == 0) | 1718 | if ((status = awi_read_1(sc, AWI_LOCKOUT_HOST)) == 0) | |
1724 | break; | 1719 | break; | |
1725 | awi_write_1(sc, AWI_LOCKOUT_MAC, 0); | 1720 | awi_write_1(sc, AWI_LOCKOUT_MAC, 0); | |
1726 | } | 1721 | } | |
1727 | if (status != 0) { | 1722 | if (status != 0) { | |
1728 | printf("%s: failed to lock interrupt\n", | 1723 | printf("%s: failed to lock interrupt\n", | |
1729 | sc->sc_if.if_xname); | 1724 | sc->sc_if.if_xname); | |
1730 | return ENXIO; | 1725 | return ENXIO; | |
1731 | } | 1726 | } | |
1732 | return 0; | 1727 | return 0; | |
1733 | } | 1728 | } | |
1734 | 1729 | |||
1735 | static void | 1730 | static void | |
1736 | awi_intr_unlock(struct awi_softc *sc) | 1731 | awi_intr_unlock(struct awi_softc *sc) | |
1737 | { | 1732 | { | |
1738 | 1733 | |||
1739 | awi_write_1(sc, AWI_LOCKOUT_MAC, 0); | 1734 | awi_write_1(sc, AWI_LOCKOUT_MAC, 0); | |
1740 | } | 1735 | } | |
1741 | 1736 | |||
1742 | static int | 1737 | static int | |
1743 | awi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) | 1738 | awi_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) | |
1744 | { | 1739 | { | |
1745 | struct ifnet *ifp = ic->ic_ifp; | 1740 | struct ifnet *ifp = ic->ic_ifp; | |
1746 | struct awi_softc *sc = ifp->if_softc; | 1741 | struct awi_softc *sc = ifp->if_softc; | |
1747 | struct ieee80211_node *ni; | 1742 | struct ieee80211_node *ni; | |
1748 | int error; | 1743 | int error; | |
1749 | uint8_t newmode; | 1744 | uint8_t newmode; | |
1750 | enum ieee80211_state ostate; | 1745 | enum ieee80211_state ostate; | |
1751 | #ifdef AWI_DEBUG | 1746 | #ifdef AWI_DEBUG | |
1752 | static const char *stname[] = | 1747 | static const char *stname[] = | |
1753 | { "INIT", "SCAN", "AUTH", "ASSOC", "RUN" }; | 1748 | { "INIT", "SCAN", "AUTH", "ASSOC", "RUN" }; | |
1754 | static const char *substname[] = | 1749 | static const char *substname[] = | |
1755 | { "NONE", "SCAN_INIT", "SCAN_SETMIB", "SCAN_SCCMD", | 1750 | { "NONE", "SCAN_INIT", "SCAN_SETMIB", "SCAN_SCCMD", | |
1756 | "SUB_INIT", "SUB_SETSS", "SUB_SYNC" }; | 1751 | "SUB_INIT", "SUB_SETSS", "SUB_SYNC" }; | |
1757 | #endif /* AWI_DEBUG */ | 1752 | #endif /* AWI_DEBUG */ | |
1758 | 1753 | |||
1759 | ostate = ic->ic_state; | 1754 | ostate = ic->ic_state; | |
1760 | DPRINTF(("awi_newstate: %s (%s/%s) -> %s\n", stname[ostate], | 1755 | DPRINTF(("awi_newstate: %s (%s/%s) -> %s\n", stname[ostate], | |
1761 | stname[sc->sc_nstate], substname[sc->sc_substate], stname[nstate])); | 1756 | stname[sc->sc_nstate], substname[sc->sc_substate], stname[nstate])); | |
1762 | 1757 | |||
1763 | /* Set LED */ | 1758 | /* Set LED */ | |
1764 | switch (nstate) { | 1759 | switch (nstate) { | |
1765 | case IEEE80211_S_INIT: | 1760 | case IEEE80211_S_INIT: | |
1766 | awi_drvstate(sc, AWI_DRV_RESET); | 1761 | awi_drvstate(sc, AWI_DRV_RESET); | |
1767 | break; | 1762 | break; | |
1768 | case IEEE80211_S_SCAN: | 1763 | case IEEE80211_S_SCAN: | |
1769 | if (ic->ic_opmode == IEEE80211_M_IBSS || | 1764 | if (ic->ic_opmode == IEEE80211_M_IBSS || | |
1770 | ic->ic_opmode == IEEE80211_M_AHDEMO) | 1765 | ic->ic_opmode == IEEE80211_M_AHDEMO) | |
1771 | awi_drvstate(sc, AWI_DRV_ADHSC); | 1766 | awi_drvstate(sc, AWI_DRV_ADHSC); | |
1772 | else | 1767 | else | |
1773 | awi_drvstate(sc, AWI_DRV_INFSY); | 1768 | awi_drvstate(sc, AWI_DRV_INFSY); | |
1774 | break; | 1769 | break; | |
1775 | case IEEE80211_S_AUTH: | 1770 | case IEEE80211_S_AUTH: | |
1776 | awi_drvstate(sc, AWI_DRV_INFSY); | 1771 | awi_drvstate(sc, AWI_DRV_INFSY); | |
1777 | break; | 1772 | break; | |
1778 | case IEEE80211_S_ASSOC: | 1773 | case IEEE80211_S_ASSOC: | |
1779 | awi_drvstate(sc, AWI_DRV_INFAUTH); | 1774 | awi_drvstate(sc, AWI_DRV_INFAUTH); | |
1780 | break; | 1775 | break; | |
1781 | case IEEE80211_S_RUN: | 1776 | case IEEE80211_S_RUN: | |
1782 | if (ic->ic_opmode == IEEE80211_M_IBSS || | 1777 | if (ic->ic_opmode == IEEE80211_M_IBSS || | |
1783 | ic->ic_opmode == IEEE80211_M_AHDEMO) | 1778 | ic->ic_opmode == IEEE80211_M_AHDEMO) | |
1784 | awi_drvstate(sc, AWI_DRV_ADHSY); | 1779 | awi_drvstate(sc, AWI_DRV_ADHSY); | |
1785 | else | 1780 | else | |
1786 | awi_drvstate(sc, AWI_DRV_INFASSOC); | 1781 | awi_drvstate(sc, AWI_DRV_INFASSOC); | |
1787 | break; | 1782 | break; | |
1788 | } | 1783 | } | |
1789 | 1784 | |||
1790 | if (nstate == IEEE80211_S_INIT) { | 1785 | if (nstate == IEEE80211_S_INIT) { | |
1791 | sc->sc_substate = AWI_ST_NONE; | 1786 | sc->sc_substate = AWI_ST_NONE; | |
1792 | ic->ic_flags &= ~IEEE80211_F_SIBSS; | 1787 | ic->ic_flags &= ~IEEE80211_F_SIBSS; | |
1793 | return (*sc->sc_newstate)(ic, nstate, arg); | 1788 | return (*sc->sc_newstate)(ic, nstate, arg); | |
1794 | } | 1789 | } | |
1795 | 1790 | |||
1796 | /* State transition */ | 1791 | /* State transition */ | |
1797 | if (nstate == IEEE80211_S_SCAN) { | 1792 | if (nstate == IEEE80211_S_SCAN) { | |
1798 | /* SCAN substate */ | 1793 | /* SCAN substate */ | |
1799 | if (sc->sc_substate == AWI_ST_NONE) { | 1794 | if (sc->sc_substate == AWI_ST_NONE) { | |
1800 | sc->sc_nstate = nstate; /* next state in transition */ | 1795 | sc->sc_nstate = nstate; /* next state in transition */ | |
1801 | sc->sc_substate = AWI_ST_SCAN_INIT; | 1796 | sc->sc_substate = AWI_ST_SCAN_INIT; | |
1802 | } | 1797 | } | |
1803 | switch (sc->sc_substate) { | 1798 | switch (sc->sc_substate) { | |
1804 | case AWI_ST_SCAN_INIT: | 1799 | case AWI_ST_SCAN_INIT: | |
1805 | sc->sc_substate = AWI_ST_SCAN_SETMIB; | 1800 | sc->sc_substate = AWI_ST_SCAN_SETMIB; | |
1806 | switch (ostate) { | 1801 | switch (ostate) { | |
1807 | case IEEE80211_S_RUN: | 1802 | case IEEE80211_S_RUN: | |
1808 | /* Beacon miss */ | 1803 | /* Beacon miss */ | |
1809 | if (ifp->if_flags & IFF_DEBUG) | 1804 | if (ifp->if_flags & IFF_DEBUG) | |
1810 | printf("%s: no recent beacons from %s;" | 1805 | printf("%s: no recent beacons from %s;" | |
1811 | " rescanning\n", | 1806 | " rescanning\n", | |
1812 | ifp->if_xname, | 1807 | ifp->if_xname, | |
1813 | ether_sprintf(ic->ic_bss->ni_bssid)); | 1808 | ether_sprintf(ic->ic_bss->ni_bssid)); | |
1814 | /* FALLTHRU */ | 1809 | /* FALLTHRU */ | |
1815 | case IEEE80211_S_AUTH: | 1810 | case IEEE80211_S_AUTH: | |
1816 | case IEEE80211_S_ASSOC: | 1811 | case IEEE80211_S_ASSOC: | |
1817 | case IEEE80211_S_INIT: | 1812 | case IEEE80211_S_INIT: | |
1818 | ieee80211_begin_scan(ic, 1); | 1813 | ieee80211_begin_scan(ic, 1); | |
1819 | /* FALLTHRU */ | 1814 | /* FALLTHRU */ | |
1820 | case IEEE80211_S_SCAN: | 1815 | case IEEE80211_S_SCAN: | |
1821 | /* Scan next */ | 1816 | /* Scan next */ | |
1822 | break; | 1817 | break; | |
1823 | } | 1818 | } | |
1824 | if (ic->ic_flags & IEEE80211_F_ASCAN) | 1819 | if (ic->ic_flags & IEEE80211_F_ASCAN) | |
1825 | newmode = AWI_SCAN_ACTIVE; | 1820 | newmode = AWI_SCAN_ACTIVE; | |
1826 | else | 1821 | else | |
1827 | newmode = AWI_SCAN_PASSIVE; | 1822 | newmode = AWI_SCAN_PASSIVE; | |
1828 | if (sc->sc_mib_mgt.aScan_Mode != newmode) { | 1823 | if (sc->sc_mib_mgt.aScan_Mode != newmode) { | |
1829 | sc->sc_mib_mgt.aScan_Mode = newmode; | 1824 | sc->sc_mib_mgt.aScan_Mode = newmode; | |
1830 | if ((error = awi_mib(sc, AWI_CMD_SET_MIB, | 1825 | if ((error = awi_mib(sc, AWI_CMD_SET_MIB, | |
1831 | AWI_MIB_MGT, AWI_NOWAIT)) != 0) | 1826 | AWI_MIB_MGT, AWI_NOWAIT)) != 0) | |
1832 | break; | 1827 | break; | |
1833 | } | 1828 | } | |
1834 | /* FALLTHRU */ | 1829 | /* FALLTHRU */ | |
1835 | case AWI_ST_SCAN_SETMIB: | 1830 | case AWI_ST_SCAN_SETMIB: | |
1836 | sc->sc_substate = AWI_ST_SCAN_SCCMD; | 1831 | sc->sc_substate = AWI_ST_SCAN_SCCMD; | |
1837 | if (sc->sc_cmd_inprog) { | 1832 | if (sc->sc_cmd_inprog) { | |
1838 | if ((error = awi_cmd_wait(sc)) != 0) | 1833 | if ((error = awi_cmd_wait(sc)) != 0) | |
1839 | break; | 1834 | break; | |
1840 | } | 1835 | } | |
1841 | sc->sc_cmd_inprog = AWI_CMD_SCAN; | 1836 | sc->sc_cmd_inprog = AWI_CMD_SCAN; | |
1842 | ni = ic->ic_bss; | 1837 | ni = ic->ic_bss; | |
1843 | awi_write_2(sc, AWI_CA_SCAN_DURATION, | 1838 | awi_write_2(sc, AWI_CA_SCAN_DURATION, | |
1844 | (ic->ic_flags & IEEE80211_F_ASCAN) ? | 1839 | (ic->ic_flags & IEEE80211_F_ASCAN) ? | |
1845 | AWI_ASCAN_DURATION : AWI_PSCAN_DURATION); | 1840 | AWI_ASCAN_DURATION : AWI_PSCAN_DURATION); | |
1846 | if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { | 1841 | if (sc->sc_mib_phy.IEEE_PHY_Type == AWI_PHY_TYPE_FH) { | |
1847 | awi_write_1(sc, AWI_CA_SCAN_SET, | 1842 | awi_write_1(sc, AWI_CA_SCAN_SET, | |
1848 | IEEE80211_FH_CHANSET( | 1843 | IEEE80211_FH_CHANSET( | |
1849 | ieee80211_chan2ieee(ic, ni->ni_chan))); | 1844 | ieee80211_chan2ieee(ic, ni->ni_chan))); | |
1850 | awi_write_1(sc, AWI_CA_SCAN_PATTERN, | 1845 | awi_write_1(sc, AWI_CA_SCAN_PATTERN, | |
1851 | IEEE80211_FH_CHANPAT( | 1846 | IEEE80211_FH_CHANPAT( | |
1852 | ieee80211_chan2ieee(ic, ni->ni_chan))); | 1847 | ieee80211_chan2ieee(ic, ni->ni_chan))); | |
1853 | awi_write_1(sc, AWI_CA_SCAN_IDX, 1); | 1848 | awi_write_1(sc, AWI_CA_SCAN_IDX, 1); | |
1854 | } else { | 1849 | } else { | |
1855 | awi_write_1(sc, AWI_CA_SCAN_SET, | 1850 | awi_write_1(sc, AWI_CA_SCAN_SET, | |
1856 | ieee80211_chan2ieee(ic, ni->ni_chan)); | 1851 | ieee80211_chan2ieee(ic, ni->ni_chan)); | |
1857 | awi_write_1(sc, AWI_CA_SCAN_PATTERN, 0); | 1852 | awi_write_1(sc, AWI_CA_SCAN_PATTERN, 0); | |
1858 | awi_write_1(sc, AWI_CA_SCAN_IDX, 0); | 1853 | awi_write_1(sc, AWI_CA_SCAN_IDX, 0); | |
1859 | } | 1854 | } | |
1860 | awi_write_1(sc, AWI_CA_SCAN_SUSP, 0); | 1855 | awi_write_1(sc, AWI_CA_SCAN_SUSP, 0); | |
1861 | sc->sc_cur_chan = ieee80211_chan2ieee(ic, ni->ni_chan); | 1856 | sc->sc_cur_chan = ieee80211_chan2ieee(ic, ni->ni_chan); | |
1862 | if ((error = awi_cmd(sc, AWI_CMD_SCAN, AWI_NOWAIT)) | 1857 | if ((error = awi_cmd(sc, AWI_CMD_SCAN, AWI_NOWAIT)) | |
1863 | != 0) | 1858 | != 0) |
--- src/sys/dev/ic/wi.c 2019/05/28 07:41:48 1.253
+++ src/sys/dev/ic/wi.c 2019/12/05 03:11:40 1.254
@@ -1,2458 +1,2453 @@ | @@ -1,2458 +1,2453 @@ | |||
1 | /* $NetBSD: wi.c,v 1.253 2019/05/28 07:41:48 msaitoh Exp $ */ | 1 | /* $NetBSD: wi.c,v 1.254 2019/12/05 03:11:40 msaitoh Exp $ */ | |
2 | 2 | |||
3 | /*- | 3 | /*- | |
4 | * Copyright (c) 2004 The NetBSD Foundation, Inc. | 4 | * Copyright (c) 2004 The NetBSD Foundation, Inc. | |
5 | * All rights reserved. | 5 | * All rights reserved. | |
6 | * | 6 | * | |
7 | * This code is derived from software contributed to The NetBSD Foundation | 7 | * This code is derived from software contributed to The NetBSD Foundation | |
8 | * by Charles M. Hannum. | 8 | * by Charles M. Hannum. | |
9 | * | 9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | 10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions | 11 | * modification, are permitted provided that the following conditions | |
12 | * are met: | 12 | * are met: | |
13 | * 1. Redistributions of source code must retain the above copyright | 13 | * 1. Redistributions of source code must retain the above copyright | |
14 | * notice, this list of conditions and the following disclaimer. | 14 | * notice, this list of conditions and the following disclaimer. | |
15 | * 2. Redistributions in binary form must reproduce the above copyright | 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
16 | * notice, this list of conditions and the following disclaimer in the | 16 | * notice, this list of conditions and the following disclaimer in the | |
17 | * documentation and/or other materials provided with the distribution. | 17 | * documentation and/or other materials provided with the distribution. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | 19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | 22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS | |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
29 | * POSSIBILITY OF SUCH DAMAGE. | 29 | * POSSIBILITY OF SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | /* | 32 | /* | |
33 | * Copyright (c) 1997, 1998, 1999 | 33 | * Copyright (c) 1997, 1998, 1999 | |
34 | * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. | 34 | * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. | |
35 | * | 35 | * | |
36 | * Redistribution and use in source and binary forms, with or without | 36 | * Redistribution and use in source and binary forms, with or without | |
37 | * modification, are permitted provided that the following conditions | 37 | * modification, are permitted provided that the following conditions | |
38 | * are met: | 38 | * are met: | |
39 | * 1. Redistributions of source code must retain the above copyright | 39 | * 1. Redistributions of source code must retain the above copyright | |
40 | * notice, this list of conditions and the following disclaimer. | 40 | * notice, this list of conditions and the following disclaimer. | |
41 | * 2. Redistributions in binary form must reproduce the above copyright | 41 | * 2. Redistributions in binary form must reproduce the above copyright | |
42 | * notice, this list of conditions and the following disclaimer in the | 42 | * notice, this list of conditions and the following disclaimer in the | |
43 | * documentation and/or other materials provided with the distribution. | 43 | * documentation and/or other materials provided with the distribution. | |
44 | * 3. All advertising materials mentioning features or use of this software | 44 | * 3. All advertising materials mentioning features or use of this software | |
45 | * must display the following acknowledgement: | 45 | * must display the following acknowledgement: | |
46 | * This product includes software developed by Bill Paul. | 46 | * This product includes software developed by Bill Paul. | |
47 | * 4. Neither the name of the author nor the names of any co-contributors | 47 | * 4. Neither the name of the author nor the names of any co-contributors | |
48 | * may be used to endorse or promote products derived from this software | 48 | * may be used to endorse or promote products derived from this software | |
49 | * without specific prior written permission. | 49 | * without specific prior written permission. | |
50 | * | 50 | * | |
51 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | 51 | * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND | |
52 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 52 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
53 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 53 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
54 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | 54 | * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD | |
55 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 55 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
56 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 56 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
57 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 57 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
58 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 58 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
59 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 59 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
60 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 60 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
61 | * THE POSSIBILITY OF SUCH DAMAGE. | 61 | * THE POSSIBILITY OF SUCH DAMAGE. | |
62 | */ | 62 | */ | |
63 | 63 | |||
64 | /* | 64 | /* | |
65 | * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for NetBSD. | 65 | * Lucent WaveLAN/IEEE 802.11 PCMCIA driver for NetBSD. | |
66 | * | 66 | * | |
67 | * Original FreeBSD driver written by Bill Paul <wpaul@ctr.columbia.edu> | 67 | * Original FreeBSD driver written by Bill Paul <wpaul@ctr.columbia.edu> | |
68 | * Electrical Engineering Department | 68 | * Electrical Engineering Department | |
69 | * Columbia University, New York City | 69 | * Columbia University, New York City | |
70 | */ | 70 | */ | |
71 | 71 | |||
72 | /* | 72 | /* | |
73 | * The WaveLAN/IEEE adapter is the second generation of the WaveLAN | 73 | * The WaveLAN/IEEE adapter is the second generation of the WaveLAN | |
74 | * from Lucent. Unlike the older cards, the new ones are programmed | 74 | * from Lucent. Unlike the older cards, the new ones are programmed | |
75 | * entirely via a firmware-driven controller called the Hermes. | 75 | * entirely via a firmware-driven controller called the Hermes. | |
76 | * Unfortunately, Lucent will not release the Hermes programming manual | 76 | * Unfortunately, Lucent will not release the Hermes programming manual | |
77 | * without an NDA (if at all). What they do release is an API library | 77 | * without an NDA (if at all). What they do release is an API library | |
78 | * called the HCF (Hardware Control Functions) which is supposed to | 78 | * called the HCF (Hardware Control Functions) which is supposed to | |
79 | * do the device-specific operations of a device driver for you. The | 79 | * do the device-specific operations of a device driver for you. The | |
80 | * publically available version of the HCF library (the 'HCF Light') is | 80 | * publically available version of the HCF library (the 'HCF Light') is | |
81 | * a) extremely gross, b) lacks certain features, particularly support | 81 | * a) extremely gross, b) lacks certain features, particularly support | |
82 | * for 802.11 frames, and c) is contaminated by the GNU Public License. | 82 | * for 802.11 frames, and c) is contaminated by the GNU Public License. | |
83 | * | 83 | * | |
84 | * This driver does not use the HCF or HCF Light at all. Instead, it | 84 | * This driver does not use the HCF or HCF Light at all. Instead, it | |
85 | * programs the Hermes controller directly, using information gleaned | 85 | * programs the Hermes controller directly, using information gleaned | |
86 | * from the HCF Light code and corresponding documentation. | 86 | * from the HCF Light code and corresponding documentation. | |
87 | * | 87 | * | |
88 | * This driver supports both the PCMCIA and ISA versions of the | 88 | * This driver supports both the PCMCIA and ISA versions of the | |
89 | * WaveLAN/IEEE cards. Note however that the ISA card isn't really | 89 | * WaveLAN/IEEE cards. Note however that the ISA card isn't really | |
90 | * anything of the sort: it's actually a PCMCIA bridge adapter | 90 | * anything of the sort: it's actually a PCMCIA bridge adapter | |
91 | * that fits into an ISA slot, into which a PCMCIA WaveLAN card is | 91 | * that fits into an ISA slot, into which a PCMCIA WaveLAN card is | |
92 | * inserted. Consequently, you need to use the pccard support for | 92 | * inserted. Consequently, you need to use the pccard support for | |
93 | * both the ISA and PCMCIA adapters. | 93 | * both the ISA and PCMCIA adapters. | |
94 | */ | 94 | */ | |
95 | 95 | |||
96 | /* | 96 | /* | |
97 | * FreeBSD driver ported to NetBSD by Bill Sommerfeld in the back of the | 97 | * FreeBSD driver ported to NetBSD by Bill Sommerfeld in the back of the | |
98 | * Oslo IETF plenary meeting. | 98 | * Oslo IETF plenary meeting. | |
99 | */ | 99 | */ | |
100 | 100 | |||
101 | #include <sys/cdefs.h> | 101 | #include <sys/cdefs.h> | |
102 | __KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.253 2019/05/28 07:41:48 msaitoh Exp $"); | 102 | __KERNEL_RCSID(0, "$NetBSD: wi.c,v 1.254 2019/12/05 03:11:40 msaitoh Exp $"); | |
103 | 103 | |||
104 | #define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */ | 104 | #define WI_HERMES_AUTOINC_WAR /* Work around data write autoinc bug. */ | |
105 | #define WI_HERMES_STATS_WAR /* Work around stats counter bug. */ | 105 | #define WI_HERMES_STATS_WAR /* Work around stats counter bug. */ | |
106 | #undef WI_HISTOGRAM | 106 | #undef WI_HISTOGRAM | |
107 | #undef WI_RING_DEBUG | 107 | #undef WI_RING_DEBUG | |
108 | #define STATIC static | 108 | #define STATIC static | |
109 | 109 | |||
110 | 110 | |||
111 | #include <sys/param.h> | 111 | #include <sys/param.h> | |
112 | #include <sys/sysctl.h> | 112 | #include <sys/sysctl.h> | |
113 | #include <sys/systm.h> | 113 | #include <sys/systm.h> | |
114 | #include <sys/callout.h> | 114 | #include <sys/callout.h> | |
115 | #include <sys/device.h> | 115 | #include <sys/device.h> | |
116 | #include <sys/socket.h> | 116 | #include <sys/socket.h> | |
117 | #include <sys/mbuf.h> | 117 | #include <sys/mbuf.h> | |
118 | #include <sys/ioctl.h> | 118 | #include <sys/ioctl.h> | |
119 | #include <sys/kernel.h> /* for hz */ | 119 | #include <sys/kernel.h> /* for hz */ | |
120 | #include <sys/proc.h> | 120 | #include <sys/proc.h> | |
121 | #include <sys/kauth.h> | 121 | #include <sys/kauth.h> | |
122 | 122 | |||
123 | #include <net/if.h> | 123 | #include <net/if.h> | |
124 | #include <net/if_dl.h> | 124 | #include <net/if_dl.h> | |
125 | #include <net/if_llc.h> | 125 | #include <net/if_llc.h> | |
126 | #include <net/if_media.h> | 126 | #include <net/if_media.h> | |
127 | #include <net/if_ether.h> | 127 | #include <net/if_ether.h> | |
128 | #include <net/route.h> | 128 | #include <net/route.h> | |
129 | #include <net/bpf.h> | 129 | #include <net/bpf.h> | |
130 | 130 | |||
131 | #include <net80211/ieee80211_netbsd.h> | 131 | #include <net80211/ieee80211_netbsd.h> | |
132 | #include <net80211/ieee80211_var.h> | 132 | #include <net80211/ieee80211_var.h> | |
133 | #include <net80211/ieee80211_ioctl.h> | 133 | #include <net80211/ieee80211_ioctl.h> | |
134 | #include <net80211/ieee80211_radiotap.h> | 134 | #include <net80211/ieee80211_radiotap.h> | |
135 | #include <net80211/ieee80211_rssadapt.h> | 135 | #include <net80211/ieee80211_rssadapt.h> | |
136 | 136 | |||
137 | #include <sys/bus.h> | 137 | #include <sys/bus.h> | |
138 | #include <sys/intr.h> | 138 | #include <sys/intr.h> | |
139 | 139 | |||
140 | #include <dev/ic/wi_ieee.h> | 140 | #include <dev/ic/wi_ieee.h> | |
141 | #include <dev/ic/wireg.h> | 141 | #include <dev/ic/wireg.h> | |
142 | #include <dev/ic/wivar.h> | 142 | #include <dev/ic/wivar.h> | |
143 | 143 | |||
144 | STATIC int wi_init(struct ifnet *); | 144 | STATIC int wi_init(struct ifnet *); | |
145 | STATIC void wi_stop(struct ifnet *, int); | 145 | STATIC void wi_stop(struct ifnet *, int); | |
146 | STATIC void wi_start(struct ifnet *); | 146 | STATIC void wi_start(struct ifnet *); | |
147 | STATIC int wi_reset(struct wi_softc *); | 147 | STATIC int wi_reset(struct wi_softc *); | |
148 | STATIC void wi_watchdog(struct ifnet *); | 148 | STATIC void wi_watchdog(struct ifnet *); | |
149 | STATIC int wi_ioctl(struct ifnet *, u_long, void *); | 149 | STATIC int wi_ioctl(struct ifnet *, u_long, void *); | |
150 | STATIC int wi_media_change(struct ifnet *); | 150 | STATIC int wi_media_change(struct ifnet *); | |
151 | STATIC void wi_media_status(struct ifnet *, struct ifmediareq *); | 151 | STATIC void wi_media_status(struct ifnet *, struct ifmediareq *); | |
152 | STATIC void wi_softintr(void *); | 152 | STATIC void wi_softintr(void *); | |
153 | 153 | |||
154 | static void wi_ioctl_init(struct wi_softc *); | 154 | static void wi_ioctl_init(struct wi_softc *); | |
155 | static int wi_ioctl_enter(struct wi_softc *); | 155 | static int wi_ioctl_enter(struct wi_softc *); | |
156 | static void wi_ioctl_exit(struct wi_softc *); | 156 | static void wi_ioctl_exit(struct wi_softc *); | |
157 | static void wi_ioctl_drain(struct wi_softc *); | 157 | static void wi_ioctl_drain(struct wi_softc *); | |
158 | 158 | |||
159 | STATIC struct ieee80211_node *wi_node_alloc(struct ieee80211_node_table *); | 159 | STATIC struct ieee80211_node *wi_node_alloc(struct ieee80211_node_table *); | |
160 | STATIC void wi_node_free(struct ieee80211_node *); | 160 | STATIC void wi_node_free(struct ieee80211_node *); | |
161 | 161 | |||
162 | STATIC void wi_raise_rate(struct ieee80211com *, struct ieee80211_rssdesc *); | 162 | STATIC void wi_raise_rate(struct ieee80211com *, struct ieee80211_rssdesc *); | |
163 | STATIC void wi_lower_rate(struct ieee80211com *, struct ieee80211_rssdesc *); | 163 | STATIC void wi_lower_rate(struct ieee80211com *, struct ieee80211_rssdesc *); | |
164 | STATIC int wi_choose_rate(struct ieee80211com *, struct ieee80211_node *, | 164 | STATIC int wi_choose_rate(struct ieee80211com *, struct ieee80211_node *, | |
165 | struct ieee80211_frame *, u_int); | 165 | struct ieee80211_frame *, u_int); | |
166 | STATIC void wi_rssadapt_updatestats_cb(void *, struct ieee80211_node *); | 166 | STATIC void wi_rssadapt_updatestats_cb(void *, struct ieee80211_node *); | |
167 | STATIC void wi_rssadapt_updatestats(void *); | 167 | STATIC void wi_rssadapt_updatestats(void *); | |
168 | STATIC void wi_rssdescs_init(struct wi_rssdesc (*)[], wi_rssdescq_t *); | 168 | STATIC void wi_rssdescs_init(struct wi_rssdesc (*)[], wi_rssdescq_t *); | |
169 | STATIC void wi_rssdescs_reset(struct ieee80211com *, struct wi_rssdesc (*)[], | 169 | STATIC void wi_rssdescs_reset(struct ieee80211com *, struct wi_rssdesc (*)[], | |
170 | wi_rssdescq_t *, uint8_t (*)[]); | 170 | wi_rssdescq_t *, uint8_t (*)[]); | |
171 | STATIC void wi_sync_bssid(struct wi_softc *, uint8_t new_bssid[]); | 171 | STATIC void wi_sync_bssid(struct wi_softc *, uint8_t new_bssid[]); | |
172 | 172 | |||
173 | STATIC void wi_rx_intr(struct wi_softc *); | 173 | STATIC void wi_rx_intr(struct wi_softc *); | |
174 | STATIC void wi_txalloc_intr(struct wi_softc *); | 174 | STATIC void wi_txalloc_intr(struct wi_softc *); | |
175 | STATIC void wi_cmd_intr(struct wi_softc *); | 175 | STATIC void wi_cmd_intr(struct wi_softc *); | |
176 | STATIC void wi_tx_intr(struct wi_softc *); | 176 | STATIC void wi_tx_intr(struct wi_softc *); | |
177 | STATIC void wi_tx_ex_intr(struct wi_softc *); | 177 | STATIC void wi_tx_ex_intr(struct wi_softc *); | |
178 | STATIC void wi_info_intr(struct wi_softc *); | 178 | STATIC void wi_info_intr(struct wi_softc *); | |
179 | 179 | |||
180 | STATIC int wi_key_delete(struct ieee80211com *, const struct ieee80211_key *); | 180 | STATIC int wi_key_delete(struct ieee80211com *, const struct ieee80211_key *); | |
181 | STATIC int wi_key_set(struct ieee80211com *, const struct ieee80211_key *, | 181 | STATIC int wi_key_set(struct ieee80211com *, const struct ieee80211_key *, | |
182 | const uint8_t[IEEE80211_ADDR_LEN]); | 182 | const uint8_t[IEEE80211_ADDR_LEN]); | |
183 | STATIC void wi_key_update_begin(struct ieee80211com *); | 183 | STATIC void wi_key_update_begin(struct ieee80211com *); | |
184 | STATIC void wi_key_update_end(struct ieee80211com *); | 184 | STATIC void wi_key_update_end(struct ieee80211com *); | |
185 | 185 | |||
186 | STATIC void wi_push_packet(struct wi_softc *); | 186 | STATIC void wi_push_packet(struct wi_softc *); | |
187 | STATIC int wi_get_cfg(struct ifnet *, u_long, void *); | 187 | STATIC int wi_get_cfg(struct ifnet *, u_long, void *); | |
188 | STATIC int wi_set_cfg(struct ifnet *, u_long, void *); | 188 | STATIC int wi_set_cfg(struct ifnet *, u_long, void *); | |
189 | STATIC int wi_cfg_txrate(struct wi_softc *); | 189 | STATIC int wi_cfg_txrate(struct wi_softc *); | |
190 | STATIC int wi_write_txrate(struct wi_softc *, int); | 190 | STATIC int wi_write_txrate(struct wi_softc *, int); | |
191 | STATIC int wi_write_wep(struct wi_softc *); | 191 | STATIC int wi_write_wep(struct wi_softc *); | |
192 | STATIC int wi_write_multi(struct wi_softc *); | 192 | STATIC int wi_write_multi(struct wi_softc *); | |
193 | STATIC int wi_alloc_fid(struct wi_softc *, int, int *); | 193 | STATIC int wi_alloc_fid(struct wi_softc *, int, int *); | |
194 | STATIC void wi_read_nicid(struct wi_softc *); | 194 | STATIC void wi_read_nicid(struct wi_softc *); | |
195 | STATIC int wi_write_ssid(struct wi_softc *, int, uint8_t *, int); | 195 | STATIC int wi_write_ssid(struct wi_softc *, int, uint8_t *, int); | |
196 | 196 | |||
197 | STATIC int wi_cmd(struct wi_softc *, int, int, int, int); | 197 | STATIC int wi_cmd(struct wi_softc *, int, int, int, int); | |
198 | STATIC int wi_cmd_start(struct wi_softc *, int, int, int, int); | 198 | STATIC int wi_cmd_start(struct wi_softc *, int, int, int, int); | |
199 | STATIC int wi_cmd_wait(struct wi_softc *, int, int); | 199 | STATIC int wi_cmd_wait(struct wi_softc *, int, int); | |
200 | STATIC int wi_seek_bap(struct wi_softc *, int, int); | 200 | STATIC int wi_seek_bap(struct wi_softc *, int, int); | |
201 | STATIC int wi_read_bap(struct wi_softc *, int, int, void *, int); | 201 | STATIC int wi_read_bap(struct wi_softc *, int, int, void *, int); | |
202 | STATIC int wi_write_bap(struct wi_softc *, int, int, void *, int); | 202 | STATIC int wi_write_bap(struct wi_softc *, int, int, void *, int); | |
203 | STATIC int wi_mwrite_bap(struct wi_softc *, int, int, struct mbuf *, int); | 203 | STATIC int wi_mwrite_bap(struct wi_softc *, int, int, struct mbuf *, int); | |
204 | STATIC int wi_read_rid(struct wi_softc *, int, void *, int *); | 204 | STATIC int wi_read_rid(struct wi_softc *, int, void *, int *); | |
205 | STATIC int wi_write_rid(struct wi_softc *, int, void *, int); | 205 | STATIC int wi_write_rid(struct wi_softc *, int, void *, int); | |
206 | 206 | |||
207 | STATIC int wi_newstate(struct ieee80211com *, enum ieee80211_state, int); | 207 | STATIC int wi_newstate(struct ieee80211com *, enum ieee80211_state, int); | |
208 | STATIC void wi_set_tim(struct ieee80211_node *, int); | 208 | STATIC void wi_set_tim(struct ieee80211_node *, int); | |
209 | 209 | |||
210 | STATIC int wi_scan_ap(struct wi_softc *, uint16_t, uint16_t); | 210 | STATIC int wi_scan_ap(struct wi_softc *, uint16_t, uint16_t); | |
211 | STATIC void wi_scan_result(struct wi_softc *, int, int); | 211 | STATIC void wi_scan_result(struct wi_softc *, int, int); | |
212 | 212 | |||
213 | STATIC void wi_dump_pkt(struct wi_frame *, struct ieee80211_node *, int rssi); | 213 | STATIC void wi_dump_pkt(struct wi_frame *, struct ieee80211_node *, int rssi); | |
214 | STATIC void wi_mend_flags(struct wi_softc *, enum ieee80211_state); | 214 | STATIC void wi_mend_flags(struct wi_softc *, enum ieee80211_state); | |
215 | 215 | |||
216 | static inline int | 216 | static inline int | |
217 | wi_write_val(struct wi_softc *sc, int rid, uint16_t val) | 217 | wi_write_val(struct wi_softc *sc, int rid, uint16_t val) | |
218 | { | 218 | { | |
219 | 219 | |||
220 | val = htole16(val); | 220 | val = htole16(val); | |
221 | return wi_write_rid(sc, rid, &val, sizeof(val)); | 221 | return wi_write_rid(sc, rid, &val, sizeof(val)); | |
222 | } | 222 | } | |
223 | 223 | |||
224 | static struct timeval lasttxerror; /* time of last tx error msg */ | 224 | static struct timeval lasttxerror; /* time of last tx error msg */ | |
225 | static int curtxeps = 0; /* current tx error msgs/sec */ | 225 | static int curtxeps = 0; /* current tx error msgs/sec */ | |
226 | static int wi_txerate = 0; /* tx error rate: max msgs/sec */ | 226 | static int wi_txerate = 0; /* tx error rate: max msgs/sec */ | |
227 | 227 | |||
228 | #ifdef WI_DEBUG | 228 | #ifdef WI_DEBUG | |
229 | #define WI_DEBUG_MAX 2 | 229 | #define WI_DEBUG_MAX 2 | |
230 | int wi_debug = 0; | 230 | int wi_debug = 0; | |
231 | 231 | |||
232 | #define DPRINTF(X) if (wi_debug) printf X | 232 | #define DPRINTF(X) if (wi_debug) printf X | |
233 | #define DPRINTF2(X) if (wi_debug > 1) printf X | 233 | #define DPRINTF2(X) if (wi_debug > 1) printf X | |
234 | #define IFF_DUMPPKTS(_ifp) \ | 234 | #define IFF_DUMPPKTS(_ifp) \ | |
235 | (((_ifp)->if_flags & (IFF_DEBUG |IFF_LINK2)) == (IFF_DEBUG |IFF_LINK2)) | 235 | (((_ifp)->if_flags & (IFF_DEBUG |IFF_LINK2)) == (IFF_DEBUG |IFF_LINK2)) | |
236 | static int wi_sysctl_verify_debug(SYSCTLFN_PROTO); | 236 | static int wi_sysctl_verify_debug(SYSCTLFN_PROTO); | |
237 | #else | 237 | #else | |
238 | #define DPRINTF(X) | 238 | #define DPRINTF(X) | |
239 | #define DPRINTF2(X) | 239 | #define DPRINTF2(X) | |
240 | #define IFF_DUMPPKTS(_ifp) 0 | 240 | #define IFF_DUMPPKTS(_ifp) 0 | |
241 | #endif | 241 | #endif | |
242 | 242 | |||
243 | #define WI_INTRS (WI_EV_RX | WI_EV_ALLOC | WI_EV_INFO | \ | 243 | #define WI_INTRS (WI_EV_RX | WI_EV_ALLOC | WI_EV_INFO | \ | |
244 | WI_EV_TX | WI_EV_TX_EXC | WI_EV_CMD) | 244 | WI_EV_TX | WI_EV_TX_EXC | WI_EV_CMD) | |
245 | 245 | |||
246 | static const struct wi_card_ident wi_card_ident[] = { | 246 | static const struct wi_card_ident wi_card_ident[] = { | |
247 | /* CARD_ID CARD_NAME FIRM_TYPE */ | 247 | /* CARD_ID CARD_NAME FIRM_TYPE */ | |
248 | { WI_NIC_LUCENT_ID, WI_NIC_LUCENT_STR, WI_LUCENT }, | 248 | { WI_NIC_LUCENT_ID, WI_NIC_LUCENT_STR, WI_LUCENT }, | |
249 | { WI_NIC_SONY_ID, WI_NIC_SONY_STR, WI_LUCENT }, | 249 | { WI_NIC_SONY_ID, WI_NIC_SONY_STR, WI_LUCENT }, | |
250 | { WI_NIC_LUCENT_EMB_ID, WI_NIC_LUCENT_EMB_STR, WI_LUCENT }, | 250 | { WI_NIC_LUCENT_EMB_ID, WI_NIC_LUCENT_EMB_STR, WI_LUCENT }, | |
251 | { WI_NIC_EVB2_ID, WI_NIC_EVB2_STR, WI_INTERSIL }, | 251 | { WI_NIC_EVB2_ID, WI_NIC_EVB2_STR, WI_INTERSIL }, | |
252 | { WI_NIC_HWB3763_ID, WI_NIC_HWB3763_STR, WI_INTERSIL }, | 252 | { WI_NIC_HWB3763_ID, WI_NIC_HWB3763_STR, WI_INTERSIL }, | |
253 | { WI_NIC_HWB3163_ID, WI_NIC_HWB3163_STR, WI_INTERSIL }, | 253 | { WI_NIC_HWB3163_ID, WI_NIC_HWB3163_STR, WI_INTERSIL }, | |
254 | { WI_NIC_HWB3163B_ID, WI_NIC_HWB3163B_STR, WI_INTERSIL }, | 254 | { WI_NIC_HWB3163B_ID, WI_NIC_HWB3163B_STR, WI_INTERSIL }, | |
255 | { WI_NIC_EVB3_ID, WI_NIC_EVB3_STR, WI_INTERSIL }, | 255 | { WI_NIC_EVB3_ID, WI_NIC_EVB3_STR, WI_INTERSIL }, | |
256 | { WI_NIC_HWB1153_ID, WI_NIC_HWB1153_STR, WI_INTERSIL }, | 256 | { WI_NIC_HWB1153_ID, WI_NIC_HWB1153_STR, WI_INTERSIL }, | |
257 | { WI_NIC_P2_SST_ID, WI_NIC_P2_SST_STR, WI_INTERSIL }, | 257 | { WI_NIC_P2_SST_ID, WI_NIC_P2_SST_STR, WI_INTERSIL }, | |
258 | { WI_NIC_EVB2_SST_ID, WI_NIC_EVB2_SST_STR, WI_INTERSIL }, | 258 | { WI_NIC_EVB2_SST_ID, WI_NIC_EVB2_SST_STR, WI_INTERSIL }, | |
259 | { WI_NIC_3842_EVA_ID, WI_NIC_3842_EVA_STR, WI_INTERSIL }, | 259 | { WI_NIC_3842_EVA_ID, WI_NIC_3842_EVA_STR, WI_INTERSIL }, | |
260 | { WI_NIC_3842_PCMCIA_AMD_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, | 260 | { WI_NIC_3842_PCMCIA_AMD_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, | |
261 | { WI_NIC_3842_PCMCIA_SST_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, | 261 | { WI_NIC_3842_PCMCIA_SST_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, | |
262 | { WI_NIC_3842_PCMCIA_ATM_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, | 262 | { WI_NIC_3842_PCMCIA_ATM_ID, WI_NIC_3842_PCMCIA_STR, WI_INTERSIL }, | |
263 | { WI_NIC_3842_MINI_AMD_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, | 263 | { WI_NIC_3842_MINI_AMD_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, | |
264 | { WI_NIC_3842_MINI_SST_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, | 264 | { WI_NIC_3842_MINI_SST_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, | |
265 | { WI_NIC_3842_MINI_ATM_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, | 265 | { WI_NIC_3842_MINI_ATM_ID, WI_NIC_3842_MINI_STR, WI_INTERSIL }, | |
266 | { WI_NIC_3842_PCI_AMD_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, | 266 | { WI_NIC_3842_PCI_AMD_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, | |
267 | { WI_NIC_3842_PCI_SST_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, | 267 | { WI_NIC_3842_PCI_SST_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, | |
268 | { WI_NIC_3842_PCI_ATM_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, | 268 | { WI_NIC_3842_PCI_ATM_ID, WI_NIC_3842_PCI_STR, WI_INTERSIL }, | |
269 | { WI_NIC_P3_PCMCIA_AMD_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL }, | 269 | { WI_NIC_P3_PCMCIA_AMD_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL }, | |
270 | { WI_NIC_P3_PCMCIA_SST_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL }, | 270 | { WI_NIC_P3_PCMCIA_SST_ID, WI_NIC_P3_PCMCIA_STR, WI_INTERSIL }, | |
271 | { WI_NIC_P3_MINI_AMD_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL }, | 271 | { WI_NIC_P3_MINI_AMD_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL }, | |
272 | { WI_NIC_P3_MINI_SST_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL }, | 272 | { WI_NIC_P3_MINI_SST_ID, WI_NIC_P3_MINI_STR, WI_INTERSIL }, | |
273 | { 0, NULL, 0 }, | 273 | { 0, NULL, 0 }, | |
274 | }; | 274 | }; | |
275 | 275 | |||
276 | #ifndef _MODULE | 276 | #ifndef _MODULE | |
277 | /* | 277 | /* | |
278 | * Setup sysctl(3) MIB, hw.wi.* | 278 | * Setup sysctl(3) MIB, hw.wi.* | |
279 | * | 279 | * | |
280 | * TBD condition CTLFLAG_PERMANENT on being a module or not | 280 | * TBD condition CTLFLAG_PERMANENT on being a module or not | |
281 | */ | 281 | */ | |
282 | SYSCTL_SETUP(sysctl_wi, "sysctl wi(4) subtree setup") | 282 | SYSCTL_SETUP(sysctl_wi, "sysctl wi(4) subtree setup") | |
283 | { | 283 | { | |
284 | int rc; | 284 | int rc; | |
285 | const struct sysctlnode *rnode; | 285 | const struct sysctlnode *rnode; | |
286 | #ifdef WI_DEBUG | 286 | #ifdef WI_DEBUG | |
287 | const struct sysctlnode *cnode; | 287 | const struct sysctlnode *cnode; | |
288 | #endif /* WI_DEBUG */ | 288 | #endif /* WI_DEBUG */ | |
289 | 289 | |||
290 | if ((rc = sysctl_createv(clog, 0, NULL, &rnode, | 290 | if ((rc = sysctl_createv(clog, 0, NULL, &rnode, | |
291 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "wi", | 291 | CTLFLAG_PERMANENT, CTLTYPE_NODE, "wi", | |
292 | "Lucent/Prism/Symbol 802.11 controls", | 292 | "Lucent/Prism/Symbol 802.11 controls", | |
293 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) | 293 | NULL, 0, NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL)) != 0) | |
294 | goto err; | 294 | goto err; | |
295 | 295 | |||
296 | #ifdef WI_DEBUG | 296 | #ifdef WI_DEBUG | |
297 | /* control debugging printfs */ | 297 | /* control debugging printfs */ | |
298 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | 298 | if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, | |
299 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | 299 | CTLFLAG_PERMANENT | CTLFLAG_READWRITE, CTLTYPE_INT, | |
300 | "debug", SYSCTL_DESCR("Enable debugging output"), | 300 | "debug", SYSCTL_DESCR("Enable debugging output"), | |
301 | wi_sysctl_verify_debug, 0, &wi_debug, 0, CTL_CREATE, CTL_EOL)) != 0) | 301 | wi_sysctl_verify_debug, 0, &wi_debug, 0, CTL_CREATE, CTL_EOL)) != 0) | |
302 | goto err; | 302 | goto err; | |
303 | #endif /* WI_DEBUG */ | 303 | #endif /* WI_DEBUG */ | |
304 | return; | 304 | return; | |
305 | err: | 305 | err: | |
306 | printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); | 306 | printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); | |
307 | } | 307 | } | |
308 | #endif | 308 | #endif | |
309 | 309 | |||
310 | #ifdef WI_DEBUG | 310 | #ifdef WI_DEBUG | |
311 | static int | 311 | static int | |
312 | wi_sysctl_verify(SYSCTLFN_ARGS, int lower, int upper) | 312 | wi_sysctl_verify(SYSCTLFN_ARGS, int lower, int upper) | |
313 | { | 313 | { | |
314 | int error, t; | 314 | int error, t; | |
315 | struct sysctlnode node; | 315 | struct sysctlnode node; | |
316 | 316 | |||
317 | node = *rnode; | 317 | node = *rnode; | |
318 | t = *(int*)rnode->sysctl_data; | 318 | t = *(int*)rnode->sysctl_data; | |
319 | node.sysctl_data = &t; | 319 | node.sysctl_data = &t; | |
320 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); | 320 | error = sysctl_lookup(SYSCTLFN_CALL(&node)); | |
321 | if (error || newp == NULL) | 321 | if (error || newp == NULL) | |
322 | return (error); | 322 | return (error); | |
323 | 323 | |||
324 | if (t < lower || t > upper) | 324 | if (t < lower || t > upper) | |
325 | return (EINVAL); | 325 | return (EINVAL); | |
326 | 326 | |||
327 | *(int*)rnode->sysctl_data = t; | 327 | *(int*)rnode->sysctl_data = t; | |
328 | 328 | |||
329 | return (0); | 329 | return (0); | |
330 | } | 330 | } | |
331 | 331 | |||
332 | static int | 332 | static int | |
333 | wi_sysctl_verify_debug(SYSCTLFN_ARGS) | 333 | wi_sysctl_verify_debug(SYSCTLFN_ARGS) | |
334 | { | 334 | { | |
335 | return wi_sysctl_verify(SYSCTLFN_CALL(__UNCONST(rnode)), | 335 | return wi_sysctl_verify(SYSCTLFN_CALL(__UNCONST(rnode)), | |
336 | 0, WI_DEBUG_MAX); | 336 | 0, WI_DEBUG_MAX); | |
337 | } | 337 | } | |
338 | #endif /* WI_DEBUG */ | 338 | #endif /* WI_DEBUG */ | |
339 | 339 | |||
340 | STATIC int | 340 | STATIC int | |
341 | wi_read_xrid(struct wi_softc *sc, int rid, void *buf, int ebuflen) | 341 | wi_read_xrid(struct wi_softc *sc, int rid, void *buf, int ebuflen) | |
342 | { | 342 | { | |
343 | int buflen, rc; | 343 | int buflen, rc; | |
344 | 344 | |||
345 | buflen = ebuflen; | 345 | buflen = ebuflen; | |
346 | if ((rc = wi_read_rid(sc, rid, buf, &buflen)) != 0) | 346 | if ((rc = wi_read_rid(sc, rid, buf, &buflen)) != 0) | |
347 | return rc; | 347 | return rc; | |
348 | 348 | |||
349 | if (buflen < ebuflen) { | 349 | if (buflen < ebuflen) { | |
350 | #ifdef WI_DEBUG | 350 | #ifdef WI_DEBUG | |
351 | printf("%s: rid=%#04x read %d, expected %d\n", __func__, | 351 | printf("%s: rid=%#04x read %d, expected %d\n", __func__, | |
352 | rid, buflen, ebuflen); | 352 | rid, buflen, ebuflen); | |
353 | #endif | 353 | #endif | |
354 | return -1; | 354 | return -1; | |
355 | } | 355 | } | |
356 | return 0; | 356 | return 0; | |
357 | } | 357 | } | |
358 | 358 | |||
359 | int | 359 | int | |
360 | wi_attach(struct wi_softc *sc, const uint8_t *macaddr) | 360 | wi_attach(struct wi_softc *sc, const uint8_t *macaddr) | |
361 | { | 361 | { | |
362 | struct ieee80211com *ic = &sc->sc_ic; | 362 | struct ieee80211com *ic = &sc->sc_ic; | |
363 | struct ifnet *ifp = &sc->sc_if; | 363 | struct ifnet *ifp = &sc->sc_if; | |
364 | int chan, nrate, buflen; | 364 | int chan, nrate, buflen; | |
365 | uint16_t val, chanavail; | 365 | uint16_t val, chanavail; | |
366 | struct { | 366 | struct { | |
367 | uint16_t nrates; | 367 | uint16_t nrates; | |
368 | char rates[IEEE80211_RATE_SIZE]; | 368 | char rates[IEEE80211_RATE_SIZE]; | |
369 | } ratebuf; | 369 | } ratebuf; | |
370 | static const uint8_t empty_macaddr[IEEE80211_ADDR_LEN] = { | 370 | static const uint8_t empty_macaddr[IEEE80211_ADDR_LEN] = { | |
371 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | 371 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | |
372 | }; | 372 | }; | |
373 | int s, rv; | 373 | int s, rv; | |
374 | 374 | |||
375 | sc->sc_soft_ih = softint_establish(SOFTINT_NET, wi_softintr, sc); | 375 | sc->sc_soft_ih = softint_establish(SOFTINT_NET, wi_softintr, sc); | |
376 | if (sc->sc_soft_ih == NULL) { | 376 | if (sc->sc_soft_ih == NULL) { | |
377 | printf(" could not establish softint\n"); | 377 | printf(" could not establish softint\n"); | |
378 | goto err; | 378 | goto err; | |
379 | } | 379 | } | |
380 | 380 | |||
381 | wi_ioctl_init(sc); | 381 | wi_ioctl_init(sc); | |
382 | 382 | |||
383 | s = splnet(); | 383 | s = splnet(); | |
384 | 384 | |||
385 | /* Make sure interrupts are disabled. */ | 385 | /* Make sure interrupts are disabled. */ | |
386 | CSR_WRITE_2(sc, WI_INT_EN, 0); | 386 | CSR_WRITE_2(sc, WI_INT_EN, 0); | |
387 | CSR_WRITE_2(sc, WI_EVENT_ACK, ~0); | 387 | CSR_WRITE_2(sc, WI_EVENT_ACK, ~0); | |
388 | 388 | |||
389 | sc->sc_invalid = 0; | 389 | sc->sc_invalid = 0; | |
390 | 390 | |||
391 | /* Reset the NIC. */ | 391 | /* Reset the NIC. */ | |
392 | if (wi_reset(sc) != 0) { | 392 | if (wi_reset(sc) != 0) { | |
393 | sc->sc_invalid = 1; | 393 | sc->sc_invalid = 1; | |
394 | goto fail; | 394 | goto fail; | |
395 | } | 395 | } | |
396 | 396 | |||
397 | if (wi_read_xrid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, | 397 | if (wi_read_xrid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, | |
398 | IEEE80211_ADDR_LEN) != 0 || | 398 | IEEE80211_ADDR_LEN) != 0 || | |
399 | IEEE80211_ADDR_EQ(ic->ic_myaddr, empty_macaddr)) { | 399 | IEEE80211_ADDR_EQ(ic->ic_myaddr, empty_macaddr)) { | |
400 | if (macaddr != NULL) | 400 | if (macaddr != NULL) | |
401 | memcpy(ic->ic_myaddr, macaddr, IEEE80211_ADDR_LEN); | 401 | memcpy(ic->ic_myaddr, macaddr, IEEE80211_ADDR_LEN); | |
402 | else { | 402 | else { | |
403 | printf(" could not get mac address, attach failed\n"); | 403 | printf(" could not get mac address, attach failed\n"); | |
404 | goto fail; | 404 | goto fail; | |
405 | } | 405 | } | |
406 | } | 406 | } | |
407 | 407 | |||
408 | printf(" 802.11 address %s\n", ether_sprintf(ic->ic_myaddr)); | 408 | printf(" 802.11 address %s\n", ether_sprintf(ic->ic_myaddr)); | |
409 | 409 | |||
410 | /* Read NIC identification */ | 410 | /* Read NIC identification */ | |
411 | wi_read_nicid(sc); | 411 | wi_read_nicid(sc); | |
412 | 412 | |||
413 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | 413 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); | |
414 | ifp->if_softc = sc; | 414 | ifp->if_softc = sc; | |
415 | ifp->if_start = wi_start; | 415 | ifp->if_start = wi_start; | |
416 | ifp->if_ioctl = wi_ioctl; | 416 | ifp->if_ioctl = wi_ioctl; | |
417 | ifp->if_watchdog = wi_watchdog; | 417 | ifp->if_watchdog = wi_watchdog; | |
418 | ifp->if_init = wi_init; | 418 | ifp->if_init = wi_init; | |
419 | ifp->if_stop = wi_stop; | 419 | ifp->if_stop = wi_stop; | |
420 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | 420 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; | |
421 | IFQ_SET_READY(&ifp->if_snd); | 421 | IFQ_SET_READY(&ifp->if_snd); | |
422 | 422 | |||
423 | ic->ic_ifp = ifp; | 423 | ic->ic_ifp = ifp; | |
424 | ic->ic_phytype = IEEE80211_T_DS; | 424 | ic->ic_phytype = IEEE80211_T_DS; | |
425 | ic->ic_opmode = IEEE80211_M_STA; | 425 | ic->ic_opmode = IEEE80211_M_STA; | |
426 | ic->ic_caps = IEEE80211_C_AHDEMO; | 426 | ic->ic_caps = IEEE80211_C_AHDEMO; | |
427 | ic->ic_state = IEEE80211_S_INIT; | 427 | ic->ic_state = IEEE80211_S_INIT; | |
428 | ic->ic_max_aid = WI_MAX_AID; | 428 | ic->ic_max_aid = WI_MAX_AID; | |
429 | 429 | |||
430 | /* Find available channel */ | 430 | /* Find available channel */ | |
431 | if (wi_read_xrid(sc, WI_RID_CHANNEL_LIST, &chanavail, | 431 | if (wi_read_xrid(sc, WI_RID_CHANNEL_LIST, &chanavail, | |
432 | sizeof(chanavail)) != 0) { | 432 | sizeof(chanavail)) != 0) { | |
433 | aprint_normal_dev(sc->sc_dev, "using default channel list\n"); | 433 | aprint_normal_dev(sc->sc_dev, "using default channel list\n"); | |
434 | chanavail = htole16(0x1fff); /* assume 1-13 */ | 434 | chanavail = htole16(0x1fff); /* assume 1-13 */ | |
435 | } | 435 | } | |
436 | for (chan = 16; chan > 0; chan--) { | 436 | for (chan = 16; chan > 0; chan--) { | |
437 | if (!isset((uint8_t*)&chanavail, chan - 1)) | 437 | if (!isset((uint8_t*)&chanavail, chan - 1)) | |
438 | continue; | 438 | continue; | |
439 | ic->ic_ibss_chan = &ic->ic_channels[chan]; | 439 | ic->ic_ibss_chan = &ic->ic_channels[chan]; | |
440 | ic->ic_channels[chan].ic_freq = | 440 | ic->ic_channels[chan].ic_freq = | |
441 | ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); | 441 | ieee80211_ieee2mhz(chan, IEEE80211_CHAN_2GHZ); | |
442 | ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_B; | 442 | ic->ic_channels[chan].ic_flags = IEEE80211_CHAN_B; | |
443 | } | 443 | } | |
444 | 444 | |||
445 | /* Find default IBSS channel */ | 445 | /* Find default IBSS channel */ | |
446 | if (wi_read_xrid(sc, WI_RID_OWN_CHNL, &val, sizeof(val)) == 0) { | 446 | if (wi_read_xrid(sc, WI_RID_OWN_CHNL, &val, sizeof(val)) == 0) { | |
447 | chan = le16toh(val); | 447 | chan = le16toh(val); | |
448 | if (isset((uint8_t*)&chanavail, chan - 1)) | 448 | if (isset((uint8_t*)&chanavail, chan - 1)) | |
449 | ic->ic_ibss_chan = &ic->ic_channels[chan]; | 449 | ic->ic_ibss_chan = &ic->ic_channels[chan]; | |
450 | } | 450 | } | |
451 | if (ic->ic_ibss_chan == NULL) { | 451 | if (ic->ic_ibss_chan == NULL) { | |
452 | aprint_error_dev(sc->sc_dev, "no available channel\n"); | 452 | aprint_error_dev(sc->sc_dev, "no available channel\n"); | |
453 | goto fail; | 453 | goto fail; | |
454 | } | 454 | } | |
455 | 455 | |||
456 | if (sc->sc_firmware_type == WI_LUCENT) { | 456 | if (sc->sc_firmware_type == WI_LUCENT) { | |
457 | sc->sc_dbm_offset = WI_LUCENT_DBM_OFFSET; | 457 | sc->sc_dbm_offset = WI_LUCENT_DBM_OFFSET; | |
458 | } else { | 458 | } else { | |
459 | if ((sc->sc_flags & WI_FLAGS_HAS_DBMADJUST) && | 459 | if ((sc->sc_flags & WI_FLAGS_HAS_DBMADJUST) && | |
460 | wi_read_xrid(sc, WI_RID_DBM_ADJUST, &val, sizeof(val)) == 0) | 460 | wi_read_xrid(sc, WI_RID_DBM_ADJUST, &val, sizeof(val)) == 0) | |
461 | sc->sc_dbm_offset = le16toh(val); | 461 | sc->sc_dbm_offset = le16toh(val); | |
462 | else | 462 | else | |
463 | sc->sc_dbm_offset = WI_PRISM_DBM_OFFSET; | 463 | sc->sc_dbm_offset = WI_PRISM_DBM_OFFSET; | |
464 | } | 464 | } | |
465 | 465 | |||
466 | sc->sc_flags |= WI_FLAGS_RSSADAPTSTA; | 466 | sc->sc_flags |= WI_FLAGS_RSSADAPTSTA; | |
467 | 467 | |||
468 | /* | 468 | /* | |
469 | * Set flags based on firmware version. | 469 | * Set flags based on firmware version. | |
470 | */ | 470 | */ | |
471 | switch (sc->sc_firmware_type) { | 471 | switch (sc->sc_firmware_type) { | |
472 | case WI_LUCENT: | 472 | case WI_LUCENT: | |
473 | sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE; | 473 | sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE; | |
474 | #ifdef WI_HERMES_AUTOINC_WAR | 474 | #ifdef WI_HERMES_AUTOINC_WAR | |
475 | /* XXX: not confirmed, but never seen for recent firmware */ | 475 | /* XXX: not confirmed, but never seen for recent firmware */ | |
476 | if (sc->sc_sta_firmware_ver < 40000) { | 476 | if (sc->sc_sta_firmware_ver < 40000) { | |
477 | sc->sc_flags |= WI_FLAGS_BUG_AUTOINC; | 477 | sc->sc_flags |= WI_FLAGS_BUG_AUTOINC; | |
478 | } | 478 | } | |
479 | #endif | 479 | #endif | |
480 | if (sc->sc_sta_firmware_ver >= 60000) | 480 | if (sc->sc_sta_firmware_ver >= 60000) | |
481 | sc->sc_flags |= WI_FLAGS_HAS_MOR; | 481 | sc->sc_flags |= WI_FLAGS_HAS_MOR; | |
482 | if (sc->sc_sta_firmware_ver >= 60006) { | 482 | if (sc->sc_sta_firmware_ver >= 60006) { | |
483 | ic->ic_caps |= IEEE80211_C_IBSS; | 483 | ic->ic_caps |= IEEE80211_C_IBSS; | |
484 | ic->ic_caps |= IEEE80211_C_MONITOR; | 484 | ic->ic_caps |= IEEE80211_C_MONITOR; | |
485 | } | 485 | } | |
486 | ic->ic_caps |= IEEE80211_C_PMGT; | 486 | ic->ic_caps |= IEEE80211_C_PMGT; | |
487 | sc->sc_ibss_port = 1; | 487 | sc->sc_ibss_port = 1; | |
488 | break; | 488 | break; | |
489 | 489 | |||
490 | case WI_INTERSIL: | 490 | case WI_INTERSIL: | |
491 | sc->sc_flags |= WI_FLAGS_HAS_FRAGTHR; | 491 | sc->sc_flags |= WI_FLAGS_HAS_FRAGTHR; | |
492 | sc->sc_flags |= WI_FLAGS_HAS_ROAMING; | 492 | sc->sc_flags |= WI_FLAGS_HAS_ROAMING; | |
493 | sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE; | 493 | sc->sc_flags |= WI_FLAGS_HAS_SYSSCALE; | |
494 | if (sc->sc_sta_firmware_ver > 10101) | 494 | if (sc->sc_sta_firmware_ver > 10101) | |
495 | sc->sc_flags |= WI_FLAGS_HAS_DBMADJUST; | 495 | sc->sc_flags |= WI_FLAGS_HAS_DBMADJUST; | |
496 | if (sc->sc_sta_firmware_ver >= 800) { | 496 | if (sc->sc_sta_firmware_ver >= 800) { | |
497 | if (sc->sc_sta_firmware_ver != 10402) | 497 | if (sc->sc_sta_firmware_ver != 10402) | |
498 | ic->ic_caps |= IEEE80211_C_HOSTAP; | 498 | ic->ic_caps |= IEEE80211_C_HOSTAP; | |
499 | ic->ic_caps |= IEEE80211_C_IBSS; | 499 | ic->ic_caps |= IEEE80211_C_IBSS; | |
500 | ic->ic_caps |= IEEE80211_C_MONITOR; | 500 | ic->ic_caps |= IEEE80211_C_MONITOR; | |
501 | } | 501 | } | |
502 | ic->ic_caps |= IEEE80211_C_PMGT; | 502 | ic->ic_caps |= IEEE80211_C_PMGT; | |
503 | sc->sc_ibss_port = 0; | 503 | sc->sc_ibss_port = 0; | |
504 | sc->sc_alt_retry = 2; | 504 | sc->sc_alt_retry = 2; | |
505 | break; | 505 | break; | |
506 | 506 | |||
507 | case WI_SYMBOL: | 507 | case WI_SYMBOL: | |
508 | sc->sc_flags |= WI_FLAGS_HAS_DIVERSITY; | 508 | sc->sc_flags |= WI_FLAGS_HAS_DIVERSITY; | |
509 | if (sc->sc_sta_firmware_ver >= 20000) | 509 | if (sc->sc_sta_firmware_ver >= 20000) | |
510 | ic->ic_caps |= IEEE80211_C_IBSS; | 510 | ic->ic_caps |= IEEE80211_C_IBSS; | |
511 | sc->sc_ibss_port = 4; | 511 | sc->sc_ibss_port = 4; | |
512 | break; | 512 | break; | |
513 | } | 513 | } | |
514 | 514 | |||
515 | /* | 515 | /* | |
516 | * Find out if we support WEP on this card. | 516 | * Find out if we support WEP on this card. | |
517 | */ | 517 | */ | |
518 | if (wi_read_xrid(sc, WI_RID_WEP_AVAIL, &val, sizeof(val)) == 0 && | 518 | if (wi_read_xrid(sc, WI_RID_WEP_AVAIL, &val, sizeof(val)) == 0 && | |
519 | val != htole16(0)) | 519 | val != htole16(0)) | |
520 | ic->ic_caps |= IEEE80211_C_WEP; | 520 | ic->ic_caps |= IEEE80211_C_WEP; | |
521 | 521 | |||
522 | /* Find supported rates. */ | 522 | /* Find supported rates. */ | |
523 | buflen = sizeof(ratebuf); | 523 | buflen = sizeof(ratebuf); | |
524 | if (wi_read_rid(sc, WI_RID_DATA_RATES, &ratebuf, &buflen) == 0 && | 524 | if (wi_read_rid(sc, WI_RID_DATA_RATES, &ratebuf, &buflen) == 0 && | |
525 | buflen > 2) { | 525 | buflen > 2) { | |
526 | nrate = le16toh(ratebuf.nrates); | 526 | nrate = le16toh(ratebuf.nrates); | |
527 | if (nrate > IEEE80211_RATE_SIZE) | 527 | if (nrate > IEEE80211_RATE_SIZE) | |
528 | nrate = IEEE80211_RATE_SIZE; | 528 | nrate = IEEE80211_RATE_SIZE; | |
529 | memcpy(ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates, | 529 | memcpy(ic->ic_sup_rates[IEEE80211_MODE_11B].rs_rates, | |
530 | &ratebuf.rates[0], nrate); | 530 | &ratebuf.rates[0], nrate); | |
531 | ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = nrate; | 531 | ic->ic_sup_rates[IEEE80211_MODE_11B].rs_nrates = nrate; | |
532 | } else { | 532 | } else { | |
533 | aprint_error_dev(sc->sc_dev, "no supported rate list\n"); | 533 | aprint_error_dev(sc->sc_dev, "no supported rate list\n"); | |
534 | goto fail; | 534 | goto fail; | |
535 | } | 535 | } | |
536 | 536 | |||
537 | sc->sc_max_datalen = 2304; | 537 | sc->sc_max_datalen = 2304; | |
538 | sc->sc_rts_thresh = 2347; | 538 | sc->sc_rts_thresh = 2347; | |
539 | sc->sc_frag_thresh = 2346; | 539 | sc->sc_frag_thresh = 2346; | |
540 | sc->sc_system_scale = 1; | 540 | sc->sc_system_scale = 1; | |
541 | sc->sc_cnfauthmode = IEEE80211_AUTH_OPEN; | 541 | sc->sc_cnfauthmode = IEEE80211_AUTH_OPEN; | |
542 | sc->sc_roaming_mode = 1; | 542 | sc->sc_roaming_mode = 1; | |
543 | 543 | |||
544 | callout_init(&sc->sc_rssadapt_ch, 0); | 544 | callout_init(&sc->sc_rssadapt_ch, 0); | |
545 | 545 | |||
546 | /* | 546 | /* | |
547 | * Call MI attach routines. | 547 | * Call MI attach routines. | |
548 | */ | 548 | */ | |
549 | rv = if_initialize(ifp); | 549 | rv = if_initialize(ifp); | |
550 | if (rv != 0) { | 550 | if (rv != 0) { | |
551 | aprint_error_dev(sc->sc_dev, "if_initialize failed(%d)\n", rv); | 551 | aprint_error_dev(sc->sc_dev, "if_initialize failed(%d)\n", rv); | |
552 | goto fail_2; | 552 | goto fail_2; | |
553 | } | 553 | } | |
554 | ieee80211_ifattach(ic); | 554 | ieee80211_ifattach(ic); | |
555 | /* Use common softint-based if_input */ | 555 | /* Use common softint-based if_input */ | |
556 | ifp->if_percpuq = if_percpuq_create(ifp); | 556 | ifp->if_percpuq = if_percpuq_create(ifp); | |
557 | if_register(ifp); | 557 | if_register(ifp); | |
558 | 558 | |||
559 | sc->sc_newstate = ic->ic_newstate; | 559 | sc->sc_newstate = ic->ic_newstate; | |
560 | sc->sc_set_tim = ic->ic_set_tim; | 560 | sc->sc_set_tim = ic->ic_set_tim; | |
561 | ic->ic_newstate = wi_newstate; | 561 | ic->ic_newstate = wi_newstate; | |
562 | ic->ic_node_alloc = wi_node_alloc; | 562 | ic->ic_node_alloc = wi_node_alloc; | |
563 | ic->ic_node_free = wi_node_free; | 563 | ic->ic_node_free = wi_node_free; | |
564 | ic->ic_set_tim = wi_set_tim; | 564 | ic->ic_set_tim = wi_set_tim; | |
565 | 565 | |||
566 | ic->ic_crypto.cs_key_delete = wi_key_delete; | 566 | ic->ic_crypto.cs_key_delete = wi_key_delete; | |
567 | ic->ic_crypto.cs_key_set = wi_key_set; | 567 | ic->ic_crypto.cs_key_set = wi_key_set; | |
568 | ic->ic_crypto.cs_key_update_begin = wi_key_update_begin; | 568 | ic->ic_crypto.cs_key_update_begin = wi_key_update_begin; | |
569 | ic->ic_crypto.cs_key_update_end = wi_key_update_end; | 569 | ic->ic_crypto.cs_key_update_end = wi_key_update_end; | |
570 | 570 | |||
571 | ieee80211_media_init(ic, wi_media_change, wi_media_status); | 571 | ieee80211_media_init(ic, wi_media_change, wi_media_status); | |
572 | 572 | |||
573 | bpf_attach2(ifp, DLT_IEEE802_11_RADIO, | 573 | bpf_attach2(ifp, DLT_IEEE802_11_RADIO, | |
574 | sizeof(struct ieee80211_frame) + 64, &sc->sc_drvbpf); | 574 | sizeof(struct ieee80211_frame) + 64, &sc->sc_drvbpf); | |
575 | 575 | |||
576 | memset(&sc->sc_rxtapu, 0, sizeof(sc->sc_rxtapu)); | 576 | memset(&sc->sc_rxtapu, 0, sizeof(sc->sc_rxtapu)); | |
577 | sc->sc_rxtap.wr_ihdr.it_len = htole16(sizeof(sc->sc_rxtapu)); | 577 | sc->sc_rxtap.wr_ihdr.it_len = htole16(sizeof(sc->sc_rxtapu)); | |
578 | sc->sc_rxtap.wr_ihdr.it_present = htole32(WI_RX_RADIOTAP_PRESENT); | 578 | sc->sc_rxtap.wr_ihdr.it_present = htole32(WI_RX_RADIOTAP_PRESENT); | |
579 | 579 | |||
580 | memset(&sc->sc_txtapu, 0, sizeof(sc->sc_txtapu)); | 580 | memset(&sc->sc_txtapu, 0, sizeof(sc->sc_txtapu)); | |
581 | sc->sc_txtap.wt_ihdr.it_len = htole16(sizeof(sc->sc_txtapu)); | 581 | sc->sc_txtap.wt_ihdr.it_len = htole16(sizeof(sc->sc_txtapu)); | |
582 | sc->sc_txtap.wt_ihdr.it_present = htole32(WI_TX_RADIOTAP_PRESENT); | 582 | sc->sc_txtap.wt_ihdr.it_present = htole32(WI_TX_RADIOTAP_PRESENT); | |
583 | 583 | |||
584 | /* Attach is successful. */ | 584 | /* Attach is successful. */ | |
585 | sc->sc_attached = 1; | 585 | sc->sc_attached = 1; | |
586 | 586 | |||
587 | splx(s); | 587 | splx(s); | |
588 | ieee80211_announce(ic); | 588 | ieee80211_announce(ic); | |
589 | return 0; | 589 | return 0; | |
590 | 590 | |||
591 | fail_2: | 591 | fail_2: | |
592 | callout_destroy(&sc->sc_rssadapt_ch); | 592 | callout_destroy(&sc->sc_rssadapt_ch); | |
593 | 593 | |||
594 | fail: splx(s); | 594 | fail: splx(s); | |
595 | softint_disestablish(sc->sc_soft_ih); | 595 | softint_disestablish(sc->sc_soft_ih); | |
596 | sc->sc_soft_ih = NULL; | 596 | sc->sc_soft_ih = NULL; | |
597 | err: return 1; | 597 | err: return 1; | |
598 | } | 598 | } | |
599 | 599 | |||
600 | int | 600 | int | |
601 | wi_detach(struct wi_softc *sc) | 601 | wi_detach(struct wi_softc *sc) | |
602 | { | 602 | { | |
603 | struct ifnet *ifp = &sc->sc_if; | 603 | struct ifnet *ifp = &sc->sc_if; | |
604 | int s; | 604 | int s; | |
605 | 605 | |||
606 | if (!sc->sc_attached) | 606 | if (!sc->sc_attached) | |
607 | return 0; | 607 | return 0; | |
608 | 608 | |||
609 | sc->sc_invalid = 1; | 609 | sc->sc_invalid = 1; | |
610 | s = splnet(); | 610 | s = splnet(); | |
611 | 611 | |||
612 | wi_stop(ifp, 1); | 612 | wi_stop(ifp, 1); | |
613 | 613 | |||
614 | ieee80211_ifdetach(&sc->sc_ic); | 614 | ieee80211_ifdetach(&sc->sc_ic); | |
615 | if_detach(ifp); | 615 | if_detach(ifp); | |
616 | splx(s); | 616 | splx(s); | |
617 | wi_ioctl_drain(sc); | 617 | wi_ioctl_drain(sc); | |
618 | softint_disestablish(sc->sc_soft_ih); | 618 | softint_disestablish(sc->sc_soft_ih); | |
619 | sc->sc_soft_ih = NULL; | 619 | sc->sc_soft_ih = NULL; | |
620 | return 0; | 620 | return 0; | |
621 | } | 621 | } | |
622 | 622 | |||
623 | int | 623 | int | |
624 | wi_activate(device_t self, enum devact act) | 624 | wi_activate(device_t self, enum devact act) | |
625 | { | 625 | { | |
626 | struct wi_softc *sc = device_private(self); | 626 | struct wi_softc *sc = device_private(self); | |
627 | 627 | |||
628 | switch (act) { | 628 | switch (act) { | |
629 | case DVACT_DEACTIVATE: | 629 | case DVACT_DEACTIVATE: | |
630 | if_deactivate(&sc->sc_if); | 630 | if_deactivate(&sc->sc_if); | |
631 | return 0; | 631 | return 0; | |
632 | default: | 632 | default: | |
633 | return EOPNOTSUPP; | 633 | return EOPNOTSUPP; | |
634 | } | 634 | } | |
635 | } | 635 | } | |
636 | 636 | |||
637 | int | 637 | int | |
638 | wi_intr(void *arg) | 638 | wi_intr(void *arg) | |
639 | { | 639 | { | |
640 | struct wi_softc *sc = arg; | 640 | struct wi_softc *sc = arg; | |
641 | struct ifnet *ifp = &sc->sc_if; | 641 | struct ifnet *ifp = &sc->sc_if; | |
642 | uint16_t status; | 642 | uint16_t status; | |
643 | 643 | |||
644 | if (sc->sc_enabled == 0 || | 644 | if (sc->sc_enabled == 0 || | |
645 | !device_is_active(sc->sc_dev) || | 645 | !device_is_active(sc->sc_dev) || | |
646 | (ifp->if_flags & IFF_RUNNING) == 0) | 646 | (ifp->if_flags & IFF_RUNNING) == 0) | |
647 | return 0; | 647 | return 0; | |
648 | 648 | |||
649 | if ((ifp->if_flags & IFF_UP) == 0) { | 649 | if ((ifp->if_flags & IFF_UP) == 0) { | |
650 | CSR_WRITE_2(sc, WI_INT_EN, 0); | 650 | CSR_WRITE_2(sc, WI_INT_EN, 0); | |
651 | CSR_WRITE_2(sc, WI_EVENT_ACK, ~0); | 651 | CSR_WRITE_2(sc, WI_EVENT_ACK, ~0); | |
652 | return 1; | 652 | return 1; | |
653 | } | 653 | } | |
654 | 654 | |||
655 | /* This is superfluous on Prism, but Lucent breaks if we | 655 | /* This is superfluous on Prism, but Lucent breaks if we | |
656 | * do not disable interrupts. | 656 | * do not disable interrupts. | |
657 | */ | 657 | */ | |
658 | CSR_WRITE_2(sc, WI_INT_EN, 0); | 658 | CSR_WRITE_2(sc, WI_INT_EN, 0); | |
659 | 659 | |||
660 | status = CSR_READ_2(sc, WI_EVENT_STAT); | 660 | status = CSR_READ_2(sc, WI_EVENT_STAT); | |
661 | #ifdef WI_DEBUG | 661 | #ifdef WI_DEBUG | |
662 | if (wi_debug > 1) { | 662 | if (wi_debug > 1) { | |
663 | printf("%s: status %#04x\n", __func__, status); | 663 | printf("%s: status %#04x\n", __func__, status); | |
664 | } | 664 | } | |
665 | #endif /* WI_DEBUG */ | 665 | #endif /* WI_DEBUG */ | |
666 | if ((status & WI_INTRS) == 0) { | 666 | if ((status & WI_INTRS) == 0) { | |
667 | /* re-enable interrupts */ | 667 | /* re-enable interrupts */ | |
668 | CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); | 668 | CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); | |
669 | return 0; | 669 | return 0; | |
670 | } | 670 | } | |
671 | 671 | |||
672 | softint_schedule(sc->sc_soft_ih); | 672 | softint_schedule(sc->sc_soft_ih); | |
673 | return 1; | 673 | return 1; | |
674 | } | 674 | } | |
675 | 675 | |||
676 | STATIC void | 676 | STATIC void | |
677 | wi_softintr(void *arg) | 677 | wi_softintr(void *arg) | |
678 | { | 678 | { | |
679 | int i, s; | 679 | int i, s; | |
680 | struct wi_softc *sc = arg; | 680 | struct wi_softc *sc = arg; | |
681 | struct ifnet *ifp = &sc->sc_if; | 681 | struct ifnet *ifp = &sc->sc_if; | |
682 | uint16_t status; | 682 | uint16_t status; | |
683 | 683 | |||
684 | if (sc->sc_enabled == 0 || | 684 | if (sc->sc_enabled == 0 || | |
685 | !device_is_active(sc->sc_dev) || | 685 | !device_is_active(sc->sc_dev) || | |
686 | (ifp->if_flags & IFF_RUNNING) == 0) | 686 | (ifp->if_flags & IFF_RUNNING) == 0) | |
687 | goto out; | 687 | goto out; | |
688 | 688 | |||
689 | if ((ifp->if_flags & IFF_UP) == 0) { | 689 | if ((ifp->if_flags & IFF_UP) == 0) { | |
690 | CSR_WRITE_2(sc, WI_EVENT_ACK, ~0); | 690 | CSR_WRITE_2(sc, WI_EVENT_ACK, ~0); | |
691 | return; | 691 | return; | |
692 | } | 692 | } | |
693 | 693 | |||
694 | /* maximum 10 loops per interrupt */ | 694 | /* maximum 10 loops per interrupt */ | |
695 | for (i = 0; i < 10; i++) { | 695 | for (i = 0; i < 10; i++) { | |
696 | status = CSR_READ_2(sc, WI_EVENT_STAT); | 696 | status = CSR_READ_2(sc, WI_EVENT_STAT); | |
697 | #ifdef WI_DEBUG | 697 | #ifdef WI_DEBUG | |
698 | if (wi_debug > 1) { | 698 | if (wi_debug > 1) { | |
699 | printf("%s: iter %d status %#04x\n", __func__, i, | 699 | printf("%s: iter %d status %#04x\n", __func__, i, | |
700 | status); | 700 | status); | |
701 | } | 701 | } | |
702 | #endif /* WI_DEBUG */ | 702 | #endif /* WI_DEBUG */ | |
703 | if ((status & WI_INTRS) == 0) | 703 | if ((status & WI_INTRS) == 0) | |
704 | break; | 704 | break; | |
705 | 705 | |||
706 | sc->sc_status = status; | 706 | sc->sc_status = status; | |
707 | 707 | |||
708 | if (status & WI_EV_RX) | 708 | if (status & WI_EV_RX) | |
709 | wi_rx_intr(sc); | 709 | wi_rx_intr(sc); | |
710 | 710 | |||
711 | if (status & WI_EV_ALLOC) | 711 | if (status & WI_EV_ALLOC) | |
712 | wi_txalloc_intr(sc); | 712 | wi_txalloc_intr(sc); | |
713 | 713 | |||
714 | if (status & WI_EV_TX) | 714 | if (status & WI_EV_TX) | |
715 | wi_tx_intr(sc); | 715 | wi_tx_intr(sc); | |
716 | 716 | |||
717 | if (status & WI_EV_TX_EXC) | 717 | if (status & WI_EV_TX_EXC) | |
718 | wi_tx_ex_intr(sc); | 718 | wi_tx_ex_intr(sc); | |
719 | 719 | |||
720 | if (status & WI_EV_INFO) | 720 | if (status & WI_EV_INFO) | |
721 | wi_info_intr(sc); | 721 | wi_info_intr(sc); | |
722 | 722 | |||
723 | CSR_WRITE_2(sc, WI_EVENT_ACK, sc->sc_status); | 723 | CSR_WRITE_2(sc, WI_EVENT_ACK, sc->sc_status); | |
724 | 724 | |||
725 | if (sc->sc_status & WI_EV_CMD) | 725 | if (sc->sc_status & WI_EV_CMD) | |
726 | wi_cmd_intr(sc); | 726 | wi_cmd_intr(sc); | |
727 | 727 | |||
728 | if ((ifp->if_flags & IFF_OACTIVE) == 0 && | 728 | if ((ifp->if_flags & IFF_OACTIVE) == 0 && | |
729 | (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0 && | 729 | (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0 && | |
730 | !IFQ_IS_EMPTY(&ifp->if_snd)) { | 730 | !IFQ_IS_EMPTY(&ifp->if_snd)) { | |
731 | s = splnet(); | 731 | s = splnet(); | |
732 | wi_start(ifp); | 732 | wi_start(ifp); | |
733 | splx(s); | 733 | splx(s); | |
734 | } | 734 | } | |
735 | 735 | |||
736 | sc->sc_status = 0; | 736 | sc->sc_status = 0; | |
737 | } | 737 | } | |
738 | if (i == 10) | 738 | if (i == 10) | |
739 | softint_schedule(sc->sc_soft_ih); | 739 | softint_schedule(sc->sc_soft_ih); | |
740 | 740 | |||
741 | out: | 741 | out: | |
742 | sc->sc_status = 0; | 742 | sc->sc_status = 0; | |
743 | 743 | |||
744 | /* re-enable interrupts */ | 744 | /* re-enable interrupts */ | |
745 | CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); | 745 | CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); | |
746 | } | 746 | } | |
747 | 747 | |||
748 | #define arraylen(a) (sizeof(a) / sizeof((a)[0])) | 748 | #define arraylen(a) (sizeof(a) / sizeof((a)[0])) | |
749 | 749 | |||
750 | STATIC void | 750 | STATIC void | |
751 | wi_rssdescs_init(struct wi_rssdesc (*rssd)[WI_NTXRSS], wi_rssdescq_t *rssdfree) | 751 | wi_rssdescs_init(struct wi_rssdesc (*rssd)[WI_NTXRSS], wi_rssdescq_t *rssdfree) | |
752 | { | 752 | { | |
753 | int i; | 753 | int i; | |
754 | SLIST_INIT(rssdfree); | 754 | SLIST_INIT(rssdfree); | |
755 | for (i = 0; i < arraylen(*rssd); i++) { | 755 | for (i = 0; i < arraylen(*rssd); i++) { | |
756 | SLIST_INSERT_HEAD(rssdfree, &(*rssd)[i], rd_next); | 756 | SLIST_INSERT_HEAD(rssdfree, &(*rssd)[i], rd_next); | |
757 | } | 757 | } | |
758 | } | 758 | } | |
759 | 759 | |||
760 | STATIC void | 760 | STATIC void | |
761 | wi_rssdescs_reset(struct ieee80211com *ic, struct wi_rssdesc (*rssd)[WI_NTXRSS], | 761 | wi_rssdescs_reset(struct ieee80211com *ic, struct wi_rssdesc (*rssd)[WI_NTXRSS], | |
762 | wi_rssdescq_t *rssdfree, uint8_t (*txpending)[IEEE80211_RATE_MAXSIZE]) | 762 | wi_rssdescq_t *rssdfree, uint8_t (*txpending)[IEEE80211_RATE_MAXSIZE]) | |
763 | { | 763 | { | |
764 | struct ieee80211_node *ni; | 764 | struct ieee80211_node *ni; | |
765 | int i; | 765 | int i; | |
766 | for (i = 0; i < arraylen(*rssd); i++) { | 766 | for (i = 0; i < arraylen(*rssd); i++) { | |
767 | ni = (*rssd)[i].rd_desc.id_node; | 767 | ni = (*rssd)[i].rd_desc.id_node; | |
768 | (*rssd)[i].rd_desc.id_node = NULL; | 768 | (*rssd)[i].rd_desc.id_node = NULL; | |
769 | if (ni != NULL && (ic->ic_ifp->if_flags & IFF_DEBUG) != 0) | 769 | if (ni != NULL && (ic->ic_ifp->if_flags & IFF_DEBUG) != 0) | |
770 | printf("%s: cleaning outstanding rssadapt " | 770 | printf("%s: cleaning outstanding rssadapt " | |
771 | "descriptor for %s\n", | 771 | "descriptor for %s\n", | |
772 | ic->ic_ifp->if_xname, ether_sprintf(ni->ni_macaddr)); | 772 | ic->ic_ifp->if_xname, ether_sprintf(ni->ni_macaddr)); | |
773 | if (ni != NULL) | 773 | if (ni != NULL) | |
774 | ieee80211_free_node(ni); | 774 | ieee80211_free_node(ni); | |
775 | } | 775 | } | |
776 | memset(*txpending, 0, sizeof(*txpending)); | 776 | memset(*txpending, 0, sizeof(*txpending)); | |
777 | wi_rssdescs_init(rssd, rssdfree); | 777 | wi_rssdescs_init(rssd, rssdfree); | |
778 | } | 778 | } | |
779 | 779 | |||
780 | STATIC int | 780 | STATIC int | |
781 | wi_init(struct ifnet *ifp) | 781 | wi_init(struct ifnet *ifp) | |
782 | { | 782 | { | |
783 | struct wi_softc *sc = ifp->if_softc; | 783 | struct wi_softc *sc = ifp->if_softc; | |
784 | struct ieee80211com *ic = &sc->sc_ic; | 784 | struct ieee80211com *ic = &sc->sc_ic; | |
785 | struct wi_joinreq join; | 785 | struct wi_joinreq join; | |
786 | int i; | 786 | int i; | |
787 | int error = 0, wasenabled; | 787 | int error = 0, wasenabled; | |
788 | 788 | |||
789 | DPRINTF(("wi_init: enabled %d\n", sc->sc_enabled)); | 789 | DPRINTF(("wi_init: enabled %d\n", sc->sc_enabled)); | |
790 | wasenabled = sc->sc_enabled; | 790 | wasenabled = sc->sc_enabled; | |
791 | if (!sc->sc_enabled) { | 791 | if (!sc->sc_enabled) { | |
792 | if ((error = (*sc->sc_enable)(sc->sc_dev, 1)) != 0) | 792 | if ((error = (*sc->sc_enable)(sc->sc_dev, 1)) != 0) | |
793 | goto out; | 793 | goto out; | |
794 | sc->sc_enabled = 1; | 794 | sc->sc_enabled = 1; | |
795 | } else | 795 | } else | |
796 | wi_stop(ifp, 0); | 796 | wi_stop(ifp, 0); | |
797 | 797 | |||
798 | /* Symbol firmware cannot be initialized more than once */ | 798 | /* Symbol firmware cannot be initialized more than once */ | |
799 | if (sc->sc_firmware_type != WI_SYMBOL || !wasenabled) | 799 | if (sc->sc_firmware_type != WI_SYMBOL || !wasenabled) | |
800 | if ((error = wi_reset(sc)) != 0) | 800 | if ((error = wi_reset(sc)) != 0) | |
801 | goto out; | 801 | goto out; | |
802 | 802 | |||
803 | /* common 802.11 configuration */ | 803 | /* common 802.11 configuration */ | |
804 | ic->ic_flags &= ~IEEE80211_F_IBSSON; | 804 | ic->ic_flags &= ~IEEE80211_F_IBSSON; | |
805 | sc->sc_flags &= ~WI_FLAGS_OUTRANGE; | 805 | sc->sc_flags &= ~WI_FLAGS_OUTRANGE; | |
806 | switch (ic->ic_opmode) { | 806 | switch (ic->ic_opmode) { | |
807 | case IEEE80211_M_STA: | 807 | case IEEE80211_M_STA: | |
808 | wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_BSS); | 808 | wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_BSS); | |
809 | break; | 809 | break; | |
810 | case IEEE80211_M_IBSS: | 810 | case IEEE80211_M_IBSS: | |
811 | wi_write_val(sc, WI_RID_PORTTYPE, sc->sc_ibss_port); | 811 | wi_write_val(sc, WI_RID_PORTTYPE, sc->sc_ibss_port); | |
812 | ic->ic_flags |= IEEE80211_F_IBSSON; | 812 | ic->ic_flags |= IEEE80211_F_IBSSON; | |
813 | break; | 813 | break; | |
814 | case IEEE80211_M_AHDEMO: | 814 | case IEEE80211_M_AHDEMO: | |
815 | wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_ADHOC); | 815 | wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_ADHOC); | |
816 | break; | 816 | break; | |
817 | case IEEE80211_M_HOSTAP: | 817 | case IEEE80211_M_HOSTAP: | |
818 | wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_HOSTAP); | 818 | wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_HOSTAP); | |
819 | break; | 819 | break; | |
820 | case IEEE80211_M_MONITOR: | 820 | case IEEE80211_M_MONITOR: | |
821 | if (sc->sc_firmware_type == WI_LUCENT) | 821 | if (sc->sc_firmware_type == WI_LUCENT) | |
822 | wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_ADHOC); | 822 | wi_write_val(sc, WI_RID_PORTTYPE, WI_PORTTYPE_ADHOC); | |
823 | wi_cmd(sc, WI_CMD_TEST | (WI_TEST_MONITOR << 8), 0, 0, 0); | 823 | wi_cmd(sc, WI_CMD_TEST | (WI_TEST_MONITOR << 8), 0, 0, 0); | |
824 | break; | 824 | break; | |
825 | } | 825 | } | |
826 | 826 | |||
827 | /* Intersil interprets this RID as joining ESS even in IBSS mode */ | 827 | /* Intersil interprets this RID as joining ESS even in IBSS mode */ | |
828 | if (sc->sc_firmware_type == WI_LUCENT && | 828 | if (sc->sc_firmware_type == WI_LUCENT && | |
829 | (ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_esslen > 0) | 829 | (ic->ic_flags & IEEE80211_F_IBSSON) && ic->ic_des_esslen > 0) | |
830 | wi_write_val(sc, WI_RID_CREATE_IBSS, 1); | 830 | wi_write_val(sc, WI_RID_CREATE_IBSS, 1); | |
831 | else | 831 | else | |
832 | wi_write_val(sc, WI_RID_CREATE_IBSS, 0); | 832 | wi_write_val(sc, WI_RID_CREATE_IBSS, 0); | |
833 | wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval); | 833 | wi_write_val(sc, WI_RID_MAX_SLEEP, ic->ic_lintval); | |
834 | wi_write_ssid(sc, WI_RID_DESIRED_SSID, ic->ic_des_essid, | 834 | wi_write_ssid(sc, WI_RID_DESIRED_SSID, ic->ic_des_essid, | |
835 | ic->ic_des_esslen); | 835 | ic->ic_des_esslen); | |
836 | wi_write_val(sc, WI_RID_OWN_CHNL, | 836 | wi_write_val(sc, WI_RID_OWN_CHNL, | |
837 | ieee80211_chan2ieee(ic, ic->ic_ibss_chan)); | 837 | ieee80211_chan2ieee(ic, ic->ic_ibss_chan)); | |
838 | wi_write_ssid(sc, WI_RID_OWN_SSID, ic->ic_des_essid, ic->ic_des_esslen); | 838 | wi_write_ssid(sc, WI_RID_OWN_SSID, ic->ic_des_essid, ic->ic_des_esslen); | |
839 | IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl)); | 839 | IEEE80211_ADDR_COPY(ic->ic_myaddr, CLLADDR(ifp->if_sadl)); | |
840 | wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN); | 840 | wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, IEEE80211_ADDR_LEN); | |
841 | if (ic->ic_caps & IEEE80211_C_PMGT) | 841 | if (ic->ic_caps & IEEE80211_C_PMGT) | |
842 | wi_write_val(sc, WI_RID_PM_ENABLED, | 842 | wi_write_val(sc, WI_RID_PM_ENABLED, | |
843 | (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0); | 843 | (ic->ic_flags & IEEE80211_F_PMGTON) ? 1 : 0); | |
844 | 844 | |||
845 | /* not yet common 802.11 configuration */ | 845 | /* not yet common 802.11 configuration */ | |
846 | wi_write_val(sc, WI_RID_MAX_DATALEN, sc->sc_max_datalen); | 846 | wi_write_val(sc, WI_RID_MAX_DATALEN, sc->sc_max_datalen); | |
847 | wi_write_val(sc, WI_RID_RTS_THRESH, sc->sc_rts_thresh); | 847 | wi_write_val(sc, WI_RID_RTS_THRESH, sc->sc_rts_thresh); | |
848 | if (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR) | 848 | if (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR) | |
849 | wi_write_val(sc, WI_RID_FRAG_THRESH, sc->sc_frag_thresh); | 849 | wi_write_val(sc, WI_RID_FRAG_THRESH, sc->sc_frag_thresh); | |
850 | 850 | |||
851 | /* driver specific 802.11 configuration */ | 851 | /* driver specific 802.11 configuration */ | |
852 | if (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE) | 852 | if (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE) | |
853 | wi_write_val(sc, WI_RID_SYSTEM_SCALE, sc->sc_system_scale); | 853 | wi_write_val(sc, WI_RID_SYSTEM_SCALE, sc->sc_system_scale); | |
854 | if (sc->sc_flags & WI_FLAGS_HAS_ROAMING) | 854 | if (sc->sc_flags & WI_FLAGS_HAS_ROAMING) | |
855 | wi_write_val(sc, WI_RID_ROAMING_MODE, sc->sc_roaming_mode); | 855 | wi_write_val(sc, WI_RID_ROAMING_MODE, sc->sc_roaming_mode); | |
856 | if (sc->sc_flags & WI_FLAGS_HAS_MOR) | 856 | if (sc->sc_flags & WI_FLAGS_HAS_MOR) | |
857 | wi_write_val(sc, WI_RID_MICROWAVE_OVEN, sc->sc_microwave_oven); | 857 | wi_write_val(sc, WI_RID_MICROWAVE_OVEN, sc->sc_microwave_oven); | |
858 | wi_cfg_txrate(sc); | 858 | wi_cfg_txrate(sc); | |
859 | wi_write_ssid(sc, WI_RID_NODENAME, sc->sc_nodename, sc->sc_nodelen); | 859 | wi_write_ssid(sc, WI_RID_NODENAME, sc->sc_nodename, sc->sc_nodelen); | |
860 | 860 | |||
861 | #ifndef IEEE80211_NO_HOSTAP | 861 | #ifndef IEEE80211_NO_HOSTAP | |
862 | if (ic->ic_opmode == IEEE80211_M_HOSTAP && | 862 | if (ic->ic_opmode == IEEE80211_M_HOSTAP && | |
863 | sc->sc_firmware_type == WI_INTERSIL) { | 863 | sc->sc_firmware_type == WI_INTERSIL) { | |
864 | wi_write_val(sc, WI_RID_OWN_BEACON_INT, ic->ic_lintval); | 864 | wi_write_val(sc, WI_RID_OWN_BEACON_INT, ic->ic_lintval); | |
865 | wi_write_val(sc, WI_RID_DTIM_PERIOD, 1); | 865 | wi_write_val(sc, WI_RID_DTIM_PERIOD, 1); | |
866 | } | 866 | } | |
867 | #endif /* !IEEE80211_NO_HOSTAP */ | 867 | #endif /* !IEEE80211_NO_HOSTAP */ | |
868 | 868 | |||
869 | if (sc->sc_firmware_type == WI_INTERSIL) { | 869 | if (sc->sc_firmware_type == WI_INTERSIL) { | |
870 | struct ieee80211_rateset *rs = | 870 | struct ieee80211_rateset *rs = | |
871 | &ic->ic_sup_rates[IEEE80211_MODE_11B]; | 871 | &ic->ic_sup_rates[IEEE80211_MODE_11B]; | |
872 | uint16_t basic = 0, supported = 0, rate; | 872 | uint16_t basic = 0, supported = 0, rate; | |
873 | 873 | |||
874 | for (i = 0; i < rs->rs_nrates; i++) { | 874 | for (i = 0; i < rs->rs_nrates; i++) { | |
875 | switch (rs->rs_rates[i] & IEEE80211_RATE_VAL) { | 875 | switch (rs->rs_rates[i] & IEEE80211_RATE_VAL) { | |
876 | case 2: | 876 | case 2: | |
877 | rate = 1; | 877 | rate = 1; | |
878 | break; | 878 | break; | |
879 | case 4: | 879 | case 4: | |
880 | rate = 2; | 880 | rate = 2; | |
881 | break; | 881 | break; | |
882 | case 11: | 882 | case 11: | |
883 | rate = 4; | 883 | rate = 4; | |
884 | break; | 884 | break; | |
885 | case 22: | 885 | case 22: | |
886 | rate = 8; | 886 | rate = 8; | |
887 | break; | 887 | break; | |
888 | default: | 888 | default: | |
889 | rate = 0; | 889 | rate = 0; | |
890 | break; | 890 | break; | |
891 | } | 891 | } | |
892 | if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) | 892 | if (rs->rs_rates[i] & IEEE80211_RATE_BASIC) | |
893 | basic |= rate; | 893 | basic |= rate; | |
894 | supported |= rate; | 894 | supported |= rate; | |
895 | } | 895 | } | |
896 | wi_write_val(sc, WI_RID_BASIC_RATE, basic); | 896 | wi_write_val(sc, WI_RID_BASIC_RATE, basic); | |
897 | wi_write_val(sc, WI_RID_SUPPORT_RATE, supported); | 897 | wi_write_val(sc, WI_RID_SUPPORT_RATE, supported); | |
898 | wi_write_val(sc, WI_RID_ALT_RETRY_COUNT, sc->sc_alt_retry); | 898 | wi_write_val(sc, WI_RID_ALT_RETRY_COUNT, sc->sc_alt_retry); | |
899 | } | 899 | } | |
900 | 900 | |||
901 | /* | 901 | /* | |
902 | * Initialize promisc mode. | 902 | * Initialize promisc mode. | |
903 | * Being in Host-AP mode causes a great | 903 | * Being in Host-AP mode causes a great | |
904 | * deal of pain if promiscuous mode is set. | 904 | * deal of pain if promiscuous mode is set. | |
905 | * Therefore we avoid confusing the firmware | 905 | * Therefore we avoid confusing the firmware | |
906 | * and always reset promisc mode in Host-AP | 906 | * and always reset promisc mode in Host-AP | |
907 | * mode. Host-AP sees all the packets anyway. | 907 | * mode. Host-AP sees all the packets anyway. | |
908 | */ | 908 | */ | |
909 | if (ic->ic_opmode != IEEE80211_M_HOSTAP && | 909 | if (ic->ic_opmode != IEEE80211_M_HOSTAP && | |
910 | (ifp->if_flags & IFF_PROMISC) != 0) { | 910 | (ifp->if_flags & IFF_PROMISC) != 0) { | |
911 | wi_write_val(sc, WI_RID_PROMISC, 1); | 911 | wi_write_val(sc, WI_RID_PROMISC, 1); | |
912 | } else { | 912 | } else { | |
913 | wi_write_val(sc, WI_RID_PROMISC, 0); | 913 | wi_write_val(sc, WI_RID_PROMISC, 0); | |
914 | } | 914 | } | |
915 | 915 | |||
916 | /* Configure WEP. */ | 916 | /* Configure WEP. */ | |
917 | if (ic->ic_caps & IEEE80211_C_WEP) { | 917 | if (ic->ic_caps & IEEE80211_C_WEP) { | |
918 | sc->sc_cnfauthmode = ic->ic_bss->ni_authmode; | 918 | sc->sc_cnfauthmode = ic->ic_bss->ni_authmode; | |
919 | wi_write_wep(sc); | 919 | wi_write_wep(sc); | |
920 | } | 920 | } | |
921 | 921 | |||
922 | /* Set multicast filter. */ | 922 | /* Set multicast filter. */ | |
923 | wi_write_multi(sc); | 923 | wi_write_multi(sc); | |
924 | 924 | |||
925 | sc->sc_txalloc = 0; | 925 | sc->sc_txalloc = 0; | |
926 | sc->sc_txalloced = 0; | 926 | sc->sc_txalloced = 0; | |
927 | sc->sc_txqueue = 0; | 927 | sc->sc_txqueue = 0; | |
928 | sc->sc_txqueued = 0; | 928 | sc->sc_txqueued = 0; | |
929 | sc->sc_txstart = 0; | 929 | sc->sc_txstart = 0; | |
930 | sc->sc_txstarted = 0; | 930 | sc->sc_txstarted = 0; | |
931 | 931 | |||
932 | if (sc->sc_firmware_type != WI_SYMBOL || !wasenabled) { | 932 | if (sc->sc_firmware_type != WI_SYMBOL || !wasenabled) { | |
933 | sc->sc_buflen = IEEE80211_MAX_LEN + sizeof(struct wi_frame); | 933 | sc->sc_buflen = IEEE80211_MAX_LEN + sizeof(struct wi_frame); | |
934 | if (sc->sc_firmware_type == WI_SYMBOL) | 934 | if (sc->sc_firmware_type == WI_SYMBOL) | |
935 | sc->sc_buflen = 1585; /* XXX */ | 935 | sc->sc_buflen = 1585; /* XXX */ | |
936 | for (i = 0; i < WI_NTXBUF; i++) { | 936 | for (i = 0; i < WI_NTXBUF; i++) { | |
937 | error = wi_alloc_fid(sc, sc->sc_buflen, | 937 | error = wi_alloc_fid(sc, sc->sc_buflen, | |
938 | &sc->sc_txd[i].d_fid); | 938 | &sc->sc_txd[i].d_fid); | |
939 | if (error) { | 939 | if (error) { | |
940 | aprint_error_dev(sc->sc_dev, | 940 | aprint_error_dev(sc->sc_dev, | |
941 | "tx buffer allocation failed\n"); | 941 | "tx buffer allocation failed\n"); | |
942 | goto out; | 942 | goto out; | |
943 | } | 943 | } | |
944 | DPRINTF2(("wi_init: txbuf %d allocated %x\n", i, | 944 | DPRINTF2(("wi_init: txbuf %d allocated %x\n", i, | |
945 | sc->sc_txd[i].d_fid)); | 945 | sc->sc_txd[i].d_fid)); | |
946 | ++sc->sc_txalloced; | 946 | ++sc->sc_txalloced; | |
947 | } | 947 | } | |
948 | } | 948 | } | |
949 | 949 | |||
950 | wi_rssdescs_init(&sc->sc_rssd, &sc->sc_rssdfree); | 950 | wi_rssdescs_init(&sc->sc_rssd, &sc->sc_rssdfree); | |
951 | 951 | |||
952 | /* Enable desired port */ | 952 | /* Enable desired port */ | |
953 | wi_cmd(sc, WI_CMD_ENABLE | sc->sc_portnum, 0, 0, 0); | 953 | wi_cmd(sc, WI_CMD_ENABLE | sc->sc_portnum, 0, 0, 0); | |
954 | ifp->if_flags |= IFF_RUNNING; | 954 | ifp->if_flags |= IFF_RUNNING; | |
955 | ifp->if_flags &= ~IFF_OACTIVE; | 955 | ifp->if_flags &= ~IFF_OACTIVE; | |
956 | ic->ic_state = IEEE80211_S_INIT; | 956 | ic->ic_state = IEEE80211_S_INIT; | |
957 | 957 | |||
958 | if (ic->ic_opmode == IEEE80211_M_AHDEMO || | 958 | if (ic->ic_opmode == IEEE80211_M_AHDEMO || | |
959 | ic->ic_opmode == IEEE80211_M_IBSS || | 959 | ic->ic_opmode == IEEE80211_M_IBSS || | |
960 | ic->ic_opmode == IEEE80211_M_MONITOR || | 960 | ic->ic_opmode == IEEE80211_M_MONITOR || | |
961 | ic->ic_opmode == IEEE80211_M_HOSTAP) | 961 | ic->ic_opmode == IEEE80211_M_HOSTAP) | |
962 | ieee80211_create_ibss(ic, ic->ic_ibss_chan); | 962 | ieee80211_create_ibss(ic, ic->ic_ibss_chan); | |
963 | 963 | |||
964 | /* Enable interrupts */ | 964 | /* Enable interrupts */ | |
965 | CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); | 965 | CSR_WRITE_2(sc, WI_INT_EN, WI_INTRS); | |
966 | 966 | |||
967 | #ifndef IEEE80211_NO_HOSTAP | 967 | #ifndef IEEE80211_NO_HOSTAP | |
968 | if (!wasenabled && | 968 | if (!wasenabled && | |
969 | ic->ic_opmode == IEEE80211_M_HOSTAP && | 969 | ic->ic_opmode == IEEE80211_M_HOSTAP && | |
970 | sc->sc_firmware_type == WI_INTERSIL) { | 970 | sc->sc_firmware_type == WI_INTERSIL) { | |
971 | /* XXX: some card need to be re-enabled for hostap */ | 971 | /* XXX: some card need to be re-enabled for hostap */ | |
972 | wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0); | 972 | wi_cmd(sc, WI_CMD_DISABLE | WI_PORT0, 0, 0, 0); | |
973 | wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0); | 973 | wi_cmd(sc, WI_CMD_ENABLE | WI_PORT0, 0, 0, 0); | |
974 | } | 974 | } | |
975 | #endif /* !IEEE80211_NO_HOSTAP */ | 975 | #endif /* !IEEE80211_NO_HOSTAP */ | |
976 | 976 | |||
977 | if (ic->ic_opmode == IEEE80211_M_STA && | 977 | if (ic->ic_opmode == IEEE80211_M_STA && | |
978 | ((ic->ic_flags & IEEE80211_F_DESBSSID) || | 978 | ((ic->ic_flags & IEEE80211_F_DESBSSID) || | |
979 | ic->ic_des_chan != IEEE80211_CHAN_ANYC)) { | 979 | ic->ic_des_chan != IEEE80211_CHAN_ANYC)) { | |
980 | memset(&join, 0, sizeof(join)); | 980 | memset(&join, 0, sizeof(join)); | |
981 | if (ic->ic_flags & IEEE80211_F_DESBSSID) | 981 | if (ic->ic_flags & IEEE80211_F_DESBSSID) | |
982 | IEEE80211_ADDR_COPY(&join.wi_bssid, ic->ic_des_bssid); | 982 | IEEE80211_ADDR_COPY(&join.wi_bssid, ic->ic_des_bssid); | |
983 | if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) | 983 | if (ic->ic_des_chan != IEEE80211_CHAN_ANYC) | |
984 | join.wi_chan = | 984 | join.wi_chan = | |
985 | htole16(ieee80211_chan2ieee(ic, ic->ic_des_chan)); | 985 | htole16(ieee80211_chan2ieee(ic, ic->ic_des_chan)); | |
986 | /* Lucent firmware does not support the JOIN RID. */ | 986 | /* Lucent firmware does not support the JOIN RID. */ | |
987 | if (sc->sc_firmware_type != WI_LUCENT) | 987 | if (sc->sc_firmware_type != WI_LUCENT) | |
988 | wi_write_rid(sc, WI_RID_JOIN_REQ, &join, sizeof(join)); | 988 | wi_write_rid(sc, WI_RID_JOIN_REQ, &join, sizeof(join)); | |
989 | } | 989 | } | |
990 | 990 | |||
991 | out: | 991 | out: | |
992 | if (error) { | 992 | if (error) { | |
993 | printf("%s: interface not running\n", device_xname(sc->sc_dev)); | 993 | printf("%s: interface not running\n", device_xname(sc->sc_dev)); | |
994 | wi_stop(ifp, 0); | 994 | wi_stop(ifp, 0); | |
995 | } | 995 | } | |
996 | DPRINTF(("wi_init: return %d\n", error)); | 996 | DPRINTF(("wi_init: return %d\n", error)); | |
997 | return error; | 997 | return error; | |
998 | } | 998 | } | |
999 | 999 | |||
1000 | STATIC void | 1000 | STATIC void | |
1001 | wi_txcmd_wait(struct wi_softc *sc) | 1001 | wi_txcmd_wait(struct wi_softc *sc) | |
1002 | { | 1002 | { | |
1003 | KASSERT(sc->sc_txcmds == 1); | 1003 | KASSERT(sc->sc_txcmds == 1); | |
1004 | if (sc->sc_status & WI_EV_CMD) { | 1004 | if (sc->sc_status & WI_EV_CMD) { | |
1005 | sc->sc_status &= ~WI_EV_CMD; | 1005 | sc->sc_status &= ~WI_EV_CMD; | |
1006 | CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD); | 1006 | CSR_WRITE_2(sc, WI_EVENT_ACK, WI_EV_CMD); | |
1007 | } else | 1007 | } else | |
1008 | (void)wi_cmd_wait(sc, WI_CMD_TX | WI_RECLAIM, 0); | 1008 | (void)wi_cmd_wait(sc, WI_CMD_TX | WI_RECLAIM, 0); | |
1009 | } | 1009 | } | |
1010 | 1010 | |||
1011 | STATIC void | 1011 | STATIC void | |
1012 | wi_stop(struct ifnet *ifp, int disable) | 1012 | wi_stop(struct ifnet *ifp, int disable) | |
1013 | { | 1013 | { | |
1014 | struct wi_softc *sc = ifp->if_softc; | 1014 | struct wi_softc *sc = ifp->if_softc; | |
1015 | struct ieee80211com *ic = &sc->sc_ic; | 1015 | struct ieee80211com *ic = &sc->sc_ic; | |
1016 | int s; | 1016 | int s; | |
1017 | 1017 | |||
1018 | if (!sc->sc_enabled) | 1018 | if (!sc->sc_enabled) | |
1019 | return; | 1019 | return; | |
1020 | 1020 | |||
1021 | s = splnet(); | 1021 | s = splnet(); | |
1022 | 1022 | |||
1023 | DPRINTF(("wi_stop: disable %d\n", disable)); | 1023 | DPRINTF(("wi_stop: disable %d\n", disable)); | |
1024 | 1024 | |||
1025 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | 1025 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | |
1026 | 1026 | |||
1027 | /* wait for tx command completion (deassoc, deauth) */ | 1027 | /* wait for tx command completion (deassoc, deauth) */ | |
1028 | while (sc->sc_txcmds > 0) { | 1028 | while (sc->sc_txcmds > 0) { | |
1029 | wi_txcmd_wait(sc); | 1029 | wi_txcmd_wait(sc); | |
1030 | wi_cmd_intr(sc); | 1030 | wi_cmd_intr(sc); | |
1031 | } | 1031 | } | |
1032 | 1032 | |||
1033 | /* TBD wait for deassoc, deauth tx completion? */ | 1033 | /* TBD wait for deassoc, deauth tx completion? */ | |
1034 | 1034 | |||
1035 | if (!sc->sc_invalid) { | 1035 | if (!sc->sc_invalid) { | |
1036 | CSR_WRITE_2(sc, WI_INT_EN, 0); | 1036 | CSR_WRITE_2(sc, WI_INT_EN, 0); | |
1037 | wi_cmd(sc, WI_CMD_DISABLE | sc->sc_portnum, 0, 0, 0); | 1037 | wi_cmd(sc, WI_CMD_DISABLE | sc->sc_portnum, 0, 0, 0); | |
1038 | } | 1038 | } | |
1039 | 1039 | |||
1040 | wi_rssdescs_reset(ic, &sc->sc_rssd, &sc->sc_rssdfree, | 1040 | wi_rssdescs_reset(ic, &sc->sc_rssd, &sc->sc_rssdfree, | |
1041 | &sc->sc_txpending); | 1041 | &sc->sc_txpending); | |
1042 | 1042 | |||
1043 | sc->sc_tx_timer = 0; | 1043 | sc->sc_tx_timer = 0; | |
1044 | sc->sc_scan_timer = 0; | 1044 | sc->sc_scan_timer = 0; | |
1045 | sc->sc_false_syns = 0; | 1045 | sc->sc_false_syns = 0; | |
1046 | sc->sc_naps = 0; | 1046 | sc->sc_naps = 0; | |
1047 | ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING); | 1047 | ifp->if_flags &= ~(IFF_OACTIVE | IFF_RUNNING); | |
1048 | ifp->if_timer = 0; | 1048 | ifp->if_timer = 0; | |
1049 | 1049 | |||
1050 | if (disable) { | 1050 | if (disable) { | |
1051 | (*sc->sc_enable)(sc->sc_dev, 0); | 1051 | (*sc->sc_enable)(sc->sc_dev, 0); | |
1052 | sc->sc_enabled = 0; | 1052 | sc->sc_enabled = 0; | |
1053 | } | 1053 | } | |
1054 | splx(s); | 1054 | splx(s); | |
1055 | } | 1055 | } | |
1056 | 1056 | |||
1057 | /* | 1057 | /* | |
1058 | * Choose a data rate for a packet len bytes long that suits the packet | 1058 | * Choose a data rate for a packet len bytes long that suits the packet | |
1059 | * type and the wireless conditions. | 1059 | * type and the wireless conditions. | |
1060 | * | 1060 | * | |
1061 | * TBD Adapt fragmentation threshold. | 1061 | * TBD Adapt fragmentation threshold. | |
1062 | */ | 1062 | */ | |
1063 | STATIC int | 1063 | STATIC int | |
1064 | wi_choose_rate(struct ieee80211com *ic, struct ieee80211_node *ni, | 1064 | wi_choose_rate(struct ieee80211com *ic, struct ieee80211_node *ni, | |
1065 | struct ieee80211_frame *wh, u_int len) | 1065 | struct ieee80211_frame *wh, u_int len) | |
1066 | { | 1066 | { | |
1067 | struct wi_softc *sc = ic->ic_ifp->if_softc; | 1067 | struct wi_softc *sc = ic->ic_ifp->if_softc; | |
1068 | struct wi_node *wn = (void*)ni; | 1068 | struct wi_node *wn = (void*)ni; | |
1069 | struct ieee80211_rssadapt *ra = &wn->wn_rssadapt; | 1069 | struct ieee80211_rssadapt *ra = &wn->wn_rssadapt; | |
1070 | int do_not_adapt, i, rateidx, s; | 1070 | int do_not_adapt, i, rateidx, s; | |
1071 | 1071 | |||
1072 | do_not_adapt = (ic->ic_opmode != IEEE80211_M_HOSTAP) && | 1072 | do_not_adapt = (ic->ic_opmode != IEEE80211_M_HOSTAP) && | |
1073 | (sc->sc_flags & WI_FLAGS_RSSADAPTSTA) == 0; | 1073 | (sc->sc_flags & WI_FLAGS_RSSADAPTSTA) == 0; | |
1074 | 1074 | |||
1075 | s = splnet(); | 1075 | s = splnet(); | |
1076 | 1076 | |||
1077 | rateidx = ieee80211_rssadapt_choose(ra, &ni->ni_rates, wh, len, | 1077 | rateidx = ieee80211_rssadapt_choose(ra, &ni->ni_rates, wh, len, | |
1078 | ic->ic_fixed_rate, | 1078 | ic->ic_fixed_rate, | |
1079 | ((ic->ic_ifp->if_flags & IFF_DEBUG) == 0) ? NULL : ic->ic_ifp->if_xname, | 1079 | ((ic->ic_ifp->if_flags & IFF_DEBUG) == 0) ? NULL : ic->ic_ifp->if_xname, | |
1080 | do_not_adapt); | 1080 | do_not_adapt); | |
1081 | 1081 | |||
1082 | ni->ni_txrate = rateidx; | 1082 | ni->ni_txrate = rateidx; | |
1083 | 1083 | |||
1084 | if (ic->ic_opmode != IEEE80211_M_HOSTAP) { | 1084 | if (ic->ic_opmode != IEEE80211_M_HOSTAP) { | |
1085 | /* choose the slowest pending rate so that we don't | 1085 | /* choose the slowest pending rate so that we don't | |
1086 | * accidentally send a packet on the MAC's queue | 1086 | * accidentally send a packet on the MAC's queue | |
1087 | * too fast. TBD find out if the MAC labels Tx | 1087 | * too fast. TBD find out if the MAC labels Tx | |
1088 | * packets w/ rate when enqueued or dequeued. | 1088 | * packets w/ rate when enqueued or dequeued. | |
1089 | */ | 1089 | */ | |
1090 | for (i = 0; i < rateidx && sc->sc_txpending[i] == 0; i++); | 1090 | for (i = 0; i < rateidx && sc->sc_txpending[i] == 0; i++); | |
1091 | rateidx = i; | 1091 | rateidx = i; | |
1092 | } | 1092 | } | |
1093 | 1093 | |||
1094 | splx(s); | 1094 | splx(s); | |
1095 | return (rateidx); | 1095 | return (rateidx); | |
1096 | } | 1096 | } | |
1097 | 1097 | |||
1098 | STATIC void | 1098 | STATIC void | |
1099 | wi_raise_rate(struct ieee80211com *ic, struct ieee80211_rssdesc *id) | 1099 | wi_raise_rate(struct ieee80211com *ic, struct ieee80211_rssdesc *id) | |
1100 | { | 1100 | { | |
1101 | struct wi_node *wn; | 1101 | struct wi_node *wn; | |
1102 | int s; | 1102 | int s; | |
1103 | 1103 | |||
1104 | s = splnet(); | 1104 | s = splnet(); | |
1105 | if (id->id_node == NULL) | 1105 | if (id->id_node == NULL) | |
1106 | goto out; | 1106 | goto out; | |
1107 | 1107 | |||
1108 | wn = (void*)id->id_node; | 1108 | wn = (void*)id->id_node; | |
1109 | ieee80211_rssadapt_raise_rate(ic, &wn->wn_rssadapt, id); | 1109 | ieee80211_rssadapt_raise_rate(ic, &wn->wn_rssadapt, id); | |
1110 | out: | 1110 | out: | |
1111 | splx(s); | 1111 | splx(s); | |
1112 | } | 1112 | } | |
1113 | 1113 | |||
1114 | STATIC void | 1114 | STATIC void | |
1115 | wi_lower_rate(struct ieee80211com *ic, struct ieee80211_rssdesc *id) | 1115 | wi_lower_rate(struct ieee80211com *ic, struct ieee80211_rssdesc *id) | |
1116 | { | 1116 | { | |
1117 | struct ieee80211_node *ni; | 1117 | struct ieee80211_node *ni; | |
1118 | struct wi_node *wn; | 1118 | struct wi_node *wn; | |
1119 | int s; | 1119 | int s; | |
1120 | 1120 | |||
1121 | s = splnet(); | 1121 | s = splnet(); | |
1122 | 1122 | |||
1123 | if ((ni = id->id_node) == NULL) { | 1123 | if ((ni = id->id_node) == NULL) { | |
1124 | DPRINTF(("wi_lower_rate: missing node\n")); | 1124 | DPRINTF(("wi_lower_rate: missing node\n")); | |
1125 | goto out; | 1125 | goto out; | |
1126 | } | 1126 | } | |
1127 | 1127 | |||
1128 | wn = (void *)ni; | 1128 | wn = (void *)ni; | |
1129 | 1129 | |||
1130 | ieee80211_rssadapt_lower_rate(ic, ni, &wn->wn_rssadapt, id); | 1130 | ieee80211_rssadapt_lower_rate(ic, ni, &wn->wn_rssadapt, id); | |
1131 | out: | 1131 | out: | |
1132 | splx(s); | 1132 | splx(s); | |
1133 | } | 1133 | } | |
1134 | 1134 | |||
1135 | STATIC void | 1135 | STATIC void | |
1136 | wi_start(struct ifnet *ifp) | 1136 | wi_start(struct ifnet *ifp) | |
1137 | { | 1137 | { | |
1138 | struct wi_softc *sc = ifp->if_softc; | 1138 | struct wi_softc *sc = ifp->if_softc; | |
1139 | struct ieee80211com *ic = &sc->sc_ic; | 1139 | struct ieee80211com *ic = &sc->sc_ic; | |
1140 | struct ether_header *eh; | 1140 | struct ether_header *eh; | |
1141 | struct ieee80211_node *ni; | 1141 | struct ieee80211_node *ni; | |
1142 | struct ieee80211_frame *wh; | 1142 | struct ieee80211_frame *wh; | |
1143 | struct ieee80211_rateset *rs; | 1143 | struct ieee80211_rateset *rs; | |
1144 | struct wi_rssdesc *rd; | 1144 | struct wi_rssdesc *rd; | |
1145 | struct ieee80211_rssdesc *id; | 1145 | struct ieee80211_rssdesc *id; | |
1146 | struct mbuf *m0; | 1146 | struct mbuf *m0; | |
1147 | struct wi_frame frmhdr; | 1147 | struct wi_frame frmhdr; | |
1148 | int cur, fid, off, rateidx; | 1148 | int cur, fid, off, rateidx; | |
1149 | 1149 | |||
1150 | if (!sc->sc_enabled || sc->sc_invalid) | 1150 | if (!sc->sc_enabled || sc->sc_invalid) | |
1151 | return; | 1151 | return; | |
1152 | if (sc->sc_flags & WI_FLAGS_OUTRANGE) | 1152 | if (sc->sc_flags & WI_FLAGS_OUTRANGE) | |
1153 | return; | 1153 | return; | |
1154 | 1154 | |||
1155 | memset(&frmhdr, 0, sizeof(frmhdr)); | 1155 | memset(&frmhdr, 0, sizeof(frmhdr)); | |
1156 | cur = sc->sc_txqueue; | 1156 | cur = sc->sc_txqueue; | |
1157 | for (;;) { | 1157 | for (;;) { | |
1158 | ni = ic->ic_bss; | 1158 | ni = ic->ic_bss; | |
1159 | if (sc->sc_txalloced == 0 || SLIST_EMPTY(&sc->sc_rssdfree)) { | 1159 | if (sc->sc_txalloced == 0 || SLIST_EMPTY(&sc->sc_rssdfree)) { | |
1160 | ifp->if_flags |= IFF_OACTIVE; | 1160 | ifp->if_flags |= IFF_OACTIVE; | |
1161 | break; | 1161 | break; | |
1162 | } | 1162 | } | |
1163 | if (!IF_IS_EMPTY(&ic->ic_mgtq)) { | 1163 | if (!IF_IS_EMPTY(&ic->ic_mgtq)) { | |
1164 | IF_DEQUEUE(&ic->ic_mgtq, m0); | 1164 | IF_DEQUEUE(&ic->ic_mgtq, m0); | |
1165 | m_copydata(m0, 4, ETHER_ADDR_LEN * 2, | 1165 | m_copydata(m0, 4, ETHER_ADDR_LEN * 2, | |
1166 | (void *)&frmhdr.wi_ehdr); | 1166 | (void *)&frmhdr.wi_ehdr); | |
1167 | frmhdr.wi_ehdr.ether_type = 0; | 1167 | frmhdr.wi_ehdr.ether_type = 0; | |
1168 | wh = mtod(m0, struct ieee80211_frame *); | 1168 | wh = mtod(m0, struct ieee80211_frame *); | |
1169 | ni = M_GETCTX(m0, struct ieee80211_node *); | 1169 | ni = M_GETCTX(m0, struct ieee80211_node *); | |
1170 | M_CLEARCTX(m0); | 1170 | M_CLEARCTX(m0); | |
1171 | } else if (ic->ic_state == IEEE80211_S_RUN) { | 1171 | } else if (ic->ic_state == IEEE80211_S_RUN) { | |
1172 | IFQ_POLL(&ifp->if_snd, m0); | 1172 | IFQ_POLL(&ifp->if_snd, m0); | |
1173 | if (m0 == NULL) | 1173 | if (m0 == NULL) | |
1174 | break; | 1174 | break; | |
1175 | IFQ_DEQUEUE(&ifp->if_snd, m0); | 1175 | IFQ_DEQUEUE(&ifp->if_snd, m0); | |
1176 | ifp->if_opackets++; | 1176 | ifp->if_opackets++; | |
1177 | m_copydata(m0, 0, ETHER_HDR_LEN, | 1177 | m_copydata(m0, 0, ETHER_HDR_LEN, | |
1178 | (void *)&frmhdr.wi_ehdr); | 1178 | (void *)&frmhdr.wi_ehdr); | |
1179 | bpf_mtap(ifp, m0, BPF_D_OUT); | 1179 | bpf_mtap(ifp, m0, BPF_D_OUT); | |
1180 | 1180 | |||
1181 | eh = mtod(m0, struct ether_header *); | 1181 | eh = mtod(m0, struct ether_header *); | |
1182 | ni = ieee80211_find_txnode(ic, eh->ether_dhost); | 1182 | ni = ieee80211_find_txnode(ic, eh->ether_dhost); | |
1183 | if (ni == NULL) { | 1183 | if (ni == NULL) { | |
1184 | ifp->if_oerrors++; | 1184 | ifp->if_oerrors++; | |
1185 | continue; | 1185 | continue; | |
1186 | } | 1186 | } | |
1187 | if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && | 1187 | if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && | |
1188 | (m0->m_flags & M_PWR_SAV) == 0) { | 1188 | (m0->m_flags & M_PWR_SAV) == 0) { | |
1189 | ieee80211_pwrsave(ic, ni, m0); | 1189 | ieee80211_pwrsave(ic, ni, m0); | |
1190 | goto next; | 1190 | goto next; | |
1191 | } | 1191 | } | |
1192 | if ((m0 = ieee80211_encap(ic, m0, ni)) == NULL) { | 1192 | if ((m0 = ieee80211_encap(ic, m0, ni)) == NULL) { | |
1193 | ieee80211_free_node(ni); | 1193 | ieee80211_free_node(ni); | |
1194 | ifp->if_oerrors++; | 1194 | ifp->if_oerrors++; | |
1195 | continue; | 1195 | continue; | |
1196 | } | 1196 | } | |
1197 | wh = mtod(m0, struct ieee80211_frame *); | 1197 | wh = mtod(m0, struct ieee80211_frame *); | |
1198 | } else | 1198 | } else | |
1199 | break; | 1199 | break; | |
1200 | bpf_mtap3(ic->ic_rawbpf, m0, BPF_D_OUT); | 1200 | bpf_mtap3(ic->ic_rawbpf, m0, BPF_D_OUT); | |
1201 | frmhdr.wi_tx_ctl = | 1201 | frmhdr.wi_tx_ctl = | |
1202 | htole16(WI_ENC_TX_802_11|WI_TXCNTL_TX_EX|WI_TXCNTL_TX_OK); | 1202 | htole16(WI_ENC_TX_802_11|WI_TXCNTL_TX_EX|WI_TXCNTL_TX_OK); | |
1203 | #ifndef IEEE80211_NO_HOSTAP | 1203 | #ifndef IEEE80211_NO_HOSTAP | |
1204 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) | 1204 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) | |
1205 | frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_ALTRTRY); | 1205 | frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_ALTRTRY); | |
1206 | if (ic->ic_opmode == IEEE80211_M_HOSTAP && | 1206 | if (ic->ic_opmode == IEEE80211_M_HOSTAP && | |
1207 | (wh->i_fc[1] & IEEE80211_FC1_WEP)) { | 1207 | (wh->i_fc[1] & IEEE80211_FC1_WEP)) { | |
1208 | if (ieee80211_crypto_encap(ic, ni, m0) == NULL) { | 1208 | if (ieee80211_crypto_encap(ic, ni, m0) == NULL) { | |
1209 | m_freem(m0); | 1209 | m_freem(m0); | |
1210 | ifp->if_oerrors++; | 1210 | ifp->if_oerrors++; | |
1211 | goto next; | 1211 | goto next; | |
1212 | } | 1212 | } | |
1213 | frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT); | 1213 | frmhdr.wi_tx_ctl |= htole16(WI_TXCNTL_NOCRYPT); | |
1214 | } | 1214 | } | |
1215 | #endif /* !IEEE80211_NO_HOSTAP */ | 1215 | #endif /* !IEEE80211_NO_HOSTAP */ | |
1216 | 1216 | |||
1217 | rateidx = wi_choose_rate(ic, ni, wh, m0->m_pkthdr.len); | 1217 | rateidx = wi_choose_rate(ic, ni, wh, m0->m_pkthdr.len); | |
1218 | rs = &ni->ni_rates; | 1218 | rs = &ni->ni_rates; | |
1219 | 1219 | |||
1220 | if (sc->sc_drvbpf) { | 1220 | if (sc->sc_drvbpf) { | |
1221 | struct wi_tx_radiotap_header *tap = &sc->sc_txtap; | 1221 | struct wi_tx_radiotap_header *tap = &sc->sc_txtap; | |
1222 | 1222 | |||
1223 | tap->wt_rate = rs->rs_rates[rateidx]; | 1223 | tap->wt_rate = rs->rs_rates[rateidx]; | |
1224 | tap->wt_chan_freq = | 1224 | tap->wt_chan_freq = | |
1225 | htole16(ic->ic_bss->ni_chan->ic_freq); | 1225 | htole16(ic->ic_bss->ni_chan->ic_freq); | |
1226 | tap->wt_chan_flags = | 1226 | tap->wt_chan_flags = | |
1227 | htole16(ic->ic_bss->ni_chan->ic_flags); | 1227 | htole16(ic->ic_bss->ni_chan->ic_flags); | |
1228 | /* TBD tap->wt_flags */ | 1228 | /* TBD tap->wt_flags */ | |
1229 | 1229 | |||
1230 | bpf_mtap2(sc->sc_drvbpf, tap, tap->wt_ihdr.it_len, m0, | 1230 | bpf_mtap2(sc->sc_drvbpf, tap, tap->wt_ihdr.it_len, m0, | |
1231 | BPF_D_OUT); | 1231 | BPF_D_OUT); | |
1232 | } | 1232 | } | |
1233 | 1233 | |||
1234 | rd = SLIST_FIRST(&sc->sc_rssdfree); | 1234 | rd = SLIST_FIRST(&sc->sc_rssdfree); | |
1235 | id = &rd->rd_desc; | 1235 | id = &rd->rd_desc; | |
1236 | id->id_len = m0->m_pkthdr.len; | 1236 | id->id_len = m0->m_pkthdr.len; | |
1237 | id->id_rateidx = ni->ni_txrate; | 1237 | id->id_rateidx = ni->ni_txrate; | |
1238 | id->id_rssi = ni->ni_rssi; | 1238 | id->id_rssi = ni->ni_rssi; | |
1239 | 1239 | |||
1240 | frmhdr.wi_tx_idx = rd - sc->sc_rssd; | 1240 | frmhdr.wi_tx_idx = rd - sc->sc_rssd; | |
1241 | 1241 | |||
1242 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) | 1242 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) | |
1243 | frmhdr.wi_tx_rate = 5 * (rs->rs_rates[rateidx] & | 1243 | frmhdr.wi_tx_rate = 5 * (rs->rs_rates[rateidx] & | |
1244 | IEEE80211_RATE_VAL); | 1244 | IEEE80211_RATE_VAL); | |
1245 | else if (sc->sc_flags & WI_FLAGS_RSSADAPTSTA) | 1245 | else if (sc->sc_flags & WI_FLAGS_RSSADAPTSTA) | |
1246 | (void)wi_write_txrate(sc, rs->rs_rates[rateidx]); | 1246 | (void)wi_write_txrate(sc, rs->rs_rates[rateidx]); | |
1247 | 1247 | |||
1248 | m_copydata(m0, 0, sizeof(struct ieee80211_frame), | 1248 | m_copydata(m0, 0, sizeof(struct ieee80211_frame), | |
1249 | (void *)&frmhdr.wi_whdr); | 1249 | (void *)&frmhdr.wi_whdr); | |
1250 | m_adj(m0, sizeof(struct ieee80211_frame)); | 1250 | m_adj(m0, sizeof(struct ieee80211_frame)); | |
1251 | frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len); | 1251 | frmhdr.wi_dat_len = htole16(m0->m_pkthdr.len); | |
1252 | if (IFF_DUMPPKTS(ifp)) | 1252 | if (IFF_DUMPPKTS(ifp)) | |
1253 | wi_dump_pkt(&frmhdr, ni, -1); | 1253 | wi_dump_pkt(&frmhdr, ni, -1); | |
1254 | fid = sc->sc_txd[cur].d_fid; | 1254 | fid = sc->sc_txd[cur].d_fid; | |
1255 | off = sizeof(frmhdr); | 1255 | off = sizeof(frmhdr); | |
1256 | if (wi_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0 || | 1256 | if (wi_write_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0 || | |
1257 | wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0) { | 1257 | wi_mwrite_bap(sc, fid, off, m0, m0->m_pkthdr.len) != 0) { | |
1258 | aprint_error_dev(sc->sc_dev, "%s write fid %x failed\n", | 1258 | aprint_error_dev(sc->sc_dev, "%s write fid %x failed\n", | |
1259 | __func__, fid); | 1259 | __func__, fid); | |
1260 | ifp->if_oerrors++; | 1260 | ifp->if_oerrors++; | |
1261 | m_freem(m0); | 1261 | m_freem(m0); | |
1262 | goto next; | 1262 | goto next; | |
1263 | } | 1263 | } | |
1264 | m_freem(m0); | 1264 | m_freem(m0); | |
1265 | sc->sc_txpending[ni->ni_txrate]++; | 1265 | sc->sc_txpending[ni->ni_txrate]++; | |
1266 | --sc->sc_txalloced; | 1266 | --sc->sc_txalloced; | |
1267 | if (sc->sc_txqueued++ == 0) { | 1267 | if (sc->sc_txqueued++ == 0) { | |
1268 | #ifdef DIAGNOSTIC | 1268 | #ifdef DIAGNOSTIC | |
1269 | if (cur != sc->sc_txstart) | 1269 | if (cur != sc->sc_txstart) | |
1270 | printf("%s: ring is desynchronized\n", | 1270 | printf("%s: ring is desynchronized\n", | |
1271 | device_xname(sc->sc_dev)); | 1271 | device_xname(sc->sc_dev)); | |
1272 | #endif | 1272 | #endif | |
1273 | wi_push_packet(sc); | 1273 | wi_push_packet(sc); | |
1274 | } else { | 1274 | } else { | |
1275 | #ifdef WI_RING_DEBUG | 1275 | #ifdef WI_RING_DEBUG | |
1276 | printf("%s: queue %04x, alloc %d queue %d start %d alloced %d queued %d started %d\n", | 1276 | printf("%s: queue %04x, alloc %d queue %d start %d alloced %d queued %d started %d\n", | |
1277 | device_xname(sc->sc_dev), fid, | 1277 | device_xname(sc->sc_dev), fid, | |
1278 | sc->sc_txalloc, sc->sc_txqueue, sc->sc_txstart, | 1278 | sc->sc_txalloc, sc->sc_txqueue, sc->sc_txstart, | |
1279 | sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted); | 1279 | sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted); | |
1280 | #endif | 1280 | #endif | |
1281 | } | 1281 | } | |
1282 | sc->sc_txqueue = cur = (cur + 1) % WI_NTXBUF; | 1282 | sc->sc_txqueue = cur = (cur + 1) % WI_NTXBUF; | |
1283 | SLIST_REMOVE_HEAD(&sc->sc_rssdfree, rd_next); | 1283 | SLIST_REMOVE_HEAD(&sc->sc_rssdfree, rd_next); | |
1284 | id->id_node = ni; | 1284 | id->id_node = ni; | |
1285 | continue; | 1285 | continue; | |
1286 | next: | 1286 | next: | |
1287 | if (ni != NULL) | 1287 | if (ni != NULL) | |
1288 | ieee80211_free_node(ni); | 1288 | ieee80211_free_node(ni); | |
1289 | } | 1289 | } | |
1290 | } | 1290 | } | |
1291 | 1291 | |||
1292 | 1292 | |||
1293 | STATIC int | 1293 | STATIC int | |
1294 | wi_reset(struct wi_softc *sc) | 1294 | wi_reset(struct wi_softc *sc) | |
1295 | { | 1295 | { | |
1296 | int i, error; | 1296 | int i, error; | |
1297 | 1297 | |||
1298 | DPRINTF(("wi_reset\n")); | 1298 | DPRINTF(("wi_reset\n")); | |
1299 | 1299 | |||
1300 | if (sc->sc_reset) | 1300 | if (sc->sc_reset) | |
1301 | (*sc->sc_reset)(sc); | 1301 | (*sc->sc_reset)(sc); | |
1302 | 1302 | |||
1303 | error = 0; | 1303 | error = 0; | |
1304 | for (i = 0; i < 5; i++) { | 1304 | for (i = 0; i < 5; i++) { | |
1305 | if (sc->sc_invalid) | 1305 | if (sc->sc_invalid) | |
1306 | return ENXIO; | 1306 | return ENXIO; | |
1307 | DELAY(20*1000); /* XXX: way too long! */ | 1307 | DELAY(20*1000); /* XXX: way too long! */ | |
1308 | if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0) | 1308 | if ((error = wi_cmd(sc, WI_CMD_INI, 0, 0, 0)) == 0) | |
1309 | break; | 1309 | break; | |
1310 | } | 1310 | } | |
1311 | if (error) { | 1311 | if (error) { | |
1312 | aprint_error_dev(sc->sc_dev, "init failed\n"); | 1312 | aprint_error_dev(sc->sc_dev, "init failed\n"); | |
1313 | return error; | 1313 | return error; | |
1314 | } | 1314 | } | |
1315 | CSR_WRITE_2(sc, WI_INT_EN, 0); | 1315 | CSR_WRITE_2(sc, WI_INT_EN, 0); | |
1316 | CSR_WRITE_2(sc, WI_EVENT_ACK, ~0); | 1316 | CSR_WRITE_2(sc, WI_EVENT_ACK, ~0); | |
1317 | 1317 | |||
1318 | /* Calibrate timer. */ | 1318 | /* Calibrate timer. */ | |
1319 | wi_write_val(sc, WI_RID_TICK_TIME, 0); | 1319 | wi_write_val(sc, WI_RID_TICK_TIME, 0); | |
1320 | return 0; | 1320 | return 0; | |
1321 | } | 1321 | } | |
1322 | 1322 | |||
1323 | STATIC void | 1323 | STATIC void | |
1324 | wi_watchdog(struct ifnet *ifp) | 1324 | wi_watchdog(struct ifnet *ifp) | |
1325 | { | 1325 | { | |
1326 | struct wi_softc *sc = ifp->if_softc; | 1326 | struct wi_softc *sc = ifp->if_softc; | |
1327 | 1327 | |||
1328 | ifp->if_timer = 0; | 1328 | ifp->if_timer = 0; | |
1329 | if (!sc->sc_enabled) | 1329 | if (!sc->sc_enabled) | |
1330 | return; | 1330 | return; | |
1331 | 1331 | |||
1332 | if (sc->sc_tx_timer) { | 1332 | if (sc->sc_tx_timer) { | |
1333 | if (--sc->sc_tx_timer == 0) { | 1333 | if (--sc->sc_tx_timer == 0) { | |
1334 | printf("%s: device timeout\n", ifp->if_xname); | 1334 | printf("%s: device timeout\n", ifp->if_xname); | |
1335 | ifp->if_oerrors++; | 1335 | ifp->if_oerrors++; | |
1336 | wi_init(ifp); | 1336 | wi_init(ifp); | |
1337 | return; | 1337 | return; | |
1338 | } | 1338 | } | |
1339 | ifp->if_timer = 1; | 1339 | ifp->if_timer = 1; | |
1340 | } | 1340 | } | |
1341 | 1341 | |||
1342 | if (sc->sc_scan_timer) { | 1342 | if (sc->sc_scan_timer) { | |
1343 | if (--sc->sc_scan_timer <= WI_SCAN_WAIT - WI_SCAN_INQWAIT && | 1343 | if (--sc->sc_scan_timer <= WI_SCAN_WAIT - WI_SCAN_INQWAIT && | |
1344 | sc->sc_firmware_type == WI_INTERSIL) { | 1344 | sc->sc_firmware_type == WI_INTERSIL) { | |
1345 | DPRINTF(("wi_watchdog: inquire scan\n")); | 1345 | DPRINTF(("wi_watchdog: inquire scan\n")); | |
1346 | wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0); | 1346 | wi_cmd(sc, WI_CMD_INQUIRE, WI_INFO_SCAN_RESULTS, 0, 0); | |
1347 | } | 1347 | } | |
1348 | if (sc->sc_scan_timer) | 1348 | if (sc->sc_scan_timer) | |
1349 | ifp->if_timer = 1; | 1349 | ifp->if_timer = 1; | |
1350 | } | 1350 | } | |
1351 | 1351 | |||
1352 | /* TODO: rate control */ | 1352 | /* TODO: rate control */ | |
1353 | ieee80211_watchdog(&sc->sc_ic); | 1353 | ieee80211_watchdog(&sc->sc_ic); | |
1354 | } | 1354 | } | |
1355 | 1355 | |||
1356 | static int | 1356 | static int | |
1357 | wi_ioctl_enter(struct wi_softc *sc) | 1357 | wi_ioctl_enter(struct wi_softc *sc) | |
1358 | { | 1358 | { | |
1359 | int rc = 0; | 1359 | int rc = 0; | |
1360 | 1360 | |||
1361 | mutex_enter(&sc->sc_ioctl_mtx); | 1361 | mutex_enter(&sc->sc_ioctl_mtx); | |
1362 | sc->sc_ioctl_nwait++; | 1362 | sc->sc_ioctl_nwait++; | |
1363 | while (sc->sc_ioctl_lwp != NULL && sc->sc_ioctl_lwp != curlwp) { | 1363 | while (sc->sc_ioctl_lwp != NULL && sc->sc_ioctl_lwp != curlwp) { | |
1364 | rc = sc->sc_ioctl_gone | 1364 | rc = sc->sc_ioctl_gone | |
1365 | ? ENXIO | 1365 | ? ENXIO | |
1366 | : cv_wait_sig(&sc->sc_ioctl_cv, &sc->sc_ioctl_mtx); | 1366 | : cv_wait_sig(&sc->sc_ioctl_cv, &sc->sc_ioctl_mtx); | |
1367 | if (rc != 0) | 1367 | if (rc != 0) | |
1368 | break; | 1368 | break; | |
1369 | } | 1369 | } | |
1370 | if (rc == 0) { | 1370 | if (rc == 0) { | |
1371 | sc->sc_ioctl_lwp = curlwp; | 1371 | sc->sc_ioctl_lwp = curlwp; | |
1372 | sc->sc_ioctl_depth++; | 1372 | sc->sc_ioctl_depth++; | |
1373 | } | 1373 | } | |
1374 | if (--sc->sc_ioctl_nwait == 0) | 1374 | if (--sc->sc_ioctl_nwait == 0) | |
1375 | cv_signal(&sc->sc_ioctl_cv); | 1375 | cv_signal(&sc->sc_ioctl_cv); | |
1376 | mutex_exit(&sc->sc_ioctl_mtx); | 1376 | mutex_exit(&sc->sc_ioctl_mtx); | |
1377 | return rc; | 1377 | return rc; | |
1378 | } | 1378 | } | |
1379 | 1379 | |||
1380 | static void | 1380 | static void | |
1381 | wi_ioctl_exit(struct wi_softc *sc) | 1381 | wi_ioctl_exit(struct wi_softc *sc) | |
1382 | { | 1382 | { | |
1383 | KASSERT(sc->sc_ioctl_lwp == curlwp); | 1383 | KASSERT(sc->sc_ioctl_lwp == curlwp); | |
1384 | mutex_enter(&sc->sc_ioctl_mtx); | 1384 | mutex_enter(&sc->sc_ioctl_mtx); | |
1385 | if (--sc->sc_ioctl_depth == 0) { | 1385 | if (--sc->sc_ioctl_depth == 0) { | |
1386 | sc->sc_ioctl_lwp = NULL; | 1386 | sc->sc_ioctl_lwp = NULL; | |
1387 | cv_signal(&sc->sc_ioctl_cv); | 1387 | cv_signal(&sc->sc_ioctl_cv); | |
1388 | } | 1388 | } | |
1389 | mutex_exit(&sc->sc_ioctl_mtx); | 1389 | mutex_exit(&sc->sc_ioctl_mtx); | |
1390 | } | 1390 | } | |
1391 | 1391 | |||
1392 | static void | 1392 | static void | |
1393 | wi_ioctl_init(struct wi_softc *sc) | 1393 | wi_ioctl_init(struct wi_softc *sc) | |
1394 | { | 1394 | { | |
1395 | mutex_init(&sc->sc_ioctl_mtx, MUTEX_DEFAULT, IPL_NONE); | 1395 | mutex_init(&sc->sc_ioctl_mtx, MUTEX_DEFAULT, IPL_NONE); | |
1396 | cv_init(&sc->sc_ioctl_cv, device_xname(sc->sc_dev)); | 1396 | cv_init(&sc->sc_ioctl_cv, device_xname(sc->sc_dev)); | |
1397 | } | 1397 | } | |
1398 | 1398 | |||
1399 | static void | 1399 | static void | |
1400 | wi_ioctl_drain(struct wi_softc *sc) | 1400 | wi_ioctl_drain(struct wi_softc *sc) | |
1401 | { | 1401 | { | |
1402 | wi_ioctl_enter(sc); | 1402 | wi_ioctl_enter(sc); | |
1403 | 1403 | |||
1404 | mutex_enter(&sc->sc_ioctl_mtx); | 1404 | mutex_enter(&sc->sc_ioctl_mtx); | |
1405 | sc->sc_ioctl_gone = true; | 1405 | sc->sc_ioctl_gone = true; | |
1406 | cv_broadcast(&sc->sc_ioctl_cv); | 1406 | cv_broadcast(&sc->sc_ioctl_cv); | |
1407 | while (sc->sc_ioctl_nwait != 0) | 1407 | while (sc->sc_ioctl_nwait != 0) | |
1408 | cv_wait(&sc->sc_ioctl_cv, &sc->sc_ioctl_mtx); | 1408 | cv_wait(&sc->sc_ioctl_cv, &sc->sc_ioctl_mtx); | |
1409 | mutex_exit(&sc->sc_ioctl_mtx); | 1409 | mutex_exit(&sc->sc_ioctl_mtx); | |
1410 | 1410 | |||
1411 | wi_ioctl_exit(sc); | 1411 | wi_ioctl_exit(sc); | |
1412 | 1412 | |||
1413 | mutex_destroy(&sc->sc_ioctl_mtx); | 1413 | mutex_destroy(&sc->sc_ioctl_mtx); | |
1414 | cv_destroy(&sc->sc_ioctl_cv); | 1414 | cv_destroy(&sc->sc_ioctl_cv); | |
1415 | } | 1415 | } | |
1416 | 1416 | |||
1417 | STATIC int | 1417 | STATIC int | |
1418 | wi_ioctl(struct ifnet *ifp, u_long cmd, void *data) | 1418 | wi_ioctl(struct ifnet *ifp, u_long cmd, void *data) | |
1419 | { | 1419 | { | |
1420 | struct wi_softc *sc = ifp->if_softc; | 1420 | struct wi_softc *sc = ifp->if_softc; | |
1421 | struct ieee80211com *ic = &sc->sc_ic; | 1421 | struct ieee80211com *ic = &sc->sc_ic; | |
1422 | struct ifreq *ifr = (struct ifreq *)data; | |||
1423 | int s, error = 0; | 1422 | int s, error = 0; | |
1424 | 1423 | |||
1425 | if (!device_is_active(sc->sc_dev)) | 1424 | if (!device_is_active(sc->sc_dev)) | |
1426 | return ENXIO; | 1425 | return ENXIO; | |
1427 | 1426 | |||
1428 | s = splnet(); | 1427 | s = splnet(); | |
1429 | 1428 | |||
1430 | if ((error = wi_ioctl_enter(sc)) != 0) { | 1429 | if ((error = wi_ioctl_enter(sc)) != 0) { | |
1431 | splx(s); | 1430 | splx(s); | |
1432 | return error; | 1431 | return error; | |
1433 | } | 1432 | } | |
1434 | 1433 | |||
1435 | switch (cmd) { | 1434 | switch (cmd) { | |
1436 | case SIOCSIFFLAGS: | 1435 | case SIOCSIFFLAGS: | |
1437 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | 1436 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) | |
1438 | break; | 1437 | break; | |
1439 | /* | 1438 | /* | |
1440 | * Can't do promisc and hostap at the same time. If all that's | 1439 | * Can't do promisc and hostap at the same time. If all that's | |
1441 | * changing is the promisc flag, try to short-circuit a call to | 1440 | * changing is the promisc flag, try to short-circuit a call to | |
1442 | * wi_init() by just setting PROMISC in the hardware. | 1441 | * wi_init() by just setting PROMISC in the hardware. | |
1443 | */ | 1442 | */ | |
1444 | if (ifp->if_flags & IFF_UP) { | 1443 | if (ifp->if_flags & IFF_UP) { | |
1445 | if (sc->sc_enabled) { | 1444 | if (sc->sc_enabled) { | |
1446 | if (ic->ic_opmode != IEEE80211_M_HOSTAP && | 1445 | if (ic->ic_opmode != IEEE80211_M_HOSTAP && | |
1447 | (ifp->if_flags & IFF_PROMISC) != 0) | 1446 | (ifp->if_flags & IFF_PROMISC) != 0) | |
1448 | wi_write_val(sc, WI_RID_PROMISC, 1); | 1447 | wi_write_val(sc, WI_RID_PROMISC, 1); | |
1449 | else | 1448 | else | |
1450 | wi_write_val(sc, WI_RID_PROMISC, 0); | 1449 | wi_write_val(sc, WI_RID_PROMISC, 0); | |
1451 | } else | 1450 | } else | |
1452 | error = wi_init(ifp); | 1451 | error = wi_init(ifp); | |
1453 | } else if (sc->sc_enabled) | 1452 | } else if (sc->sc_enabled) | |
1454 | wi_stop(ifp, 1); | 1453 | wi_stop(ifp, 1); | |
1455 | break; | 1454 | break; | |
1456 | case SIOCSIFMEDIA: | |||
1457 | case SIOCGIFMEDIA: | |||
1458 | error = ifmedia_ioctl(ifp, ifr, &ic->ic_media, cmd); | |||
1459 | break; | |||
1460 | case SIOCADDMULTI: | 1455 | case SIOCADDMULTI: | |
1461 | case SIOCDELMULTI: | 1456 | case SIOCDELMULTI: | |
1462 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { | 1457 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { | |
1463 | if (ifp->if_flags & IFF_RUNNING) { | 1458 | if (ifp->if_flags & IFF_RUNNING) { | |
1464 | /* do not rescan */ | 1459 | /* do not rescan */ | |
1465 | error = wi_write_multi(sc); | 1460 | error = wi_write_multi(sc); | |
1466 | } else | 1461 | } else | |
1467 | error = 0; | 1462 | error = 0; | |
1468 | } | 1463 | } | |
1469 | break; | 1464 | break; | |
1470 | case SIOCGIFGENERIC: | 1465 | case SIOCGIFGENERIC: | |
1471 | error = wi_get_cfg(ifp, cmd, data); | 1466 | error = wi_get_cfg(ifp, cmd, data); | |
1472 | break; | 1467 | break; | |
1473 | case SIOCSIFGENERIC: | 1468 | case SIOCSIFGENERIC: | |
1474 | error = kauth_authorize_network(curlwp->l_cred, | 1469 | error = kauth_authorize_network(curlwp->l_cred, | |
1475 | KAUTH_NETWORK_INTERFACE, | 1470 | KAUTH_NETWORK_INTERFACE, | |
1476 | KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, KAUTH_ARG(cmd), | 1471 | KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, KAUTH_ARG(cmd), | |
1477 | NULL); | 1472 | NULL); | |
1478 | if (error) | 1473 | if (error) | |
1479 | break; | 1474 | break; | |
1480 | error = wi_set_cfg(ifp, cmd, data); | 1475 | error = wi_set_cfg(ifp, cmd, data); | |
1481 | if (error == ENETRESET) { | 1476 | if (error == ENETRESET) { | |
1482 | if (ifp->if_flags & IFF_RUNNING) | 1477 | if (ifp->if_flags & IFF_RUNNING) | |
1483 | error = wi_init(ifp); | 1478 | error = wi_init(ifp); | |
1484 | else | 1479 | else | |
1485 | error = 0; | 1480 | error = 0; | |
1486 | } | 1481 | } | |
1487 | break; | 1482 | break; | |
1488 | case SIOCS80211BSSID: | 1483 | case SIOCS80211BSSID: | |
1489 | if (sc->sc_firmware_type == WI_LUCENT) { | 1484 | if (sc->sc_firmware_type == WI_LUCENT) { | |
1490 | error = ENODEV; | 1485 | error = ENODEV; | |
1491 | break; | 1486 | break; | |
1492 | } | 1487 | } | |
1493 | /* fall through */ | 1488 | /* fall through */ | |
1494 | default: | 1489 | default: | |
1495 | ic->ic_flags |= sc->sc_ic_flags; | 1490 | ic->ic_flags |= sc->sc_ic_flags; | |
1496 | error = ieee80211_ioctl(&sc->sc_ic, cmd, data); | 1491 | error = ieee80211_ioctl(&sc->sc_ic, cmd, data); | |
1497 | sc->sc_ic_flags = ic->ic_flags & IEEE80211_F_DROPUNENC; | 1492 | sc->sc_ic_flags = ic->ic_flags & IEEE80211_F_DROPUNENC; | |
1498 | if (error == ENETRESET) { | 1493 | if (error == ENETRESET) { | |
1499 | if (sc->sc_enabled) | 1494 | if (sc->sc_enabled) | |
1500 | error = wi_init(ifp); | 1495 | error = wi_init(ifp); | |
1501 | else | 1496 | else | |
1502 | error = 0; | 1497 | error = 0; | |
1503 | } | 1498 | } | |
1504 | break; | 1499 | break; | |
1505 | } | 1500 | } | |
1506 | wi_mend_flags(sc, ic->ic_state); | 1501 | wi_mend_flags(sc, ic->ic_state); | |
1507 | wi_ioctl_exit(sc); | 1502 | wi_ioctl_exit(sc); | |
1508 | splx(s); | 1503 | splx(s); | |
1509 | return error; | 1504 | return error; | |
1510 | } | 1505 | } | |
1511 | 1506 | |||
1512 | STATIC int | 1507 | STATIC int | |
1513 | wi_media_change(struct ifnet *ifp) | 1508 | wi_media_change(struct ifnet *ifp) | |
1514 | { | 1509 | { | |
1515 | struct wi_softc *sc = ifp->if_softc; | 1510 | struct wi_softc *sc = ifp->if_softc; | |
1516 | struct ieee80211com *ic = &sc->sc_ic; | 1511 | struct ieee80211com *ic = &sc->sc_ic; | |
1517 | int error; | 1512 | int error; | |
1518 | 1513 | |||
1519 | error = ieee80211_media_change(ifp); | 1514 | error = ieee80211_media_change(ifp); | |
1520 | if (error == ENETRESET) { | 1515 | if (error == ENETRESET) { | |
1521 | if (sc->sc_enabled) | 1516 | if (sc->sc_enabled) | |
1522 | error = wi_init(ifp); | 1517 | error = wi_init(ifp); | |
1523 | else | 1518 | else | |
1524 | error = 0; | 1519 | error = 0; | |
1525 | } | 1520 | } | |
1526 | ifp->if_baudrate = ifmedia_baudrate(ic->ic_media.ifm_cur->ifm_media); | 1521 | ifp->if_baudrate = ifmedia_baudrate(ic->ic_media.ifm_cur->ifm_media); | |
1527 | 1522 | |||
1528 | return error; | 1523 | return error; | |
1529 | } | 1524 | } | |
1530 | 1525 | |||
1531 | STATIC void | 1526 | STATIC void | |
1532 | wi_media_status(struct ifnet *ifp, struct ifmediareq *imr) | 1527 | wi_media_status(struct ifnet *ifp, struct ifmediareq *imr) | |
1533 | { | 1528 | { | |
1534 | struct wi_softc *sc = ifp->if_softc; | 1529 | struct wi_softc *sc = ifp->if_softc; | |
1535 | struct ieee80211com *ic = &sc->sc_ic; | 1530 | struct ieee80211com *ic = &sc->sc_ic; | |
1536 | uint16_t val; | 1531 | uint16_t val; | |
1537 | int rate; | 1532 | int rate; | |
1538 | 1533 | |||
1539 | if (sc->sc_enabled == 0) { | 1534 | if (sc->sc_enabled == 0) { | |
1540 | imr->ifm_active = IFM_IEEE80211 | IFM_NONE; | 1535 | imr->ifm_active = IFM_IEEE80211 | IFM_NONE; | |
1541 | imr->ifm_status = 0; | 1536 | imr->ifm_status = 0; | |
1542 | return; | 1537 | return; | |
1543 | } | 1538 | } | |
1544 | 1539 | |||
1545 | imr->ifm_status = IFM_AVALID; | 1540 | imr->ifm_status = IFM_AVALID; | |
1546 | imr->ifm_active = IFM_IEEE80211; | 1541 | imr->ifm_active = IFM_IEEE80211; | |
1547 | if (ic->ic_state == IEEE80211_S_RUN && | 1542 | if (ic->ic_state == IEEE80211_S_RUN && | |
1548 | (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0) | 1543 | (sc->sc_flags & WI_FLAGS_OUTRANGE) == 0) | |
1549 | imr->ifm_status |= IFM_ACTIVE; | 1544 | imr->ifm_status |= IFM_ACTIVE; | |
1550 | if (wi_read_xrid(sc, WI_RID_CUR_TX_RATE, &val, sizeof(val)) == 0) { | 1545 | if (wi_read_xrid(sc, WI_RID_CUR_TX_RATE, &val, sizeof(val)) == 0) { | |
1551 | /* convert to 802.11 rate */ | 1546 | /* convert to 802.11 rate */ | |
1552 | val = le16toh(val); | 1547 | val = le16toh(val); | |
1553 | rate = val * 2; | 1548 | rate = val * 2; | |
1554 | if (sc->sc_firmware_type == WI_LUCENT) { | 1549 | if (sc->sc_firmware_type == WI_LUCENT) { | |
1555 | if (rate == 10) | 1550 | if (rate == 10) | |
1556 | rate = 11; /* 5.5Mbps */ | 1551 | rate = 11; /* 5.5Mbps */ | |
1557 | } else { | 1552 | } else { | |
1558 | if (rate == 4*2) | 1553 | if (rate == 4*2) | |
1559 | rate = 11; /* 5.5Mbps */ | 1554 | rate = 11; /* 5.5Mbps */ | |
1560 | else if (rate == 8*2) | 1555 | else if (rate == 8*2) | |
1561 | rate = 22; /* 11Mbps */ | 1556 | rate = 22; /* 11Mbps */ | |
1562 | } | 1557 | } | |
1563 | } else | 1558 | } else | |
1564 | rate = 0; | 1559 | rate = 0; | |
1565 | imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B); | 1560 | imr->ifm_active |= ieee80211_rate2media(ic, rate, IEEE80211_MODE_11B); | |
1566 | switch (ic->ic_opmode) { | 1561 | switch (ic->ic_opmode) { | |
1567 | case IEEE80211_M_STA: | 1562 | case IEEE80211_M_STA: | |
1568 | break; | 1563 | break; | |
1569 | case IEEE80211_M_IBSS: | 1564 | case IEEE80211_M_IBSS: | |
1570 | imr->ifm_active |= IFM_IEEE80211_ADHOC; | 1565 | imr->ifm_active |= IFM_IEEE80211_ADHOC; | |
1571 | break; | 1566 | break; | |
1572 | case IEEE80211_M_AHDEMO: | 1567 | case IEEE80211_M_AHDEMO: | |
1573 | imr->ifm_active |= IFM_IEEE80211_ADHOC | IFM_FLAG0; | 1568 | imr->ifm_active |= IFM_IEEE80211_ADHOC | IFM_FLAG0; | |
1574 | break; | 1569 | break; | |
1575 | case IEEE80211_M_HOSTAP: | 1570 | case IEEE80211_M_HOSTAP: | |
1576 | imr->ifm_active |= IFM_IEEE80211_HOSTAP; | 1571 | imr->ifm_active |= IFM_IEEE80211_HOSTAP; | |
1577 | break; | 1572 | break; | |
1578 | case IEEE80211_M_MONITOR: | 1573 | case IEEE80211_M_MONITOR: | |
1579 | imr->ifm_active |= IFM_IEEE80211_MONITOR; | 1574 | imr->ifm_active |= IFM_IEEE80211_MONITOR; | |
1580 | break; | 1575 | break; | |
1581 | } | 1576 | } | |
1582 | } | 1577 | } | |
1583 | 1578 | |||
1584 | STATIC struct ieee80211_node * | 1579 | STATIC struct ieee80211_node * | |
1585 | wi_node_alloc(struct ieee80211_node_table *nt) | 1580 | wi_node_alloc(struct ieee80211_node_table *nt) | |
1586 | { | 1581 | { | |
1587 | struct wi_node *wn = | 1582 | struct wi_node *wn = | |
1588 | malloc(sizeof(struct wi_node), M_DEVBUF, M_NOWAIT | M_ZERO); | 1583 | malloc(sizeof(struct wi_node), M_DEVBUF, M_NOWAIT | M_ZERO); | |
1589 | return wn ? &wn->wn_node : NULL; | 1584 | return wn ? &wn->wn_node : NULL; | |
1590 | } | 1585 | } | |
1591 | 1586 | |||
1592 | STATIC void | 1587 | STATIC void | |
1593 | wi_node_free(struct ieee80211_node *ni) | 1588 | wi_node_free(struct ieee80211_node *ni) | |
1594 | { | 1589 | { | |
1595 | struct wi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | 1590 | struct wi_softc *sc = ni->ni_ic->ic_ifp->if_softc; | |
1596 | int i; | 1591 | int i; | |
1597 | 1592 | |||
1598 | for (i = 0; i < WI_NTXRSS; i++) { | 1593 | for (i = 0; i < WI_NTXRSS; i++) { | |
1599 | if (sc->sc_rssd[i].rd_desc.id_node == ni) | 1594 | if (sc->sc_rssd[i].rd_desc.id_node == ni) | |
1600 | sc->sc_rssd[i].rd_desc.id_node = NULL; | 1595 | sc->sc_rssd[i].rd_desc.id_node = NULL; | |
1601 | } | 1596 | } | |
1602 | free(ni, M_DEVBUF); | 1597 | free(ni, M_DEVBUF); | |
1603 | } | 1598 | } | |
1604 | 1599 | |||
1605 | STATIC void | 1600 | STATIC void | |
1606 | wi_sync_bssid(struct wi_softc *sc, uint8_t new_bssid[IEEE80211_ADDR_LEN]) | 1601 | wi_sync_bssid(struct wi_softc *sc, uint8_t new_bssid[IEEE80211_ADDR_LEN]) | |
1607 | { | 1602 | { | |
1608 | struct ieee80211com *ic = &sc->sc_ic; | 1603 | struct ieee80211com *ic = &sc->sc_ic; | |
1609 | struct ieee80211_node *ni = ic->ic_bss; | 1604 | struct ieee80211_node *ni = ic->ic_bss; | |
1610 | struct ifnet *ifp = &sc->sc_if; | 1605 | struct ifnet *ifp = &sc->sc_if; | |
1611 | int s; | 1606 | int s; | |
1612 | 1607 | |||
1613 | if (IEEE80211_ADDR_EQ(new_bssid, ni->ni_bssid)) | 1608 | if (IEEE80211_ADDR_EQ(new_bssid, ni->ni_bssid)) | |
1614 | return; | 1609 | return; | |
1615 | 1610 | |||
1616 | DPRINTF(("wi_sync_bssid: bssid %s -> ", ether_sprintf(ni->ni_bssid))); | 1611 | DPRINTF(("wi_sync_bssid: bssid %s -> ", ether_sprintf(ni->ni_bssid))); | |
1617 | DPRINTF(("%s ?\n", ether_sprintf(new_bssid))); | 1612 | DPRINTF(("%s ?\n", ether_sprintf(new_bssid))); | |
1618 | 1613 | |||
1619 | /* In promiscuous mode, the BSSID field is not a reliable | 1614 | /* In promiscuous mode, the BSSID field is not a reliable | |
1620 | * indicator of the firmware's BSSID. Damp spurious | 1615 | * indicator of the firmware's BSSID. Damp spurious | |
1621 | * change-of-BSSID indications. | 1616 | * change-of-BSSID indications. | |
1622 | */ | 1617 | */ | |
1623 | if ((ifp->if_flags & IFF_PROMISC) != 0 && | 1618 | if ((ifp->if_flags & IFF_PROMISC) != 0 && | |
1624 | !ppsratecheck(&sc->sc_last_syn, &sc->sc_false_syns, | 1619 | !ppsratecheck(&sc->sc_last_syn, &sc->sc_false_syns, | |
1625 | WI_MAX_FALSE_SYNS)) | 1620 | WI_MAX_FALSE_SYNS)) | |
1626 | return; | 1621 | return; | |
1627 | 1622 | |||
1628 | sc->sc_false_syns = MAX(0, sc->sc_false_syns - 1); | 1623 | sc->sc_false_syns = MAX(0, sc->sc_false_syns - 1); | |
1629 | /* | 1624 | /* | |
1630 | * XXX hack; we should create a new node with the new bssid | 1625 | * XXX hack; we should create a new node with the new bssid | |
1631 | * and replace the existing ic_bss with it but since we don't | 1626 | * and replace the existing ic_bss with it but since we don't | |
1632 | * process management frames to collect state we cheat by | 1627 | * process management frames to collect state we cheat by | |
1633 | * reusing the existing node as we know wi_newstate will be | 1628 | * reusing the existing node as we know wi_newstate will be | |
1634 | * called and it will overwrite the node state. | 1629 | * called and it will overwrite the node state. | |
1635 | */ | 1630 | */ | |
1636 | s = splnet(); | 1631 | s = splnet(); | |
1637 | ieee80211_sta_join(ic, ieee80211_ref_node(ni)); | 1632 | ieee80211_sta_join(ic, ieee80211_ref_node(ni)); | |
1638 | splx(s); | 1633 | splx(s); | |
1639 | } | 1634 | } | |
1640 | 1635 | |||
1641 | static inline void | 1636 | static inline void | |
1642 | wi_rssadapt_input(struct ieee80211com *ic, struct ieee80211_node *ni, | 1637 | wi_rssadapt_input(struct ieee80211com *ic, struct ieee80211_node *ni, | |
1643 | struct ieee80211_frame *wh, int rssi) | 1638 | struct ieee80211_frame *wh, int rssi) | |
1644 | { | 1639 | { | |
1645 | struct wi_node *wn; | 1640 | struct wi_node *wn; | |
1646 | 1641 | |||
1647 | if (ni == NULL) { | 1642 | if (ni == NULL) { | |
1648 | printf("%s: null node", __func__); | 1643 | printf("%s: null node", __func__); | |
1649 | return; | 1644 | return; | |
1650 | } | 1645 | } | |
1651 | 1646 | |||
1652 | wn = (void*)ni; | 1647 | wn = (void*)ni; | |
1653 | ieee80211_rssadapt_input(ic, ni, &wn->wn_rssadapt, rssi); | 1648 | ieee80211_rssadapt_input(ic, ni, &wn->wn_rssadapt, rssi); | |
1654 | } | 1649 | } | |
1655 | 1650 | |||
1656 | STATIC void | 1651 | STATIC void | |
1657 | wi_rx_intr(struct wi_softc *sc) | 1652 | wi_rx_intr(struct wi_softc *sc) | |
1658 | { | 1653 | { | |
1659 | struct ieee80211com *ic = &sc->sc_ic; | 1654 | struct ieee80211com *ic = &sc->sc_ic; | |
1660 | struct ifnet *ifp = &sc->sc_if; | 1655 | struct ifnet *ifp = &sc->sc_if; | |
1661 | struct ieee80211_node *ni; | 1656 | struct ieee80211_node *ni; | |
1662 | struct wi_frame frmhdr; | 1657 | struct wi_frame frmhdr; | |
1663 | struct mbuf *m; | 1658 | struct mbuf *m; | |
1664 | struct ieee80211_frame *wh; | 1659 | struct ieee80211_frame *wh; | |
1665 | int fid, len, off, rssi; | 1660 | int fid, len, off, rssi; | |
1666 | uint8_t dir; | 1661 | uint8_t dir; | |
1667 | uint16_t status; | 1662 | uint16_t status; | |
1668 | uint32_t rstamp; | 1663 | uint32_t rstamp; | |
1669 | int s; | 1664 | int s; | |
1670 | 1665 | |||
1671 | fid = CSR_READ_2(sc, WI_RX_FID); | 1666 | fid = CSR_READ_2(sc, WI_RX_FID); | |
1672 | 1667 | |||
1673 | /* First read in the frame header */ | 1668 | /* First read in the frame header */ | |
1674 | if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr))) { | 1669 | if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr))) { | |
1675 | aprint_error_dev(sc->sc_dev, "%s read fid %x failed\n", | 1670 | aprint_error_dev(sc->sc_dev, "%s read fid %x failed\n", | |
1676 | __func__, fid); | 1671 | __func__, fid); | |
1677 | ifp->if_ierrors++; | 1672 | ifp->if_ierrors++; | |
1678 | return; | 1673 | return; | |
1679 | } | 1674 | } | |
1680 | 1675 | |||
1681 | if (IFF_DUMPPKTS(ifp)) | 1676 | if (IFF_DUMPPKTS(ifp)) | |
1682 | wi_dump_pkt(&frmhdr, NULL, frmhdr.wi_rx_signal); | 1677 | wi_dump_pkt(&frmhdr, NULL, frmhdr.wi_rx_signal); | |
1683 | 1678 | |||
1684 | /* | 1679 | /* | |
1685 | * Drop undecryptable or packets with receive errors here | 1680 | * Drop undecryptable or packets with receive errors here | |
1686 | */ | 1681 | */ | |
1687 | status = le16toh(frmhdr.wi_status); | 1682 | status = le16toh(frmhdr.wi_status); | |
1688 | if ((status & WI_STAT_ERRSTAT) != 0 && | 1683 | if ((status & WI_STAT_ERRSTAT) != 0 && | |
1689 | ic->ic_opmode != IEEE80211_M_MONITOR) { | 1684 | ic->ic_opmode != IEEE80211_M_MONITOR) { | |
1690 | ifp->if_ierrors++; | 1685 | ifp->if_ierrors++; | |
1691 | DPRINTF(("wi_rx_intr: fid %x error status %x\n", fid, status)); | 1686 | DPRINTF(("wi_rx_intr: fid %x error status %x\n", fid, status)); | |
1692 | return; | 1687 | return; | |
1693 | } | 1688 | } | |
1694 | rssi = frmhdr.wi_rx_signal; | 1689 | rssi = frmhdr.wi_rx_signal; | |
1695 | rstamp = (le16toh(frmhdr.wi_rx_tstamp0) << 16) | | 1690 | rstamp = (le16toh(frmhdr.wi_rx_tstamp0) << 16) | | |
1696 | le16toh(frmhdr.wi_rx_tstamp1); | 1691 | le16toh(frmhdr.wi_rx_tstamp1); | |
1697 | 1692 | |||
1698 | len = le16toh(frmhdr.wi_dat_len); | 1693 | len = le16toh(frmhdr.wi_dat_len); | |
1699 | off = ALIGN(sizeof(struct ieee80211_frame)); | 1694 | off = ALIGN(sizeof(struct ieee80211_frame)); | |
1700 | 1695 | |||
1701 | /* Sometimes the PRISM2.x returns bogusly large frames. Except | 1696 | /* Sometimes the PRISM2.x returns bogusly large frames. Except | |
1702 | * in monitor mode, just throw them away. | 1697 | * in monitor mode, just throw them away. | |
1703 | */ | 1698 | */ | |
1704 | if (off + len > MCLBYTES) { | 1699 | if (off + len > MCLBYTES) { | |
1705 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { | 1700 | if (ic->ic_opmode != IEEE80211_M_MONITOR) { | |
1706 | ifp->if_ierrors++; | 1701 | ifp->if_ierrors++; | |
1707 | DPRINTF(("wi_rx_intr: oversized packet\n")); | 1702 | DPRINTF(("wi_rx_intr: oversized packet\n")); | |
1708 | return; | 1703 | return; | |
1709 | } else | 1704 | } else | |
1710 | len = 0; | 1705 | len = 0; | |
1711 | } | 1706 | } | |
1712 | 1707 | |||
1713 | MGETHDR(m, M_DONTWAIT, MT_DATA); | 1708 | MGETHDR(m, M_DONTWAIT, MT_DATA); | |
1714 | if (m == NULL) { | 1709 | if (m == NULL) { | |
1715 | ifp->if_ierrors++; | 1710 | ifp->if_ierrors++; | |
1716 | DPRINTF(("wi_rx_intr: MGET failed\n")); | 1711 | DPRINTF(("wi_rx_intr: MGET failed\n")); | |
1717 | return; | 1712 | return; | |
1718 | } | 1713 | } | |
1719 | if (off + len > MHLEN) { | 1714 | if (off + len > MHLEN) { | |
1720 | MCLGET(m, M_DONTWAIT); | 1715 | MCLGET(m, M_DONTWAIT); | |
1721 | if ((m->m_flags & M_EXT) == 0) { | 1716 | if ((m->m_flags & M_EXT) == 0) { | |
1722 | m_freem(m); | 1717 | m_freem(m); | |
1723 | ifp->if_ierrors++; | 1718 | ifp->if_ierrors++; | |
1724 | DPRINTF(("wi_rx_intr: MCLGET failed\n")); | 1719 | DPRINTF(("wi_rx_intr: MCLGET failed\n")); | |
1725 | return; | 1720 | return; | |
1726 | } | 1721 | } | |
1727 | } | 1722 | } | |
1728 | 1723 | |||
1729 | m->m_data += off - sizeof(struct ieee80211_frame); | 1724 | m->m_data += off - sizeof(struct ieee80211_frame); | |
1730 | memcpy(m->m_data, &frmhdr.wi_whdr, sizeof(struct ieee80211_frame)); | 1725 | memcpy(m->m_data, &frmhdr.wi_whdr, sizeof(struct ieee80211_frame)); | |
1731 | wi_read_bap(sc, fid, sizeof(frmhdr), | 1726 | wi_read_bap(sc, fid, sizeof(frmhdr), | |
1732 | m->m_data + sizeof(struct ieee80211_frame), len); | 1727 | m->m_data + sizeof(struct ieee80211_frame), len); | |
1733 | m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len; | 1728 | m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame) + len; | |
1734 | m_set_rcvif(m, ifp); | 1729 | m_set_rcvif(m, ifp); | |
1735 | 1730 | |||
1736 | wh = mtod(m, struct ieee80211_frame *); | 1731 | wh = mtod(m, struct ieee80211_frame *); | |
1737 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { | 1732 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { | |
1738 | /* | 1733 | /* | |
1739 | * WEP is decrypted by hardware. Clear WEP bit | 1734 | * WEP is decrypted by hardware. Clear WEP bit | |
1740 | * header for ieee80211_input(). | 1735 | * header for ieee80211_input(). | |
1741 | */ | 1736 | */ | |
1742 | wh->i_fc[1] &= ~IEEE80211_FC1_WEP; | 1737 | wh->i_fc[1] &= ~IEEE80211_FC1_WEP; | |
1743 | } | 1738 | } | |
1744 | 1739 | |||
1745 | s = splnet(); | 1740 | s = splnet(); | |
1746 | 1741 | |||
1747 | if (sc->sc_drvbpf) { | 1742 | if (sc->sc_drvbpf) { | |
1748 | struct wi_rx_radiotap_header *tap = &sc->sc_rxtap; | 1743 | struct wi_rx_radiotap_header *tap = &sc->sc_rxtap; | |
1749 | 1744 | |||
1750 | tap->wr_rate = frmhdr.wi_rx_rate / 5; | 1745 | tap->wr_rate = frmhdr.wi_rx_rate / 5; | |
1751 | tap->wr_antsignal = frmhdr.wi_rx_signal; | 1746 | tap->wr_antsignal = frmhdr.wi_rx_signal; | |
1752 | tap->wr_antnoise = frmhdr.wi_rx_silence; | 1747 | tap->wr_antnoise = frmhdr.wi_rx_silence; | |
1753 | tap->wr_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq); | 1748 | tap->wr_chan_freq = htole16(ic->ic_bss->ni_chan->ic_freq); | |
1754 | tap->wr_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags); | 1749 | tap->wr_chan_flags = htole16(ic->ic_bss->ni_chan->ic_flags); | |
1755 | if (frmhdr.wi_status & WI_STAT_PCF) | 1750 | if (frmhdr.wi_status & WI_STAT_PCF) | |
1756 | tap->wr_flags |= IEEE80211_RADIOTAP_F_CFP; | 1751 | tap->wr_flags |= IEEE80211_RADIOTAP_F_CFP; | |
1757 | 1752 | |||
1758 | /* XXX IEEE80211_RADIOTAP_F_WEP */ | 1753 | /* XXX IEEE80211_RADIOTAP_F_WEP */ | |
1759 | bpf_mtap2(sc->sc_drvbpf, tap, tap->wr_ihdr.it_len, m, | 1754 | bpf_mtap2(sc->sc_drvbpf, tap, tap->wr_ihdr.it_len, m, | |
1760 | BPF_D_IN); | 1755 | BPF_D_IN); | |
1761 | } | 1756 | } | |
1762 | 1757 | |||
1763 | /* synchronize driver's BSSID with firmware's BSSID */ | 1758 | /* synchronize driver's BSSID with firmware's BSSID */ | |
1764 | dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; | 1759 | dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; | |
1765 | if (ic->ic_opmode == IEEE80211_M_IBSS && dir == IEEE80211_FC1_DIR_NODS) | 1760 | if (ic->ic_opmode == IEEE80211_M_IBSS && dir == IEEE80211_FC1_DIR_NODS) | |
1766 | wi_sync_bssid(sc, wh->i_addr3); | 1761 | wi_sync_bssid(sc, wh->i_addr3); | |
1767 | 1762 | |||
1768 | ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *)); | 1763 | ni = ieee80211_find_rxnode(ic, mtod(m, struct ieee80211_frame_min *)); | |
1769 | 1764 | |||
1770 | ieee80211_input(ic, m, ni, rssi, rstamp); | 1765 | ieee80211_input(ic, m, ni, rssi, rstamp); | |
1771 | 1766 | |||
1772 | wi_rssadapt_input(ic, ni, wh, rssi); | 1767 | wi_rssadapt_input(ic, ni, wh, rssi); | |
1773 | 1768 | |||
1774 | /* | 1769 | /* | |
1775 | * The frame may have caused the node to be marked for | 1770 | * The frame may have caused the node to be marked for | |
1776 | * reclamation (e.g. in response to a DEAUTH message) | 1771 | * reclamation (e.g. in response to a DEAUTH message) | |
1777 | * so use release_node here instead of unref_node. | 1772 | * so use release_node here instead of unref_node. | |
1778 | */ | 1773 | */ | |
1779 | ieee80211_free_node(ni); | 1774 | ieee80211_free_node(ni); | |
1780 | 1775 | |||
1781 | splx(s); | 1776 | splx(s); | |
1782 | } | 1777 | } | |
1783 | 1778 | |||
1784 | STATIC void | 1779 | STATIC void | |
1785 | wi_tx_ex_intr(struct wi_softc *sc) | 1780 | wi_tx_ex_intr(struct wi_softc *sc) | |
1786 | { | 1781 | { | |
1787 | struct ieee80211com *ic = &sc->sc_ic; | 1782 | struct ieee80211com *ic = &sc->sc_ic; | |
1788 | struct ifnet *ifp = &sc->sc_if; | 1783 | struct ifnet *ifp = &sc->sc_if; | |
1789 | struct ieee80211_node *ni; | 1784 | struct ieee80211_node *ni; | |
1790 | struct ieee80211_rssdesc *id; | 1785 | struct ieee80211_rssdesc *id; | |
1791 | struct wi_rssdesc *rssd; | 1786 | struct wi_rssdesc *rssd; | |
1792 | struct wi_frame frmhdr; | 1787 | struct wi_frame frmhdr; | |
1793 | int fid, s; | 1788 | int fid, s; | |
1794 | uint16_t status; | 1789 | uint16_t status; | |
1795 | 1790 | |||
1796 | s = splnet(); | 1791 | s = splnet(); | |
1797 | 1792 | |||
1798 | fid = CSR_READ_2(sc, WI_TX_CMP_FID); | 1793 | fid = CSR_READ_2(sc, WI_TX_CMP_FID); | |
1799 | /* Read in the frame header */ | 1794 | /* Read in the frame header */ | |
1800 | if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) { | 1795 | if (wi_read_bap(sc, fid, 0, &frmhdr, sizeof(frmhdr)) != 0) { | |
1801 | aprint_error_dev(sc->sc_dev, "%s read fid %x failed\n", | 1796 | aprint_error_dev(sc->sc_dev, "%s read fid %x failed\n", | |
1802 | __func__, fid); | 1797 | __func__, fid); | |
1803 | wi_rssdescs_reset(ic, &sc->sc_rssd, &sc->sc_rssdfree, | 1798 | wi_rssdescs_reset(ic, &sc->sc_rssd, &sc->sc_rssdfree, | |
1804 | &sc->sc_txpending); | 1799 | &sc->sc_txpending); | |
1805 | goto out; | 1800 | goto out; | |
1806 | } | 1801 | } | |
1807 | 1802 | |||
1808 | if (frmhdr.wi_tx_idx >= WI_NTXRSS) { | 1803 | if (frmhdr.wi_tx_idx >= WI_NTXRSS) { | |
1809 | aprint_error_dev(sc->sc_dev, "%s bad idx %02x\n", | 1804 | aprint_error_dev(sc->sc_dev, "%s bad idx %02x\n", | |
1810 | __func__, frmhdr.wi_tx_idx); | 1805 | __func__, frmhdr.wi_tx_idx); | |
1811 | wi_rssdescs_reset(ic, &sc->sc_rssd, &sc->sc_rssdfree, | 1806 | wi_rssdescs_reset(ic, &sc->sc_rssd, &sc->sc_rssdfree, | |
1812 | &sc->sc_txpending); | 1807 | &sc->sc_txpending); | |
1813 | goto out; | 1808 | goto out; | |
1814 | } | 1809 | } | |
1815 | 1810 | |||
1816 | status = le16toh(frmhdr.wi_status); | 1811 | status = le16toh(frmhdr.wi_status); | |
1817 | 1812 | |||
1818 | /* | 1813 | /* | |
1819 | * Spontaneous station disconnects appear as xmit | 1814 | * Spontaneous station disconnects appear as xmit | |
1820 | * errors. Don't announce them and/or count them | 1815 | * errors. Don't announce them and/or count them | |
1821 | * as an output error. | 1816 | * as an output error. | |
1822 | */ | 1817 | */ | |
1823 | if (ppsratecheck(&lasttxerror, &curtxeps, wi_txerate)) { | 1818 | if (ppsratecheck(&lasttxerror, &curtxeps, wi_txerate)) { | |
1824 | aprint_error_dev(sc->sc_dev, "tx failed"); | 1819 | aprint_error_dev(sc->sc_dev, "tx failed"); | |
1825 | if (status & WI_TXSTAT_RET_ERR) | 1820 | if (status & WI_TXSTAT_RET_ERR) | |
1826 | printf(", retry limit exceeded"); | 1821 | printf(", retry limit exceeded"); | |
1827 | if (status & WI_TXSTAT_AGED_ERR) | 1822 | if (status & WI_TXSTAT_AGED_ERR) | |
1828 | printf(", max transmit lifetime exceeded"); | 1823 | printf(", max transmit lifetime exceeded"); | |
1829 | if (status & WI_TXSTAT_DISCONNECT) | 1824 | if (status & WI_TXSTAT_DISCONNECT) | |
1830 | printf(", port disconnected"); | 1825 | printf(", port disconnected"); | |
1831 | if (status & WI_TXSTAT_FORM_ERR) | 1826 | if (status & WI_TXSTAT_FORM_ERR) | |
1832 | printf(", invalid format (data len %u src %s)", | 1827 | printf(", invalid format (data len %u src %s)", | |
1833 | le16toh(frmhdr.wi_dat_len), | 1828 | le16toh(frmhdr.wi_dat_len), | |
1834 | ether_sprintf(frmhdr.wi_ehdr.ether_shost)); | 1829 | ether_sprintf(frmhdr.wi_ehdr.ether_shost)); | |
1835 | if (status & ~0xf) | 1830 | if (status & ~0xf) | |
1836 | printf(", status=0x%x", status); | 1831 | printf(", status=0x%x", status); | |
1837 | printf("\n"); | 1832 | printf("\n"); | |
1838 | } | 1833 | } | |
1839 | ifp->if_oerrors++; | 1834 | ifp->if_oerrors++; | |
1840 | rssd = &sc->sc_rssd[frmhdr.wi_tx_idx]; | 1835 | rssd = &sc->sc_rssd[frmhdr.wi_tx_idx]; | |
1841 | id = &rssd->rd_desc; | 1836 | id = &rssd->rd_desc; | |
1842 | if ((status & WI_TXSTAT_RET_ERR) != 0) | 1837 | if ((status & WI_TXSTAT_RET_ERR) != 0) | |
1843 | wi_lower_rate(ic, id); | 1838 | wi_lower_rate(ic, id); | |
1844 | 1839 | |||
1845 | ni = id->id_node; | 1840 | ni = id->id_node; | |
1846 | id->id_node = NULL; | 1841 | id->id_node = NULL; | |
1847 | 1842 | |||
1848 | if (ni == NULL) { | 1843 | if (ni == NULL) { | |
1849 | aprint_error_dev(sc->sc_dev, "%s null node, rssdesc %02x\n", | 1844 | aprint_error_dev(sc->sc_dev, "%s null node, rssdesc %02x\n", | |
1850 | __func__, frmhdr.wi_tx_idx); | 1845 | __func__, frmhdr.wi_tx_idx); | |
1851 | goto out; | 1846 | goto out; | |
1852 | } | 1847 | } | |
1853 | 1848 | |||
1854 | if (sc->sc_txpending[id->id_rateidx]-- == 0) { | 1849 | if (sc->sc_txpending[id->id_rateidx]-- == 0) { | |
1855 | aprint_error_dev(sc->sc_dev, "%s txpending[%i] wraparound", | 1850 | aprint_error_dev(sc->sc_dev, "%s txpending[%i] wraparound", | |
1856 | __func__, id->id_rateidx); | 1851 | __func__, id->id_rateidx); | |
1857 | sc->sc_txpending[id->id_rateidx] = 0; | 1852 | sc->sc_txpending[id->id_rateidx] = 0; | |
1858 | } | 1853 | } | |
1859 | if (ni != NULL) | 1854 | if (ni != NULL) | |
1860 | ieee80211_free_node(ni); | 1855 | ieee80211_free_node(ni); | |
1861 | SLIST_INSERT_HEAD(&sc->sc_rssdfree, rssd, rd_next); | 1856 | SLIST_INSERT_HEAD(&sc->sc_rssdfree, rssd, rd_next); | |
1862 | out: | 1857 | out: | |
1863 | ifp->if_flags &= ~IFF_OACTIVE; | 1858 | ifp->if_flags &= ~IFF_OACTIVE; | |
1864 | splx(s); | 1859 | splx(s); | |
1865 | } | 1860 | } | |
1866 | 1861 | |||
1867 | STATIC void | 1862 | STATIC void | |
1868 | wi_txalloc_intr(struct wi_softc *sc) | 1863 | wi_txalloc_intr(struct wi_softc *sc) | |
1869 | { | 1864 | { | |
1870 | int fid, cur, s; | 1865 | int fid, cur, s; | |
1871 | 1866 | |||
1872 | s = splnet(); | 1867 | s = splnet(); | |
1873 | 1868 | |||
1874 | fid = CSR_READ_2(sc, WI_ALLOC_FID); | 1869 | fid = CSR_READ_2(sc, WI_ALLOC_FID); | |
1875 | 1870 | |||
1876 | cur = sc->sc_txalloc; | 1871 | cur = sc->sc_txalloc; | |
1877 | #ifdef DIAGNOSTIC | 1872 | #ifdef DIAGNOSTIC | |
1878 | if (sc->sc_txstarted == 0) { | 1873 | if (sc->sc_txstarted == 0) { | |
1879 | printf("%s: spurious alloc %x != %x, alloc %d queue %d start %d alloced %d queued %d started %d\n", | 1874 | printf("%s: spurious alloc %x != %x, alloc %d queue %d start %d alloced %d queued %d started %d\n", | |
1880 | device_xname(sc->sc_dev), fid, sc->sc_txd[cur].d_fid, cur, | 1875 | device_xname(sc->sc_dev), fid, sc->sc_txd[cur].d_fid, cur, | |
1881 | sc->sc_txqueue, sc->sc_txstart, sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted); | 1876 | sc->sc_txqueue, sc->sc_txstart, sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted); | |
1882 | splx(s); | 1877 | splx(s); | |
1883 | return; | 1878 | return; | |
1884 | } | 1879 | } | |
1885 | #endif | 1880 | #endif | |
1886 | --sc->sc_txstarted; | 1881 | --sc->sc_txstarted; | |
1887 | ++sc->sc_txalloced; | 1882 | ++sc->sc_txalloced; | |
1888 | sc->sc_txd[cur].d_fid = fid; | 1883 | sc->sc_txd[cur].d_fid = fid; | |
1889 | sc->sc_txalloc = (cur + 1) % WI_NTXBUF; | 1884 | sc->sc_txalloc = (cur + 1) % WI_NTXBUF; | |
1890 | #ifdef WI_RING_DEBUG | 1885 | #ifdef WI_RING_DEBUG | |
1891 | printf("%s: alloc %04x, alloc %d queue %d start %d alloced %d queued %d started %d\n", | 1886 | printf("%s: alloc %04x, alloc %d queue %d start %d alloced %d queued %d started %d\n", | |
1892 | device_xname(sc->sc_dev), fid, | 1887 | device_xname(sc->sc_dev), fid, | |
1893 | sc->sc_txalloc, sc->sc_txqueue, sc->sc_txstart, | 1888 | sc->sc_txalloc, sc->sc_txqueue, sc->sc_txstart, | |
1894 | sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted); | 1889 | sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted); | |
1895 | #endif | 1890 | #endif | |
1896 | splx(s); | 1891 | splx(s); | |
1897 | } | 1892 | } | |
1898 | 1893 | |||
1899 | STATIC void | 1894 | STATIC void | |
1900 | wi_cmd_intr(struct wi_softc *sc) | 1895 | wi_cmd_intr(struct wi_softc *sc) | |
1901 | { | 1896 | { | |
1902 | struct ifnet *ifp = &sc->sc_if; | 1897 | struct ifnet *ifp = &sc->sc_if; | |
1903 | int s; | 1898 | int s; | |
1904 | 1899 | |||
1905 | if (sc->sc_invalid) | 1900 | if (sc->sc_invalid) | |
1906 | return; | 1901 | return; | |
1907 | 1902 | |||
1908 | s = splnet(); | 1903 | s = splnet(); | |
1909 | #ifdef WI_DEBUG | 1904 | #ifdef WI_DEBUG | |
1910 | if (wi_debug > 1) | 1905 | if (wi_debug > 1) | |
1911 | printf("%s: %d txcmds outstanding\n", __func__, sc->sc_txcmds); | 1906 | printf("%s: %d txcmds outstanding\n", __func__, sc->sc_txcmds); | |
1912 | #endif | 1907 | #endif | |
1913 | KASSERT(sc->sc_txcmds > 0); | 1908 | KASSERT(sc->sc_txcmds > 0); | |
1914 | 1909 | |||
1915 | --sc->sc_txcmds; | 1910 | --sc->sc_txcmds; | |
1916 | 1911 | |||
1917 | if (--sc->sc_txqueued == 0) { | 1912 | if (--sc->sc_txqueued == 0) { | |
1918 | sc->sc_tx_timer = 0; | 1913 | sc->sc_tx_timer = 0; | |
1919 | ifp->if_flags &= ~IFF_OACTIVE; | 1914 | ifp->if_flags &= ~IFF_OACTIVE; | |
1920 | #ifdef WI_RING_DEBUG | 1915 | #ifdef WI_RING_DEBUG | |
1921 | printf("%s: cmd , alloc %d queue %d start %d alloced %d queued %d started %d\n", | 1916 | printf("%s: cmd , alloc %d queue %d start %d alloced %d queued %d started %d\n", | |
1922 | device_xname(sc->sc_dev), | 1917 | device_xname(sc->sc_dev), | |
1923 | sc->sc_txalloc, sc->sc_txqueue, sc->sc_txstart, | 1918 | sc->sc_txalloc, sc->sc_txqueue, sc->sc_txstart, | |
1924 | sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted); | 1919 | sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted); | |
1925 | #endif | 1920 | #endif | |
1926 | } else | 1921 | } else | |
1927 | wi_push_packet(sc); | 1922 | wi_push_packet(sc); | |
1928 | splx(s); | 1923 | splx(s); | |
1929 | } | 1924 | } | |
1930 | 1925 | |||
1931 | STATIC void | 1926 | STATIC void | |
1932 | wi_push_packet(struct wi_softc *sc) | 1927 | wi_push_packet(struct wi_softc *sc) | |
1933 | { | 1928 | { | |
1934 | struct ifnet *ifp = &sc->sc_if; | 1929 | struct ifnet *ifp = &sc->sc_if; | |
1935 | int cur, fid; | 1930 | int cur, fid; | |
1936 | 1931 | |||
1937 | cur = sc->sc_txstart; | 1932 | cur = sc->sc_txstart; | |
1938 | fid = sc->sc_txd[cur].d_fid; | 1933 | fid = sc->sc_txd[cur].d_fid; | |
1939 | 1934 | |||
1940 | KASSERT(sc->sc_txcmds == 0); | 1935 | KASSERT(sc->sc_txcmds == 0); | |
1941 | 1936 | |||
1942 | if (wi_cmd_start(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) { | 1937 | if (wi_cmd_start(sc, WI_CMD_TX | WI_RECLAIM, fid, 0, 0)) { | |
1943 | aprint_error_dev(sc->sc_dev, "xmit failed\n"); | 1938 | aprint_error_dev(sc->sc_dev, "xmit failed\n"); | |
1944 | /* XXX ring might have a hole */ | 1939 | /* XXX ring might have a hole */ | |
1945 | } | 1940 | } | |
1946 | 1941 | |||
1947 | if (sc->sc_txcmds++ > 0) | 1942 | if (sc->sc_txcmds++ > 0) | |
1948 | printf("%s: %d tx cmds pending!!!\n", __func__, sc->sc_txcmds); | 1943 | printf("%s: %d tx cmds pending!!!\n", __func__, sc->sc_txcmds); | |
1949 | 1944 | |||
1950 | ++sc->sc_txstarted; | 1945 | ++sc->sc_txstarted; | |
1951 | #ifdef DIAGNOSTIC | 1946 | #ifdef DIAGNOSTIC | |
1952 | if (sc->sc_txstarted > WI_NTXBUF) | 1947 | if (sc->sc_txstarted > WI_NTXBUF) | |
1953 | aprint_error_dev(sc->sc_dev, "too many buffers started\n"); | 1948 | aprint_error_dev(sc->sc_dev, "too many buffers started\n"); | |
1954 | #endif | 1949 | #endif | |
1955 | sc->sc_txstart = (cur + 1) % WI_NTXBUF; | 1950 | sc->sc_txstart = (cur + 1) % WI_NTXBUF; | |
1956 | sc->sc_tx_timer = 5; | 1951 | sc->sc_tx_timer = 5; | |
1957 | ifp->if_timer = 1; | 1952 | ifp->if_timer = 1; | |
1958 | #ifdef WI_RING_DEBUG | 1953 | #ifdef WI_RING_DEBUG | |
1959 | printf("%s: push %04x, alloc %d queue %d start %d alloced %d queued %d started %d\n", | 1954 | printf("%s: push %04x, alloc %d queue %d start %d alloced %d queued %d started %d\n", | |
1960 | device_xname(sc->sc_dev), fid, | 1955 | device_xname(sc->sc_dev), fid, | |
1961 | sc->sc_txalloc, sc->sc_txqueue, sc->sc_txstart, | 1956 | sc->sc_txalloc, sc->sc_txqueue, sc->sc_txstart, | |
1962 | sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted); | 1957 | sc->sc_txalloced, sc->sc_txqueued, sc->sc_txstarted); | |
1963 | #endif | 1958 | #endif | |
1964 | } | 1959 | } | |
1965 | 1960 | |||
1966 | STATIC void | 1961 | STATIC void | |
1967 | wi_tx_intr(struct wi_softc *sc) | 1962 | wi_tx_intr(struct wi_softc *sc) | |
1968 | { | 1963 | { | |
1969 | struct ieee80211com *ic = &sc->sc_ic; | 1964 | struct ieee80211com *ic = &sc->sc_ic; | |
1970 | struct ifnet *ifp = &sc->sc_if; | 1965 | struct ifnet *ifp = &sc->sc_if; | |
1971 | struct ieee80211_node *ni; | 1966 | struct ieee80211_node *ni; | |
1972 | struct ieee80211_rssdesc *id; | 1967 | struct ieee80211_rssdesc *id; | |
1973 | struct wi_rssdesc *rssd; | 1968 | struct wi_rssdesc *rssd; | |
1974 | struct wi_frame frmhdr; | 1969 | struct wi_frame frmhdr; | |
1975 | int fid, s; | 1970 | int fid, s; | |
1976 | 1971 | |||
1977 | s = splnet(); | 1972 | s = splnet(); | |
1978 | 1973 | |||
1979 | fid = CSR_READ_2(sc, WI_TX_CMP_FID); | 1974 | fid = CSR_READ_2(sc, WI_TX_CMP_FID); | |
1980 | /* Read in the frame header */ | 1975 | /* Read in the frame header */ | |
1981 | if (wi_read_bap(sc, fid, offsetof(struct wi_frame, wi_tx_swsup2), | 1976 | if (wi_read_bap(sc, fid, offsetof(struct wi_frame, wi_tx_swsup2), | |
1982 | &frmhdr.wi_tx_swsup2, 2) != 0) { | 1977 | &frmhdr.wi_tx_swsup2, 2) != 0) { | |
1983 | aprint_error_dev(sc->sc_dev, "%s read fid %x failed\n", | 1978 | aprint_error_dev(sc->sc_dev, "%s read fid %x failed\n", | |
1984 | __func__, fid); | 1979 | __func__, fid); | |
1985 | wi_rssdescs_reset(ic, &sc->sc_rssd, &sc->sc_rssdfree, | 1980 | wi_rssdescs_reset(ic, &sc->sc_rssd, &sc->sc_rssdfree, | |
1986 | &sc->sc_txpending); | 1981 | &sc->sc_txpending); | |
1987 | goto out; | 1982 | goto out; | |
1988 | } | 1983 | } | |
1989 | 1984 | |||
1990 | if (frmhdr.wi_tx_idx >= WI_NTXRSS) { | 1985 | if (frmhdr.wi_tx_idx >= WI_NTXRSS) { | |
1991 | aprint_error_dev(sc->sc_dev, "%s bad idx %02x\n", | 1986 | aprint_error_dev(sc->sc_dev, "%s bad idx %02x\n", | |
1992 | __func__, frmhdr.wi_tx_idx); | 1987 | __func__, frmhdr.wi_tx_idx); | |
1993 | wi_rssdescs_reset(ic, &sc->sc_rssd, &sc->sc_rssdfree, | 1988 | wi_rssdescs_reset(ic, &sc->sc_rssd, &sc->sc_rssdfree, | |
1994 | &sc->sc_txpending); | 1989 | &sc->sc_txpending); | |
1995 | goto out; | 1990 | goto out; | |
1996 | } | 1991 | } | |
1997 | 1992 | |||
1998 | rssd = &sc->sc_rssd[frmhdr.wi_tx_idx]; | 1993 | rssd = &sc->sc_rssd[frmhdr.wi_tx_idx]; | |
1999 | id = &rssd->rd_desc; | 1994 | id = &rssd->rd_desc; | |
2000 | wi_raise_rate(ic, id); | 1995 | wi_raise_rate(ic, id); | |
2001 | 1996 | |||
2002 | ni = id->id_node; | 1997 | ni = id->id_node; | |
2003 | id->id_node = NULL; | 1998 | id->id_node = NULL; | |
2004 | 1999 | |||
2005 | if (ni == NULL) { | 2000 | if (ni == NULL) { | |
2006 | aprint_error_dev(sc->sc_dev, "%s null node, rssdesc %02x\n", | 2001 | aprint_error_dev(sc->sc_dev, "%s null node, rssdesc %02x\n", | |
2007 | __func__, frmhdr.wi_tx_idx); | 2002 | __func__, frmhdr.wi_tx_idx); | |
2008 | goto out; | 2003 | goto out; | |
2009 | } | 2004 | } | |
2010 | 2005 | |||
2011 | if (sc->sc_txpending[id->id_rateidx]-- == 0) { | 2006 | if (sc->sc_txpending[id->id_rateidx]-- == 0) { | |
2012 | aprint_error_dev(sc->sc_dev, "%s txpending[%i] wraparound", | 2007 | aprint_error_dev(sc->sc_dev, "%s txpending[%i] wraparound", | |
2013 | __func__, id->id_rateidx); | 2008 | __func__, id->id_rateidx); | |
2014 | sc->sc_txpending[id->id_rateidx] = 0; | 2009 | sc->sc_txpending[id->id_rateidx] = 0; | |
2015 | } | 2010 | } | |
2016 | if (ni != NULL) | 2011 | if (ni != NULL) | |
2017 | ieee80211_free_node(ni); | 2012 | ieee80211_free_node(ni); | |
2018 | SLIST_INSERT_HEAD(&sc->sc_rssdfree, rssd, rd_next); | 2013 | SLIST_INSERT_HEAD(&sc->sc_rssdfree, rssd, rd_next); | |
2019 | out: | 2014 | out: | |
2020 | ifp->if_flags &= ~IFF_OACTIVE; | 2015 | ifp->if_flags &= ~IFF_OACTIVE; | |
2021 | splx(s); | 2016 | splx(s); | |
2022 | } | 2017 | } | |
2023 | 2018 | |||
2024 | STATIC void | 2019 | STATIC void | |
2025 | wi_info_intr(struct wi_softc *sc) | 2020 | wi_info_intr(struct wi_softc *sc) | |
2026 | { | 2021 | { | |
2027 | struct ieee80211com *ic = &sc->sc_ic; | 2022 | struct ieee80211com *ic = &sc->sc_ic; | |
2028 | struct ifnet *ifp = &sc->sc_if; | 2023 | struct ifnet *ifp = &sc->sc_if; | |
2029 | int i, s, fid, len, off; | 2024 | int i, s, fid, len, off; | |
2030 | uint16_t ltbuf[2]; | 2025 | uint16_t ltbuf[2]; | |
2031 | uint16_t stat; | 2026 | uint16_t stat; | |
2032 | uint32_t *ptr; | 2027 | uint32_t *ptr; | |
2033 | 2028 | |||
2034 | fid = CSR_READ_2(sc, WI_INFO_FID); | 2029 | fid = CSR_READ_2(sc, WI_INFO_FID); | |
2035 | wi_read_bap(sc, fid, 0, ltbuf, sizeof(ltbuf)); | 2030 | wi_read_bap(sc, fid, 0, ltbuf, sizeof(ltbuf)); | |
2036 | 2031 | |||
2037 | switch (le16toh(ltbuf[1])) { | 2032 | switch (le16toh(ltbuf[1])) { | |
2038 | 2033 | |||
2039 | case WI_INFO_LINK_STAT: | 2034 | case WI_INFO_LINK_STAT: | |
2040 | wi_read_bap(sc, fid, sizeof(ltbuf), &stat, sizeof(stat)); | 2035 | wi_read_bap(sc, fid, sizeof(ltbuf), &stat, sizeof(stat)); | |
2041 | DPRINTF(("wi_info_intr: LINK_STAT 0x%x\n", le16toh(stat))); | 2036 | DPRINTF(("wi_info_intr: LINK_STAT 0x%x\n", le16toh(stat))); | |
2042 | switch (le16toh(stat)) { | 2037 | switch (le16toh(stat)) { | |
2043 | case CONNECTED: | 2038 | case CONNECTED: | |
2044 | sc->sc_flags &= ~WI_FLAGS_OUTRANGE; | 2039 | sc->sc_flags &= ~WI_FLAGS_OUTRANGE; | |
2045 | if (ic->ic_state == IEEE80211_S_RUN && | 2040 | if (ic->ic_state == IEEE80211_S_RUN && | |
2046 | ic->ic_opmode != IEEE80211_M_IBSS) | 2041 | ic->ic_opmode != IEEE80211_M_IBSS) | |
2047 | break; | 2042 | break; | |
2048 | /* FALLTHROUGH */ | 2043 | /* FALLTHROUGH */ | |
2049 | case AP_CHANGE: | 2044 | case AP_CHANGE: | |
2050 | s = splnet(); | 2045 | s = splnet(); | |
2051 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1); | 2046 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1); | |
2052 | splx(s); | 2047 | splx(s); | |
2053 | break; | 2048 | break; | |
2054 | case AP_IN_RANGE: | 2049 | case AP_IN_RANGE: | |
2055 | sc->sc_flags &= ~WI_FLAGS_OUTRANGE; | 2050 | sc->sc_flags &= ~WI_FLAGS_OUTRANGE; | |
2056 | break; | 2051 | break; | |
2057 | case AP_OUT_OF_RANGE: | 2052 | case AP_OUT_OF_RANGE: | |
2058 | if (sc->sc_firmware_type == WI_SYMBOL && | 2053 | if (sc->sc_firmware_type == WI_SYMBOL && | |
2059 | sc->sc_scan_timer > 0) { | 2054 | sc->sc_scan_timer > 0) { | |
2060 | if (wi_cmd(sc, WI_CMD_INQUIRE, | 2055 | if (wi_cmd(sc, WI_CMD_INQUIRE, | |
2061 | WI_INFO_HOST_SCAN_RESULTS, 0, 0) != 0) | 2056 | WI_INFO_HOST_SCAN_RESULTS, 0, 0) != 0) | |
2062 | sc->sc_scan_timer = 0; | 2057 | sc->sc_scan_timer = 0; | |
2063 | break; | 2058 | break; | |
2064 | } | 2059 | } | |
2065 | if (ic->ic_opmode == IEEE80211_M_STA) | 2060 | if (ic->ic_opmode == IEEE80211_M_STA) | |
2066 | sc->sc_flags |= WI_FLAGS_OUTRANGE; | 2061 | sc->sc_flags |= WI_FLAGS_OUTRANGE; | |
2067 | break; | 2062 | break; | |
2068 | case DISCONNECTED: | 2063 | case DISCONNECTED: | |
2069 | case ASSOC_FAILED: | 2064 | case ASSOC_FAILED: | |
2070 | s = splnet(); | 2065 | s = splnet(); | |
2071 | if (ic->ic_opmode == IEEE80211_M_STA) | 2066 | if (ic->ic_opmode == IEEE80211_M_STA) | |
2072 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | 2067 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | |
2073 | splx(s); | 2068 | splx(s); | |
2074 | break; | 2069 | break; | |
2075 | } | 2070 | } | |
2076 | break; | 2071 | break; | |
2077 | 2072 | |||
2078 | case WI_INFO_COUNTERS: | 2073 | case WI_INFO_COUNTERS: | |
2079 | /* some card versions have a larger stats structure */ | 2074 | /* some card versions have a larger stats structure */ | |
2080 | len = uimin(le16toh(ltbuf[0]) - 1, sizeof(sc->sc_stats) / 4); | 2075 | len = uimin(le16toh(ltbuf[0]) - 1, sizeof(sc->sc_stats) / 4); | |
2081 | ptr = (uint32_t *)&sc->sc_stats; | 2076 | ptr = (uint32_t *)&sc->sc_stats; | |
2082 | off = sizeof(ltbuf); | 2077 | off = sizeof(ltbuf); | |
2083 | for (i = 0; i < len; i++, off += 2, ptr++) { | 2078 | for (i = 0; i < len; i++, off += 2, ptr++) { | |
2084 | wi_read_bap(sc, fid, off, &stat, sizeof(stat)); | 2079 | wi_read_bap(sc, fid, off, &stat, sizeof(stat)); | |
2085 | stat = le16toh(stat); | 2080 | stat = le16toh(stat); | |
2086 | #ifdef WI_HERMES_STATS_WAR | 2081 | #ifdef WI_HERMES_STATS_WAR | |
2087 | if (stat & 0xf000) | 2082 | if (stat & 0xf000) | |
2088 | stat = ~stat; | 2083 | stat = ~stat; | |
2089 | #endif | 2084 | #endif | |
2090 | *ptr += stat; | 2085 | *ptr += stat; | |
2091 | } | 2086 | } | |
2092 | ifp->if_collisions = sc->sc_stats.wi_tx_single_retries + | 2087 | ifp->if_collisions = sc->sc_stats.wi_tx_single_retries + | |
2093 | sc->sc_stats.wi_tx_multi_retries + | 2088 | sc->sc_stats.wi_tx_multi_retries + | |
2094 | sc->sc_stats.wi_tx_retry_limit; | 2089 | sc->sc_stats.wi_tx_retry_limit; | |
2095 | break; | 2090 | break; | |
2096 | 2091 | |||
2097 | case WI_INFO_SCAN_RESULTS: | 2092 | case WI_INFO_SCAN_RESULTS: | |
2098 | case WI_INFO_HOST_SCAN_RESULTS: | 2093 | case WI_INFO_HOST_SCAN_RESULTS: | |
2099 | wi_scan_result(sc, fid, le16toh(ltbuf[0])); | 2094 | wi_scan_result(sc, fid, le16toh(ltbuf[0])); | |
2100 | break; | 2095 | break; | |
2101 | 2096 | |||
2102 | default: | 2097 | default: | |
2103 | DPRINTF(("wi_info_intr: got fid %x type %x len %d\n", fid, | 2098 | DPRINTF(("wi_info_intr: got fid %x type %x len %d\n", fid, | |
2104 | le16toh(ltbuf[1]), le16toh(ltbuf[0]))); | 2099 | le16toh(ltbuf[1]), le16toh(ltbuf[0]))); | |
2105 | break; | 2100 | break; | |
2106 | } | 2101 | } | |
2107 | } | 2102 | } | |
2108 | 2103 | |||
2109 | STATIC int | 2104 | STATIC int | |
2110 | wi_write_multi(struct wi_softc *sc) | 2105 | wi_write_multi(struct wi_softc *sc) | |
2111 | { | 2106 | { | |
2112 | struct ethercom *ec = &sc->sc_ec; | 2107 | struct ethercom *ec = &sc->sc_ec; | |
2113 | struct ifnet *ifp = &sc->sc_if; | 2108 | struct ifnet *ifp = &sc->sc_if; | |
2114 | int n; | 2109 | int n; | |
2115 | struct wi_mcast mlist; | 2110 | struct wi_mcast mlist; | |
2116 | struct ether_multi *enm; | 2111 | struct ether_multi *enm; | |
2117 | struct ether_multistep estep; | 2112 | struct ether_multistep estep; | |
2118 | 2113 | |||
2119 | if ((ifp->if_flags & IFF_PROMISC) != 0) { | 2114 | if ((ifp->if_flags & IFF_PROMISC) != 0) { | |
2120 | allmulti: | 2115 | allmulti: | |
2121 | ifp->if_flags |= IFF_ALLMULTI; | 2116 | ifp->if_flags |= IFF_ALLMULTI; | |
2122 | memset(&mlist, 0, sizeof(mlist)); | 2117 | memset(&mlist, 0, sizeof(mlist)); | |
2123 | return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, | 2118 | return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, | |
2124 | sizeof(mlist)); | 2119 | sizeof(mlist)); | |
2125 | } | 2120 | } | |
2126 | 2121 | |||
2127 | n = 0; | 2122 | n = 0; | |
2128 | ETHER_LOCK(ec); | 2123 | ETHER_LOCK(ec); | |
2129 | ETHER_FIRST_MULTI(estep, ec, enm); | 2124 | ETHER_FIRST_MULTI(estep, ec, enm); | |
2130 | while (enm != NULL) { | 2125 | while (enm != NULL) { | |
2131 | /* Punt on ranges or too many multicast addresses. */ | 2126 | /* Punt on ranges or too many multicast addresses. */ | |
2132 | if (!IEEE80211_ADDR_EQ(enm->enm_addrlo, enm->enm_addrhi) || | 2127 | if (!IEEE80211_ADDR_EQ(enm->enm_addrlo, enm->enm_addrhi) || | |
2133 | n >= sizeof(mlist) / sizeof(mlist.wi_mcast[0])) { | 2128 | n >= sizeof(mlist) / sizeof(mlist.wi_mcast[0])) { | |
2134 | ETHER_UNLOCK(ec); | 2129 | ETHER_UNLOCK(ec); | |
2135 | goto allmulti; | 2130 | goto allmulti; | |
2136 | } | 2131 | } | |
2137 | 2132 | |||
2138 | IEEE80211_ADDR_COPY(&mlist.wi_mcast[n], enm->enm_addrlo); | 2133 | IEEE80211_ADDR_COPY(&mlist.wi_mcast[n], enm->enm_addrlo); | |
2139 | n++; | 2134 | n++; | |
2140 | ETHER_NEXT_MULTI(estep, enm); | 2135 | ETHER_NEXT_MULTI(estep, enm); | |
2141 | } | 2136 | } | |
2142 | ETHER_UNLOCK(ec); | 2137 | ETHER_UNLOCK(ec); | |
2143 | ifp->if_flags &= ~IFF_ALLMULTI; | 2138 | ifp->if_flags &= ~IFF_ALLMULTI; | |
2144 | return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, | 2139 | return wi_write_rid(sc, WI_RID_MCAST_LIST, &mlist, | |
2145 | IEEE80211_ADDR_LEN * n); | 2140 | IEEE80211_ADDR_LEN * n); | |
2146 | } | 2141 | } | |
2147 | 2142 | |||
2148 | 2143 | |||
2149 | STATIC void | 2144 | STATIC void | |
2150 | wi_read_nicid(struct wi_softc *sc) | 2145 | wi_read_nicid(struct wi_softc *sc) | |
2151 | { | 2146 | { | |
2152 | const struct wi_card_ident *id; | 2147 | const struct wi_card_ident *id; | |
2153 | char *p; | 2148 | char *p; | |
2154 | int len; | 2149 | int len; | |
2155 | uint16_t ver[4]; | 2150 | uint16_t ver[4]; | |
2156 | 2151 | |||
2157 | /* getting chip identity */ | 2152 | /* getting chip identity */ | |
2158 | memset(ver, 0, sizeof(ver)); | 2153 | memset(ver, 0, sizeof(ver)); | |
2159 | len = sizeof(ver); | 2154 | len = sizeof(ver); | |
2160 | wi_read_rid(sc, WI_RID_CARD_ID, ver, &len); | 2155 | wi_read_rid(sc, WI_RID_CARD_ID, ver, &len); | |
2161 | printf("%s: using ", device_xname(sc->sc_dev)); | 2156 | printf("%s: using ", device_xname(sc->sc_dev)); | |
2162 | DPRINTF2(("wi_read_nicid: CARD_ID: %x %x %x %x\n", le16toh(ver[0]), le16toh(ver[1]), le16toh(ver[2]), le16toh(ver[3]))); | 2157 | DPRINTF2(("wi_read_nicid: CARD_ID: %x %x %x %x\n", le16toh(ver[0]), le16toh(ver[1]), le16toh(ver[2]), le16toh(ver[3]))); | |
2163 | 2158 | |||
2164 | sc->sc_firmware_type = WI_NOTYPE; | 2159 | sc->sc_firmware_type = WI_NOTYPE; | |
2165 | for (id = wi_card_ident; id->card_name != NULL; id++) { | 2160 | for (id = wi_card_ident; id->card_name != NULL; id++) { | |
2166 | if (le16toh(ver[0]) == id->card_id) { | 2161 | if (le16toh(ver[0]) == id->card_id) { | |
2167 | printf("%s", id->card_name); | 2162 | printf("%s", id->card_name); | |
2168 | sc->sc_firmware_type = id->firm_type; | 2163 | sc->sc_firmware_type = id->firm_type; | |
2169 | break; | 2164 | break; | |
2170 | } | 2165 | } | |
2171 | } | 2166 | } | |
2172 | if (sc->sc_firmware_type == WI_NOTYPE) { | 2167 | if (sc->sc_firmware_type == WI_NOTYPE) { | |
2173 | if (le16toh(ver[0]) & 0x8000) { | 2168 | if (le16toh(ver[0]) & 0x8000) { | |
2174 | printf("Unknown PRISM2 chip"); | 2169 | printf("Unknown PRISM2 chip"); | |
2175 | sc->sc_firmware_type = WI_INTERSIL; | 2170 | sc->sc_firmware_type = WI_INTERSIL; | |
2176 | } else { | 2171 | } else { | |
2177 | printf("Unknown Lucent chip"); | 2172 | printf("Unknown Lucent chip"); | |
2178 | sc->sc_firmware_type = WI_LUCENT; | 2173 | sc->sc_firmware_type = WI_LUCENT; | |
2179 | } | 2174 | } | |
2180 | } | 2175 | } | |
2181 | 2176 | |||
2182 | /* get primary firmware version (Only Prism chips) */ | 2177 | /* get primary firmware version (Only Prism chips) */ | |
2183 | if (sc->sc_firmware_type != WI_LUCENT) { | 2178 | if (sc->sc_firmware_type != WI_LUCENT) { | |
2184 | memset(ver, 0, sizeof(ver)); | 2179 | memset(ver, 0, sizeof(ver)); | |
2185 | len = sizeof(ver); | 2180 | len = sizeof(ver); | |
2186 | wi_read_rid(sc, WI_RID_PRI_IDENTITY, ver, &len); | 2181 | wi_read_rid(sc, WI_RID_PRI_IDENTITY, ver, &len); | |
2187 | sc->sc_pri_firmware_ver = le16toh(ver[2]) * 10000 + | 2182 | sc->sc_pri_firmware_ver = le16toh(ver[2]) * 10000 + | |
2188 | le16toh(ver[3]) * 100 + le16toh(ver[1]); | 2183 | le16toh(ver[3]) * 100 + le16toh(ver[1]); | |
2189 | } | 2184 | } | |
2190 | 2185 | |||
2191 | /* get station firmware version */ | 2186 | /* get station firmware version */ | |
2192 | memset(ver, 0, sizeof(ver)); | 2187 | memset(ver, 0, sizeof(ver)); | |
2193 | len = sizeof(ver); | 2188 | len = sizeof(ver); | |
2194 | wi_read_rid(sc, WI_RID_STA_IDENTITY, ver, &len); | 2189 | wi_read_rid(sc, WI_RID_STA_IDENTITY, ver, &len); | |
2195 | sc->sc_sta_firmware_ver = le16toh(ver[2]) * 10000 + | 2190 | sc->sc_sta_firmware_ver = le16toh(ver[2]) * 10000 + | |
2196 | le16toh(ver[3]) * 100 + le16toh(ver[1]); | 2191 | le16toh(ver[3]) * 100 + le16toh(ver[1]); | |
2197 | if (sc->sc_firmware_type == WI_INTERSIL && | 2192 | if (sc->sc_firmware_type == WI_INTERSIL && | |
2198 | (sc->sc_sta_firmware_ver == 10102 || | 2193 | (sc->sc_sta_firmware_ver == 10102 || | |
2199 | sc->sc_sta_firmware_ver == 20102)) { | 2194 | sc->sc_sta_firmware_ver == 20102)) { | |
2200 | char ident[12]; | 2195 | char ident[12]; | |
2201 | memset(ident, 0, sizeof(ident)); | 2196 | memset(ident, 0, sizeof(ident)); | |
2202 | len = sizeof(ident); | 2197 | len = sizeof(ident); | |
2203 | /* value should be the format like "V2.00-11" */ | 2198 | /* value should be the format like "V2.00-11" */ | |
2204 | if (wi_read_rid(sc, WI_RID_SYMBOL_IDENTITY, ident, &len) == 0 && | 2199 | if (wi_read_rid(sc, WI_RID_SYMBOL_IDENTITY, ident, &len) == 0 && | |
2205 | *(p = (char *)ident) >= 'A' && | 2200 | *(p = (char *)ident) >= 'A' && | |
2206 | p[2] == '.' && p[5] == '-' && p[8] == '\0') { | 2201 | p[2] == '.' && p[5] == '-' && p[8] == '\0') { | |
2207 | sc->sc_firmware_type = WI_SYMBOL; | 2202 | sc->sc_firmware_type = WI_SYMBOL; | |
2208 | sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 + | 2203 | sc->sc_sta_firmware_ver = (p[1] - '0') * 10000 + | |
2209 | (p[3] - '0') * 1000 + (p[4] - '0') * 100 + | 2204 | (p[3] - '0') * 1000 + (p[4] - '0') * 100 + | |
2210 | (p[6] - '0') * 10 + (p[7] - '0'); | 2205 | (p[6] - '0') * 10 + (p[7] - '0'); | |
2211 | } | 2206 | } | |
2212 | } | 2207 | } | |
2213 | 2208 | |||
2214 | printf("\n%s: %s Firmware: ", device_xname(sc->sc_dev), | 2209 | printf("\n%s: %s Firmware: ", device_xname(sc->sc_dev), | |
2215 | sc->sc_firmware_type == WI_LUCENT ? "Lucent" : | 2210 | sc->sc_firmware_type == WI_LUCENT ? "Lucent" : | |
2216 | (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil")); | 2211 | (sc->sc_firmware_type == WI_SYMBOL ? "Symbol" : "Intersil")); | |
2217 | if (sc->sc_firmware_type != WI_LUCENT) /* XXX */ | 2212 | if (sc->sc_firmware_type != WI_LUCENT) /* XXX */ | |
2218 | printf("Primary (%u.%u.%u), ", | 2213 | printf("Primary (%u.%u.%u), ", | |
2219 | sc->sc_pri_firmware_ver / 10000, | 2214 | sc->sc_pri_firmware_ver / 10000, | |
2220 | (sc->sc_pri_firmware_ver % 10000) / 100, | 2215 | (sc->sc_pri_firmware_ver % 10000) / 100, | |
2221 | sc->sc_pri_firmware_ver % 100); | 2216 | sc->sc_pri_firmware_ver % 100); | |
2222 | printf("Station (%u.%u.%u)\n", | 2217 | printf("Station (%u.%u.%u)\n", | |
2223 | sc->sc_sta_firmware_ver / 10000, | 2218 | sc->sc_sta_firmware_ver / 10000, | |
2224 | (sc->sc_sta_firmware_ver % 10000) / 100, | 2219 | (sc->sc_sta_firmware_ver % 10000) / 100, | |
2225 | sc->sc_sta_firmware_ver % 100); | 2220 | sc->sc_sta_firmware_ver % 100); | |
2226 | } | 2221 | } | |
2227 | 2222 | |||
2228 | STATIC int | 2223 | STATIC int | |
2229 | wi_write_ssid(struct wi_softc *sc, int rid, uint8_t *buf, int buflen) | 2224 | wi_write_ssid(struct wi_softc *sc, int rid, uint8_t *buf, int buflen) | |
2230 | { | 2225 | { | |
2231 | struct wi_ssid ssid; | 2226 | struct wi_ssid ssid; | |
2232 | 2227 | |||
2233 | if (buflen > IEEE80211_NWID_LEN) | 2228 | if (buflen > IEEE80211_NWID_LEN) | |
2234 | return ENOBUFS; | 2229 | return ENOBUFS; | |
2235 | memset(&ssid, 0, sizeof(ssid)); | 2230 | memset(&ssid, 0, sizeof(ssid)); | |
2236 | ssid.wi_len = htole16(buflen); | 2231 | ssid.wi_len = htole16(buflen); | |
2237 | memcpy(ssid.wi_ssid, buf, buflen); | 2232 | memcpy(ssid.wi_ssid, buf, buflen); | |
2238 | return wi_write_rid(sc, rid, &ssid, sizeof(ssid)); | 2233 | return wi_write_rid(sc, rid, &ssid, sizeof(ssid)); | |
2239 | } | 2234 | } | |
2240 | 2235 | |||
2241 | STATIC int | 2236 | STATIC int | |
2242 | wi_get_cfg(struct ifnet *ifp, u_long cmd, void *data) | 2237 | wi_get_cfg(struct ifnet *ifp, u_long cmd, void *data) | |
2243 | { | 2238 | { | |
2244 | struct wi_softc *sc = ifp->if_softc; | 2239 | struct wi_softc *sc = ifp->if_softc; | |
2245 | struct ieee80211com *ic = &sc->sc_ic; | 2240 | struct ieee80211com *ic = &sc->sc_ic; | |
2246 | struct ifreq *ifr = (struct ifreq *)data; | 2241 | struct ifreq *ifr = (struct ifreq *)data; | |
2247 | struct wi_req wreq; | 2242 | struct wi_req wreq; | |
2248 | int len, n, error; | 2243 | int len, n, error; | |
2249 | 2244 | |||
2250 | error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); | 2245 | error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); | |
2251 | if (error) | 2246 | if (error) | |
2252 | return error; | 2247 | return error; | |
2253 | len = (wreq.wi_len - 1) * 2; | 2248 | len = (wreq.wi_len - 1) * 2; | |
2254 | if (len < sizeof(uint16_t)) | 2249 | if (len < sizeof(uint16_t)) | |
2255 | return ENOSPC; | 2250 | return ENOSPC; | |
2256 | if (len > sizeof(wreq.wi_val)) | 2251 | if (len > sizeof(wreq.wi_val)) | |
2257 | len = sizeof(wreq.wi_val); | 2252 | len = sizeof(wreq.wi_val); | |
2258 | 2253 | |||
2259 | switch (wreq.wi_type) { | 2254 | switch (wreq.wi_type) { | |
2260 | 2255 | |||
2261 | case WI_RID_IFACE_STATS: | 2256 | case WI_RID_IFACE_STATS: | |
2262 | memcpy(wreq.wi_val, &sc->sc_stats, sizeof(sc->sc_stats)); | 2257 | memcpy(wreq.wi_val, &sc->sc_stats, sizeof(sc->sc_stats)); | |
2263 | if (len < sizeof(sc->sc_stats)) | 2258 | if (len < sizeof(sc->sc_stats)) | |
2264 | error = ENOSPC; | 2259 | error = ENOSPC; | |
2265 | else | 2260 | else | |
2266 | len = sizeof(sc->sc_stats); | 2261 | len = sizeof(sc->sc_stats); | |
2267 | break; | 2262 | break; | |
2268 | 2263 | |||
2269 | case WI_RID_ENCRYPTION: | 2264 | case WI_RID_ENCRYPTION: | |
2270 | case WI_RID_TX_CRYPT_KEY: | 2265 | case WI_RID_TX_CRYPT_KEY: | |
2271 | case WI_RID_DEFLT_CRYPT_KEYS: | 2266 | case WI_RID_DEFLT_CRYPT_KEYS: | |
2272 | case WI_RID_TX_RATE: | 2267 | case WI_RID_TX_RATE: | |
2273 | return ieee80211_cfgget(ic, cmd, data); | 2268 | return ieee80211_cfgget(ic, cmd, data); | |
2274 | 2269 | |||
2275 | case WI_RID_MICROWAVE_OVEN: | 2270 | case WI_RID_MICROWAVE_OVEN: | |
2276 | if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_MOR)) { | 2271 | if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_MOR)) { | |
2277 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | 2272 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | |
2278 | &len); | 2273 | &len); | |
2279 | break; | 2274 | break; | |
2280 | } | 2275 | } | |
2281 | wreq.wi_val[0] = htole16(sc->sc_microwave_oven); | 2276 | wreq.wi_val[0] = htole16(sc->sc_microwave_oven); | |
2282 | len = sizeof(uint16_t); | 2277 | len = sizeof(uint16_t); | |
2283 | break; | 2278 | break; | |
2284 | 2279 | |||
2285 | case WI_RID_DBM_ADJUST: | 2280 | case WI_RID_DBM_ADJUST: | |
2286 | if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_DBMADJUST)) { | 2281 | if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_DBMADJUST)) { | |
2287 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | 2282 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | |
2288 | &len); | 2283 | &len); | |
2289 | break; | 2284 | break; | |
2290 | } | 2285 | } | |
2291 | wreq.wi_val[0] = htole16(sc->sc_dbm_offset); | 2286 | wreq.wi_val[0] = htole16(sc->sc_dbm_offset); | |
2292 | len = sizeof(uint16_t); | 2287 | len = sizeof(uint16_t); | |
2293 | break; | 2288 | break; | |
2294 | 2289 | |||
2295 | case WI_RID_ROAMING_MODE: | 2290 | case WI_RID_ROAMING_MODE: | |
2296 | if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_ROAMING)) { | 2291 | if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_ROAMING)) { | |
2297 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | 2292 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | |
2298 | &len); | 2293 | &len); | |
2299 | break; | 2294 | break; | |
2300 | } | 2295 | } | |
2301 | wreq.wi_val[0] = htole16(sc->sc_roaming_mode); | 2296 | wreq.wi_val[0] = htole16(sc->sc_roaming_mode); | |
2302 | len = sizeof(uint16_t); | 2297 | len = sizeof(uint16_t); | |
2303 | break; | 2298 | break; | |
2304 | 2299 | |||
2305 | case WI_RID_SYSTEM_SCALE: | 2300 | case WI_RID_SYSTEM_SCALE: | |
2306 | if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE)) { | 2301 | if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE)) { | |
2307 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | 2302 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | |
2308 | &len); | 2303 | &len); | |
2309 | break; | 2304 | break; | |
2310 | } | 2305 | } | |
2311 | wreq.wi_val[0] = htole16(sc->sc_system_scale); | 2306 | wreq.wi_val[0] = htole16(sc->sc_system_scale); | |
2312 | len = sizeof(uint16_t); | 2307 | len = sizeof(uint16_t); | |
2313 | break; | 2308 | break; | |
2314 | 2309 | |||
2315 | case WI_RID_FRAG_THRESH: | 2310 | case WI_RID_FRAG_THRESH: | |
2316 | if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)) { | 2311 | if (sc->sc_enabled && (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR)) { | |
2317 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | 2312 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | |
2318 | &len); | 2313 | &len); | |
2319 | break; | 2314 | break; | |
2320 | } | 2315 | } | |
2321 | wreq.wi_val[0] = htole16(sc->sc_frag_thresh); | 2316 | wreq.wi_val[0] = htole16(sc->sc_frag_thresh); | |
2322 | len = sizeof(uint16_t); | 2317 | len = sizeof(uint16_t); | |
2323 | break; | 2318 | break; | |
2324 | 2319 | |||
2325 | case WI_RID_READ_APS: | 2320 | case WI_RID_READ_APS: | |
2326 | #ifndef IEEE80211_NO_HOSTAP | 2321 | #ifndef IEEE80211_NO_HOSTAP | |
2327 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) | 2322 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) | |
2328 | return ieee80211_cfgget(ic, cmd, data); | 2323 | return ieee80211_cfgget(ic, cmd, data); | |
2329 | #endif /* !IEEE80211_NO_HOSTAP */ | 2324 | #endif /* !IEEE80211_NO_HOSTAP */ | |
2330 | if (sc->sc_scan_timer > 0) { | 2325 | if (sc->sc_scan_timer > 0) { | |
2331 | error = EINPROGRESS; | 2326 | error = EINPROGRESS; | |
2332 | break; | 2327 | break; | |
2333 | } | 2328 | } | |
2334 | n = sc->sc_naps; | 2329 | n = sc->sc_naps; | |
2335 | if (len < sizeof(n)) { | 2330 | if (len < sizeof(n)) { | |
2336 | error = ENOSPC; | 2331 | error = ENOSPC; | |
2337 | break; | 2332 | break; | |
2338 | } | 2333 | } | |
2339 | if (len < sizeof(n) + sizeof(struct wi_apinfo) * n) | 2334 | if (len < sizeof(n) + sizeof(struct wi_apinfo) * n) | |
2340 | n = (len - sizeof(n)) / sizeof(struct wi_apinfo); | 2335 | n = (len - sizeof(n)) / sizeof(struct wi_apinfo); | |
2341 | len = sizeof(n) + sizeof(struct wi_apinfo) * n; | 2336 | len = sizeof(n) + sizeof(struct wi_apinfo) * n; | |
2342 | memcpy(wreq.wi_val, &n, sizeof(n)); | 2337 | memcpy(wreq.wi_val, &n, sizeof(n)); | |
2343 | memcpy((char *)wreq.wi_val + sizeof(n), sc->sc_aps, | 2338 | memcpy((char *)wreq.wi_val + sizeof(n), sc->sc_aps, | |
2344 | sizeof(struct wi_apinfo) * n); | 2339 | sizeof(struct wi_apinfo) * n); | |
2345 | break; | 2340 | break; | |
2346 | 2341 | |||
2347 | default: | 2342 | default: | |
2348 | if (sc->sc_enabled) { | 2343 | if (sc->sc_enabled) { | |
2349 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | 2344 | error = wi_read_rid(sc, wreq.wi_type, wreq.wi_val, | |
2350 | &len); | 2345 | &len); | |
2351 | break; | 2346 | break; | |
2352 | } | 2347 | } | |
2353 | switch (wreq.wi_type) { | 2348 | switch (wreq.wi_type) { | |
2354 | case WI_RID_MAX_DATALEN: | 2349 | case WI_RID_MAX_DATALEN: | |
2355 | wreq.wi_val[0] = htole16(sc->sc_max_datalen); | 2350 | wreq.wi_val[0] = htole16(sc->sc_max_datalen); | |
2356 | len = sizeof(uint16_t); | 2351 | len = sizeof(uint16_t); | |
2357 | break; | 2352 | break; | |
2358 | case WI_RID_FRAG_THRESH: | 2353 | case WI_RID_FRAG_THRESH: | |
2359 | wreq.wi_val[0] = htole16(sc->sc_frag_thresh); | 2354 | wreq.wi_val[0] = htole16(sc->sc_frag_thresh); | |
2360 | len = sizeof(uint16_t); | 2355 | len = sizeof(uint16_t); | |
2361 | break; | 2356 | break; | |
2362 | case WI_RID_RTS_THRESH: | 2357 | case WI_RID_RTS_THRESH: | |
2363 | wreq.wi_val[0] = htole16(sc->sc_rts_thresh); | 2358 | wreq.wi_val[0] = htole16(sc->sc_rts_thresh); | |
2364 | len = sizeof(uint16_t); | 2359 | len = sizeof(uint16_t); | |
2365 | break; | 2360 | break; | |
2366 | case WI_RID_CNFAUTHMODE: | 2361 | case WI_RID_CNFAUTHMODE: | |
2367 | wreq.wi_val[0] = htole16(sc->sc_cnfauthmode); | 2362 | wreq.wi_val[0] = htole16(sc->sc_cnfauthmode); | |
2368 | len = sizeof(uint16_t); | 2363 | len = sizeof(uint16_t); | |
2369 | break; | 2364 | break; | |
2370 | case WI_RID_NODENAME: | 2365 | case WI_RID_NODENAME: | |
2371 | if (len < sc->sc_nodelen + sizeof(uint16_t)) { | 2366 | if (len < sc->sc_nodelen + sizeof(uint16_t)) { | |
2372 | error = ENOSPC; | 2367 | error = ENOSPC; | |
2373 | break; | 2368 | break; | |
2374 | } | 2369 | } | |
2375 | len = sc->sc_nodelen + sizeof(uint16_t); | 2370 | len = sc->sc_nodelen + sizeof(uint16_t); | |
2376 | wreq.wi_val[0] = htole16((sc->sc_nodelen + 1) / 2); | 2371 | wreq.wi_val[0] = htole16((sc->sc_nodelen + 1) / 2); | |
2377 | memcpy(&wreq.wi_val[1], sc->sc_nodename, | 2372 | memcpy(&wreq.wi_val[1], sc->sc_nodename, | |
2378 | sc->sc_nodelen); | 2373 | sc->sc_nodelen); | |
2379 | break; | 2374 | break; | |
2380 | default: | 2375 | default: | |
2381 | return ieee80211_cfgget(ic, cmd, data); | 2376 | return ieee80211_cfgget(ic, cmd, data); | |
2382 | } | 2377 | } | |
2383 | break; | 2378 | break; | |
2384 | } | 2379 | } | |
2385 | if (error) | 2380 | if (error) | |
2386 | return error; | 2381 | return error; | |
2387 | wreq.wi_len = (len + 1) / 2 + 1; | 2382 | wreq.wi_len = (len + 1) / 2 + 1; | |
2388 | return copyout(&wreq, ifr->ifr_data, (wreq.wi_len + 1) * 2); | 2383 | return copyout(&wreq, ifr->ifr_data, (wreq.wi_len + 1) * 2); | |
2389 | } | 2384 | } | |
2390 | 2385 | |||
2391 | STATIC int | 2386 | STATIC int | |
2392 | wi_set_cfg(struct ifnet *ifp, u_long cmd, void *data) | 2387 | wi_set_cfg(struct ifnet *ifp, u_long cmd, void *data) | |
2393 | { | 2388 | { | |
2394 | struct wi_softc *sc = ifp->if_softc; | 2389 | struct wi_softc *sc = ifp->if_softc; | |
2395 | struct ieee80211com *ic = &sc->sc_ic; | 2390 | struct ieee80211com *ic = &sc->sc_ic; | |
2396 | struct ifreq *ifr = (struct ifreq *)data; | 2391 | struct ifreq *ifr = (struct ifreq *)data; | |
2397 | struct ieee80211_rateset *rs = &ic->ic_sup_rates[IEEE80211_MODE_11B]; | 2392 | struct ieee80211_rateset *rs = &ic->ic_sup_rates[IEEE80211_MODE_11B]; | |
2398 | struct wi_req wreq; | 2393 | struct wi_req wreq; | |
2399 | struct mbuf *m; | 2394 | struct mbuf *m; | |
2400 | int i, len, error; | 2395 | int i, len, error; | |
2401 | 2396 | |||
2402 | error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); | 2397 | error = copyin(ifr->ifr_data, &wreq, sizeof(wreq)); | |
2403 | if (error) | 2398 | if (error) | |
2404 | return error; | 2399 | return error; | |
2405 | len = (wreq.wi_len - 1) * 2; | 2400 | len = (wreq.wi_len - 1) * 2; | |
2406 | switch (wreq.wi_type) { | 2401 | switch (wreq.wi_type) { | |
2407 | case WI_RID_MAC_NODE: | 2402 | case WI_RID_MAC_NODE: | |
2408 | /* XXX convert to SIOCALIFADDR, AF_LINK, IFLR_ACTIVE */ | 2403 | /* XXX convert to SIOCALIFADDR, AF_LINK, IFLR_ACTIVE */ | |
2409 | (void)memcpy(ic->ic_myaddr, wreq.wi_val, ETHER_ADDR_LEN); | 2404 | (void)memcpy(ic->ic_myaddr, wreq.wi_val, ETHER_ADDR_LEN); | |
2410 | if_set_sadl(ifp, ic->ic_myaddr, ETHER_ADDR_LEN, false); | 2405 | if_set_sadl(ifp, ic->ic_myaddr, ETHER_ADDR_LEN, false); | |
2411 | wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, | 2406 | wi_write_rid(sc, WI_RID_MAC_NODE, ic->ic_myaddr, | |
2412 | IEEE80211_ADDR_LEN); | 2407 | IEEE80211_ADDR_LEN); | |
2413 | break; | 2408 | break; | |
2414 | 2409 | |||
2415 | case WI_RID_DBM_ADJUST: | 2410 | case WI_RID_DBM_ADJUST: | |
2416 | return ENODEV; | 2411 | return ENODEV; | |
2417 | 2412 | |||
2418 | case WI_RID_NODENAME: | 2413 | case WI_RID_NODENAME: | |
2419 | if (le16toh(wreq.wi_val[0]) * 2 > len || | 2414 | if (le16toh(wreq.wi_val[0]) * 2 > len || | |
2420 | le16toh(wreq.wi_val[0]) > sizeof(sc->sc_nodename)) { | 2415 | le16toh(wreq.wi_val[0]) > sizeof(sc->sc_nodename)) { | |
2421 | error = ENOSPC; | 2416 | error = ENOSPC; | |
2422 | break; | 2417 | break; | |
2423 | } | 2418 | } | |
2424 | if (sc->sc_enabled) { | 2419 | if (sc->sc_enabled) { | |
2425 | error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val, | 2420 | error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val, | |
2426 | len); | 2421 | len); | |
2427 | if (error) | 2422 | if (error) | |
2428 | break; | 2423 | break; | |
2429 | } | 2424 | } | |
2430 | sc->sc_nodelen = le16toh(wreq.wi_val[0]) * 2; | 2425 | sc->sc_nodelen = le16toh(wreq.wi_val[0]) * 2; | |
2431 | memcpy(sc->sc_nodename, &wreq.wi_val[1], sc->sc_nodelen); | 2426 | memcpy(sc->sc_nodename, &wreq.wi_val[1], sc->sc_nodelen); | |
2432 | break; | 2427 | break; | |
2433 | 2428 | |||
2434 | case WI_RID_MICROWAVE_OVEN: | 2429 | case WI_RID_MICROWAVE_OVEN: | |
2435 | case WI_RID_ROAMING_MODE: | 2430 | case WI_RID_ROAMING_MODE: | |
2436 | case WI_RID_SYSTEM_SCALE: | 2431 | case WI_RID_SYSTEM_SCALE: | |
2437 | case WI_RID_FRAG_THRESH: | 2432 | case WI_RID_FRAG_THRESH: | |
2438 | if (wreq.wi_type == WI_RID_MICROWAVE_OVEN && | 2433 | if (wreq.wi_type == WI_RID_MICROWAVE_OVEN && | |
2439 | (sc->sc_flags & WI_FLAGS_HAS_MOR) == 0) | 2434 | (sc->sc_flags & WI_FLAGS_HAS_MOR) == 0) | |
2440 | break; | 2435 | break; | |
2441 | if (wreq.wi_type == WI_RID_ROAMING_MODE && | 2436 | if (wreq.wi_type == WI_RID_ROAMING_MODE && | |
2442 | (sc->sc_flags & WI_FLAGS_HAS_ROAMING) == 0) | 2437 | (sc->sc_flags & WI_FLAGS_HAS_ROAMING) == 0) | |
2443 | break; | 2438 | break; | |
2444 | if (wreq.wi_type == WI_RID_SYSTEM_SCALE && | 2439 | if (wreq.wi_type == WI_RID_SYSTEM_SCALE && | |
2445 | (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE) == 0) | 2440 | (sc->sc_flags & WI_FLAGS_HAS_SYSSCALE) == 0) | |
2446 | break; | 2441 | break; | |
2447 | if (wreq.wi_type == WI_RID_FRAG_THRESH && | 2442 | if (wreq.wi_type == WI_RID_FRAG_THRESH && | |
2448 | (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR) == 0) | 2443 | (sc->sc_flags & WI_FLAGS_HAS_FRAGTHR) == 0) | |
2449 | break; | 2444 | break; | |
2450 | /* FALLTHROUGH */ | 2445 | /* FALLTHROUGH */ | |
2451 | case WI_RID_RTS_THRESH: | 2446 | case WI_RID_RTS_THRESH: | |
2452 | case WI_RID_CNFAUTHMODE: | 2447 | case WI_RID_CNFAUTHMODE: | |
2453 | case WI_RID_MAX_DATALEN: | 2448 | case WI_RID_MAX_DATALEN: | |
2454 | if (sc->sc_enabled) { | 2449 | if (sc->sc_enabled) { | |
2455 | error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val, | 2450 | error = wi_write_rid(sc, wreq.wi_type, wreq.wi_val, | |
2456 | sizeof(uint16_t)); | 2451 | sizeof(uint16_t)); | |
2457 | if (error) | 2452 | if (error) | |
2458 | break; | 2453 | break; |
--- src/sys/dev/usb/if_atu.c 2019/12/01 12:47:10 1.67
+++ src/sys/dev/usb/if_atu.c 2019/12/05 03:11:41 1.68
@@ -1,1050 +1,1050 @@ | @@ -1,1050 +1,1050 @@ | |||
1 | /* $NetBSD: if_atu.c,v 1.67 2019/12/01 12:47:10 maxv Exp $ */ | 1 | /* $NetBSD: if_atu.c,v 1.68 2019/12/05 03:11:41 msaitoh Exp $ */ | |
2 | /* $OpenBSD: if_atu.c,v 1.48 2004/12/30 01:53:21 dlg Exp $ */ | 2 | /* $OpenBSD: if_atu.c,v 1.48 2004/12/30 01:53:21 dlg Exp $ */ | |
3 | /* | 3 | /* | |
4 | * Copyright (c) 2003, 2004 | 4 | * Copyright (c) 2003, 2004 | |
5 | * Daan Vreeken <Danovitsch@Vitsch.net>. All rights reserved. | 5 | * Daan Vreeken <Danovitsch@Vitsch.net>. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. All advertising materials mentioning features or use of this software | 15 | * 3. All advertising materials mentioning features or use of this software | |
16 | * must display the following acknowledgement: | 16 | * must display the following acknowledgement: | |
17 | * This product includes software developed by Daan Vreeken. | 17 | * This product includes software developed by Daan Vreeken. | |
18 | * 4. Neither the name of the author nor the names of any co-contributors | 18 | * 4. Neither the name of the author nor the names of any co-contributors | |
19 | * may be used to endorse or promote products derived from this software | 19 | * may be used to endorse or promote products derived from this software | |
20 | * without specific prior written permission. | 20 | * without specific prior written permission. | |
21 | * | 21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY Daan Vreeken AND CONTRIBUTORS ``AS IS'' AND | 22 | * THIS SOFTWARE IS PROVIDED BY Daan Vreeken AND CONTRIBUTORS ``AS IS'' AND | |
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL Daan Vreeken OR THE VOICES IN HIS HEAD | 25 | * ARE DISCLAIMED. IN NO EVENT SHALL Daan Vreeken OR THE VOICES IN HIS HEAD | |
26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 26 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
32 | * THE POSSIBILITY OF SUCH DAMAGE. | 32 | * THE POSSIBILITY OF SUCH DAMAGE. | |
33 | */ | 33 | */ | |
34 | 34 | |||
35 | /* | 35 | /* | |
36 | * Atmel AT76c503 / AT76c503a / AT76c505 / AT76c505a USB WLAN driver | 36 | * Atmel AT76c503 / AT76c503a / AT76c505 / AT76c505a USB WLAN driver | |
37 | * version 0.5 - 2004-08-03 | 37 | * version 0.5 - 2004-08-03 | |
38 | * | 38 | * | |
39 | * Originally written by Daan Vreeken <Danovitsch @ Vitsch . net> | 39 | * Originally written by Daan Vreeken <Danovitsch @ Vitsch . net> | |
40 | * http://vitsch.net/bsd/atuwi | 40 | * http://vitsch.net/bsd/atuwi | |
41 | * | 41 | * | |
42 | * Contributed to by : | 42 | * Contributed to by : | |
43 | * Chris Whitehouse, Alistair Phillips, Peter Pilka, Martijn van Buul, | 43 | * Chris Whitehouse, Alistair Phillips, Peter Pilka, Martijn van Buul, | |
44 | * Suihong Liang, Arjan van Leeuwen, Stuart Walsh | 44 | * Suihong Liang, Arjan van Leeuwen, Stuart Walsh | |
45 | * | 45 | * | |
46 | * Ported to OpenBSD by Theo de Raadt and David Gwynne. | 46 | * Ported to OpenBSD by Theo de Raadt and David Gwynne. | |
47 | * Ported to NetBSD by Jesse Off | 47 | * Ported to NetBSD by Jesse Off | |
48 | */ | 48 | */ | |
49 | 49 | |||
50 | #include <sys/cdefs.h> | 50 | #include <sys/cdefs.h> | |
51 | __KERNEL_RCSID(0, "$NetBSD: if_atu.c,v 1.67 2019/12/01 12:47:10 maxv Exp $"); | 51 | __KERNEL_RCSID(0, "$NetBSD: if_atu.c,v 1.68 2019/12/05 03:11:41 msaitoh Exp $"); | |
52 | 52 | |||
53 | #ifdef _KERNEL_OPT | 53 | #ifdef _KERNEL_OPT | |
54 | #include "opt_usb.h" | 54 | #include "opt_usb.h" | |
55 | #endif | 55 | #endif | |
56 | 56 | |||
57 | #include <sys/param.h> | 57 | #include <sys/param.h> | |
58 | #include <sys/sockio.h> | 58 | #include <sys/sockio.h> | |
59 | #include <sys/mbuf.h> | 59 | #include <sys/mbuf.h> | |
60 | #include <sys/kernel.h> | 60 | #include <sys/kernel.h> | |
61 | #include <sys/socket.h> | 61 | #include <sys/socket.h> | |
62 | #include <sys/systm.h> | 62 | #include <sys/systm.h> | |
63 | #include <sys/kthread.h> | 63 | #include <sys/kthread.h> | |
64 | #include <sys/queue.h> | 64 | #include <sys/queue.h> | |
65 | #include <sys/device.h> | 65 | #include <sys/device.h> | |
66 | #include <sys/bus.h> | 66 | #include <sys/bus.h> | |
67 | 67 | |||
68 | #include <dev/usb/usb.h> | 68 | #include <dev/usb/usb.h> | |
69 | #include <dev/usb/usbdi.h> | 69 | #include <dev/usb/usbdi.h> | |
70 | #include <dev/usb/usbdi_util.h> | 70 | #include <dev/usb/usbdi_util.h> | |
71 | #include <dev/usb/usbdivar.h> | 71 | #include <dev/usb/usbdivar.h> | |
72 | #include <dev/usb/usbdevs.h> | 72 | #include <dev/usb/usbdevs.h> | |
73 | 73 | |||
74 | #include <dev/microcode/atmel/atmel_intersil_fw.h> | 74 | #include <dev/microcode/atmel/atmel_intersil_fw.h> | |
75 | #include <dev/microcode/atmel/atmel_rfmd2958-smc_fw.h> | 75 | #include <dev/microcode/atmel/atmel_rfmd2958-smc_fw.h> | |
76 | #include <dev/microcode/atmel/atmel_rfmd2958_fw.h> | 76 | #include <dev/microcode/atmel/atmel_rfmd2958_fw.h> | |
77 | #include <dev/microcode/atmel/atmel_rfmd_fw.h> | 77 | #include <dev/microcode/atmel/atmel_rfmd_fw.h> | |
78 | 78 | |||
79 | #include <net/bpf.h> | 79 | #include <net/bpf.h> | |
80 | #include <net/if.h> | 80 | #include <net/if.h> | |
81 | #include <net/if_dl.h> | 81 | #include <net/if_dl.h> | |
82 | #include <net/if_media.h> | 82 | #include <net/if_media.h> | |
83 | #include <net/if_ether.h> | 83 | #include <net/if_ether.h> | |
84 | 84 | |||
85 | #ifdef INET | 85 | #ifdef INET | |
86 | #include <netinet/in.h> | 86 | #include <netinet/in.h> | |
87 | #include <netinet/if_ether.h> | 87 | #include <netinet/if_ether.h> | |
88 | #endif | 88 | #endif | |
89 | 89 | |||
90 | #include <net80211/ieee80211_var.h> | 90 | #include <net80211/ieee80211_var.h> | |
91 | #include <net80211/ieee80211_radiotap.h> | 91 | #include <net80211/ieee80211_radiotap.h> | |
92 | 92 | |||
93 | #include <dev/usb/if_atureg.h> | 93 | #include <dev/usb/if_atureg.h> | |
94 | 94 | |||
95 | #ifdef ATU_DEBUG | 95 | #ifdef ATU_DEBUG | |
96 | #define DPRINTF(x) do { if (atudebug) printf x; } while (0) | 96 | #define DPRINTF(x) do { if (atudebug) printf x; } while (0) | |
97 | #define DPRINTFN(n,x) do { if (atudebug>(n)) printf x; } while (0) | 97 | #define DPRINTFN(n,x) do { if (atudebug>(n)) printf x; } while (0) | |
98 | int atudebug = 1; | 98 | int atudebug = 1; | |
99 | #else | 99 | #else | |
100 | #define DPRINTF(x) | 100 | #define DPRINTF(x) | |
101 | #define DPRINTFN(n,x) | 101 | #define DPRINTFN(n,x) | |
102 | #endif | 102 | #endif | |
103 | 103 | |||
104 | /* | 104 | /* | |
105 | * Various supported device vendors/products/radio type. | 105 | * Various supported device vendors/products/radio type. | |
106 | */ | 106 | */ | |
107 | static const struct atu_type atu_devs[] = { | 107 | static const struct atu_type atu_devs[] = { | |
108 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3CRSHEW696, | 108 | { USB_VENDOR_3COM, USB_PRODUCT_3COM_3CRSHEW696, | |
109 | RadioRFMD, ATU_NO_QUIRK }, | 109 | RadioRFMD, ATU_NO_QUIRK }, | |
110 | { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_BWU613, | 110 | { USB_VENDOR_ABOCOM, USB_PRODUCT_ABOCOM_BWU613, | |
111 | RadioRFMD, ATU_NO_QUIRK }, | 111 | RadioRFMD, ATU_NO_QUIRK }, | |
112 | { USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_2664W, | 112 | { USB_VENDOR_ACCTON, USB_PRODUCT_ACCTON_2664W, | |
113 | AT76C503_rfmd_acc, ATU_NO_QUIRK }, | 113 | AT76C503_rfmd_acc, ATU_NO_QUIRK }, | |
114 | { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_AWL300, | 114 | { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_AWL300, | |
115 | RadioIntersil, ATU_NO_QUIRK }, | 115 | RadioIntersil, ATU_NO_QUIRK }, | |
116 | { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_AWL400, | 116 | { USB_VENDOR_ACERP, USB_PRODUCT_ACERP_AWL400, | |
117 | RadioRFMD, ATU_NO_QUIRK }, | 117 | RadioRFMD, ATU_NO_QUIRK }, | |
118 | { USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_UAT1, | 118 | { USB_VENDOR_ACTIONTEC, USB_PRODUCT_ACTIONTEC_UAT1, | |
119 | RadioRFMD, ATU_NO_QUIRK }, | 119 | RadioRFMD, ATU_NO_QUIRK }, | |
120 | { USB_VENDOR_ADDTRON, USB_PRODUCT_ADDTRON_AWU120, | 120 | { USB_VENDOR_ADDTRON, USB_PRODUCT_ADDTRON_AWU120, | |
121 | RadioIntersil, ATU_NO_QUIRK }, | 121 | RadioIntersil, ATU_NO_QUIRK }, | |
122 | { USB_VENDOR_AINCOMM, USB_PRODUCT_AINCOMM_AWU2000B, | 122 | { USB_VENDOR_AINCOMM, USB_PRODUCT_AINCOMM_AWU2000B, | |
123 | RadioRFMD2958, ATU_NO_QUIRK }, | 123 | RadioRFMD2958, ATU_NO_QUIRK }, | |
124 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_VOYAGER1010, | 124 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_VOYAGER1010, | |
125 | RadioIntersil, ATU_NO_QUIRK }, | 125 | RadioIntersil, ATU_NO_QUIRK }, | |
126 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_WLL013I, | 126 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_WLL013I, | |
127 | RadioIntersil, ATU_NO_QUIRK }, | 127 | RadioIntersil, ATU_NO_QUIRK }, | |
128 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_WLL013, | 128 | { USB_VENDOR_ASKEY, USB_PRODUCT_ASKEY_WLL013, | |
129 | RadioRFMD, ATU_NO_QUIRK }, | 129 | RadioRFMD, ATU_NO_QUIRK }, | |
130 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503I1, | 130 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503I1, | |
131 | RadioIntersil, ATU_NO_QUIRK }, | 131 | RadioIntersil, ATU_NO_QUIRK }, | |
132 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503I2, | 132 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503I2, | |
133 | AT76C503_i3863, ATU_NO_QUIRK }, | 133 | AT76C503_i3863, ATU_NO_QUIRK }, | |
134 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503RFMD, | 134 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C503RFMD, | |
135 | RadioRFMD, ATU_NO_QUIRK }, | 135 | RadioRFMD, ATU_NO_QUIRK }, | |
136 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505RFMD, | 136 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505RFMD, | |
137 | AT76C505_rfmd, ATU_NO_QUIRK }, | 137 | AT76C505_rfmd, ATU_NO_QUIRK }, | |
138 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505RFMD2958, | 138 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505RFMD2958, | |
139 | RadioRFMD2958, ATU_NO_QUIRK }, | 139 | RadioRFMD2958, ATU_NO_QUIRK }, | |
140 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505A, /* SMC2662 V.4 */ | 140 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505A, /* SMC2662 V.4 */ | |
141 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | 141 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | |
142 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505AS, /* quirk? */ | 142 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_AT76C505AS, /* quirk? */ | |
143 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | 143 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | |
144 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_WN210, | 144 | { USB_VENDOR_ATMEL, USB_PRODUCT_ATMEL_WN210, | |
145 | RadioRFMD, ATU_NO_QUIRK }, | 145 | RadioRFMD, ATU_NO_QUIRK }, | |
146 | { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D6050, | 146 | { USB_VENDOR_BELKIN, USB_PRODUCT_BELKIN_F5D6050, | |
147 | RadioRFMD, ATU_NO_QUIRK }, | 147 | RadioRFMD, ATU_NO_QUIRK }, | |
148 | { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_C11U, | 148 | { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_C11U, | |
149 | RadioIntersil, ATU_NO_QUIRK }, | 149 | RadioIntersil, ATU_NO_QUIRK }, | |
150 | { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_WL210, | 150 | { USB_VENDOR_CONCEPTRONIC, USB_PRODUCT_CONCEPTRONIC_WL210, | |
151 | RadioIntersil, ATU_NO_QUIRK }, | 151 | RadioIntersil, ATU_NO_QUIRK }, | |
152 | { USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQWLAN, | 152 | { USB_VENDOR_COMPAQ, USB_PRODUCT_COMPAQ_IPAQWLAN, | |
153 | RadioRFMD, ATU_NO_QUIRK }, | 153 | RadioRFMD, ATU_NO_QUIRK }, | |
154 | { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLUSB_11_STICK, | 154 | { USB_VENDOR_COREGA, USB_PRODUCT_COREGA_WLUSB_11_STICK, | |
155 | RadioRFMD2958, ATU_NO_QUIRK }, | 155 | RadioRFMD2958, ATU_NO_QUIRK }, | |
156 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_CHUSB611G, | 156 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_CHUSB611G, | |
157 | RadioRFMD2958, ATU_NO_QUIRK }, | 157 | RadioRFMD2958, ATU_NO_QUIRK }, | |
158 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_WL200U, | 158 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_WL200U, | |
159 | RadioRFMD, ATU_NO_QUIRK }, | 159 | RadioRFMD, ATU_NO_QUIRK }, | |
160 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_WL240U, | 160 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_WL240U, | |
161 | RadioRFMD2958, ATU_NO_QUIRK }, | 161 | RadioRFMD2958, ATU_NO_QUIRK }, | |
162 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_XH1153, | 162 | { USB_VENDOR_DICKSMITH, USB_PRODUCT_DICKSMITH_XH1153, | |
163 | RadioRFMD, ATU_NO_QUIRK }, | 163 | RadioRFMD, ATU_NO_QUIRK }, | |
164 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL120E, | 164 | { USB_VENDOR_DLINK, USB_PRODUCT_DLINK_DWL120E, | |
165 | RadioRFMD, ATU_NO_QUIRK }, | 165 | RadioRFMD, ATU_NO_QUIRK }, | |
166 | { USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWLBM101, | 166 | { USB_VENDOR_GIGABYTE, USB_PRODUCT_GIGABYTE_GNWLBM101, | |
167 | RadioRFMD, ATU_NO_QUIRK }, | 167 | RadioRFMD, ATU_NO_QUIRK }, | |
168 | { USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_WLAN, /* quirk? */ | 168 | { USB_VENDOR_GIGASET, USB_PRODUCT_GIGASET_WLAN, /* quirk? */ | |
169 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | 169 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | |
170 | { USB_VENDOR_HP, USB_PRODUCT_HP_HN210W, | 170 | { USB_VENDOR_HP, USB_PRODUCT_HP_HN210W, | |
171 | RadioIntersil, ATU_NO_QUIRK }, | 171 | RadioIntersil, ATU_NO_QUIRK }, | |
172 | { USB_VENDOR_INTEL, USB_PRODUCT_INTEL_AP310, | 172 | { USB_VENDOR_INTEL, USB_PRODUCT_INTEL_AP310, | |
173 | RadioIntersil, ATU_NO_QUIRK }, | 173 | RadioIntersil, ATU_NO_QUIRK }, | |
174 | { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBWNB11A, | 174 | { USB_VENDOR_IODATA, USB_PRODUCT_IODATA_USBWNB11A, | |
175 | RadioIntersil, ATU_NO_QUIRK }, | 175 | RadioIntersil, ATU_NO_QUIRK }, | |
176 | { USB_VENDOR_LEXAR, USB_PRODUCT_LEXAR_2662WAR, | 176 | { USB_VENDOR_LEXAR, USB_PRODUCT_LEXAR_2662WAR, | |
177 | RadioRFMD, ATU_NO_QUIRK }, | 177 | RadioRFMD, ATU_NO_QUIRK }, | |
178 | { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB11, | 178 | { USB_VENDOR_LINKSYS, USB_PRODUCT_LINKSYS_WUSB11, | |
179 | RadioIntersil, ATU_NO_QUIRK }, | 179 | RadioIntersil, ATU_NO_QUIRK }, | |
180 | { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_WUSB11, | 180 | { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_WUSB11, | |
181 | RadioRFMD, ATU_NO_QUIRK }, | 181 | RadioRFMD, ATU_NO_QUIRK }, | |
182 | { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_NWU11B, | 182 | { USB_VENDOR_LINKSYS2, USB_PRODUCT_LINKSYS2_NWU11B, | |
183 | RadioRFMD, ATU_NO_QUIRK }, | 183 | RadioRFMD, ATU_NO_QUIRK }, | |
184 | { USB_VENDOR_LINKSYS3, USB_PRODUCT_LINKSYS3_WUSB11V28, | 184 | { USB_VENDOR_LINKSYS3, USB_PRODUCT_LINKSYS3_WUSB11V28, | |
185 | RadioRFMD2958, ATU_NO_QUIRK }, | 185 | RadioRFMD2958, ATU_NO_QUIRK }, | |
186 | { USB_VENDOR_MSI, USB_PRODUCT_MSI_WLAN, | 186 | { USB_VENDOR_MSI, USB_PRODUCT_MSI_WLAN, | |
187 | RadioRFMD2958, ATU_NO_QUIRK }, | 187 | RadioRFMD2958, ATU_NO_QUIRK }, | |
188 | { USB_VENDOR_NETGEAR2, USB_PRODUCT_NETGEAR2_MA101, | 188 | { USB_VENDOR_NETGEAR2, USB_PRODUCT_NETGEAR2_MA101, | |
189 | RadioIntersil, ATU_NO_QUIRK }, | 189 | RadioIntersil, ATU_NO_QUIRK }, | |
190 | { USB_VENDOR_NETGEAR2, USB_PRODUCT_NETGEAR2_MA101B, | 190 | { USB_VENDOR_NETGEAR2, USB_PRODUCT_NETGEAR2_MA101B, | |
191 | RadioRFMD, ATU_NO_QUIRK }, | 191 | RadioRFMD, ATU_NO_QUIRK }, | |
192 | { USB_VENDOR_OQO, USB_PRODUCT_OQO_WIFI01, | 192 | { USB_VENDOR_OQO, USB_PRODUCT_OQO_WIFI01, | |
193 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | 193 | RadioRFMD2958_SMC, ATU_QUIRK_NO_REMAP | ATU_QUIRK_FW_DELAY }, | |
194 | { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GW_US11S, | 194 | { USB_VENDOR_PLANEX2, USB_PRODUCT_PLANEX2_GW_US11S, | |
195 | RadioRFMD, ATU_NO_QUIRK }, | 195 | RadioRFMD, ATU_NO_QUIRK }, | |
196 | { USB_VENDOR_SAMSUNG, USB_PRODUCT_SAMSUNG_SWL2100W, | 196 | { USB_VENDOR_SAMSUNG, USB_PRODUCT_SAMSUNG_SWL2100W, | |
197 | AT76C503_i3863, ATU_NO_QUIRK }, | 197 | AT76C503_i3863, ATU_NO_QUIRK }, | |
198 | { USB_VENDOR_SIEMENS2, USB_PRODUCT_SIEMENS2_WLL013, | 198 | { USB_VENDOR_SIEMENS2, USB_PRODUCT_SIEMENS2_WLL013, | |
199 | RadioRFMD, ATU_NO_QUIRK }, | 199 | RadioRFMD, ATU_NO_QUIRK }, | |
200 | { USB_VENDOR_SMC3, USB_PRODUCT_SMC3_2662WV1, | 200 | { USB_VENDOR_SMC3, USB_PRODUCT_SMC3_2662WV1, | |
201 | RadioIntersil, ATU_NO_QUIRK }, | 201 | RadioIntersil, ATU_NO_QUIRK }, | |
202 | { USB_VENDOR_SMC3, USB_PRODUCT_SMC3_2662WV2, | 202 | { USB_VENDOR_SMC3, USB_PRODUCT_SMC3_2662WV2, | |
203 | AT76C503_rfmd_acc, ATU_NO_QUIRK }, | 203 | AT76C503_rfmd_acc, ATU_NO_QUIRK }, | |
204 | { USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_U300C, | 204 | { USB_VENDOR_TEKRAM, USB_PRODUCT_TEKRAM_U300C, | |
205 | RadioIntersil, ATU_NO_QUIRK }, | 205 | RadioIntersil, ATU_NO_QUIRK }, | |
206 | { USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_M4Y750, | 206 | { USB_VENDOR_ZCOM, USB_PRODUCT_ZCOM_M4Y750, | |
207 | RadioIntersil, ATU_NO_QUIRK }, | 207 | RadioIntersil, ATU_NO_QUIRK }, | |
208 | }; | 208 | }; | |
209 | 209 | |||
210 | static const struct atu_radfirm { | 210 | static const struct atu_radfirm { | |
211 | enum atu_radio_type atur_type; | 211 | enum atu_radio_type atur_type; | |
212 | unsigned char *atur_internal; | 212 | unsigned char *atur_internal; | |
213 | size_t atur_internal_sz; | 213 | size_t atur_internal_sz; | |
214 | unsigned char *atur_external; | 214 | unsigned char *atur_external; | |
215 | size_t atur_external_sz; | 215 | size_t atur_external_sz; | |
216 | } atu_radfirm[] = { | 216 | } atu_radfirm[] = { | |
217 | { RadioRFMD, | 217 | { RadioRFMD, | |
218 | atmel_fw_rfmd_int, sizeof(atmel_fw_rfmd_int), | 218 | atmel_fw_rfmd_int, sizeof(atmel_fw_rfmd_int), | |
219 | atmel_fw_rfmd_ext, sizeof(atmel_fw_rfmd_ext) }, | 219 | atmel_fw_rfmd_ext, sizeof(atmel_fw_rfmd_ext) }, | |
220 | { RadioRFMD2958, | 220 | { RadioRFMD2958, | |
221 | atmel_fw_rfmd2958_int, sizeof(atmel_fw_rfmd2958_int), | 221 | atmel_fw_rfmd2958_int, sizeof(atmel_fw_rfmd2958_int), | |
222 | atmel_fw_rfmd2958_ext, sizeof(atmel_fw_rfmd2958_ext) }, | 222 | atmel_fw_rfmd2958_ext, sizeof(atmel_fw_rfmd2958_ext) }, | |
223 | { RadioRFMD2958_SMC, | 223 | { RadioRFMD2958_SMC, | |
224 | atmel_fw_rfmd2958_smc_int, sizeof(atmel_fw_rfmd2958_smc_int), | 224 | atmel_fw_rfmd2958_smc_int, sizeof(atmel_fw_rfmd2958_smc_int), | |
225 | atmel_fw_rfmd2958_smc_ext, sizeof(atmel_fw_rfmd2958_smc_ext) }, | 225 | atmel_fw_rfmd2958_smc_ext, sizeof(atmel_fw_rfmd2958_smc_ext) }, | |
226 | { RadioIntersil, | 226 | { RadioIntersil, | |
227 | atmel_fw_intersil_int, sizeof(atmel_fw_intersil_int), | 227 | atmel_fw_intersil_int, sizeof(atmel_fw_intersil_int), | |
228 | atmel_fw_intersil_ext, sizeof(atmel_fw_intersil_ext) } | 228 | atmel_fw_intersil_ext, sizeof(atmel_fw_intersil_ext) } | |
229 | }; | 229 | }; | |
230 | 230 | |||
231 | static int atu_newbuf(struct atu_softc *, struct atu_chain *, struct mbuf *); | 231 | static int atu_newbuf(struct atu_softc *, struct atu_chain *, struct mbuf *); | |
232 | static void atu_rxeof(struct usbd_xfer *, void *, usbd_status); | 232 | static void atu_rxeof(struct usbd_xfer *, void *, usbd_status); | |
233 | static void atu_txeof(struct usbd_xfer *, void *, usbd_status); | 233 | static void atu_txeof(struct usbd_xfer *, void *, usbd_status); | |
234 | static void atu_start(struct ifnet *); | 234 | static void atu_start(struct ifnet *); | |
235 | static int atu_ioctl(struct ifnet *, u_long, void *); | 235 | static int atu_ioctl(struct ifnet *, u_long, void *); | |
236 | static int atu_init(struct ifnet *); | 236 | static int atu_init(struct ifnet *); | |
237 | static void atu_stop(struct ifnet *, int); | 237 | static void atu_stop(struct ifnet *, int); | |
238 | static void atu_watchdog(struct ifnet *); | 238 | static void atu_watchdog(struct ifnet *); | |
239 | static usbd_status atu_usb_request(struct atu_softc *, uint8_t, | 239 | static usbd_status atu_usb_request(struct atu_softc *, uint8_t, | |
240 | uint8_t, uint16_t, uint16_t, | 240 | uint8_t, uint16_t, uint16_t, | |
241 | uint16_t, uint8_t *); | 241 | uint16_t, uint8_t *); | |
242 | static int atu_send_command(struct atu_softc *, uint8_t *, int); | 242 | static int atu_send_command(struct atu_softc *, uint8_t *, int); | |
243 | static int atu_get_cmd_status(struct atu_softc *, uint8_t, | 243 | static int atu_get_cmd_status(struct atu_softc *, uint8_t, | |
244 | uint8_t *); | 244 | uint8_t *); | |
245 | static int atu_wait_completion(struct atu_softc *, uint8_t, | 245 | static int atu_wait_completion(struct atu_softc *, uint8_t, | |
246 | uint8_t *); | 246 | uint8_t *); | |
247 | static int atu_send_mib(struct atu_softc *, uint8_t, | 247 | static int atu_send_mib(struct atu_softc *, uint8_t, | |
248 | uint8_t, uint8_t, void *); | 248 | uint8_t, uint8_t, void *); | |
249 | static int atu_get_mib(struct atu_softc *, uint8_t, | 249 | static int atu_get_mib(struct atu_softc *, uint8_t, | |
250 | uint8_t, uint8_t, uint8_t *); | 250 | uint8_t, uint8_t, uint8_t *); | |
251 | #if 0 | 251 | #if 0 | |
252 | int atu_start_ibss(struct atu_softc *); | 252 | int atu_start_ibss(struct atu_softc *); | |
253 | #endif | 253 | #endif | |
254 | static int atu_start_scan(struct atu_softc *); | 254 | static int atu_start_scan(struct atu_softc *); | |
255 | static int atu_switch_radio(struct atu_softc *, int); | 255 | static int atu_switch_radio(struct atu_softc *, int); | |
256 | static int atu_initial_config(struct atu_softc *); | 256 | static int atu_initial_config(struct atu_softc *); | |
257 | static int atu_join(struct atu_softc *, struct ieee80211_node *); | 257 | static int atu_join(struct atu_softc *, struct ieee80211_node *); | |
258 | static int8_t atu_get_dfu_state(struct atu_softc *); | 258 | static int8_t atu_get_dfu_state(struct atu_softc *); | |
259 | static uint8_t atu_get_opmode(struct atu_softc *, uint8_t *); | 259 | static uint8_t atu_get_opmode(struct atu_softc *, uint8_t *); | |
260 | static void atu_internal_firmware(device_t); | 260 | static void atu_internal_firmware(device_t); | |
261 | static void atu_external_firmware(device_t); | 261 | static void atu_external_firmware(device_t); | |
262 | static int atu_get_card_config(struct atu_softc *); | 262 | static int atu_get_card_config(struct atu_softc *); | |
263 | static int atu_media_change(struct ifnet *); | 263 | static int atu_media_change(struct ifnet *); | |
264 | static void atu_media_status(struct ifnet *, struct ifmediareq *); | 264 | static void atu_media_status(struct ifnet *, struct ifmediareq *); | |
265 | static int atu_tx_list_init(struct atu_softc *); | 265 | static int atu_tx_list_init(struct atu_softc *); | |
266 | static int atu_rx_list_init(struct atu_softc *); | 266 | static int atu_rx_list_init(struct atu_softc *); | |
267 | static void atu_xfer_list_free(struct atu_softc *, struct atu_chain *, | 267 | static void atu_xfer_list_free(struct atu_softc *, struct atu_chain *, | |
268 | int); | 268 | int); | |
269 | 269 | |||
270 | static void atu_task(void *); | 270 | static void atu_task(void *); | |
271 | static int atu_newstate(struct ieee80211com *, enum ieee80211_state, int); | 271 | static int atu_newstate(struct ieee80211com *, enum ieee80211_state, int); | |
272 | static int atu_tx_start(struct atu_softc *, struct ieee80211_node *, | 272 | static int atu_tx_start(struct atu_softc *, struct ieee80211_node *, | |
273 | struct atu_chain *, struct mbuf *); | 273 | struct atu_chain *, struct mbuf *); | |
274 | static void atu_complete_attach(struct atu_softc *); | 274 | static void atu_complete_attach(struct atu_softc *); | |
275 | static uint8_t atu_calculate_padding(int); | 275 | static uint8_t atu_calculate_padding(int); | |
276 | 276 | |||
277 | static int atu_match(device_t, cfdata_t, void *); | 277 | static int atu_match(device_t, cfdata_t, void *); | |
278 | static void atu_attach(device_t, device_t, void *); | 278 | static void atu_attach(device_t, device_t, void *); | |
279 | static int atu_detach(device_t, int); | 279 | static int atu_detach(device_t, int); | |
280 | static int atu_activate(device_t, enum devact); | 280 | static int atu_activate(device_t, enum devact); | |
281 | 281 | |||
282 | CFATTACH_DECL_NEW(atu, sizeof(struct atu_softc), atu_match, atu_attach, | 282 | CFATTACH_DECL_NEW(atu, sizeof(struct atu_softc), atu_match, atu_attach, | |
283 | atu_detach, atu_activate); | 283 | atu_detach, atu_activate); | |
284 | 284 | |||
285 | static usbd_status | 285 | static usbd_status | |
286 | atu_usb_request(struct atu_softc *sc, uint8_t type, | 286 | atu_usb_request(struct atu_softc *sc, uint8_t type, | |
287 | uint8_t request, uint16_t value, uint16_t index, uint16_t length, | 287 | uint8_t request, uint16_t value, uint16_t index, uint16_t length, | |
288 | uint8_t *data) | 288 | uint8_t *data) | |
289 | { | 289 | { | |
290 | usb_device_request_t req; | 290 | usb_device_request_t req; | |
291 | struct usbd_xfer *xfer; | 291 | struct usbd_xfer *xfer; | |
292 | usbd_status err; | 292 | usbd_status err; | |
293 | int total_len = 0, s; | 293 | int total_len = 0, s; | |
294 | 294 | |||
295 | req.bmRequestType = type; | 295 | req.bmRequestType = type; | |
296 | req.bRequest = request; | 296 | req.bRequest = request; | |
297 | USETW(req.wValue, value); | 297 | USETW(req.wValue, value); | |
298 | USETW(req.wIndex, index); | 298 | USETW(req.wIndex, index); | |
299 | USETW(req.wLength, length); | 299 | USETW(req.wLength, length); | |
300 | 300 | |||
301 | #ifdef ATU_DEBUG | 301 | #ifdef ATU_DEBUG | |
302 | if (atudebug) { | 302 | if (atudebug) { | |
303 | DPRINTFN(20, ("%s: req=%02x val=%02x ind=%02x " | 303 | DPRINTFN(20, ("%s: req=%02x val=%02x ind=%02x " | |
304 | "len=%02x\n", device_xname(sc->atu_dev), request, | 304 | "len=%02x\n", device_xname(sc->atu_dev), request, | |
305 | value, index, length)); | 305 | value, index, length)); | |
306 | } | 306 | } | |
307 | #endif /* ATU_DEBUG */ | 307 | #endif /* ATU_DEBUG */ | |
308 | 308 | |||
309 | s = splnet(); | 309 | s = splnet(); | |
310 | 310 | |||
311 | struct usbd_pipe *pipe0 = usbd_get_pipe0(sc->atu_udev); | 311 | struct usbd_pipe *pipe0 = usbd_get_pipe0(sc->atu_udev); | |
312 | int error = usbd_create_xfer(pipe0, length, 0, 0, | 312 | int error = usbd_create_xfer(pipe0, length, 0, 0, | |
313 | &xfer); | 313 | &xfer); | |
314 | if (error) { | 314 | if (error) { | |
315 | splx(s); | 315 | splx(s); | |
316 | return USBD_IOERROR; | 316 | return USBD_IOERROR; | |
317 | } | 317 | } | |
318 | usbd_setup_default_xfer(xfer, sc->atu_udev, 0, 500000, &req, data, | 318 | usbd_setup_default_xfer(xfer, sc->atu_udev, 0, 500000, &req, data, | |
319 | length, USBD_SHORT_XFER_OK, NULL); | 319 | length, USBD_SHORT_XFER_OK, NULL); | |
320 | 320 | |||
321 | err = usbd_sync_transfer(xfer); | 321 | err = usbd_sync_transfer(xfer); | |
322 | 322 | |||
323 | usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); | 323 | usbd_get_xfer_status(xfer, NULL, NULL, &total_len, NULL); | |
324 | 324 | |||
325 | #ifdef ATU_DEBUG | 325 | #ifdef ATU_DEBUG | |
326 | if (atudebug) { | 326 | if (atudebug) { | |
327 | if (type & UT_READ) { | 327 | if (type & UT_READ) { | |
328 | DPRINTFN(20, ("%s: transfered 0x%x bytes in\n", | 328 | DPRINTFN(20, ("%s: transfered 0x%x bytes in\n", | |
329 | device_xname(sc->atu_dev), total_len)); | 329 | device_xname(sc->atu_dev), total_len)); | |
330 | } else { | 330 | } else { | |
331 | if (total_len != length) | 331 | if (total_len != length) | |
332 | DPRINTF(("%s: wrote only %x bytes\n", | 332 | DPRINTF(("%s: wrote only %x bytes\n", | |
333 | device_xname(sc->atu_dev), total_len)); | 333 | device_xname(sc->atu_dev), total_len)); | |
334 | } | 334 | } | |
335 | } | 335 | } | |
336 | #endif /* ATU_DEBUG */ | 336 | #endif /* ATU_DEBUG */ | |
337 | 337 | |||
338 | usbd_destroy_xfer(xfer); | 338 | usbd_destroy_xfer(xfer); | |
339 | 339 | |||
340 | splx(s); | 340 | splx(s); | |
341 | return err; | 341 | return err; | |
342 | } | 342 | } | |
343 | 343 | |||
344 | static int | 344 | static int | |
345 | atu_send_command(struct atu_softc *sc, uint8_t *command, int size) | 345 | atu_send_command(struct atu_softc *sc, uint8_t *command, int size) | |
346 | { | 346 | { | |
347 | return atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000, | 347 | return atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000, | |
348 | 0x0000, size, command); | 348 | 0x0000, size, command); | |
349 | } | 349 | } | |
350 | 350 | |||
351 | static int | 351 | static int | |
352 | atu_get_cmd_status(struct atu_softc *sc, uint8_t cmd, uint8_t *status) | 352 | atu_get_cmd_status(struct atu_softc *sc, uint8_t cmd, uint8_t *status) | |
353 | { | 353 | { | |
354 | /* | 354 | /* | |
355 | * all other drivers (including Windoze) request 40 bytes of status | 355 | * all other drivers (including Windoze) request 40 bytes of status | |
356 | * and get a short-xfer of just 6 bytes. we can save 34 bytes of | 356 | * and get a short-xfer of just 6 bytes. we can save 34 bytes of | |
357 | * buffer if we just request those 6 bytes in the first place :) | 357 | * buffer if we just request those 6 bytes in the first place :) | |
358 | */ | 358 | */ | |
359 | /* | 359 | /* | |
360 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x22, cmd, | 360 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x22, cmd, | |
361 | 0x0000, 40, status); | 361 | 0x0000, 40, status); | |
362 | */ | 362 | */ | |
363 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x22, cmd, | 363 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x22, cmd, | |
364 | 0x0000, 6, status); | 364 | 0x0000, 6, status); | |
365 | } | 365 | } | |
366 | 366 | |||
367 | static int | 367 | static int | |
368 | atu_wait_completion(struct atu_softc *sc, uint8_t cmd, uint8_t *status) | 368 | atu_wait_completion(struct atu_softc *sc, uint8_t cmd, uint8_t *status) | |
369 | { | 369 | { | |
370 | int idle_count = 0, err; | 370 | int idle_count = 0, err; | |
371 | uint8_t statusreq[6]; | 371 | uint8_t statusreq[6]; | |
372 | 372 | |||
373 | DPRINTFN(15, ("%s: wait-completion: cmd=%02x\n", | 373 | DPRINTFN(15, ("%s: wait-completion: cmd=%02x\n", | |
374 | device_xname(sc->atu_dev), cmd)); | 374 | device_xname(sc->atu_dev), cmd)); | |
375 | 375 | |||
376 | while (1) { | 376 | while (1) { | |
377 | err = atu_get_cmd_status(sc, cmd, statusreq); | 377 | err = atu_get_cmd_status(sc, cmd, statusreq); | |
378 | if (err) | 378 | if (err) | |
379 | return err; | 379 | return err; | |
380 | 380 | |||
381 | #ifdef ATU_DEBUG | 381 | #ifdef ATU_DEBUG | |
382 | if (atudebug) { | 382 | if (atudebug) { | |
383 | DPRINTFN(20, ("%s: status=%s cmd=%02x\n", | 383 | DPRINTFN(20, ("%s: status=%s cmd=%02x\n", | |
384 | device_xname(sc->atu_dev), | 384 | device_xname(sc->atu_dev), | |
385 | ether_sprintf(statusreq), cmd)); | 385 | ether_sprintf(statusreq), cmd)); | |
386 | } | 386 | } | |
387 | #endif /* ATU_DEBUG */ | 387 | #endif /* ATU_DEBUG */ | |
388 | 388 | |||
389 | /* | 389 | /* | |
390 | * during normal operations waiting on STATUS_IDLE | 390 | * during normal operations waiting on STATUS_IDLE | |
391 | * will never happen more than once | 391 | * will never happen more than once | |
392 | */ | 392 | */ | |
393 | if ((statusreq[5] == STATUS_IDLE) && (idle_count++ > 20)) { | 393 | if ((statusreq[5] == STATUS_IDLE) && (idle_count++ > 20)) { | |
394 | DPRINTF(("%s: idle_count > 20!\n", | 394 | DPRINTF(("%s: idle_count > 20!\n", | |
395 | device_xname(sc->atu_dev))); | 395 | device_xname(sc->atu_dev))); | |
396 | return 0; | 396 | return 0; | |
397 | } | 397 | } | |
398 | 398 | |||
399 | if ((statusreq[5] != STATUS_IN_PROGRESS) && | 399 | if ((statusreq[5] != STATUS_IN_PROGRESS) && | |
400 | (statusreq[5] != STATUS_IDLE)) { | 400 | (statusreq[5] != STATUS_IDLE)) { | |
401 | if (status != NULL) | 401 | if (status != NULL) | |
402 | *status = statusreq[5]; | 402 | *status = statusreq[5]; | |
403 | return 0; | 403 | return 0; | |
404 | } | 404 | } | |
405 | usbd_delay_ms(sc->atu_udev, 25); | 405 | usbd_delay_ms(sc->atu_udev, 25); | |
406 | } | 406 | } | |
407 | } | 407 | } | |
408 | 408 | |||
409 | static int | 409 | static int | |
410 | atu_send_mib(struct atu_softc *sc, uint8_t type, uint8_t size, | 410 | atu_send_mib(struct atu_softc *sc, uint8_t type, uint8_t size, | |
411 | uint8_t index, void *data) | 411 | uint8_t index, void *data) | |
412 | { | 412 | { | |
413 | int err; | 413 | int err; | |
414 | struct atu_cmd_set_mib request; | 414 | struct atu_cmd_set_mib request; | |
415 | 415 | |||
416 | /* | 416 | /* | |
417 | * We don't construct a MIB packet first and then memcpy it into an | 417 | * We don't construct a MIB packet first and then memcpy it into an | |
418 | * Atmel-command-packet, we just construct it the right way at once :) | 418 | * Atmel-command-packet, we just construct it the right way at once :) | |
419 | */ | 419 | */ | |
420 | 420 | |||
421 | memset(&request, 0, sizeof(request)); | 421 | memset(&request, 0, sizeof(request)); | |
422 | 422 | |||
423 | request.AtCmd = CMD_SET_MIB; | 423 | request.AtCmd = CMD_SET_MIB; | |
424 | USETW(request.AtSize, size + 4); | 424 | USETW(request.AtSize, size + 4); | |
425 | 425 | |||
426 | request.MIBType = type; | 426 | request.MIBType = type; | |
427 | request.MIBSize = size; | 427 | request.MIBSize = size; | |
428 | request.MIBIndex = index; | 428 | request.MIBIndex = index; | |
429 | request.MIBReserved = 0; | 429 | request.MIBReserved = 0; | |
430 | 430 | |||
431 | /* | 431 | /* | |
432 | * For 1 and 2 byte requests we assume a direct value, | 432 | * For 1 and 2 byte requests we assume a direct value, | |
433 | * everything bigger than 2 bytes we assume a pointer to the data | 433 | * everything bigger than 2 bytes we assume a pointer to the data | |
434 | */ | 434 | */ | |
435 | switch (size) { | 435 | switch (size) { | |
436 | case 0: | 436 | case 0: | |
437 | break; | 437 | break; | |
438 | case 1: | 438 | case 1: | |
439 | request.data[0]=(long)data & 0x000000ff; | 439 | request.data[0]=(long)data & 0x000000ff; | |
440 | break; | 440 | break; | |
441 | case 2: | 441 | case 2: | |
442 | request.data[0]=(long)data & 0x000000ff; | 442 | request.data[0]=(long)data & 0x000000ff; | |
443 | request.data[1]=(long)data >> 8; | 443 | request.data[1]=(long)data >> 8; | |
444 | break; | 444 | break; | |
445 | default: | 445 | default: | |
446 | memcpy(request.data, data, size); | 446 | memcpy(request.data, data, size); | |
447 | break; | 447 | break; | |
448 | } | 448 | } | |
449 | 449 | |||
450 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000, | 450 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0000, | |
451 | 0x0000, size+8, (uByte *)&request); | 451 | 0x0000, size+8, (uByte *)&request); | |
452 | if (err) | 452 | if (err) | |
453 | return err; | 453 | return err; | |
454 | 454 | |||
455 | DPRINTFN(15, ("%s: sendmib : waitcompletion...\n", | 455 | DPRINTFN(15, ("%s: sendmib : waitcompletion...\n", | |
456 | device_xname(sc->atu_dev))); | 456 | device_xname(sc->atu_dev))); | |
457 | return atu_wait_completion(sc, CMD_SET_MIB, NULL); | 457 | return atu_wait_completion(sc, CMD_SET_MIB, NULL); | |
458 | } | 458 | } | |
459 | 459 | |||
460 | static int | 460 | static int | |
461 | atu_get_mib(struct atu_softc *sc, uint8_t type, uint8_t size, | 461 | atu_get_mib(struct atu_softc *sc, uint8_t type, uint8_t size, | |
462 | uint8_t index, uint8_t *buf) | 462 | uint8_t index, uint8_t *buf) | |
463 | { | 463 | { | |
464 | 464 | |||
465 | /* linux/at76c503.c - 478 */ | 465 | /* linux/at76c503.c - 478 */ | |
466 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x033, | 466 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x033, | |
467 | type << 8, index, size, buf); | 467 | type << 8, index, size, buf); | |
468 | } | 468 | } | |
469 | 469 | |||
470 | #if 0 | 470 | #if 0 | |
471 | int | 471 | int | |
472 | atu_start_ibss(struct atu_softc *sc) | 472 | atu_start_ibss(struct atu_softc *sc) | |
473 | { | 473 | { | |
474 | struct ieee80211com *ic = &sc->sc_ic; | 474 | struct ieee80211com *ic = &sc->sc_ic; | |
475 | int err; | 475 | int err; | |
476 | struct atu_cmd_start_ibss Request; | 476 | struct atu_cmd_start_ibss Request; | |
477 | 477 | |||
478 | Request.Cmd = CMD_START_IBSS; | 478 | Request.Cmd = CMD_START_IBSS; | |
479 | Request.Reserved = 0; | 479 | Request.Reserved = 0; | |
480 | Request.Size = sizeof(Request) - 4; | 480 | Request.Size = sizeof(Request) - 4; | |
481 | 481 | |||
482 | memset(Request.BSSID, 0x00, sizeof(Request.BSSID)); | 482 | memset(Request.BSSID, 0x00, sizeof(Request.BSSID)); | |
483 | memset(Request.SSID, 0x00, sizeof(Request.SSID)); | 483 | memset(Request.SSID, 0x00, sizeof(Request.SSID)); | |
484 | memcpy(Request.SSID, ic->ic_des_ssid, ic->ic_des_ssidlen); | 484 | memcpy(Request.SSID, ic->ic_des_ssid, ic->ic_des_ssidlen); | |
485 | Request.SSIDSize = ic->ic_des_ssidlen; | 485 | Request.SSIDSize = ic->ic_des_ssidlen; | |
486 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | 486 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | |
487 | Request.Channel = (uint8_t)sc->atu_desired_channel; | 487 | Request.Channel = (uint8_t)sc->atu_desired_channel; | |
488 | else | 488 | else | |
489 | Request.Channel = ATU_DEFAULT_CHANNEL; | 489 | Request.Channel = ATU_DEFAULT_CHANNEL; | |
490 | Request.BSSType = AD_HOC_MODE; | 490 | Request.BSSType = AD_HOC_MODE; | |
491 | memset(Request.Res, 0x00, sizeof(Request.Res)); | 491 | memset(Request.Res, 0x00, sizeof(Request.Res)); | |
492 | 492 | |||
493 | /* Write config to adapter */ | 493 | /* Write config to adapter */ | |
494 | err = atu_send_command(sc, (uint8_t *)&Request, sizeof(Request)); | 494 | err = atu_send_command(sc, (uint8_t *)&Request, sizeof(Request)); | |
495 | if (err) { | 495 | if (err) { | |
496 | DPRINTF(("%s: start ibss failed!\n", | 496 | DPRINTF(("%s: start ibss failed!\n", | |
497 | device_xname(sc->atu_dev))); | 497 | device_xname(sc->atu_dev))); | |
498 | return err; | 498 | return err; | |
499 | } | 499 | } | |
500 | 500 | |||
501 | /* Wait for the adapter to do its thing */ | 501 | /* Wait for the adapter to do its thing */ | |
502 | err = atu_wait_completion(sc, CMD_START_IBSS, NULL); | 502 | err = atu_wait_completion(sc, CMD_START_IBSS, NULL); | |
503 | if (err) { | 503 | if (err) { | |
504 | DPRINTF(("%s: error waiting for start_ibss\n", | 504 | DPRINTF(("%s: error waiting for start_ibss\n", | |
505 | device_xname(sc->atu_dev))); | 505 | device_xname(sc->atu_dev))); | |
506 | return err; | 506 | return err; | |
507 | } | 507 | } | |
508 | 508 | |||
509 | /* Get the current BSSID */ | 509 | /* Get the current BSSID */ | |
510 | err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_BSSID, sc->atu_bssid); | 510 | err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_BSSID, sc->atu_bssid); | |
511 | if (err) { | 511 | if (err) { | |
512 | DPRINTF(("%s: could not get BSSID!\n", | 512 | DPRINTF(("%s: could not get BSSID!\n", | |
513 | device_xname(sc->atu_dev))); | 513 | device_xname(sc->atu_dev))); | |
514 | return err; | 514 | return err; | |
515 | } | 515 | } | |
516 | 516 | |||
517 | DPRINTF(("%s: started a new IBSS (BSSID=%s)\n", | 517 | DPRINTF(("%s: started a new IBSS (BSSID=%s)\n", | |
518 | device_xname(sc->atu_dev), ether_sprintf(sc->atu_bssid))); | 518 | device_xname(sc->atu_dev), ether_sprintf(sc->atu_bssid))); | |
519 | return 0; | 519 | return 0; | |
520 | } | 520 | } | |
521 | #endif | 521 | #endif | |
522 | 522 | |||
523 | static int | 523 | static int | |
524 | atu_start_scan(struct atu_softc *sc) | 524 | atu_start_scan(struct atu_softc *sc) | |
525 | { | 525 | { | |
526 | struct ieee80211com *ic = &sc->sc_ic; | 526 | struct ieee80211com *ic = &sc->sc_ic; | |
527 | struct atu_cmd_do_scan Scan; | 527 | struct atu_cmd_do_scan Scan; | |
528 | usbd_status err; | 528 | usbd_status err; | |
529 | int Cnt; | 529 | int Cnt; | |
530 | 530 | |||
531 | memset(&Scan, 0, sizeof(Scan)); | 531 | memset(&Scan, 0, sizeof(Scan)); | |
532 | 532 | |||
533 | Scan.Cmd = CMD_START_SCAN; | 533 | Scan.Cmd = CMD_START_SCAN; | |
534 | Scan.Reserved = 0; | 534 | Scan.Reserved = 0; | |
535 | USETW(Scan.Size, sizeof(Scan) - 4); | 535 | USETW(Scan.Size, sizeof(Scan) - 4); | |
536 | 536 | |||
537 | /* use the broadcast BSSID (in active scan) */ | 537 | /* use the broadcast BSSID (in active scan) */ | |
538 | for (Cnt=0; Cnt<6; Cnt++) | 538 | for (Cnt=0; Cnt<6; Cnt++) | |
539 | Scan.BSSID[Cnt] = 0xff; | 539 | Scan.BSSID[Cnt] = 0xff; | |
540 | 540 | |||
541 | memset(Scan.SSID, 0x00, sizeof(Scan.SSID)); | 541 | memset(Scan.SSID, 0x00, sizeof(Scan.SSID)); | |
542 | memcpy(Scan.SSID, ic->ic_des_essid, ic->ic_des_esslen); | 542 | memcpy(Scan.SSID, ic->ic_des_essid, ic->ic_des_esslen); | |
543 | Scan.SSID_Len = ic->ic_des_esslen; | 543 | Scan.SSID_Len = ic->ic_des_esslen; | |
544 | 544 | |||
545 | /* default values for scan */ | 545 | /* default values for scan */ | |
546 | Scan.ScanType = ATU_SCAN_ACTIVE; | 546 | Scan.ScanType = ATU_SCAN_ACTIVE; | |
547 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | 547 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | |
548 | Scan.Channel = (uint8_t)sc->atu_desired_channel; | 548 | Scan.Channel = (uint8_t)sc->atu_desired_channel; | |
549 | else | 549 | else | |
550 | Scan.Channel = sc->atu_channel; | 550 | Scan.Channel = sc->atu_channel; | |
551 | 551 | |||
552 | ic->ic_curchan = &ic->ic_channels[Scan.Channel]; | 552 | ic->ic_curchan = &ic->ic_channels[Scan.Channel]; | |
553 | 553 | |||
554 | /* we like scans to be quick :) */ | 554 | /* we like scans to be quick :) */ | |
555 | /* the time we wait before sending probe's */ | 555 | /* the time we wait before sending probe's */ | |
556 | USETW(Scan.ProbeDelay, 0); | 556 | USETW(Scan.ProbeDelay, 0); | |
557 | /* the time we stay on one channel */ | 557 | /* the time we stay on one channel */ | |
558 | USETW(Scan.MinChannelTime, 100); | 558 | USETW(Scan.MinChannelTime, 100); | |
559 | USETW(Scan.MaxChannelTime, 200); | 559 | USETW(Scan.MaxChannelTime, 200); | |
560 | /* whether or not we scan all channels */ | 560 | /* whether or not we scan all channels */ | |
561 | Scan.InternationalScan = 0xc1; | 561 | Scan.InternationalScan = 0xc1; | |
562 | 562 | |||
563 | #ifdef ATU_DEBUG | 563 | #ifdef ATU_DEBUG | |
564 | if (atudebug) { | 564 | if (atudebug) { | |
565 | DPRINTFN(20, ("%s: scan cmd len=%02zx\n", | 565 | DPRINTFN(20, ("%s: scan cmd len=%02zx\n", | |
566 | device_xname(sc->atu_dev), sizeof(Scan))); | 566 | device_xname(sc->atu_dev), sizeof(Scan))); | |
567 | } | 567 | } | |
568 | #endif /* ATU_DEBUG */ | 568 | #endif /* ATU_DEBUG */ | |
569 | 569 | |||
570 | /* Write config to adapter */ | 570 | /* Write config to adapter */ | |
571 | err = atu_send_command(sc, (uint8_t *)&Scan, sizeof(Scan)); | 571 | err = atu_send_command(sc, (uint8_t *)&Scan, sizeof(Scan)); | |
572 | if (err) | 572 | if (err) | |
573 | return err; | 573 | return err; | |
574 | 574 | |||
575 | /* | 575 | /* | |
576 | * We don't wait for the command to finish... the mgmt-thread will do | 576 | * We don't wait for the command to finish... the mgmt-thread will do | |
577 | * that for us | 577 | * that for us | |
578 | */ | 578 | */ | |
579 | /* | 579 | /* | |
580 | err = atu_wait_completion(sc, CMD_START_SCAN, NULL); | 580 | err = atu_wait_completion(sc, CMD_START_SCAN, NULL); | |
581 | if (err) | 581 | if (err) | |
582 | return err; | 582 | return err; | |
583 | */ | 583 | */ | |
584 | return 0; | 584 | return 0; | |
585 | } | 585 | } | |
586 | 586 | |||
587 | static int | 587 | static int | |
588 | atu_switch_radio(struct atu_softc *sc, int state) | 588 | atu_switch_radio(struct atu_softc *sc, int state) | |
589 | { | 589 | { | |
590 | usbd_status err; | 590 | usbd_status err; | |
591 | struct atu_cmd CmdRadio; | 591 | struct atu_cmd CmdRadio; | |
592 | 592 | |||
593 | if (sc->atu_radio == RadioIntersil) { | 593 | if (sc->atu_radio == RadioIntersil) { | |
594 | /* | 594 | /* | |
595 | * Intersil doesn't seem to need/support switching the radio | 595 | * Intersil doesn't seem to need/support switching the radio | |
596 | * on/off | 596 | * on/off | |
597 | */ | 597 | */ | |
598 | return 0; | 598 | return 0; | |
599 | } | 599 | } | |
600 | 600 | |||
601 | memset(&CmdRadio, 0, sizeof(CmdRadio)); | 601 | memset(&CmdRadio, 0, sizeof(CmdRadio)); | |
602 | CmdRadio.Cmd = CMD_RADIO_ON; | 602 | CmdRadio.Cmd = CMD_RADIO_ON; | |
603 | 603 | |||
604 | if (sc->atu_radio_on != state) { | 604 | if (sc->atu_radio_on != state) { | |
605 | if (state == 0) | 605 | if (state == 0) | |
606 | CmdRadio.Cmd = CMD_RADIO_OFF; | 606 | CmdRadio.Cmd = CMD_RADIO_OFF; | |
607 | 607 | |||
608 | err = atu_send_command(sc, (uint8_t *)&CmdRadio, | 608 | err = atu_send_command(sc, (uint8_t *)&CmdRadio, | |
609 | sizeof(CmdRadio)); | 609 | sizeof(CmdRadio)); | |
610 | if (err) | 610 | if (err) | |
611 | return err; | 611 | return err; | |
612 | 612 | |||
613 | err = atu_wait_completion(sc, CmdRadio.Cmd, NULL); | 613 | err = atu_wait_completion(sc, CmdRadio.Cmd, NULL); | |
614 | if (err) | 614 | if (err) | |
615 | return err; | 615 | return err; | |
616 | 616 | |||
617 | DPRINTFN(10, ("%s: radio turned %s\n", | 617 | DPRINTFN(10, ("%s: radio turned %s\n", | |
618 | device_xname(sc->atu_dev), state ? "on" : "off")); | 618 | device_xname(sc->atu_dev), state ? "on" : "off")); | |
619 | sc->atu_radio_on = state; | 619 | sc->atu_radio_on = state; | |
620 | } | 620 | } | |
621 | return 0; | 621 | return 0; | |
622 | } | 622 | } | |
623 | 623 | |||
624 | static int | 624 | static int | |
625 | atu_initial_config(struct atu_softc *sc) | 625 | atu_initial_config(struct atu_softc *sc) | |
626 | { | 626 | { | |
627 | struct ieee80211com *ic = &sc->sc_ic; | 627 | struct ieee80211com *ic = &sc->sc_ic; | |
628 | uint32_t i; | 628 | uint32_t i; | |
629 | usbd_status err; | 629 | usbd_status err; | |
630 | /* uint8_t rates[4] = {0x82, 0x84, 0x8B, 0x96};*/ | 630 | /* uint8_t rates[4] = {0x82, 0x84, 0x8B, 0x96};*/ | |
631 | uint8_t rates[4] = {0x82, 0x04, 0x0B, 0x16}; | 631 | uint8_t rates[4] = {0x82, 0x04, 0x0B, 0x16}; | |
632 | struct atu_cmd_card_config cmd; | 632 | struct atu_cmd_card_config cmd; | |
633 | uint8_t reg_domain; | 633 | uint8_t reg_domain; | |
634 | 634 | |||
635 | DPRINTFN(10, ("%s: sending mac-addr\n", device_xname(sc->atu_dev))); | 635 | DPRINTFN(10, ("%s: sending mac-addr\n", device_xname(sc->atu_dev))); | |
636 | err = atu_send_mib(sc, MIB_MAC_ADDR__ADDR, ic->ic_myaddr); | 636 | err = atu_send_mib(sc, MIB_MAC_ADDR__ADDR, ic->ic_myaddr); | |
637 | if (err) { | 637 | if (err) { | |
638 | DPRINTF(("%s: error setting mac-addr\n", | 638 | DPRINTF(("%s: error setting mac-addr\n", | |
639 | device_xname(sc->atu_dev))); | 639 | device_xname(sc->atu_dev))); | |
640 | return err; | 640 | return err; | |
641 | } | 641 | } | |
642 | 642 | |||
643 | /* | 643 | /* | |
644 | DPRINTF(("%s: sending reg-domain\n", device_xname(sc->atu_dev))); | 644 | DPRINTF(("%s: sending reg-domain\n", device_xname(sc->atu_dev))); | |
645 | err = atu_send_mib(sc, MIB_PHY__REG_DOMAIN, NR(0x30)); | 645 | err = atu_send_mib(sc, MIB_PHY__REG_DOMAIN, NR(0x30)); | |
646 | if (err) { | 646 | if (err) { | |
647 | DPRINTF(("%s: error setting mac-addr\n", | 647 | DPRINTF(("%s: error setting mac-addr\n", | |
648 | device_xname(sc->atu_dev))); | 648 | device_xname(sc->atu_dev))); | |
649 | return err; | 649 | return err; | |
650 | } | 650 | } | |
651 | */ | 651 | */ | |
652 | 652 | |||
653 | memset(&cmd, 0, sizeof(cmd)); | 653 | memset(&cmd, 0, sizeof(cmd)); | |
654 | cmd.Cmd = CMD_STARTUP; | 654 | cmd.Cmd = CMD_STARTUP; | |
655 | cmd.Reserved = 0; | 655 | cmd.Reserved = 0; | |
656 | USETW(cmd.Size, sizeof(cmd) - 4); | 656 | USETW(cmd.Size, sizeof(cmd) - 4); | |
657 | 657 | |||
658 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | 658 | if (sc->atu_desired_channel != IEEE80211_CHAN_ANY) | |
659 | cmd.Channel = (uint8_t)sc->atu_desired_channel; | 659 | cmd.Channel = (uint8_t)sc->atu_desired_channel; | |
660 | else | 660 | else | |
661 | cmd.Channel = sc->atu_channel; | 661 | cmd.Channel = sc->atu_channel; | |
662 | cmd.AutoRateFallback = 1; | 662 | cmd.AutoRateFallback = 1; | |
663 | memcpy(cmd.BasicRateSet, rates, 4); | 663 | memcpy(cmd.BasicRateSet, rates, 4); | |
664 | 664 | |||
665 | /* ShortRetryLimit should be 7 according to 802.11 spec */ | 665 | /* ShortRetryLimit should be 7 according to 802.11 spec */ | |
666 | cmd.ShortRetryLimit = 7; | 666 | cmd.ShortRetryLimit = 7; | |
667 | USETW(cmd.RTS_Threshold, 2347); | 667 | USETW(cmd.RTS_Threshold, 2347); | |
668 | USETW(cmd.FragThreshold, 2346); | 668 | USETW(cmd.FragThreshold, 2346); | |
669 | 669 | |||
670 | /* Doesn't seem to work, but we'll set it to 1 anyway */ | 670 | /* Doesn't seem to work, but we'll set it to 1 anyway */ | |
671 | cmd.PromiscuousMode = 1; | 671 | cmd.PromiscuousMode = 1; | |
672 | 672 | |||
673 | /* this goes into the beacon we transmit */ | 673 | /* this goes into the beacon we transmit */ | |
674 | if (ic->ic_flags & IEEE80211_F_PRIVACY) | 674 | if (ic->ic_flags & IEEE80211_F_PRIVACY) | |
675 | cmd.PrivacyInvoked = 1; | 675 | cmd.PrivacyInvoked = 1; | |
676 | else | 676 | else | |
677 | cmd.PrivacyInvoked = 0; | 677 | cmd.PrivacyInvoked = 0; | |
678 | 678 | |||
679 | cmd.ExcludeUnencrypted = 0; | 679 | cmd.ExcludeUnencrypted = 0; | |
680 | 680 | |||
681 | if (ic->ic_flags & IEEE80211_F_PRIVACY) { | 681 | if (ic->ic_flags & IEEE80211_F_PRIVACY) { | |
682 | switch (ic->ic_nw_keys[ic->ic_def_txkey].wk_keylen) { | 682 | switch (ic->ic_nw_keys[ic->ic_def_txkey].wk_keylen) { | |
683 | case 5: | 683 | case 5: | |
684 | cmd.EncryptionType = ATU_WEP_40BITS; | 684 | cmd.EncryptionType = ATU_WEP_40BITS; | |
685 | break; | 685 | break; | |
686 | case 13: | 686 | case 13: | |
687 | cmd.EncryptionType = ATU_WEP_104BITS; | 687 | cmd.EncryptionType = ATU_WEP_104BITS; | |
688 | break; | 688 | break; | |
689 | default: | 689 | default: | |
690 | cmd.EncryptionType = ATU_WEP_OFF; | 690 | cmd.EncryptionType = ATU_WEP_OFF; | |
691 | break; | 691 | break; | |
692 | } | 692 | } | |
693 | 693 | |||
694 | 694 | |||
695 | cmd.WEP_DefaultKeyID = ic->ic_def_txkey; | 695 | cmd.WEP_DefaultKeyID = ic->ic_def_txkey; | |
696 | for (i = 0; i < IEEE80211_WEP_NKID; i++) { | 696 | for (i = 0; i < IEEE80211_WEP_NKID; i++) { | |
697 | memcpy(cmd.WEP_DefaultKey[i], ic->ic_nw_keys[i].wk_key, | 697 | memcpy(cmd.WEP_DefaultKey[i], ic->ic_nw_keys[i].wk_key, | |
698 | ic->ic_nw_keys[i].wk_keylen); | 698 | ic->ic_nw_keys[i].wk_keylen); | |
699 | } | 699 | } | |
700 | } | 700 | } | |
701 | 701 | |||
702 | /* Setting the SSID here doesn't seem to do anything */ | 702 | /* Setting the SSID here doesn't seem to do anything */ | |
703 | memset(cmd.SSID, 0x00, sizeof(cmd.SSID)); | 703 | memset(cmd.SSID, 0x00, sizeof(cmd.SSID)); | |
704 | memcpy(cmd.SSID, ic->ic_des_essid, ic->ic_des_esslen); | 704 | memcpy(cmd.SSID, ic->ic_des_essid, ic->ic_des_esslen); | |
705 | cmd.SSID_Len = ic->ic_des_esslen; | 705 | cmd.SSID_Len = ic->ic_des_esslen; | |
706 | 706 | |||
707 | cmd.ShortPreamble = 0; | 707 | cmd.ShortPreamble = 0; | |
708 | USETW(cmd.BeaconPeriod, 100); | 708 | USETW(cmd.BeaconPeriod, 100); | |
709 | /* cmd.BeaconPeriod = 65535; */ | 709 | /* cmd.BeaconPeriod = 65535; */ | |
710 | 710 | |||
711 | /* | 711 | /* | |
712 | * TODO: | 712 | * TODO: | |
713 | * read reg domain MIB_PHY @ 0x17 (1 byte), (reply = 0x30) | 713 | * read reg domain MIB_PHY @ 0x17 (1 byte), (reply = 0x30) | |
714 | * we should do something useful with this info. right now it's just | 714 | * we should do something useful with this info. right now it's just | |
715 | * ignored | 715 | * ignored | |
716 | */ | 716 | */ | |
717 | err = atu_get_mib(sc, MIB_PHY__REG_DOMAIN, ®_domain); | 717 | err = atu_get_mib(sc, MIB_PHY__REG_DOMAIN, ®_domain); | |
718 | if (err) { | 718 | if (err) { | |
719 | DPRINTF(("%s: could not get regdomain!\n", | 719 | DPRINTF(("%s: could not get regdomain!\n", | |
720 | device_xname(sc->atu_dev))); | 720 | device_xname(sc->atu_dev))); | |
721 | } else { | 721 | } else { | |
722 | DPRINTF(("%s: in reg domain 0x%x according to the " | 722 | DPRINTF(("%s: in reg domain 0x%x according to the " | |
723 | "adapter\n", device_xname(sc->atu_dev), reg_domain)); | 723 | "adapter\n", device_xname(sc->atu_dev), reg_domain)); | |
724 | } | 724 | } | |
725 | 725 | |||
726 | #ifdef ATU_DEBUG | 726 | #ifdef ATU_DEBUG | |
727 | if (atudebug) { | 727 | if (atudebug) { | |
728 | DPRINTFN(20, ("%s: configlen=%02zx\n", | 728 | DPRINTFN(20, ("%s: configlen=%02zx\n", | |
729 | device_xname(sc->atu_dev), sizeof(cmd))); | 729 | device_xname(sc->atu_dev), sizeof(cmd))); | |
730 | } | 730 | } | |
731 | #endif /* ATU_DEBUG */ | 731 | #endif /* ATU_DEBUG */ | |
732 | 732 | |||
733 | /* Windoze : driver says exclude-unencrypted=1 & encr-type=1 */ | 733 | /* Windoze : driver says exclude-unencrypted=1 & encr-type=1 */ | |
734 | 734 | |||
735 | err = atu_send_command(sc, (uint8_t *)&cmd, sizeof(cmd)); | 735 | err = atu_send_command(sc, (uint8_t *)&cmd, sizeof(cmd)); | |
736 | if (err) | 736 | if (err) | |
737 | return err; | 737 | return err; | |
738 | err = atu_wait_completion(sc, CMD_STARTUP, NULL); | 738 | err = atu_wait_completion(sc, CMD_STARTUP, NULL); | |
739 | if (err) | 739 | if (err) | |
740 | return err; | 740 | return err; | |
741 | 741 | |||
742 | /* Turn on radio now */ | 742 | /* Turn on radio now */ | |
743 | err = atu_switch_radio(sc, 1); | 743 | err = atu_switch_radio(sc, 1); | |
744 | if (err) | 744 | if (err) | |
745 | return err; | 745 | return err; | |
746 | 746 | |||
747 | /* preamble type = short */ | 747 | /* preamble type = short */ | |
748 | err = atu_send_mib(sc, MIB_LOCAL__PREAMBLE, NR(PREAMBLE_SHORT)); | 748 | err = atu_send_mib(sc, MIB_LOCAL__PREAMBLE, NR(PREAMBLE_SHORT)); | |
749 | if (err) | 749 | if (err) | |
750 | return err; | 750 | return err; | |
751 | 751 | |||
752 | /* frag = 1536 */ | 752 | /* frag = 1536 */ | |
753 | err = atu_send_mib(sc, MIB_MAC__FRAG, NR(2346)); | 753 | err = atu_send_mib(sc, MIB_MAC__FRAG, NR(2346)); | |
754 | if (err) | 754 | if (err) | |
755 | return err; | 755 | return err; | |
756 | 756 | |||
757 | /* rts = 1536 */ | 757 | /* rts = 1536 */ | |
758 | err = atu_send_mib(sc, MIB_MAC__RTS, NR(2347)); | 758 | err = atu_send_mib(sc, MIB_MAC__RTS, NR(2347)); | |
759 | if (err) | 759 | if (err) | |
760 | return err; | 760 | return err; | |
761 | 761 | |||
762 | /* auto rate fallback = 1 */ | 762 | /* auto rate fallback = 1 */ | |
763 | err = atu_send_mib(sc, MIB_LOCAL__AUTO_RATE_FALLBACK, NR(1)); | 763 | err = atu_send_mib(sc, MIB_LOCAL__AUTO_RATE_FALLBACK, NR(1)); | |
764 | if (err) | 764 | if (err) | |
765 | return err; | 765 | return err; | |
766 | 766 | |||
767 | /* power mode = full on, no power saving */ | 767 | /* power mode = full on, no power saving */ | |
768 | err = atu_send_mib(sc, MIB_MAC_MGMT__POWER_MODE, | 768 | err = atu_send_mib(sc, MIB_MAC_MGMT__POWER_MODE, | |
769 | NR(POWER_MODE_ACTIVE)); | 769 | NR(POWER_MODE_ACTIVE)); | |
770 | if (err) | 770 | if (err) | |
771 | return err; | 771 | return err; | |
772 | 772 | |||
773 | DPRINTFN(10, ("%s: completed initial config\n", | 773 | DPRINTFN(10, ("%s: completed initial config\n", | |
774 | device_xname(sc->atu_dev))); | 774 | device_xname(sc->atu_dev))); | |
775 | return 0; | 775 | return 0; | |
776 | } | 776 | } | |
777 | 777 | |||
778 | static int | 778 | static int | |
779 | atu_join(struct atu_softc *sc, struct ieee80211_node *node) | 779 | atu_join(struct atu_softc *sc, struct ieee80211_node *node) | |
780 | { | 780 | { | |
781 | struct atu_cmd_join join; | 781 | struct atu_cmd_join join; | |
782 | uint8_t status = 0; /* XXX: GCC */ | 782 | uint8_t status = 0; /* XXX: GCC */ | |
783 | usbd_status err; | 783 | usbd_status err; | |
784 | 784 | |||
785 | memset(&join, 0, sizeof(join)); | 785 | memset(&join, 0, sizeof(join)); | |
786 | 786 | |||
787 | join.Cmd = CMD_JOIN; | 787 | join.Cmd = CMD_JOIN; | |
788 | join.Reserved = 0x00; | 788 | join.Reserved = 0x00; | |
789 | USETW(join.Size, sizeof(join) - 4); | 789 | USETW(join.Size, sizeof(join) - 4); | |
790 | 790 | |||
791 | DPRINTFN(15, ("%s: pre-join sc->atu_bssid=%s\n", | 791 | DPRINTFN(15, ("%s: pre-join sc->atu_bssid=%s\n", | |
792 | device_xname(sc->atu_dev), ether_sprintf(sc->atu_bssid))); | 792 | device_xname(sc->atu_dev), ether_sprintf(sc->atu_bssid))); | |
793 | DPRINTFN(15, ("%s: mode=%d\n", device_xname(sc->atu_dev), | 793 | DPRINTFN(15, ("%s: mode=%d\n", device_xname(sc->atu_dev), | |
794 | sc->atu_mode)); | 794 | sc->atu_mode)); | |
795 | memcpy(join.bssid, node->ni_bssid, IEEE80211_ADDR_LEN); | 795 | memcpy(join.bssid, node->ni_bssid, IEEE80211_ADDR_LEN); | |
796 | memset(join.essid, 0x00, 32); | 796 | memset(join.essid, 0x00, 32); | |
797 | memcpy(join.essid, node->ni_essid, node->ni_esslen); | 797 | memcpy(join.essid, node->ni_essid, node->ni_esslen); | |
798 | join.essid_size = node->ni_esslen; | 798 | join.essid_size = node->ni_esslen; | |
799 | if (node->ni_capinfo & IEEE80211_CAPINFO_IBSS) | 799 | if (node->ni_capinfo & IEEE80211_CAPINFO_IBSS) | |
800 | join.bss_type = AD_HOC_MODE; | 800 | join.bss_type = AD_HOC_MODE; | |
801 | else | 801 | else | |
802 | join.bss_type = INFRASTRUCTURE_MODE; | 802 | join.bss_type = INFRASTRUCTURE_MODE; | |
803 | join.channel = ieee80211_chan2ieee(&sc->sc_ic, node->ni_chan); | 803 | join.channel = ieee80211_chan2ieee(&sc->sc_ic, node->ni_chan); | |
804 | 804 | |||
805 | USETW(join.timeout, ATU_JOIN_TIMEOUT); | 805 | USETW(join.timeout, ATU_JOIN_TIMEOUT); | |
806 | join.reserved = 0x00; | 806 | join.reserved = 0x00; | |
807 | 807 | |||
808 | DPRINTFN(10, ("%s: trying to join BSSID=%s\n", | 808 | DPRINTFN(10, ("%s: trying to join BSSID=%s\n", | |
809 | device_xname(sc->atu_dev), ether_sprintf(join.bssid))); | 809 | device_xname(sc->atu_dev), ether_sprintf(join.bssid))); | |
810 | err = atu_send_command(sc, (uint8_t *)&join, sizeof(join)); | 810 | err = atu_send_command(sc, (uint8_t *)&join, sizeof(join)); | |
811 | if (err) { | 811 | if (err) { | |
812 | DPRINTF(("%s: ERROR trying to join IBSS\n", | 812 | DPRINTF(("%s: ERROR trying to join IBSS\n", | |
813 | device_xname(sc->atu_dev))); | 813 | device_xname(sc->atu_dev))); | |
814 | return err; | 814 | return err; | |
815 | } | 815 | } | |
816 | err = atu_wait_completion(sc, CMD_JOIN, &status); | 816 | err = atu_wait_completion(sc, CMD_JOIN, &status); | |
817 | if (err) { | 817 | if (err) { | |
818 | DPRINTF(("%s: error joining BSS!\n", | 818 | DPRINTF(("%s: error joining BSS!\n", | |
819 | device_xname(sc->atu_dev))); | 819 | device_xname(sc->atu_dev))); | |
820 | return err; | 820 | return err; | |
821 | } | 821 | } | |
822 | if (status != STATUS_COMPLETE) { | 822 | if (status != STATUS_COMPLETE) { | |
823 | DPRINTF(("%s: error joining... [status=%02x]\n", | 823 | DPRINTF(("%s: error joining... [status=%02x]\n", | |
824 | device_xname(sc->atu_dev), status)); | 824 | device_xname(sc->atu_dev), status)); | |
825 | return status; | 825 | return status; | |
826 | } else { | 826 | } else { | |
827 | DPRINTFN(10, ("%s: joined BSS\n", device_xname(sc->atu_dev))); | 827 | DPRINTFN(10, ("%s: joined BSS\n", device_xname(sc->atu_dev))); | |
828 | } | 828 | } | |
829 | return err; | 829 | return err; | |
830 | } | 830 | } | |
831 | 831 | |||
832 | /* | 832 | /* | |
833 | * Get the state of the DFU unit | 833 | * Get the state of the DFU unit | |
834 | */ | 834 | */ | |
835 | static int8_t | 835 | static int8_t | |
836 | atu_get_dfu_state(struct atu_softc *sc) | 836 | atu_get_dfu_state(struct atu_softc *sc) | |
837 | { | 837 | { | |
838 | uint8_t state; | 838 | uint8_t state; | |
839 | 839 | |||
840 | if (atu_usb_request(sc, DFU_GETSTATE, 0, 0, 1, &state)) | 840 | if (atu_usb_request(sc, DFU_GETSTATE, 0, 0, 1, &state)) | |
841 | return -1; | 841 | return -1; | |
842 | return state; | 842 | return state; | |
843 | } | 843 | } | |
844 | 844 | |||
845 | /* | 845 | /* | |
846 | * Get MAC opmode | 846 | * Get MAC opmode | |
847 | */ | 847 | */ | |
848 | static uint8_t | 848 | static uint8_t | |
849 | atu_get_opmode(struct atu_softc *sc, uint8_t *mode) | 849 | atu_get_opmode(struct atu_softc *sc, uint8_t *mode) | |
850 | { | 850 | { | |
851 | 851 | |||
852 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x33, 0x0001, | 852 | return atu_usb_request(sc, UT_READ_VENDOR_INTERFACE, 0x33, 0x0001, | |
853 | 0x0000, 1, mode); | 853 | 0x0000, 1, mode); | |
854 | } | 854 | } | |
855 | 855 | |||
856 | /* | 856 | /* | |
857 | * Upload the internal firmware into the device | 857 | * Upload the internal firmware into the device | |
858 | */ | 858 | */ | |
859 | static void | 859 | static void | |
860 | atu_internal_firmware(device_t arg) | 860 | atu_internal_firmware(device_t arg) | |
861 | { | 861 | { | |
862 | struct atu_softc *sc = device_private(arg); | 862 | struct atu_softc *sc = device_private(arg); | |
863 | u_char state, *ptr = NULL, *firm = NULL, status[6]; | 863 | u_char state, *ptr = NULL, *firm = NULL, status[6]; | |
864 | int block_size, block = 0, err, i; | 864 | int block_size, block = 0, err, i; | |
865 | size_t bytes_left = 0; | 865 | size_t bytes_left = 0; | |
866 | 866 | |||
867 | /* | 867 | /* | |
868 | * Uploading firmware is done with the DFU (Device Firmware Upgrade) | 868 | * Uploading firmware is done with the DFU (Device Firmware Upgrade) | |
869 | * interface. See "Universal Serial Bus - Device Class Specification | 869 | * interface. See "Universal Serial Bus - Device Class Specification | |
870 | * for Device Firmware Upgrade" pdf for details of the protocol. | 870 | * for Device Firmware Upgrade" pdf for details of the protocol. | |
871 | * Maybe this could be moved to a separate 'firmware driver' once more | 871 | * Maybe this could be moved to a separate 'firmware driver' once more | |
872 | * device drivers need it... For now we'll just do it here. | 872 | * device drivers need it... For now we'll just do it here. | |
873 | * | 873 | * | |
874 | * Just for your information, the Atmel's DFU descriptor looks like | 874 | * Just for your information, the Atmel's DFU descriptor looks like | |
875 | * this: | 875 | * this: | |
876 | * | 876 | * | |
877 | * 07 size | 877 | * 07 size | |
878 | * 21 type | 878 | * 21 type | |
879 | * 01 capabilities : only firmware download, need reset | 879 | * 01 capabilities : only firmware download, need reset | |
880 | * after download | 880 | * after download | |
881 | * 13 05 detach timeout : max 1299ms between DFU_DETACH and | 881 | * 13 05 detach timeout : max 1299ms between DFU_DETACH and | |
882 | * reset | 882 | * reset | |
883 | * 00 04 max bytes of firmware per transaction : 1024 | 883 | * 00 04 max bytes of firmware per transaction : 1024 | |
884 | */ | 884 | */ | |
885 | 885 | |||
886 | /* Choose the right firmware for the device */ | 886 | /* Choose the right firmware for the device */ | |
887 | for (i = 0; i < __arraycount(atu_radfirm); i++) | 887 | for (i = 0; i < __arraycount(atu_radfirm); i++) | |
888 | if (sc->atu_radio == atu_radfirm[i].atur_type) { | 888 | if (sc->atu_radio == atu_radfirm[i].atur_type) { | |
889 | firm = atu_radfirm[i].atur_internal; | 889 | firm = atu_radfirm[i].atur_internal; | |
890 | bytes_left = atu_radfirm[i].atur_internal_sz; | 890 | bytes_left = atu_radfirm[i].atur_internal_sz; | |
891 | } | 891 | } | |
892 | 892 | |||
893 | if (firm == NULL) { | 893 | if (firm == NULL) { | |
894 | aprint_error_dev(arg, "no firmware found\n"); | 894 | aprint_error_dev(arg, "no firmware found\n"); | |
895 | return; | 895 | return; | |
896 | } | 896 | } | |
897 | 897 | |||
898 | ptr = firm; | 898 | ptr = firm; | |
899 | state = atu_get_dfu_state(sc); | 899 | state = atu_get_dfu_state(sc); | |
900 | 900 | |||
901 | while (block >= 0 && state > 0) { | 901 | while (block >= 0 && state > 0) { | |
902 | switch (state) { | 902 | switch (state) { | |
903 | case DFUState_DnLoadSync: | 903 | case DFUState_DnLoadSync: | |
904 | /* get DFU status */ | 904 | /* get DFU status */ | |
905 | err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0 , 6, | 905 | err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0 , 6, | |
906 | status); | 906 | status); | |
907 | if (err) { | 907 | if (err) { | |
908 | DPRINTF(("%s: dfu_getstatus failed!\n", | 908 | DPRINTF(("%s: dfu_getstatus failed!\n", | |
909 | device_xname(sc->atu_dev))); | 909 | device_xname(sc->atu_dev))); | |
910 | return; | 910 | return; | |
911 | } | 911 | } | |
912 | /* success means state => DnLoadIdle */ | 912 | /* success means state => DnLoadIdle */ | |
913 | state = DFUState_DnLoadIdle; | 913 | state = DFUState_DnLoadIdle; | |
914 | continue; | 914 | continue; | |
915 | break; | 915 | break; | |
916 | 916 | |||
917 | case DFUState_DFUIdle: | 917 | case DFUState_DFUIdle: | |
918 | case DFUState_DnLoadIdle: | 918 | case DFUState_DnLoadIdle: | |
919 | if (bytes_left>=DFU_MaxBlockSize) | 919 | if (bytes_left>=DFU_MaxBlockSize) | |
920 | block_size = DFU_MaxBlockSize; | 920 | block_size = DFU_MaxBlockSize; | |
921 | else | 921 | else | |
922 | block_size = bytes_left; | 922 | block_size = bytes_left; | |
923 | DPRINTFN(15, ("%s: firmware block %d\n", | 923 | DPRINTFN(15, ("%s: firmware block %d\n", | |
924 | device_xname(sc->atu_dev), block)); | 924 | device_xname(sc->atu_dev), block)); | |
925 | 925 | |||
926 | err = atu_usb_request(sc, DFU_DNLOAD, block++, 0, | 926 | err = atu_usb_request(sc, DFU_DNLOAD, block++, 0, | |
927 | block_size, ptr); | 927 | block_size, ptr); | |
928 | if (err) { | 928 | if (err) { | |
929 | DPRINTF(("%s: dfu_dnload failed\n", | 929 | DPRINTF(("%s: dfu_dnload failed\n", | |
930 | device_xname(sc->atu_dev))); | 930 | device_xname(sc->atu_dev))); | |
931 | return; | 931 | return; | |
932 | } | 932 | } | |
933 | 933 | |||
934 | ptr += block_size; | 934 | ptr += block_size; | |
935 | bytes_left -= block_size; | 935 | bytes_left -= block_size; | |
936 | if (block_size == 0) | 936 | if (block_size == 0) | |
937 | block = -1; | 937 | block = -1; | |
938 | break; | 938 | break; | |
939 | 939 | |||
940 | default: | 940 | default: | |
941 | usbd_delay_ms(sc->atu_udev, 100); | 941 | usbd_delay_ms(sc->atu_udev, 100); | |
942 | DPRINTFN(20, ("%s: sleeping for a while\n", | 942 | DPRINTFN(20, ("%s: sleeping for a while\n", | |
943 | device_xname(sc->atu_dev))); | 943 | device_xname(sc->atu_dev))); | |
944 | break; | 944 | break; | |
945 | } | 945 | } | |
946 | 946 | |||
947 | state = atu_get_dfu_state(sc); | 947 | state = atu_get_dfu_state(sc); | |
948 | } | 948 | } | |
949 | 949 | |||
950 | if (state != DFUState_ManifestSync) { | 950 | if (state != DFUState_ManifestSync) { | |
951 | DPRINTF(("%s: state != manifestsync... eek!\n", | 951 | DPRINTF(("%s: state != manifestsync... eek!\n", | |
952 | device_xname(sc->atu_dev))); | 952 | device_xname(sc->atu_dev))); | |
953 | } | 953 | } | |
954 | 954 | |||
955 | err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0, 6, status); | 955 | err = atu_usb_request(sc, DFU_GETSTATUS, 0, 0, 6, status); | |
956 | if (err) { | 956 | if (err) { | |
957 | DPRINTF(("%s: dfu_getstatus failed!\n", | 957 | DPRINTF(("%s: dfu_getstatus failed!\n", | |
958 | device_xname(sc->atu_dev))); | 958 | device_xname(sc->atu_dev))); | |
959 | return; | 959 | return; | |
960 | } | 960 | } | |
961 | 961 | |||
962 | DPRINTFN(15, ("%s: sending remap\n", device_xname(sc->atu_dev))); | 962 | DPRINTFN(15, ("%s: sending remap\n", device_xname(sc->atu_dev))); | |
963 | err = atu_usb_request(sc, DFU_REMAP, 0, 0, 0, NULL); | 963 | err = atu_usb_request(sc, DFU_REMAP, 0, 0, 0, NULL); | |
964 | if ((err) && !(sc->atu_quirk & ATU_QUIRK_NO_REMAP)) { | 964 | if ((err) && !(sc->atu_quirk & ATU_QUIRK_NO_REMAP)) { | |
965 | DPRINTF(("%s: remap failed!\n", device_xname(sc->atu_dev))); | 965 | DPRINTF(("%s: remap failed!\n", device_xname(sc->atu_dev))); | |
966 | return; | 966 | return; | |
967 | } | 967 | } | |
968 | 968 | |||
969 | /* after a lot of trying and measuring I found out the device needs | 969 | /* after a lot of trying and measuring I found out the device needs | |
970 | * about 56 miliseconds after sending the remap command before | 970 | * about 56 miliseconds after sending the remap command before | |
971 | * it's ready to communicate again. So we'll wait just a little bit | 971 | * it's ready to communicate again. So we'll wait just a little bit | |
972 | * longer than that to be sure... | 972 | * longer than that to be sure... | |
973 | */ | 973 | */ | |
974 | usbd_delay_ms(sc->atu_udev, 56+100); | 974 | usbd_delay_ms(sc->atu_udev, 56+100); | |
975 | 975 | |||
976 | aprint_error_dev(arg, "reattaching after firmware upload\n"); | 976 | aprint_error_dev(arg, "reattaching after firmware upload\n"); | |
977 | usb_needs_reattach(sc->atu_udev); | 977 | usb_needs_reattach(sc->atu_udev); | |
978 | } | 978 | } | |
979 | 979 | |||
980 | static void | 980 | static void | |
981 | atu_external_firmware(device_t arg) | 981 | atu_external_firmware(device_t arg) | |
982 | { | 982 | { | |
983 | struct atu_softc *sc = device_private(arg); | 983 | struct atu_softc *sc = device_private(arg); | |
984 | u_char *ptr = NULL, *firm = NULL; | 984 | u_char *ptr = NULL, *firm = NULL; | |
985 | int block_size, block = 0, err, i; | 985 | int block_size, block = 0, err, i; | |
986 | size_t bytes_left = 0; | 986 | size_t bytes_left = 0; | |
987 | 987 | |||
988 | for (i = 0; i < __arraycount(atu_radfirm); i++) | 988 | for (i = 0; i < __arraycount(atu_radfirm); i++) | |
989 | if (sc->atu_radio == atu_radfirm[i].atur_type) { | 989 | if (sc->atu_radio == atu_radfirm[i].atur_type) { | |
990 | firm = atu_radfirm[i].atur_external; | 990 | firm = atu_radfirm[i].atur_external; | |
991 | bytes_left = atu_radfirm[i].atur_external_sz; | 991 | bytes_left = atu_radfirm[i].atur_external_sz; | |
992 | } | 992 | } | |
993 | 993 | |||
994 | if (firm == NULL) { | 994 | if (firm == NULL) { | |
995 | aprint_error_dev(arg, "no firmware found\n"); | 995 | aprint_error_dev(arg, "no firmware found\n"); | |
996 | return; | 996 | return; | |
997 | } | 997 | } | |
998 | ptr = firm; | 998 | ptr = firm; | |
999 | 999 | |||
1000 | while (bytes_left) { | 1000 | while (bytes_left) { | |
1001 | if (bytes_left > 1024) | 1001 | if (bytes_left > 1024) | |
1002 | block_size = 1024; | 1002 | block_size = 1024; | |
1003 | else | 1003 | else | |
1004 | block_size = bytes_left; | 1004 | block_size = bytes_left; | |
1005 | 1005 | |||
1006 | DPRINTFN(15, ("%s: block:%d size:%d\n", | 1006 | DPRINTFN(15, ("%s: block:%d size:%d\n", | |
1007 | device_xname(sc->atu_dev), block, block_size)); | 1007 | device_xname(sc->atu_dev), block, block_size)); | |
1008 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, | 1008 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, | |
1009 | 0x0802, block, block_size, ptr); | 1009 | 0x0802, block, block_size, ptr); | |
1010 | if (err) { | 1010 | if (err) { | |
1011 | DPRINTF(("%s: could not load external firmware " | 1011 | DPRINTF(("%s: could not load external firmware " | |
1012 | "block\n", device_xname(sc->atu_dev))); | 1012 | "block\n", device_xname(sc->atu_dev))); | |
1013 | return; | 1013 | return; | |
1014 | } | 1014 | } | |
1015 | 1015 | |||
1016 | ptr += block_size; | 1016 | ptr += block_size; | |
1017 | block++; | 1017 | block++; | |
1018 | bytes_left -= block_size; | 1018 | bytes_left -= block_size; | |
1019 | } | 1019 | } | |
1020 | 1020 | |||
1021 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0802, | 1021 | err = atu_usb_request(sc, UT_WRITE_VENDOR_DEVICE, 0x0e, 0x0802, | |
1022 | block, 0, NULL); | 1022 | block, 0, NULL); | |
1023 | if (err) { | 1023 | if (err) { | |
1024 | DPRINTF(("%s: could not load last zero-length firmware " | 1024 | DPRINTF(("%s: could not load last zero-length firmware " | |
1025 | "block\n", device_xname(sc->atu_dev))); | 1025 | "block\n", device_xname(sc->atu_dev))); | |
1026 | return; | 1026 | return; | |
1027 | } | 1027 | } | |
1028 | 1028 | |||
1029 | /* | 1029 | /* | |
1030 | * The SMC2662w V.4 seems to require some time to do its thing with | 1030 | * The SMC2662w V.4 seems to require some time to do its thing with | |
1031 | * the external firmware... 20 ms isn't enough, but 21 ms works 100 | 1031 | * the external firmware... 20 ms isn't enough, but 21 ms works 100 | |
1032 | * times out of 100 tries. We'll wait a bit longer just to be sure | 1032 | * times out of 100 tries. We'll wait a bit longer just to be sure | |
1033 | */ | 1033 | */ | |
1034 | if (sc->atu_quirk & ATU_QUIRK_FW_DELAY) | 1034 | if (sc->atu_quirk & ATU_QUIRK_FW_DELAY) | |
1035 | usbd_delay_ms(sc->atu_udev, 21 + 100); | 1035 | usbd_delay_ms(sc->atu_udev, 21 + 100); | |
1036 | 1036 | |||
1037 | DPRINTFN(10, ("%s: external firmware upload done\n", | 1037 | DPRINTFN(10, ("%s: external firmware upload done\n", | |
1038 | device_xname(sc->atu_dev))); | 1038 | device_xname(sc->atu_dev))); | |
1039 | /* complete configuration after the firmwares have been uploaded */ | 1039 | /* complete configuration after the firmwares have been uploaded */ | |
1040 | atu_complete_attach(sc); | 1040 | atu_complete_attach(sc); | |
1041 | } | 1041 | } | |
1042 | 1042 | |||
1043 | static int | 1043 | static int | |
1044 | atu_get_card_config(struct atu_softc *sc) | 1044 | atu_get_card_config(struct atu_softc *sc) | |
1045 | { | 1045 | { | |
1046 | struct ieee80211com *ic = &sc->sc_ic; | 1046 | struct ieee80211com *ic = &sc->sc_ic; | |
1047 | struct atu_rfmd_conf rfmd_conf; | 1047 | struct atu_rfmd_conf rfmd_conf; | |
1048 | struct atu_intersil_conf intersil_conf; | 1048 | struct atu_intersil_conf intersil_conf; | |
1049 | int err; | 1049 | int err; | |
1050 | 1050 | |||
@@ -1142,1139 +1142,1133 @@ atu_media_status(struct ifnet *ifp, stru | @@ -1142,1139 +1142,1133 @@ atu_media_status(struct ifnet *ifp, stru | |||
1142 | 1142 | |||
1143 | static void | 1143 | static void | |
1144 | atu_task(void *arg) | 1144 | atu_task(void *arg) | |
1145 | { | 1145 | { | |
1146 | struct atu_softc *sc = (struct atu_softc *)arg; | 1146 | struct atu_softc *sc = (struct atu_softc *)arg; | |
1147 | struct ieee80211com *ic = &sc->sc_ic; | 1147 | struct ieee80211com *ic = &sc->sc_ic; | |
1148 | usbd_status err; | 1148 | usbd_status err; | |
1149 | int s; | 1149 | int s; | |
1150 | 1150 | |||
1151 | DPRINTFN(10, ("%s: atu_task\n", device_xname(sc->atu_dev))); | 1151 | DPRINTFN(10, ("%s: atu_task\n", device_xname(sc->atu_dev))); | |
1152 | 1152 | |||
1153 | if (sc->sc_state != ATU_S_OK) | 1153 | if (sc->sc_state != ATU_S_OK) | |
1154 | return; | 1154 | return; | |
1155 | 1155 | |||
1156 | switch (sc->sc_cmd) { | 1156 | switch (sc->sc_cmd) { | |
1157 | case ATU_C_SCAN: | 1157 | case ATU_C_SCAN: | |
1158 | 1158 | |||
1159 | err = atu_start_scan(sc); | 1159 | err = atu_start_scan(sc); | |
1160 | if (err) { | 1160 | if (err) { | |
1161 | DPRINTFN(1, ("%s: atu_task: couldn't start scan!\n", | 1161 | DPRINTFN(1, ("%s: atu_task: couldn't start scan!\n", | |
1162 | device_xname(sc->atu_dev))); | 1162 | device_xname(sc->atu_dev))); | |
1163 | return; | 1163 | return; | |
1164 | } | 1164 | } | |
1165 | 1165 | |||
1166 | err = atu_wait_completion(sc, CMD_START_SCAN, NULL); | 1166 | err = atu_wait_completion(sc, CMD_START_SCAN, NULL); | |
1167 | if (err) { | 1167 | if (err) { | |
1168 | DPRINTF(("%s: atu_task: error waiting for scan\n", | 1168 | DPRINTF(("%s: atu_task: error waiting for scan\n", | |
1169 | device_xname(sc->atu_dev))); | 1169 | device_xname(sc->atu_dev))); | |
1170 | return; | 1170 | return; | |
1171 | } | 1171 | } | |
1172 | 1172 | |||
1173 | DPRINTF(("%s: ==========================> END OF SCAN!\n", | 1173 | DPRINTF(("%s: ==========================> END OF SCAN!\n", | |
1174 | device_xname(sc->atu_dev))); | 1174 | device_xname(sc->atu_dev))); | |
1175 | 1175 | |||
1176 | s = splnet(); | 1176 | s = splnet(); | |
1177 | ieee80211_next_scan(ic); | 1177 | ieee80211_next_scan(ic); | |
1178 | splx(s); | 1178 | splx(s); | |
1179 | 1179 | |||
1180 | DPRINTF(("%s: ----------------------======> END OF SCAN2!\n", | 1180 | DPRINTF(("%s: ----------------------======> END OF SCAN2!\n", | |
1181 | device_xname(sc->atu_dev))); | 1181 | device_xname(sc->atu_dev))); | |
1182 | break; | 1182 | break; | |
1183 | 1183 | |||
1184 | case ATU_C_JOIN: | 1184 | case ATU_C_JOIN: | |
1185 | atu_join(sc, ic->ic_bss); | 1185 | atu_join(sc, ic->ic_bss); | |
1186 | } | 1186 | } | |
1187 | } | 1187 | } | |
1188 | 1188 | |||
1189 | static int | 1189 | static int | |
1190 | atu_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) | 1190 | atu_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) | |
1191 | { | 1191 | { | |
1192 | struct ifnet *ifp = ic->ic_ifp; | 1192 | struct ifnet *ifp = ic->ic_ifp; | |
1193 | struct atu_softc *sc = ifp->if_softc; | 1193 | struct atu_softc *sc = ifp->if_softc; | |
1194 | enum ieee80211_state ostate = ic->ic_state; | 1194 | enum ieee80211_state ostate = ic->ic_state; | |
1195 | 1195 | |||
1196 | DPRINTFN(10, ("%s: atu_newstate: %s -> %s\n", device_xname(sc->atu_dev), | 1196 | DPRINTFN(10, ("%s: atu_newstate: %s -> %s\n", device_xname(sc->atu_dev), | |
1197 | ieee80211_state_name[ostate], ieee80211_state_name[nstate])); | 1197 | ieee80211_state_name[ostate], ieee80211_state_name[nstate])); | |
1198 | 1198 | |||
1199 | switch (nstate) { | 1199 | switch (nstate) { | |
1200 | case IEEE80211_S_SCAN: | 1200 | case IEEE80211_S_SCAN: | |
1201 | memcpy(ic->ic_chan_scan, ic->ic_chan_active, | 1201 | memcpy(ic->ic_chan_scan, ic->ic_chan_active, | |
1202 | sizeof(ic->ic_chan_active)); | 1202 | sizeof(ic->ic_chan_active)); | |
1203 | ieee80211_node_table_reset(&ic->ic_scan); | 1203 | ieee80211_node_table_reset(&ic->ic_scan); | |
1204 | 1204 | |||
1205 | /* tell the event thread that we want a scan */ | 1205 | /* tell the event thread that we want a scan */ | |
1206 | sc->sc_cmd = ATU_C_SCAN; | 1206 | sc->sc_cmd = ATU_C_SCAN; | |
1207 | usb_add_task(sc->atu_udev, &sc->sc_task, USB_TASKQ_DRIVER); | 1207 | usb_add_task(sc->atu_udev, &sc->sc_task, USB_TASKQ_DRIVER); | |
1208 | 1208 | |||
1209 | /* handle this ourselves */ | 1209 | /* handle this ourselves */ | |
1210 | ic->ic_state = nstate; | 1210 | ic->ic_state = nstate; | |
1211 | return 0; | 1211 | return 0; | |
1212 | 1212 | |||
1213 | case IEEE80211_S_AUTH: | 1213 | case IEEE80211_S_AUTH: | |
1214 | case IEEE80211_S_RUN: | 1214 | case IEEE80211_S_RUN: | |
1215 | if (ostate == IEEE80211_S_SCAN) { | 1215 | if (ostate == IEEE80211_S_SCAN) { | |
1216 | sc->sc_cmd = ATU_C_JOIN; | 1216 | sc->sc_cmd = ATU_C_JOIN; | |
1217 | usb_add_task(sc->atu_udev, &sc->sc_task, | 1217 | usb_add_task(sc->atu_udev, &sc->sc_task, | |
1218 | USB_TASKQ_DRIVER); | 1218 | USB_TASKQ_DRIVER); | |
1219 | } | 1219 | } | |
1220 | break; | 1220 | break; | |
1221 | default: | 1221 | default: | |
1222 | /* nothing to do */ | 1222 | /* nothing to do */ | |
1223 | break; | 1223 | break; | |
1224 | } | 1224 | } | |
1225 | 1225 | |||
1226 | return (*sc->sc_newstate)(ic, nstate, arg); | 1226 | return (*sc->sc_newstate)(ic, nstate, arg); | |
1227 | } | 1227 | } | |
1228 | 1228 | |||
1229 | /* | 1229 | /* | |
1230 | * Attach the interface. Allocate softc structures, do | 1230 | * Attach the interface. Allocate softc structures, do | |
1231 | * setup and ethernet/BPF attach. | 1231 | * setup and ethernet/BPF attach. | |
1232 | */ | 1232 | */ | |
1233 | static void | 1233 | static void | |
1234 | atu_attach(device_t parent, device_t self, void *aux) | 1234 | atu_attach(device_t parent, device_t self, void *aux) | |
1235 | { | 1235 | { | |
1236 | struct atu_softc *sc = device_private(self); | 1236 | struct atu_softc *sc = device_private(self); | |
1237 | struct usb_attach_arg *uaa = aux; | 1237 | struct usb_attach_arg *uaa = aux; | |
1238 | char *devinfop; | 1238 | char *devinfop; | |
1239 | usbd_status err; | 1239 | usbd_status err; | |
1240 | struct usbd_device *dev = uaa->uaa_device; | 1240 | struct usbd_device *dev = uaa->uaa_device; | |
1241 | uint8_t mode, channel; | 1241 | uint8_t mode, channel; | |
1242 | int i; | 1242 | int i; | |
1243 | 1243 | |||
1244 | sc->atu_dev = self; | 1244 | sc->atu_dev = self; | |
1245 | sc->sc_state = ATU_S_UNCONFIG; | 1245 | sc->sc_state = ATU_S_UNCONFIG; | |
1246 | 1246 | |||
1247 | aprint_naive("\n"); | 1247 | aprint_naive("\n"); | |
1248 | aprint_normal("\n"); | 1248 | aprint_normal("\n"); | |
1249 | 1249 | |||
1250 | devinfop = usbd_devinfo_alloc(dev, 0); | 1250 | devinfop = usbd_devinfo_alloc(dev, 0); | |
1251 | aprint_normal_dev(self, "%s\n", devinfop); | 1251 | aprint_normal_dev(self, "%s\n", devinfop); | |
1252 | usbd_devinfo_free(devinfop); | 1252 | usbd_devinfo_free(devinfop); | |
1253 | 1253 | |||
1254 | err = usbd_set_config_no(dev, ATU_CONFIG_NO, 1); | 1254 | err = usbd_set_config_no(dev, ATU_CONFIG_NO, 1); | |
1255 | if (err) { | 1255 | if (err) { | |
1256 | aprint_error_dev(self, "failed to set configuration" | 1256 | aprint_error_dev(self, "failed to set configuration" | |
1257 | ", err=%s\n", usbd_errstr(err)); | 1257 | ", err=%s\n", usbd_errstr(err)); | |
1258 | return; | 1258 | return; | |
1259 | } | 1259 | } | |
1260 | 1260 | |||
1261 | err = usbd_device2interface_handle(dev, ATU_IFACE_IDX, &sc->atu_iface); | 1261 | err = usbd_device2interface_handle(dev, ATU_IFACE_IDX, &sc->atu_iface); | |
1262 | if (err) { | 1262 | if (err) { | |
1263 | aprint_error_dev(self, "getting interface handle failed\n"); | 1263 | aprint_error_dev(self, "getting interface handle failed\n"); | |
1264 | return; | 1264 | return; | |
1265 | } | 1265 | } | |
1266 | 1266 | |||
1267 | sc->atu_unit = device_unit(self); | 1267 | sc->atu_unit = device_unit(self); | |
1268 | sc->atu_udev = dev; | 1268 | sc->atu_udev = dev; | |
1269 | 1269 | |||
1270 | /* | 1270 | /* | |
1271 | * look up the radio_type for the device | 1271 | * look up the radio_type for the device | |
1272 | * basically does the same as atu_match | 1272 | * basically does the same as atu_match | |
1273 | */ | 1273 | */ | |
1274 | for (i = 0; i < __arraycount(atu_devs); i++) { | 1274 | for (i = 0; i < __arraycount(atu_devs); i++) { | |
1275 | const struct atu_type *t = &atu_devs[i]; | 1275 | const struct atu_type *t = &atu_devs[i]; | |
1276 | 1276 | |||
1277 | if (uaa->uaa_vendor == t->atu_vid && | 1277 | if (uaa->uaa_vendor == t->atu_vid && | |
1278 | uaa->uaa_product == t->atu_pid) { | 1278 | uaa->uaa_product == t->atu_pid) { | |
1279 | sc->atu_radio = t->atu_radio; | 1279 | sc->atu_radio = t->atu_radio; | |
1280 | sc->atu_quirk = t->atu_quirk; | 1280 | sc->atu_quirk = t->atu_quirk; | |
1281 | } | 1281 | } | |
1282 | } | 1282 | } | |
1283 | 1283 | |||
1284 | /* | 1284 | /* | |
1285 | * Check in the interface descriptor if we're in DFU mode | 1285 | * Check in the interface descriptor if we're in DFU mode | |
1286 | * If we're in DFU mode, we upload the external firmware | 1286 | * If we're in DFU mode, we upload the external firmware | |
1287 | * If we're not, the PC must have rebooted without power-cycling | 1287 | * If we're not, the PC must have rebooted without power-cycling | |
1288 | * the device.. I've tried this out, a reboot only requeres the | 1288 | * the device.. I've tried this out, a reboot only requeres the | |
1289 | * external firmware to be reloaded :) | 1289 | * external firmware to be reloaded :) | |
1290 | * | 1290 | * | |
1291 | * Hmm. The at76c505a doesn't report a DFU descriptor when it's | 1291 | * Hmm. The at76c505a doesn't report a DFU descriptor when it's | |
1292 | * in DFU mode... Let's just try to get the opmode | 1292 | * in DFU mode... Let's just try to get the opmode | |
1293 | */ | 1293 | */ | |
1294 | err = atu_get_opmode(sc, &mode); | 1294 | err = atu_get_opmode(sc, &mode); | |
1295 | DPRINTFN(20, ("%s: opmode: %d\n", device_xname(sc->atu_dev), mode)); | 1295 | DPRINTFN(20, ("%s: opmode: %d\n", device_xname(sc->atu_dev), mode)); | |
1296 | if (err || (mode != MODE_NETCARD && mode != MODE_NOFLASHNETCARD)) { | 1296 | if (err || (mode != MODE_NETCARD && mode != MODE_NOFLASHNETCARD)) { | |
1297 | DPRINTF(("%s: starting internal firmware download\n", | 1297 | DPRINTF(("%s: starting internal firmware download\n", | |
1298 | device_xname(sc->atu_dev))); | 1298 | device_xname(sc->atu_dev))); | |
1299 | 1299 | |||
1300 | atu_internal_firmware(sc->atu_dev); | 1300 | atu_internal_firmware(sc->atu_dev); | |
1301 | /* | 1301 | /* | |
1302 | * atu_internal_firmware will cause a reset of the device | 1302 | * atu_internal_firmware will cause a reset of the device | |
1303 | * so we don't want to do any more configuration after this | 1303 | * so we don't want to do any more configuration after this | |
1304 | * point. | 1304 | * point. | |
1305 | */ | 1305 | */ | |
1306 | return; | 1306 | return; | |
1307 | } | 1307 | } | |
1308 | 1308 | |||
1309 | if (mode != MODE_NETCARD) { | 1309 | if (mode != MODE_NETCARD) { | |
1310 | DPRINTFN(15, ("%s: device needs external firmware\n", | 1310 | DPRINTFN(15, ("%s: device needs external firmware\n", | |
1311 | device_xname(sc->atu_dev))); | 1311 | device_xname(sc->atu_dev))); | |
1312 | 1312 | |||
1313 | if (mode != MODE_NOFLASHNETCARD) { | 1313 | if (mode != MODE_NOFLASHNETCARD) { | |
1314 | DPRINTF(("%s: unexpected opmode=%d\n", | 1314 | DPRINTF(("%s: unexpected opmode=%d\n", | |
1315 | device_xname(sc->atu_dev), mode)); | 1315 | device_xname(sc->atu_dev), mode)); | |
1316 | } | 1316 | } | |
1317 | 1317 | |||
1318 | /* | 1318 | /* | |
1319 | * There is no difference in opmode before and after external | 1319 | * There is no difference in opmode before and after external | |
1320 | * firmware upload with the SMC2662 V.4 . So instead we'll try | 1320 | * firmware upload with the SMC2662 V.4 . So instead we'll try | |
1321 | * to read the channel number. If we succeed, external | 1321 | * to read the channel number. If we succeed, external | |
1322 | * firmwaremust have been already uploaded... | 1322 | * firmwaremust have been already uploaded... | |
1323 | */ | 1323 | */ | |
1324 | if (sc->atu_radio != RadioIntersil) { | 1324 | if (sc->atu_radio != RadioIntersil) { | |
1325 | err = atu_get_mib(sc, MIB_PHY__CHANNEL, &channel); | 1325 | err = atu_get_mib(sc, MIB_PHY__CHANNEL, &channel); | |
1326 | if (!err) { | 1326 | if (!err) { | |
1327 | DPRINTF(("%s: external firmware has already" | 1327 | DPRINTF(("%s: external firmware has already" | |
1328 | " been downloaded\n", | 1328 | " been downloaded\n", | |
1329 | device_xname(sc->atu_dev))); | 1329 | device_xname(sc->atu_dev))); | |
1330 | atu_complete_attach(sc); | 1330 | atu_complete_attach(sc); | |
1331 | return; | 1331 | return; | |
1332 | } | 1332 | } | |
1333 | } | 1333 | } | |
1334 | 1334 | |||
1335 | atu_external_firmware(sc->atu_dev); | 1335 | atu_external_firmware(sc->atu_dev); | |
1336 | 1336 | |||
1337 | /* | 1337 | /* | |
1338 | * atu_external_firmware will call atu_complete_attach after | 1338 | * atu_external_firmware will call atu_complete_attach after | |
1339 | * it's finished so we can just return. | 1339 | * it's finished so we can just return. | |
1340 | */ | 1340 | */ | |
1341 | } else { | 1341 | } else { | |
1342 | /* all the firmwares are in place, so complete the attach */ | 1342 | /* all the firmwares are in place, so complete the attach */ | |
1343 | atu_complete_attach(sc); | 1343 | atu_complete_attach(sc); | |
1344 | } | 1344 | } | |
1345 | 1345 | |||
1346 | return; | 1346 | return; | |
1347 | } | 1347 | } | |
1348 | 1348 | |||
1349 | static void | 1349 | static void | |
1350 | atu_complete_attach(struct atu_softc *sc) | 1350 | atu_complete_attach(struct atu_softc *sc) | |
1351 | { | 1351 | { | |
1352 | struct ieee80211com *ic = &sc->sc_ic; | 1352 | struct ieee80211com *ic = &sc->sc_ic; | |
1353 | struct ifnet *ifp = &sc->sc_if; | 1353 | struct ifnet *ifp = &sc->sc_if; | |
1354 | usb_interface_descriptor_t *id; | 1354 | usb_interface_descriptor_t *id; | |
1355 | usb_endpoint_descriptor_t *ed; | 1355 | usb_endpoint_descriptor_t *ed; | |
1356 | usbd_status err; | 1356 | usbd_status err; | |
1357 | int i; | 1357 | int i; | |
1358 | #ifdef ATU_DEBUG | 1358 | #ifdef ATU_DEBUG | |
1359 | struct atu_fw fw; | 1359 | struct atu_fw fw; | |
1360 | #endif | 1360 | #endif | |
1361 | 1361 | |||
1362 | id = usbd_get_interface_descriptor(sc->atu_iface); | 1362 | id = usbd_get_interface_descriptor(sc->atu_iface); | |
1363 | 1363 | |||
1364 | /* Find endpoints. */ | 1364 | /* Find endpoints. */ | |
1365 | for (i = 0; i < id->bNumEndpoints; i++) { | 1365 | for (i = 0; i < id->bNumEndpoints; i++) { | |
1366 | ed = usbd_interface2endpoint_descriptor(sc->atu_iface, i); | 1366 | ed = usbd_interface2endpoint_descriptor(sc->atu_iface, i); | |
1367 | if (!ed) { | 1367 | if (!ed) { | |
1368 | DPRINTF(("%s: num_endp:%d\n", device_xname(sc->atu_dev), | 1368 | DPRINTF(("%s: num_endp:%d\n", device_xname(sc->atu_dev), | |
1369 | sc->atu_iface->ui_idesc->bNumEndpoints)); | 1369 | sc->atu_iface->ui_idesc->bNumEndpoints)); | |
1370 | DPRINTF(("%s: couldn't get ep %d\n", | 1370 | DPRINTF(("%s: couldn't get ep %d\n", | |
1371 | device_xname(sc->atu_dev), i)); | 1371 | device_xname(sc->atu_dev), i)); | |
1372 | return; | 1372 | return; | |
1373 | } | 1373 | } | |
1374 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | 1374 | if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN && | |
1375 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 1375 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
1376 | sc->atu_ed[ATU_ENDPT_RX] = ed->bEndpointAddress; | 1376 | sc->atu_ed[ATU_ENDPT_RX] = ed->bEndpointAddress; | |
1377 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | 1377 | } else if (UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_OUT && | |
1378 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | 1378 | UE_GET_XFERTYPE(ed->bmAttributes) == UE_BULK) { | |
1379 | sc->atu_ed[ATU_ENDPT_TX] = ed->bEndpointAddress; | 1379 | sc->atu_ed[ATU_ENDPT_TX] = ed->bEndpointAddress; | |
1380 | } | 1380 | } | |
1381 | } | 1381 | } | |
1382 | 1382 | |||
1383 | /* read device config & get MAC address */ | 1383 | /* read device config & get MAC address */ | |
1384 | err = atu_get_card_config(sc); | 1384 | err = atu_get_card_config(sc); | |
1385 | if (err) { | 1385 | if (err) { | |
1386 | aprint_error("\n%s: could not get card cfg!\n", | 1386 | aprint_error("\n%s: could not get card cfg!\n", | |
1387 | device_xname(sc->atu_dev)); | 1387 | device_xname(sc->atu_dev)); | |
1388 | return; | 1388 | return; | |
1389 | } | 1389 | } | |
1390 | 1390 | |||
1391 | #ifdef ATU_DEBUG | 1391 | #ifdef ATU_DEBUG | |
1392 | /* DEBUG : try to get firmware version */ | 1392 | /* DEBUG : try to get firmware version */ | |
1393 | err = atu_get_mib(sc, MIB_FW_VERSION, sizeof(fw), 0, (uint8_t *)&fw); | 1393 | err = atu_get_mib(sc, MIB_FW_VERSION, sizeof(fw), 0, (uint8_t *)&fw); | |
1394 | if (!err) { | 1394 | if (!err) { | |
1395 | DPRINTFN(15, ("%s: firmware: maj:%d min:%d patch:%d " | 1395 | DPRINTFN(15, ("%s: firmware: maj:%d min:%d patch:%d " | |
1396 | "build:%d\n", device_xname(sc->atu_dev), fw.major, | 1396 | "build:%d\n", device_xname(sc->atu_dev), fw.major, | |
1397 | fw.minor, fw.patch, fw.build)); | 1397 | fw.minor, fw.patch, fw.build)); | |
1398 | } else { | 1398 | } else { | |
1399 | DPRINTF(("%s: get firmware version failed\n", | 1399 | DPRINTF(("%s: get firmware version failed\n", | |
1400 | device_xname(sc->atu_dev))); | 1400 | device_xname(sc->atu_dev))); | |
1401 | } | 1401 | } | |
1402 | #endif /* ATU_DEBUG */ | 1402 | #endif /* ATU_DEBUG */ | |
1403 | 1403 | |||
1404 | /* Show the world our MAC address */ | 1404 | /* Show the world our MAC address */ | |
1405 | aprint_normal_dev(sc->atu_dev, "MAC address %s\n", | 1405 | aprint_normal_dev(sc->atu_dev, "MAC address %s\n", | |
1406 | ether_sprintf(ic->ic_myaddr)); | 1406 | ether_sprintf(ic->ic_myaddr)); | |
1407 | 1407 | |||
1408 | sc->atu_cdata.atu_tx_inuse = 0; | 1408 | sc->atu_cdata.atu_tx_inuse = 0; | |
1409 | sc->atu_encrypt = ATU_WEP_OFF; | 1409 | sc->atu_encrypt = ATU_WEP_OFF; | |
1410 | sc->atu_wepkeylen = ATU_WEP_104BITS; | 1410 | sc->atu_wepkeylen = ATU_WEP_104BITS; | |
1411 | sc->atu_wepkey = 0; | 1411 | sc->atu_wepkey = 0; | |
1412 | 1412 | |||
1413 | memset(sc->atu_bssid, 0, ETHER_ADDR_LEN); | 1413 | memset(sc->atu_bssid, 0, ETHER_ADDR_LEN); | |
1414 | sc->atu_channel = ATU_DEFAULT_CHANNEL; | 1414 | sc->atu_channel = ATU_DEFAULT_CHANNEL; | |
1415 | sc->atu_desired_channel = IEEE80211_CHAN_ANY; | 1415 | sc->atu_desired_channel = IEEE80211_CHAN_ANY; | |
1416 | sc->atu_mode = INFRASTRUCTURE_MODE; | 1416 | sc->atu_mode = INFRASTRUCTURE_MODE; | |
1417 | 1417 | |||
1418 | ic->ic_ifp = ifp; | 1418 | ic->ic_ifp = ifp; | |
1419 | ic->ic_phytype = IEEE80211_T_DS; | 1419 | ic->ic_phytype = IEEE80211_T_DS; | |
1420 | ic->ic_opmode = IEEE80211_M_STA; | 1420 | ic->ic_opmode = IEEE80211_M_STA; | |
1421 | ic->ic_state = IEEE80211_S_INIT; | 1421 | ic->ic_state = IEEE80211_S_INIT; | |
1422 | #ifdef FIXME | 1422 | #ifdef FIXME | |
1423 | ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_WEP | IEEE80211_C_SCANALL; | 1423 | ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_WEP | IEEE80211_C_SCANALL; | |
1424 | #else | 1424 | #else | |
1425 | ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_WEP; | 1425 | ic->ic_caps = IEEE80211_C_IBSS | IEEE80211_C_WEP; | |
1426 | #endif | 1426 | #endif | |
1427 | 1427 | |||
1428 | i = 0; | 1428 | i = 0; | |
1429 | ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; | 1429 | ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; | |
1430 | 1430 | |||
1431 | for (i = 1; i <= 14; i++) { | 1431 | for (i = 1; i <= 14; i++) { | |
1432 | ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B | | 1432 | ic->ic_channels[i].ic_flags = IEEE80211_CHAN_B | | |
1433 | IEEE80211_CHAN_PASSIVE; | 1433 | IEEE80211_CHAN_PASSIVE; | |
1434 | ic->ic_channels[i].ic_freq = ieee80211_ieee2mhz(i, | 1434 | ic->ic_channels[i].ic_freq = ieee80211_ieee2mhz(i, | |
1435 | ic->ic_channels[i].ic_flags); | 1435 | ic->ic_channels[i].ic_flags); | |
1436 | } | 1436 | } | |
1437 | 1437 | |||
1438 | ic->ic_ibss_chan = &ic->ic_channels[0]; | 1438 | ic->ic_ibss_chan = &ic->ic_channels[0]; | |
1439 | 1439 | |||
1440 | ifp->if_softc = sc; | 1440 | ifp->if_softc = sc; | |
1441 | memcpy(ifp->if_xname, device_xname(sc->atu_dev), IFNAMSIZ); | 1441 | memcpy(ifp->if_xname, device_xname(sc->atu_dev), IFNAMSIZ); | |
1442 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | 1442 | ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; | |
1443 | ifp->if_init = atu_init; | 1443 | ifp->if_init = atu_init; | |
1444 | ifp->if_stop = atu_stop; | 1444 | ifp->if_stop = atu_stop; | |
1445 | ifp->if_start = atu_start; | 1445 | ifp->if_start = atu_start; | |
1446 | ifp->if_ioctl = atu_ioctl; | 1446 | ifp->if_ioctl = atu_ioctl; | |
1447 | ifp->if_watchdog = atu_watchdog; | 1447 | ifp->if_watchdog = atu_watchdog; | |
1448 | ifp->if_mtu = ATU_DEFAULT_MTU; | 1448 | ifp->if_mtu = ATU_DEFAULT_MTU; | |
1449 | IFQ_SET_READY(&ifp->if_snd); | 1449 | IFQ_SET_READY(&ifp->if_snd); | |
1450 | 1450 | |||
1451 | /* Call MI attach routine. */ | 1451 | /* Call MI attach routine. */ | |
1452 | if_attach(ifp); | 1452 | if_attach(ifp); | |
1453 | ieee80211_ifattach(ic); | 1453 | ieee80211_ifattach(ic); | |
1454 | 1454 | |||
1455 | sc->sc_newstate = ic->ic_newstate; | 1455 | sc->sc_newstate = ic->ic_newstate; | |
1456 | ic->ic_newstate = atu_newstate; | 1456 | ic->ic_newstate = atu_newstate; | |
1457 | 1457 | |||
1458 | /* setup ifmedia interface */ | 1458 | /* setup ifmedia interface */ | |
1459 | ieee80211_media_init(ic, atu_media_change, atu_media_status); | 1459 | ieee80211_media_init(ic, atu_media_change, atu_media_status); | |
1460 | 1460 | |||
1461 | usb_init_task(&sc->sc_task, atu_task, sc, 0); | 1461 | usb_init_task(&sc->sc_task, atu_task, sc, 0); | |
1462 | 1462 | |||
1463 | sc->sc_state = ATU_S_OK; | 1463 | sc->sc_state = ATU_S_OK; | |
1464 | } | 1464 | } | |
1465 | 1465 | |||
1466 | static int | 1466 | static int | |
1467 | atu_detach(device_t self, int flags) | 1467 | atu_detach(device_t self, int flags) | |
1468 | { | 1468 | { | |
1469 | struct atu_softc *sc = device_private(self); | 1469 | struct atu_softc *sc = device_private(self); | |
1470 | struct ifnet *ifp = &sc->sc_if; | 1470 | struct ifnet *ifp = &sc->sc_if; | |
1471 | 1471 | |||
1472 | DPRINTFN(10, ("%s: atu_detach state=%d\n", device_xname(sc->atu_dev), | 1472 | DPRINTFN(10, ("%s: atu_detach state=%d\n", device_xname(sc->atu_dev), | |
1473 | sc->sc_state)); | 1473 | sc->sc_state)); | |
1474 | 1474 | |||
1475 | if (sc->sc_state != ATU_S_UNCONFIG) { | 1475 | if (sc->sc_state != ATU_S_UNCONFIG) { | |
1476 | atu_stop(ifp, 1); | 1476 | atu_stop(ifp, 1); | |
1477 | 1477 | |||
1478 | ieee80211_ifdetach(&sc->sc_ic); | 1478 | ieee80211_ifdetach(&sc->sc_ic); | |
1479 | if_detach(ifp); | 1479 | if_detach(ifp); | |
1480 | } | 1480 | } | |
1481 | 1481 | |||
1482 | return 0; | 1482 | return 0; | |
1483 | } | 1483 | } | |
1484 | 1484 | |||
1485 | static int | 1485 | static int | |
1486 | atu_activate(device_t self, enum devact act) | 1486 | atu_activate(device_t self, enum devact act) | |
1487 | { | 1487 | { | |
1488 | struct atu_softc *sc = device_private(self); | 1488 | struct atu_softc *sc = device_private(self); | |
1489 | 1489 | |||
1490 | switch (act) { | 1490 | switch (act) { | |
1491 | case DVACT_DEACTIVATE: | 1491 | case DVACT_DEACTIVATE: | |
1492 | if (sc->sc_state != ATU_S_UNCONFIG) { | 1492 | if (sc->sc_state != ATU_S_UNCONFIG) { | |
1493 | if_deactivate(&sc->atu_ec.ec_if); | 1493 | if_deactivate(&sc->atu_ec.ec_if); | |
1494 | sc->sc_state = ATU_S_DEAD; | 1494 | sc->sc_state = ATU_S_DEAD; | |
1495 | } | 1495 | } | |
1496 | return 0; | 1496 | return 0; | |
1497 | default: | 1497 | default: | |
1498 | return EOPNOTSUPP; | 1498 | return EOPNOTSUPP; | |
1499 | } | 1499 | } | |
1500 | } | 1500 | } | |
1501 | 1501 | |||
1502 | /* | 1502 | /* | |
1503 | * Initialize an RX descriptor and attach an MBUF cluster. | 1503 | * Initialize an RX descriptor and attach an MBUF cluster. | |
1504 | */ | 1504 | */ | |
1505 | static int | 1505 | static int | |
1506 | atu_newbuf(struct atu_softc *sc, struct atu_chain *c, struct mbuf *m) | 1506 | atu_newbuf(struct atu_softc *sc, struct atu_chain *c, struct mbuf *m) | |
1507 | { | 1507 | { | |
1508 | struct mbuf *m_new = NULL; | 1508 | struct mbuf *m_new = NULL; | |
1509 | 1509 | |||
1510 | if (m == NULL) { | 1510 | if (m == NULL) { | |
1511 | MGETHDR(m_new, M_DONTWAIT, MT_DATA); | 1511 | MGETHDR(m_new, M_DONTWAIT, MT_DATA); | |
1512 | if (m_new == NULL) { | 1512 | if (m_new == NULL) { | |
1513 | DPRINTF(("%s: no memory for rx list\n", | 1513 | DPRINTF(("%s: no memory for rx list\n", | |
1514 | device_xname(sc->atu_dev))); | 1514 | device_xname(sc->atu_dev))); | |
1515 | return ENOBUFS; | 1515 | return ENOBUFS; | |
1516 | } | 1516 | } | |
1517 | 1517 | |||
1518 | MCLGET(m_new, M_DONTWAIT); | 1518 | MCLGET(m_new, M_DONTWAIT); | |
1519 | if (!(m_new->m_flags & M_EXT)) { | 1519 | if (!(m_new->m_flags & M_EXT)) { | |
1520 | DPRINTF(("%s: no memory for rx list\n", | 1520 | DPRINTF(("%s: no memory for rx list\n", | |
1521 | device_xname(sc->atu_dev))); | 1521 | device_xname(sc->atu_dev))); | |
1522 | m_freem(m_new); | 1522 | m_freem(m_new); | |
1523 | return ENOBUFS; | 1523 | return ENOBUFS; | |
1524 | } | 1524 | } | |
1525 | m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; | 1525 | m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; | |
1526 | } else { | 1526 | } else { | |
1527 | m_new = m; | 1527 | m_new = m; | |
1528 | m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; | 1528 | m_new->m_len = m_new->m_pkthdr.len = MCLBYTES; | |
1529 | m_new->m_data = m_new->m_ext.ext_buf; | 1529 | m_new->m_data = m_new->m_ext.ext_buf; | |
1530 | } | 1530 | } | |
1531 | c->atu_mbuf = m_new; | 1531 | c->atu_mbuf = m_new; | |
1532 | return 0; | 1532 | return 0; | |
1533 | } | 1533 | } | |
1534 | 1534 | |||
1535 | static int | 1535 | static int | |
1536 | atu_rx_list_init(struct atu_softc *sc) | 1536 | atu_rx_list_init(struct atu_softc *sc) | |
1537 | { | 1537 | { | |
1538 | struct atu_cdata *cd = &sc->atu_cdata; | 1538 | struct atu_cdata *cd = &sc->atu_cdata; | |
1539 | struct atu_chain *c; | 1539 | struct atu_chain *c; | |
1540 | int i; | 1540 | int i; | |
1541 | 1541 | |||
1542 | DPRINTFN(15, ("%s: atu_rx_list_init: enter\n", | 1542 | DPRINTFN(15, ("%s: atu_rx_list_init: enter\n", | |
1543 | device_xname(sc->atu_dev))); | 1543 | device_xname(sc->atu_dev))); | |
1544 | 1544 | |||
1545 | for (i = 0; i < ATU_RX_LIST_CNT; i++) { | 1545 | for (i = 0; i < ATU_RX_LIST_CNT; i++) { | |
1546 | c = &cd->atu_rx_chain[i]; | 1546 | c = &cd->atu_rx_chain[i]; | |
1547 | c->atu_sc = sc; | 1547 | c->atu_sc = sc; | |
1548 | c->atu_idx = i; | 1548 | c->atu_idx = i; | |
1549 | if (c->atu_xfer == NULL) { | 1549 | if (c->atu_xfer == NULL) { | |
1550 | int err = usbd_create_xfer(sc->atu_ep[ATU_ENDPT_RX], | 1550 | int err = usbd_create_xfer(sc->atu_ep[ATU_ENDPT_RX], | |
1551 | ATU_RX_BUFSZ, 0, 0, &c->atu_xfer); | 1551 | ATU_RX_BUFSZ, 0, 0, &c->atu_xfer); | |
1552 | if (err) | 1552 | if (err) | |
1553 | return err; | 1553 | return err; | |
1554 | c->atu_buf = usbd_get_buffer(c->atu_xfer); | 1554 | c->atu_buf = usbd_get_buffer(c->atu_xfer); | |
1555 | if (atu_newbuf(sc, c, NULL) == ENOBUFS) /* XXX free? */ | 1555 | if (atu_newbuf(sc, c, NULL) == ENOBUFS) /* XXX free? */ | |
1556 | return ENOBUFS; | 1556 | return ENOBUFS; | |
1557 | } | 1557 | } | |
1558 | } | 1558 | } | |
1559 | return 0; | 1559 | return 0; | |
1560 | } | 1560 | } | |
1561 | 1561 | |||
1562 | static int | 1562 | static int | |
1563 | atu_tx_list_init(struct atu_softc *sc) | 1563 | atu_tx_list_init(struct atu_softc *sc) | |
1564 | { | 1564 | { | |
1565 | struct atu_cdata *cd = &sc->atu_cdata; | 1565 | struct atu_cdata *cd = &sc->atu_cdata; | |
1566 | struct atu_chain *c; | 1566 | struct atu_chain *c; | |
1567 | int i; | 1567 | int i; | |
1568 | 1568 | |||
1569 | DPRINTFN(15, ("%s: atu_tx_list_init\n", | 1569 | DPRINTFN(15, ("%s: atu_tx_list_init\n", | |
1570 | device_xname(sc->atu_dev))); | 1570 | device_xname(sc->atu_dev))); | |
1571 | 1571 | |||
1572 | SLIST_INIT(&cd->atu_tx_free); | 1572 | SLIST_INIT(&cd->atu_tx_free); | |
1573 | sc->atu_cdata.atu_tx_inuse = 0; | 1573 | sc->atu_cdata.atu_tx_inuse = 0; | |
1574 | 1574 | |||
1575 | for (i = 0; i < ATU_TX_LIST_CNT; i++) { | 1575 | for (i = 0; i < ATU_TX_LIST_CNT; i++) { | |
1576 | c = &cd->atu_tx_chain[i]; | 1576 | c = &cd->atu_tx_chain[i]; | |
1577 | c->atu_sc = sc; | 1577 | c->atu_sc = sc; | |
1578 | c->atu_idx = i; | 1578 | c->atu_idx = i; | |
1579 | if (c->atu_xfer == NULL) { | 1579 | if (c->atu_xfer == NULL) { | |
1580 | int err = usbd_create_xfer(sc->atu_ep[ATU_ENDPT_TX], | 1580 | int err = usbd_create_xfer(sc->atu_ep[ATU_ENDPT_TX], | |
1581 | ATU_TX_BUFSZ, 0, 0, &c->atu_xfer); | 1581 | ATU_TX_BUFSZ, 0, 0, &c->atu_xfer); | |
1582 | if (err) { | 1582 | if (err) { | |
1583 | return err; | 1583 | return err; | |
1584 | } | 1584 | } | |
1585 | c->atu_buf = usbd_get_buffer(c->atu_xfer); | 1585 | c->atu_buf = usbd_get_buffer(c->atu_xfer); | |
1586 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, atu_list); | 1586 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, atu_list); | |
1587 | } | 1587 | } | |
1588 | } | 1588 | } | |
1589 | return 0; | 1589 | return 0; | |
1590 | } | 1590 | } | |
1591 | 1591 | |||
1592 | static void | 1592 | static void | |
1593 | atu_xfer_list_free(struct atu_softc *sc, struct atu_chain *ch, int listlen) | 1593 | atu_xfer_list_free(struct atu_softc *sc, struct atu_chain *ch, int listlen) | |
1594 | { | 1594 | { | |
1595 | int i; | 1595 | int i; | |
1596 | 1596 | |||
1597 | /* Free resources. */ | 1597 | /* Free resources. */ | |
1598 | for (i = 0; i < listlen; i++) { | 1598 | for (i = 0; i < listlen; i++) { | |
1599 | if (ch[i].atu_buf != NULL) | 1599 | if (ch[i].atu_buf != NULL) | |
1600 | ch[i].atu_buf = NULL; | 1600 | ch[i].atu_buf = NULL; | |
1601 | if (ch[i].atu_mbuf != NULL) { | 1601 | if (ch[i].atu_mbuf != NULL) { | |
1602 | m_freem(ch[i].atu_mbuf); | 1602 | m_freem(ch[i].atu_mbuf); | |
1603 | ch[i].atu_mbuf = NULL; | 1603 | ch[i].atu_mbuf = NULL; | |
1604 | } | 1604 | } | |
1605 | if (ch[i].atu_xfer != NULL) { | 1605 | if (ch[i].atu_xfer != NULL) { | |
1606 | usbd_destroy_xfer(ch[i].atu_xfer); | 1606 | usbd_destroy_xfer(ch[i].atu_xfer); | |
1607 | ch[i].atu_xfer = NULL; | 1607 | ch[i].atu_xfer = NULL; | |
1608 | } | 1608 | } | |
1609 | } | 1609 | } | |
1610 | } | 1610 | } | |
1611 | 1611 | |||
1612 | /* | 1612 | /* | |
1613 | * A frame has been uploaded: pass the resulting mbuf chain up to | 1613 | * A frame has been uploaded: pass the resulting mbuf chain up to | |
1614 | * the higher level protocols. | 1614 | * the higher level protocols. | |
1615 | */ | 1615 | */ | |
1616 | static void | 1616 | static void | |
1617 | atu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | 1617 | atu_rxeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | |
1618 | { | 1618 | { | |
1619 | struct atu_chain *c = (struct atu_chain *)priv; | 1619 | struct atu_chain *c = (struct atu_chain *)priv; | |
1620 | struct atu_softc *sc = c->atu_sc; | 1620 | struct atu_softc *sc = c->atu_sc; | |
1621 | struct ieee80211com *ic = &sc->sc_ic; | 1621 | struct ieee80211com *ic = &sc->sc_ic; | |
1622 | struct ifnet *ifp = &sc->sc_if; | 1622 | struct ifnet *ifp = &sc->sc_if; | |
1623 | struct atu_rx_hdr *h; | 1623 | struct atu_rx_hdr *h; | |
1624 | struct ieee80211_frame_min *wh; | 1624 | struct ieee80211_frame_min *wh; | |
1625 | struct ieee80211_node *ni; | 1625 | struct ieee80211_node *ni; | |
1626 | struct mbuf *m; | 1626 | struct mbuf *m; | |
1627 | uint32_t len; | 1627 | uint32_t len; | |
1628 | int s; | 1628 | int s; | |
1629 | 1629 | |||
1630 | DPRINTFN(25, ("%s: atu_rxeof\n", device_xname(sc->atu_dev))); | 1630 | DPRINTFN(25, ("%s: atu_rxeof\n", device_xname(sc->atu_dev))); | |
1631 | 1631 | |||
1632 | if (sc->sc_state != ATU_S_OK) | 1632 | if (sc->sc_state != ATU_S_OK) | |
1633 | return; | 1633 | return; | |
1634 | 1634 | |||
1635 | if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP)) | 1635 | if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) != (IFF_RUNNING|IFF_UP)) | |
1636 | goto done; | 1636 | goto done; | |
1637 | 1637 | |||
1638 | if (status != USBD_NORMAL_COMPLETION) { | 1638 | if (status != USBD_NORMAL_COMPLETION) { | |
1639 | DPRINTF(("%s: status != USBD_NORMAL_COMPLETION\n", | 1639 | DPRINTF(("%s: status != USBD_NORMAL_COMPLETION\n", | |
1640 | device_xname(sc->atu_dev))); | 1640 | device_xname(sc->atu_dev))); | |
1641 | if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { | 1641 | if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) { | |
1642 | return; | 1642 | return; | |
1643 | } | 1643 | } | |
1644 | #if 0 | 1644 | #if 0 | |
1645 | if (status == USBD_IOERROR) { | 1645 | if (status == USBD_IOERROR) { | |
1646 | DPRINTF(("%s: rx: EEK! lost device?\n", | 1646 | DPRINTF(("%s: rx: EEK! lost device?\n", | |
1647 | device_xname(sc->atu_dev))); | 1647 | device_xname(sc->atu_dev))); | |
1648 | 1648 | |||
1649 | /* | 1649 | /* | |
1650 | * My experience with USBD_IOERROR is that trying to | 1650 | * My experience with USBD_IOERROR is that trying to | |
1651 | * restart the transfer will always fail and we'll | 1651 | * restart the transfer will always fail and we'll | |
1652 | * keep on looping restarting transfers untill someone | 1652 | * keep on looping restarting transfers untill someone | |
1653 | * pulls the plug of the device. | 1653 | * pulls the plug of the device. | |
1654 | * So we don't restart the transfer, but just let it | 1654 | * So we don't restart the transfer, but just let it | |
1655 | * die... If someone knows of a situation where we can | 1655 | * die... If someone knows of a situation where we can | |
1656 | * recover from USBD_IOERROR, let me know. | 1656 | * recover from USBD_IOERROR, let me know. | |
1657 | */ | 1657 | */ | |
1658 | splx(s); | 1658 | splx(s); | |
1659 | return; | 1659 | return; | |
1660 | } | 1660 | } | |
1661 | #endif /* 0 */ | 1661 | #endif /* 0 */ | |
1662 | 1662 | |||
1663 | if (usbd_ratecheck(&sc->atu_rx_notice)) { | 1663 | if (usbd_ratecheck(&sc->atu_rx_notice)) { | |
1664 | DPRINTF(("%s: usb error on rx: %s\n", | 1664 | DPRINTF(("%s: usb error on rx: %s\n", | |
1665 | device_xname(sc->atu_dev), usbd_errstr(status))); | 1665 | device_xname(sc->atu_dev), usbd_errstr(status))); | |
1666 | } | 1666 | } | |
1667 | if (status == USBD_STALLED) | 1667 | if (status == USBD_STALLED) | |
1668 | usbd_clear_endpoint_stall_async( | 1668 | usbd_clear_endpoint_stall_async( | |
1669 | sc->atu_ep[ATU_ENDPT_RX]); | 1669 | sc->atu_ep[ATU_ENDPT_RX]); | |
1670 | goto done; | 1670 | goto done; | |
1671 | } | 1671 | } | |
1672 | 1672 | |||
1673 | usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); | 1673 | usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); | |
1674 | 1674 | |||
1675 | if (len <= 1) { | 1675 | if (len <= 1) { | |
1676 | DPRINTF(("%s: atu_rxeof: too short\n", | 1676 | DPRINTF(("%s: atu_rxeof: too short\n", | |
1677 | device_xname(sc->atu_dev))); | 1677 | device_xname(sc->atu_dev))); | |
1678 | goto done; | 1678 | goto done; | |
1679 | } | 1679 | } | |
1680 | 1680 | |||
1681 | h = (struct atu_rx_hdr *)c->atu_buf; | 1681 | h = (struct atu_rx_hdr *)c->atu_buf; | |
1682 | len = UGETW(h->length) - 4; /* XXX magic number */ | 1682 | len = UGETW(h->length) - 4; /* XXX magic number */ | |
1683 | 1683 | |||
1684 | m = c->atu_mbuf; | 1684 | m = c->atu_mbuf; | |
1685 | memcpy(mtod(m, char *), c->atu_buf + ATU_RX_HDRLEN, len); | 1685 | memcpy(mtod(m, char *), c->atu_buf + ATU_RX_HDRLEN, len); | |
1686 | m_set_rcvif(m, ifp); | 1686 | m_set_rcvif(m, ifp); | |
1687 | m->m_pkthdr.len = m->m_len = len; | 1687 | m->m_pkthdr.len = m->m_len = len; | |
1688 | 1688 | |||
1689 | wh = mtod(m, struct ieee80211_frame_min *); | 1689 | wh = mtod(m, struct ieee80211_frame_min *); | |
1690 | ni = ieee80211_find_rxnode(ic, wh); | 1690 | ni = ieee80211_find_rxnode(ic, wh); | |
1691 | 1691 | |||
1692 | ifp->if_ipackets++; | 1692 | ifp->if_ipackets++; | |
1693 | 1693 | |||
1694 | s = splnet(); | 1694 | s = splnet(); | |
1695 | 1695 | |||
1696 | if (atu_newbuf(sc, c, NULL) == ENOBUFS) { | 1696 | if (atu_newbuf(sc, c, NULL) == ENOBUFS) { | |
1697 | ifp->if_ierrors++; | 1697 | ifp->if_ierrors++; | |
1698 | goto done1; /* XXX if we can't allocate, why restart it? */ | 1698 | goto done1; /* XXX if we can't allocate, why restart it? */ | |
1699 | } | 1699 | } | |
1700 | 1700 | |||
1701 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { | 1701 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { | |
1702 | /* | 1702 | /* | |
1703 | * WEP is decrypted by hardware. Clear WEP bit | 1703 | * WEP is decrypted by hardware. Clear WEP bit | |
1704 | * header for ieee80211_input(). | 1704 | * header for ieee80211_input(). | |
1705 | */ | 1705 | */ | |
1706 | wh->i_fc[1] &= ~IEEE80211_FC1_WEP; | 1706 | wh->i_fc[1] &= ~IEEE80211_FC1_WEP; | |
1707 | } | 1707 | } | |
1708 | 1708 | |||
1709 | ieee80211_input(ic, m, ni, h->rssi, UGETDW(h->rx_time)); | 1709 | ieee80211_input(ic, m, ni, h->rssi, UGETDW(h->rx_time)); | |
1710 | 1710 | |||
1711 | ieee80211_free_node(ni); | 1711 | ieee80211_free_node(ni); | |
1712 | done1: | 1712 | done1: | |
1713 | splx(s); | 1713 | splx(s); | |
1714 | done: | 1714 | done: | |
1715 | /* Setup new transfer. */ | 1715 | /* Setup new transfer. */ | |
1716 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, ATU_RX_BUFSZ, | 1716 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, ATU_RX_BUFSZ, | |
1717 | USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, atu_rxeof); | 1717 | USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, atu_rxeof); | |
1718 | usbd_transfer(c->atu_xfer); | 1718 | usbd_transfer(c->atu_xfer); | |
1719 | } | 1719 | } | |
1720 | 1720 | |||
1721 | /* | 1721 | /* | |
1722 | * A frame was downloaded to the chip. It's safe for us to clean up | 1722 | * A frame was downloaded to the chip. It's safe for us to clean up | |
1723 | * the list buffers. | 1723 | * the list buffers. | |
1724 | */ | 1724 | */ | |
1725 | static void | 1725 | static void | |
1726 | atu_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | 1726 | atu_txeof(struct usbd_xfer *xfer, void *priv, usbd_status status) | |
1727 | { | 1727 | { | |
1728 | struct atu_chain *c = (struct atu_chain *)priv; | 1728 | struct atu_chain *c = (struct atu_chain *)priv; | |
1729 | struct atu_softc *sc = c->atu_sc; | 1729 | struct atu_softc *sc = c->atu_sc; | |
1730 | struct ifnet *ifp = &sc->sc_if; | 1730 | struct ifnet *ifp = &sc->sc_if; | |
1731 | usbd_status err; | 1731 | usbd_status err; | |
1732 | int s; | 1732 | int s; | |
1733 | 1733 | |||
1734 | DPRINTFN(25, ("%s: atu_txeof status=%d\n", device_xname(sc->atu_dev), | 1734 | DPRINTFN(25, ("%s: atu_txeof status=%d\n", device_xname(sc->atu_dev), | |
1735 | status)); | 1735 | status)); | |
1736 | 1736 | |||
1737 | if (c->atu_mbuf) { | 1737 | if (c->atu_mbuf) { | |
1738 | m_freem(c->atu_mbuf); | 1738 | m_freem(c->atu_mbuf); | |
1739 | c->atu_mbuf = NULL; | 1739 | c->atu_mbuf = NULL; | |
1740 | } | 1740 | } | |
1741 | 1741 | |||
1742 | if (status != USBD_NORMAL_COMPLETION) { | 1742 | if (status != USBD_NORMAL_COMPLETION) { | |
1743 | if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) | 1743 | if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) | |
1744 | return; | 1744 | return; | |
1745 | 1745 | |||
1746 | DPRINTF(("%s: usb error on tx: %s\n", | 1746 | DPRINTF(("%s: usb error on tx: %s\n", | |
1747 | device_xname(sc->atu_dev), usbd_errstr(status))); | 1747 | device_xname(sc->atu_dev), usbd_errstr(status))); | |
1748 | if (status == USBD_STALLED) | 1748 | if (status == USBD_STALLED) | |
1749 | usbd_clear_endpoint_stall_async( | 1749 | usbd_clear_endpoint_stall_async( | |
1750 | sc->atu_ep[ATU_ENDPT_TX]); | 1750 | sc->atu_ep[ATU_ENDPT_TX]); | |
1751 | return; | 1751 | return; | |
1752 | } | 1752 | } | |
1753 | 1753 | |||
1754 | usbd_get_xfer_status(c->atu_xfer, NULL, NULL, NULL, &err); | 1754 | usbd_get_xfer_status(c->atu_xfer, NULL, NULL, NULL, &err); | |
1755 | 1755 | |||
1756 | if (err) | 1756 | if (err) | |
1757 | ifp->if_oerrors++; | 1757 | ifp->if_oerrors++; | |
1758 | else | 1758 | else | |
1759 | ifp->if_opackets++; | 1759 | ifp->if_opackets++; | |
1760 | 1760 | |||
1761 | s = splnet(); | 1761 | s = splnet(); | |
1762 | SLIST_INSERT_HEAD(&sc->atu_cdata.atu_tx_free, c, atu_list); | 1762 | SLIST_INSERT_HEAD(&sc->atu_cdata.atu_tx_free, c, atu_list); | |
1763 | sc->atu_cdata.atu_tx_inuse--; | 1763 | sc->atu_cdata.atu_tx_inuse--; | |
1764 | if (sc->atu_cdata.atu_tx_inuse == 0) | 1764 | if (sc->atu_cdata.atu_tx_inuse == 0) | |
1765 | ifp->if_timer = 0; | 1765 | ifp->if_timer = 0; | |
1766 | ifp->if_flags &= ~IFF_OACTIVE; | 1766 | ifp->if_flags &= ~IFF_OACTIVE; | |
1767 | splx(s); | 1767 | splx(s); | |
1768 | 1768 | |||
1769 | atu_start(ifp); | 1769 | atu_start(ifp); | |
1770 | } | 1770 | } | |
1771 | 1771 | |||
1772 | static uint8_t | 1772 | static uint8_t | |
1773 | atu_calculate_padding(int size) | 1773 | atu_calculate_padding(int size) | |
1774 | { | 1774 | { | |
1775 | size %= 64; | 1775 | size %= 64; | |
1776 | 1776 | |||
1777 | if (size < 50) | 1777 | if (size < 50) | |
1778 | return 50 - size; | 1778 | return 50 - size; | |
1779 | if (size >=61) | 1779 | if (size >=61) | |
1780 | return 64 + 50 - size; | 1780 | return 64 + 50 - size; | |
1781 | return 0; | 1781 | return 0; | |
1782 | } | 1782 | } | |
1783 | 1783 | |||
1784 | static int | 1784 | static int | |
1785 | atu_tx_start(struct atu_softc *sc, struct ieee80211_node *ni, | 1785 | atu_tx_start(struct atu_softc *sc, struct ieee80211_node *ni, | |
1786 | struct atu_chain *c, struct mbuf *m) | 1786 | struct atu_chain *c, struct mbuf *m) | |
1787 | { | 1787 | { | |
1788 | int len; | 1788 | int len; | |
1789 | struct atu_tx_hdr *h; | 1789 | struct atu_tx_hdr *h; | |
1790 | usbd_status err; | 1790 | usbd_status err; | |
1791 | uint8_t pad; | 1791 | uint8_t pad; | |
1792 | 1792 | |||
1793 | DPRINTFN(25, ("%s: atu_tx_start\n", device_xname(sc->atu_dev))); | 1793 | DPRINTFN(25, ("%s: atu_tx_start\n", device_xname(sc->atu_dev))); | |
1794 | 1794 | |||
1795 | /* Don't try to send when we're shutting down the driver */ | 1795 | /* Don't try to send when we're shutting down the driver */ | |
1796 | if (sc->sc_state != ATU_S_OK) { | 1796 | if (sc->sc_state != ATU_S_OK) { | |
1797 | m_freem(m); | 1797 | m_freem(m); | |
1798 | return EIO; | 1798 | return EIO; | |
1799 | } | 1799 | } | |
1800 | 1800 | |||
1801 | /* | 1801 | /* | |
1802 | * Copy the mbuf data into a contiguous buffer, leaving | 1802 | * Copy the mbuf data into a contiguous buffer, leaving | |
1803 | * enough room for the atmel headers | 1803 | * enough room for the atmel headers | |
1804 | */ | 1804 | */ | |
1805 | len = m->m_pkthdr.len; | 1805 | len = m->m_pkthdr.len; | |
1806 | 1806 | |||
1807 | m_copydata(m, 0, m->m_pkthdr.len, c->atu_buf + ATU_TX_HDRLEN); | 1807 | m_copydata(m, 0, m->m_pkthdr.len, c->atu_buf + ATU_TX_HDRLEN); | |
1808 | 1808 | |||
1809 | h = (struct atu_tx_hdr *)c->atu_buf; | 1809 | h = (struct atu_tx_hdr *)c->atu_buf; | |
1810 | memset(h, 0, ATU_TX_HDRLEN); | 1810 | memset(h, 0, ATU_TX_HDRLEN); | |
1811 | USETW(h->length, len); | 1811 | USETW(h->length, len); | |
1812 | h->tx_rate = 4; /* XXX rate = auto */ | 1812 | h->tx_rate = 4; /* XXX rate = auto */ | |
1813 | len += ATU_TX_HDRLEN; | 1813 | len += ATU_TX_HDRLEN; | |
1814 | 1814 | |||
1815 | pad = atu_calculate_padding(len); | 1815 | pad = atu_calculate_padding(len); | |
1816 | len += pad; | 1816 | len += pad; | |
1817 | h->padding = pad; | 1817 | h->padding = pad; | |
1818 | 1818 | |||
1819 | c->atu_length = len; | 1819 | c->atu_length = len; | |
1820 | c->atu_mbuf = m; | 1820 | c->atu_mbuf = m; | |
1821 | 1821 | |||
1822 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, c->atu_length, 0, | 1822 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, c->atu_length, 0, | |
1823 | ATU_TX_TIMEOUT, atu_txeof); | 1823 | ATU_TX_TIMEOUT, atu_txeof); | |
1824 | 1824 | |||
1825 | /* Let's get this thing into the air! */ | 1825 | /* Let's get this thing into the air! */ | |
1826 | c->atu_in_xfer = 1; | 1826 | c->atu_in_xfer = 1; | |
1827 | err = usbd_transfer(c->atu_xfer); | 1827 | err = usbd_transfer(c->atu_xfer); | |
1828 | if (err != USBD_IN_PROGRESS) { | 1828 | if (err != USBD_IN_PROGRESS) { | |
1829 | DPRINTFN(25, ("%s: atu_tx_start, err=%d", | 1829 | DPRINTFN(25, ("%s: atu_tx_start, err=%d", | |
1830 | device_xname(sc->atu_dev), err)); | 1830 | device_xname(sc->atu_dev), err)); | |
1831 | c->atu_mbuf = NULL; | 1831 | c->atu_mbuf = NULL; | |
1832 | m_freem(m); | 1832 | m_freem(m); | |
1833 | return EIO; | 1833 | return EIO; | |
1834 | } | 1834 | } | |
1835 | 1835 | |||
1836 | return 0; | 1836 | return 0; | |
1837 | } | 1837 | } | |
1838 | 1838 | |||
1839 | static void | 1839 | static void | |
1840 | atu_start(struct ifnet *ifp) | 1840 | atu_start(struct ifnet *ifp) | |
1841 | { | 1841 | { | |
1842 | struct atu_softc *sc = ifp->if_softc; | 1842 | struct atu_softc *sc = ifp->if_softc; | |
1843 | struct ieee80211com *ic = &sc->sc_ic; | 1843 | struct ieee80211com *ic = &sc->sc_ic; | |
1844 | struct atu_cdata *cd = &sc->atu_cdata; | 1844 | struct atu_cdata *cd = &sc->atu_cdata; | |
1845 | struct ieee80211_node *ni; | 1845 | struct ieee80211_node *ni; | |
1846 | struct atu_chain *c; | 1846 | struct atu_chain *c; | |
1847 | struct mbuf *m = NULL; | 1847 | struct mbuf *m = NULL; | |
1848 | int s; | 1848 | int s; | |
1849 | 1849 | |||
1850 | DPRINTFN(25, ("%s: atu_start: enter\n", device_xname(sc->atu_dev))); | 1850 | DPRINTFN(25, ("%s: atu_start: enter\n", device_xname(sc->atu_dev))); | |
1851 | 1851 | |||
1852 | if ((ifp->if_flags & IFF_RUNNING) == 0) { | 1852 | if ((ifp->if_flags & IFF_RUNNING) == 0) { | |
1853 | return; | 1853 | return; | |
1854 | } | 1854 | } | |
1855 | if (ifp->if_flags & IFF_OACTIVE) { | 1855 | if (ifp->if_flags & IFF_OACTIVE) { | |
1856 | DPRINTFN(30, ("%s: atu_start: IFF_OACTIVE\n", | 1856 | DPRINTFN(30, ("%s: atu_start: IFF_OACTIVE\n", | |
1857 | device_xname(sc->atu_dev))); | 1857 | device_xname(sc->atu_dev))); | |
1858 | return; | 1858 | return; | |
1859 | } | 1859 | } | |
1860 | 1860 | |||
1861 | for (;;) { | 1861 | for (;;) { | |
1862 | /* grab a TX buffer */ | 1862 | /* grab a TX buffer */ | |
1863 | s = splnet(); | 1863 | s = splnet(); | |
1864 | c = SLIST_FIRST(&cd->atu_tx_free); | 1864 | c = SLIST_FIRST(&cd->atu_tx_free); | |
1865 | if (c != NULL) { | 1865 | if (c != NULL) { | |
1866 | SLIST_REMOVE_HEAD(&cd->atu_tx_free, atu_list); | 1866 | SLIST_REMOVE_HEAD(&cd->atu_tx_free, atu_list); | |
1867 | cd->atu_tx_inuse++; | 1867 | cd->atu_tx_inuse++; | |
1868 | if (cd->atu_tx_inuse == ATU_TX_LIST_CNT) | 1868 | if (cd->atu_tx_inuse == ATU_TX_LIST_CNT) | |
1869 | ifp->if_flags |= IFF_OACTIVE; | 1869 | ifp->if_flags |= IFF_OACTIVE; | |
1870 | } | 1870 | } | |
1871 | splx(s); | 1871 | splx(s); | |
1872 | if (c == NULL) { | 1872 | if (c == NULL) { | |
1873 | DPRINTFN(10, ("%s: out of tx xfers\n", | 1873 | DPRINTFN(10, ("%s: out of tx xfers\n", | |
1874 | device_xname(sc->atu_dev))); | 1874 | device_xname(sc->atu_dev))); | |
1875 | ifp->if_flags |= IFF_OACTIVE; | 1875 | ifp->if_flags |= IFF_OACTIVE; | |
1876 | break; | 1876 | break; | |
1877 | } | 1877 | } | |
1878 | 1878 | |||
1879 | /* | 1879 | /* | |
1880 | * Poll the management queue for frames, it has priority over | 1880 | * Poll the management queue for frames, it has priority over | |
1881 | * normal data frames. | 1881 | * normal data frames. | |
1882 | */ | 1882 | */ | |
1883 | IF_DEQUEUE(&ic->ic_mgtq, m); | 1883 | IF_DEQUEUE(&ic->ic_mgtq, m); | |
1884 | if (m == NULL) { | 1884 | if (m == NULL) { | |
1885 | DPRINTFN(10, ("%s: atu_start: data packet\n", | 1885 | DPRINTFN(10, ("%s: atu_start: data packet\n", | |
1886 | device_xname(sc->atu_dev))); | 1886 | device_xname(sc->atu_dev))); | |
1887 | if (ic->ic_state != IEEE80211_S_RUN) { | 1887 | if (ic->ic_state != IEEE80211_S_RUN) { | |
1888 | DPRINTFN(25, ("%s: no data till running\n", | 1888 | DPRINTFN(25, ("%s: no data till running\n", | |
1889 | device_xname(sc->atu_dev))); | 1889 | device_xname(sc->atu_dev))); | |
1890 | /* put the xfer back on the list */ | 1890 | /* put the xfer back on the list */ | |
1891 | s = splnet(); | 1891 | s = splnet(); | |
1892 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | 1892 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | |
1893 | atu_list); | 1893 | atu_list); | |
1894 | cd->atu_tx_inuse--; | 1894 | cd->atu_tx_inuse--; | |
1895 | splx(s); | 1895 | splx(s); | |
1896 | break; | 1896 | break; | |
1897 | } | 1897 | } | |
1898 | 1898 | |||
1899 | IFQ_DEQUEUE(&ifp->if_snd, m); | 1899 | IFQ_DEQUEUE(&ifp->if_snd, m); | |
1900 | if (m == NULL) { | 1900 | if (m == NULL) { | |
1901 | DPRINTFN(25, ("%s: nothing to send\n", | 1901 | DPRINTFN(25, ("%s: nothing to send\n", | |
1902 | device_xname(sc->atu_dev))); | 1902 | device_xname(sc->atu_dev))); | |
1903 | s = splnet(); | 1903 | s = splnet(); | |
1904 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | 1904 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | |
1905 | atu_list); | 1905 | atu_list); | |
1906 | cd->atu_tx_inuse--; | 1906 | cd->atu_tx_inuse--; | |
1907 | splx(s); | 1907 | splx(s); | |
1908 | break; | 1908 | break; | |
1909 | } | 1909 | } | |
1910 | bpf_mtap(ifp, m, BPF_D_OUT); | 1910 | bpf_mtap(ifp, m, BPF_D_OUT); | |
1911 | ni = ieee80211_find_txnode(ic, | 1911 | ni = ieee80211_find_txnode(ic, | |
1912 | mtod(m, struct ether_header *)->ether_dhost); | 1912 | mtod(m, struct ether_header *)->ether_dhost); | |
1913 | if (ni == NULL) { | 1913 | if (ni == NULL) { | |
1914 | m_freem(m); | 1914 | m_freem(m); | |
1915 | goto bad; | 1915 | goto bad; | |
1916 | } | 1916 | } | |
1917 | m = ieee80211_encap(ic, m, ni); | 1917 | m = ieee80211_encap(ic, m, ni); | |
1918 | if (m == NULL) | 1918 | if (m == NULL) | |
1919 | goto bad; | 1919 | goto bad; | |
1920 | } else { | 1920 | } else { | |
1921 | DPRINTFN(25, ("%s: atu_start: mgmt packet\n", | 1921 | DPRINTFN(25, ("%s: atu_start: mgmt packet\n", | |
1922 | device_xname(sc->atu_dev))); | 1922 | device_xname(sc->atu_dev))); | |
1923 | 1923 | |||
1924 | /* | 1924 | /* | |
1925 | * Hack! The referenced node pointer is in the | 1925 | * Hack! The referenced node pointer is in the | |
1926 | * rcvif field of the packet header. This is | 1926 | * rcvif field of the packet header. This is | |
1927 | * placed there by ieee80211_mgmt_output because | 1927 | * placed there by ieee80211_mgmt_output because | |
1928 | * we need to hold the reference with the frame | 1928 | * we need to hold the reference with the frame | |
1929 | * and there's no other way (other than packet | 1929 | * and there's no other way (other than packet | |
1930 | * tags which we consider too expensive to use) | 1930 | * tags which we consider too expensive to use) | |
1931 | * to pass it along. | 1931 | * to pass it along. | |
1932 | */ | 1932 | */ | |
1933 | ni = M_GETCTX(m, struct ieee80211_node *); | 1933 | ni = M_GETCTX(m, struct ieee80211_node *); | |
1934 | M_CLEARCTX(m); | 1934 | M_CLEARCTX(m); | |
1935 | 1935 | |||
1936 | /* sc->sc_stats.ast_tx_mgmt++; */ | 1936 | /* sc->sc_stats.ast_tx_mgmt++; */ | |
1937 | } | 1937 | } | |
1938 | 1938 | |||
1939 | bpf_mtap3(ic->ic_rawbpf, m, BPF_D_OUT); | 1939 | bpf_mtap3(ic->ic_rawbpf, m, BPF_D_OUT); | |
1940 | 1940 | |||
1941 | if (atu_tx_start(sc, ni, c, m)) { | 1941 | if (atu_tx_start(sc, ni, c, m)) { | |
1942 | bad: | 1942 | bad: | |
1943 | s = splnet(); | 1943 | s = splnet(); | |
1944 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | 1944 | SLIST_INSERT_HEAD(&cd->atu_tx_free, c, | |
1945 | atu_list); | 1945 | atu_list); | |
1946 | cd->atu_tx_inuse--; | 1946 | cd->atu_tx_inuse--; | |
1947 | splx(s); | 1947 | splx(s); | |
1948 | /* ifp_if_oerrors++; */ | 1948 | /* ifp_if_oerrors++; */ | |
1949 | if (ni != NULL) | 1949 | if (ni != NULL) | |
1950 | ieee80211_free_node(ni); | 1950 | ieee80211_free_node(ni); | |
1951 | continue; | 1951 | continue; | |
1952 | } | 1952 | } | |
1953 | ifp->if_timer = 5; | 1953 | ifp->if_timer = 5; | |
1954 | } | 1954 | } | |
1955 | } | 1955 | } | |
1956 | 1956 | |||
1957 | static int | 1957 | static int | |
1958 | atu_init(struct ifnet *ifp) | 1958 | atu_init(struct ifnet *ifp) | |
1959 | { | 1959 | { | |
1960 | struct atu_softc *sc = ifp->if_softc; | 1960 | struct atu_softc *sc = ifp->if_softc; | |
1961 | struct ieee80211com *ic = &sc->sc_ic; | 1961 | struct ieee80211com *ic = &sc->sc_ic; | |
1962 | struct atu_chain *c; | 1962 | struct atu_chain *c; | |
1963 | usbd_status err; | 1963 | usbd_status err; | |
1964 | int i, s; | 1964 | int i, s; | |
1965 | 1965 | |||
1966 | s = splnet(); | 1966 | s = splnet(); | |
1967 | 1967 | |||
1968 | DPRINTFN(10, ("%s: atu_init\n", device_xname(sc->atu_dev))); | 1968 | DPRINTFN(10, ("%s: atu_init\n", device_xname(sc->atu_dev))); | |
1969 | 1969 | |||
1970 | if (ifp->if_flags & IFF_RUNNING) { | 1970 | if (ifp->if_flags & IFF_RUNNING) { | |
1971 | splx(s); | 1971 | splx(s); | |
1972 | return 0; | 1972 | return 0; | |
1973 | } | 1973 | } | |
1974 | 1974 | |||
1975 | /* Load the multicast filter. */ | 1975 | /* Load the multicast filter. */ | |
1976 | /*atu_setmulti(sc); */ | 1976 | /*atu_setmulti(sc); */ | |
1977 | 1977 | |||
1978 | /* Open RX and TX pipes. */ | 1978 | /* Open RX and TX pipes. */ | |
1979 | err = usbd_open_pipe(sc->atu_iface, sc->atu_ed[ATU_ENDPT_RX], | 1979 | err = usbd_open_pipe(sc->atu_iface, sc->atu_ed[ATU_ENDPT_RX], | |
1980 | USBD_EXCLUSIVE_USE, &sc->atu_ep[ATU_ENDPT_RX]); | 1980 | USBD_EXCLUSIVE_USE, &sc->atu_ep[ATU_ENDPT_RX]); | |
1981 | if (err) { | 1981 | if (err) { | |
1982 | DPRINTF(("%s: open rx pipe failed: %s\n", | 1982 | DPRINTF(("%s: open rx pipe failed: %s\n", | |
1983 | device_xname(sc->atu_dev), usbd_errstr(err))); | 1983 | device_xname(sc->atu_dev), usbd_errstr(err))); | |
1984 | splx(s); | 1984 | splx(s); | |
1985 | return EIO; | 1985 | return EIO; | |
1986 | } | 1986 | } | |
1987 | 1987 | |||
1988 | err = usbd_open_pipe(sc->atu_iface, sc->atu_ed[ATU_ENDPT_TX], | 1988 | err = usbd_open_pipe(sc->atu_iface, sc->atu_ed[ATU_ENDPT_TX], | |
1989 | USBD_EXCLUSIVE_USE, &sc->atu_ep[ATU_ENDPT_TX]); | 1989 | USBD_EXCLUSIVE_USE, &sc->atu_ep[ATU_ENDPT_TX]); | |
1990 | if (err) { | 1990 | if (err) { | |
1991 | DPRINTF(("%s: open tx pipe failed: %s\n", | 1991 | DPRINTF(("%s: open tx pipe failed: %s\n", | |
1992 | device_xname(sc->atu_dev), usbd_errstr(err))); | 1992 | device_xname(sc->atu_dev), usbd_errstr(err))); | |
1993 | splx(s); | 1993 | splx(s); | |
1994 | return EIO; | 1994 | return EIO; | |
1995 | } | 1995 | } | |
1996 | 1996 | |||
1997 | /* Init TX ring */ | 1997 | /* Init TX ring */ | |
1998 | if (atu_tx_list_init(sc)) | 1998 | if (atu_tx_list_init(sc)) | |
1999 | printf("%s: tx list init failed\n", device_xname(sc->atu_dev)); | 1999 | printf("%s: tx list init failed\n", device_xname(sc->atu_dev)); | |
2000 | 2000 | |||
2001 | /* Init RX ring */ | 2001 | /* Init RX ring */ | |
2002 | if (atu_rx_list_init(sc)) | 2002 | if (atu_rx_list_init(sc)) | |
2003 | printf("%s: rx list init failed\n", device_xname(sc->atu_dev)); | 2003 | printf("%s: rx list init failed\n", device_xname(sc->atu_dev)); | |
2004 | 2004 | |||
2005 | /* Start up the receive pipe. */ | 2005 | /* Start up the receive pipe. */ | |
2006 | for (i = 0; i < ATU_RX_LIST_CNT; i++) { | 2006 | for (i = 0; i < ATU_RX_LIST_CNT; i++) { | |
2007 | c = &sc->atu_cdata.atu_rx_chain[i]; | 2007 | c = &sc->atu_cdata.atu_rx_chain[i]; | |
2008 | 2008 | |||
2009 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, ATU_RX_BUFSZ, | 2009 | usbd_setup_xfer(c->atu_xfer, c, c->atu_buf, ATU_RX_BUFSZ, | |
2010 | USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, atu_rxeof); | 2010 | USBD_SHORT_XFER_OK, USBD_NO_TIMEOUT, atu_rxeof); | |
2011 | usbd_transfer(c->atu_xfer); | 2011 | usbd_transfer(c->atu_xfer); | |
2012 | } | 2012 | } | |
2013 | 2013 | |||
2014 | DPRINTFN(10, ("%s: starting up using MAC=%s\n", | 2014 | DPRINTFN(10, ("%s: starting up using MAC=%s\n", | |
2015 | device_xname(sc->atu_dev), ether_sprintf(ic->ic_myaddr))); | 2015 | device_xname(sc->atu_dev), ether_sprintf(ic->ic_myaddr))); | |
2016 | 2016 | |||
2017 | /* Do initial setup */ | 2017 | /* Do initial setup */ | |
2018 | err = atu_initial_config(sc); | 2018 | err = atu_initial_config(sc); | |
2019 | if (err) { | 2019 | if (err) { | |
2020 | DPRINTF(("%s: initial config failed!\n", | 2020 | DPRINTF(("%s: initial config failed!\n", | |
2021 | device_xname(sc->atu_dev))); | 2021 | device_xname(sc->atu_dev))); | |
2022 | splx(s); | 2022 | splx(s); | |
2023 | return EIO; | 2023 | return EIO; | |
2024 | } | 2024 | } | |
2025 | DPRINTFN(10, ("%s: initialised transceiver\n", | 2025 | DPRINTFN(10, ("%s: initialised transceiver\n", | |
2026 | device_xname(sc->atu_dev))); | 2026 | device_xname(sc->atu_dev))); | |
2027 | 2027 | |||
2028 | /* sc->atu_rxfilt = ATU_RXFILT_UNICAST|ATU_RXFILT_BROADCAST; */ | 2028 | /* sc->atu_rxfilt = ATU_RXFILT_UNICAST|ATU_RXFILT_BROADCAST; */ | |
2029 | 2029 | |||
2030 | /* If we want promiscuous mode, set the allframes bit. */ | 2030 | /* If we want promiscuous mode, set the allframes bit. */ | |
2031 | /* | 2031 | /* | |
2032 | if (ifp->if_flags & IFF_PROMISC) | 2032 | if (ifp->if_flags & IFF_PROMISC) | |
2033 | sc->atu_rxfilt |= ATU_RXFILT_PROMISC; | 2033 | sc->atu_rxfilt |= ATU_RXFILT_PROMISC; | |
2034 | */ | 2034 | */ | |
2035 | 2035 | |||
2036 | ifp->if_flags |= IFF_RUNNING; | 2036 | ifp->if_flags |= IFF_RUNNING; | |
2037 | ifp->if_flags &= ~IFF_OACTIVE; | 2037 | ifp->if_flags &= ~IFF_OACTIVE; | |
2038 | splx(s); | 2038 | splx(s); | |
2039 | 2039 | |||
2040 | /* XXX the following HAS to be replaced */ | 2040 | /* XXX the following HAS to be replaced */ | |
2041 | s = splnet(); | 2041 | s = splnet(); | |
2042 | err = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | 2042 | err = ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | |
2043 | if (err) { | 2043 | if (err) { | |
2044 | DPRINTFN(1, ("%s: atu_init: error calling " | 2044 | DPRINTFN(1, ("%s: atu_init: error calling " | |
2045 | "ieee80211_net_state", device_xname(sc->atu_dev))); | 2045 | "ieee80211_net_state", device_xname(sc->atu_dev))); | |
2046 | } | 2046 | } | |
2047 | splx(s); | 2047 | splx(s); | |
2048 | 2048 | |||
2049 | return 0; | 2049 | return 0; | |
2050 | } | 2050 | } | |
2051 | 2051 | |||
2052 | #if 0 && defined(ATU_DEBUG) /* XXX XXX XXX UNUSED */ | 2052 | #if 0 && defined(ATU_DEBUG) /* XXX XXX XXX UNUSED */ | |
2053 | static void atu_debug_print(struct atu_softc *); | 2053 | static void atu_debug_print(struct atu_softc *); | |
2054 | static void | 2054 | static void | |
2055 | atu_debug_print(struct atu_softc *sc) | 2055 | atu_debug_print(struct atu_softc *sc) | |
2056 | { | 2056 | { | |
2057 | usbd_status err; | 2057 | usbd_status err; | |
2058 | uint8_t tmp[32]; | 2058 | uint8_t tmp[32]; | |
2059 | 2059 | |||
2060 | /* DEBUG */ | 2060 | /* DEBUG */ | |
2061 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_BSSID, tmp))) | 2061 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_BSSID, tmp))) | |
2062 | return; | 2062 | return; | |
2063 | DPRINTF(("%s: DEBUG: current BSSID=%s\n", device_xname(sc->atu_dev), | 2063 | DPRINTF(("%s: DEBUG: current BSSID=%s\n", device_xname(sc->atu_dev), | |
2064 | ether_sprintf(tmp))); | 2064 | ether_sprintf(tmp))); | |
2065 | 2065 | |||
2066 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__BEACON_PERIOD, tmp))) | 2066 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__BEACON_PERIOD, tmp))) | |
2067 | return; | 2067 | return; | |
2068 | DPRINTF(("%s: DEBUG: beacon period=%d\n", device_xname(sc->atu_dev), | 2068 | DPRINTF(("%s: DEBUG: beacon period=%d\n", device_xname(sc->atu_dev), | |
2069 | tmp[0])); | 2069 | tmp[0])); | |
2070 | 2070 | |||
2071 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__PRIVACY_INVOKED, tmp))) | 2071 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__PRIVACY_INVOKED, tmp))) | |
2072 | return; | 2072 | return; | |
2073 | DPRINTF(("%s: DEBUG: privacy invoked=%d\n", device_xname(sc->atu_dev), | 2073 | DPRINTF(("%s: DEBUG: privacy invoked=%d\n", device_xname(sc->atu_dev), | |
2074 | tmp[0])); | 2074 | tmp[0])); | |
2075 | 2075 | |||
2076 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__ENCR_LEVEL, tmp))) | 2076 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__ENCR_LEVEL, tmp))) | |
2077 | return; | 2077 | return; | |
2078 | DPRINTF(("%s: DEBUG: encr_level=%d\n", device_xname(sc->atu_dev), | 2078 | DPRINTF(("%s: DEBUG: encr_level=%d\n", device_xname(sc->atu_dev), | |
2079 | tmp[0])); | 2079 | tmp[0])); | |
2080 | 2080 | |||
2081 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__ICV_ERROR_COUNT, tmp))) | 2081 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__ICV_ERROR_COUNT, tmp))) | |
2082 | return; | 2082 | return; | |
2083 | DPRINTF(("%s: DEBUG: icv error count=%d\n", device_xname(sc->atu_dev), | 2083 | DPRINTF(("%s: DEBUG: icv error count=%d\n", device_xname(sc->atu_dev), | |
2084 | *(short *)tmp)); | 2084 | *(short *)tmp)); | |
2085 | 2085 | |||
2086 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__EXCLUDED_COUNT, tmp))) | 2086 | if ((err = atu_get_mib(sc, MIB_MAC_WEP__EXCLUDED_COUNT, tmp))) | |
2087 | return; | 2087 | return; | |
2088 | DPRINTF(("%s: DEBUG: wep excluded count=%d\n", | 2088 | DPRINTF(("%s: DEBUG: wep excluded count=%d\n", | |
2089 | device_xname(sc->atu_dev), *(short *)tmp)); | 2089 | device_xname(sc->atu_dev), *(short *)tmp)); | |
2090 | 2090 | |||
2091 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__POWER_MODE, tmp))) | 2091 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__POWER_MODE, tmp))) | |
2092 | return; | 2092 | return; | |
2093 | DPRINTF(("%s: DEBUG: power mode=%d\n", device_xname(sc->atu_dev), | 2093 | DPRINTF(("%s: DEBUG: power mode=%d\n", device_xname(sc->atu_dev), | |
2094 | tmp[0])); | 2094 | tmp[0])); | |
2095 | 2095 | |||
2096 | if ((err = atu_get_mib(sc, MIB_PHY__CHANNEL, tmp))) | 2096 | if ((err = atu_get_mib(sc, MIB_PHY__CHANNEL, tmp))) | |
2097 | return; | 2097 | return; | |
2098 | DPRINTF(("%s: DEBUG: channel=%d\n", device_xname(sc->atu_dev), tmp[0])); | 2098 | DPRINTF(("%s: DEBUG: channel=%d\n", device_xname(sc->atu_dev), tmp[0])); | |
2099 | 2099 | |||
2100 | if ((err = atu_get_mib(sc, MIB_PHY__REG_DOMAIN, tmp))) | 2100 | if ((err = atu_get_mib(sc, MIB_PHY__REG_DOMAIN, tmp))) | |
2101 | return; | 2101 | return; | |
2102 | DPRINTF(("%s: DEBUG: reg domain=%d\n", device_xname(sc->atu_dev), | 2102 | DPRINTF(("%s: DEBUG: reg domain=%d\n", device_xname(sc->atu_dev), | |
2103 | tmp[0])); | 2103 | tmp[0])); | |
2104 | 2104 | |||
2105 | if ((err = atu_get_mib(sc, MIB_LOCAL__SSID_SIZE, tmp))) | 2105 | if ((err = atu_get_mib(sc, MIB_LOCAL__SSID_SIZE, tmp))) | |
2106 | return; | 2106 | return; | |
2107 | DPRINTF(("%s: DEBUG: ssid size=%d\n", device_xname(sc->atu_dev), | 2107 | DPRINTF(("%s: DEBUG: ssid size=%d\n", device_xname(sc->atu_dev), | |
2108 | tmp[0])); | 2108 | tmp[0])); | |
2109 | 2109 | |||
2110 | if ((err = atu_get_mib(sc, MIB_LOCAL__BEACON_ENABLE, tmp))) | 2110 | if ((err = atu_get_mib(sc, MIB_LOCAL__BEACON_ENABLE, tmp))) | |
2111 | return; | 2111 | return; | |
2112 | DPRINTF(("%s: DEBUG: beacon enable=%d\n", device_xname(sc->atu_dev), | 2112 | DPRINTF(("%s: DEBUG: beacon enable=%d\n", device_xname(sc->atu_dev), | |
2113 | tmp[0])); | 2113 | tmp[0])); | |
2114 | 2114 | |||
2115 | if ((err = atu_get_mib(sc, MIB_LOCAL__AUTO_RATE_FALLBACK, tmp))) | 2115 | if ((err = atu_get_mib(sc, MIB_LOCAL__AUTO_RATE_FALLBACK, tmp))) | |
2116 | return; | 2116 | return; | |
2117 | DPRINTF(("%s: DEBUG: auto rate fallback=%d\n", | 2117 | DPRINTF(("%s: DEBUG: auto rate fallback=%d\n", | |
2118 | device_xname(sc->atu_dev), tmp[0])); | 2118 | device_xname(sc->atu_dev), tmp[0])); | |
2119 | 2119 | |||
2120 | if ((err = atu_get_mib(sc, MIB_MAC_ADDR__ADDR, tmp))) | 2120 | if ((err = atu_get_mib(sc, MIB_MAC_ADDR__ADDR, tmp))) | |
2121 | return; | 2121 | return; | |
2122 | DPRINTF(("%s: DEBUG: mac addr=%s\n", device_xname(sc->atu_dev), | 2122 | DPRINTF(("%s: DEBUG: mac addr=%s\n", device_xname(sc->atu_dev), | |
2123 | ether_sprintf(tmp))); | 2123 | ether_sprintf(tmp))); | |
2124 | 2124 | |||
2125 | if ((err = atu_get_mib(sc, MIB_MAC__DESIRED_SSID, tmp))) | 2125 | if ((err = atu_get_mib(sc, MIB_MAC__DESIRED_SSID, tmp))) | |
2126 | return; | 2126 | return; | |
2127 | DPRINTF(("%s: DEBUG: desired ssid=%s\n", device_xname(sc->atu_dev), | 2127 | DPRINTF(("%s: DEBUG: desired ssid=%s\n", device_xname(sc->atu_dev), | |
2128 | tmp)); | 2128 | tmp)); | |
2129 | 2129 | |||
2130 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_ESSID, tmp))) | 2130 | if ((err = atu_get_mib(sc, MIB_MAC_MGMT__CURRENT_ESSID, tmp))) | |
2131 | return; | 2131 | return; | |
2132 | DPRINTF(("%s: DEBUG: current ESSID=%s\n", device_xname(sc->atu_dev), | 2132 | DPRINTF(("%s: DEBUG: current ESSID=%s\n", device_xname(sc->atu_dev), | |
2133 | tmp)); | 2133 | tmp)); | |
2134 | } | 2134 | } | |
2135 | #endif /* ATU_DEBUG */ | 2135 | #endif /* ATU_DEBUG */ | |
2136 | 2136 | |||
2137 | static int | 2137 | static int | |
2138 | atu_ioctl(struct ifnet *ifp, u_long command, void *data) | 2138 | atu_ioctl(struct ifnet *ifp, u_long command, void *data) | |
2139 | { | 2139 | { | |
2140 | struct atu_softc *sc = ifp->if_softc; | 2140 | struct atu_softc *sc = ifp->if_softc; | |
2141 | struct ifreq *ifr = (struct ifreq *)data; | |||
2142 | struct ieee80211com *ic = &sc->sc_ic; | 2141 | struct ieee80211com *ic = &sc->sc_ic; | |
2143 | int err = 0, s; | 2142 | int err = 0, s; | |
2144 | 2143 | |||
2145 | s = splnet(); | 2144 | s = splnet(); | |
2146 | switch (command) { | 2145 | switch (command) { | |
2147 | case SIOCSIFMEDIA: | |||
2148 | case SIOCGIFMEDIA: | |||
2149 | err = ifmedia_ioctl(ifp, ifr, &ic->ic_media, command); | |||
2150 | break; | |||
2151 | ||||
2152 | default: | 2146 | default: | |
2153 | DPRINTFN(15, ("%s: ieee80211_ioctl (%lu)\n", | 2147 | DPRINTFN(15, ("%s: ieee80211_ioctl (%lu)\n", | |
2154 | device_xname(sc->atu_dev), command)); | 2148 | device_xname(sc->atu_dev), command)); | |
2155 | err = ieee80211_ioctl(ic, command, data); | 2149 | err = ieee80211_ioctl(ic, command, data); | |
2156 | break; | 2150 | break; | |
2157 | } | 2151 | } | |
2158 | 2152 | |||
2159 | if (err == ENETRESET) { | 2153 | if (err == ENETRESET) { | |
2160 | if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) == | 2154 | if ((ifp->if_flags & (IFF_RUNNING|IFF_UP)) == | |
2161 | (IFF_RUNNING|IFF_UP)) { | 2155 | (IFF_RUNNING|IFF_UP)) { | |
2162 | DPRINTF(("%s: atu_ioctl(): netreset %lu\n", | 2156 | DPRINTF(("%s: atu_ioctl(): netreset %lu\n", | |
2163 | device_xname(sc->atu_dev), command)); | 2157 | device_xname(sc->atu_dev), command)); | |
2164 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | 2158 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | |
2165 | atu_initial_config(sc); | 2159 | atu_initial_config(sc); | |
2166 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | 2160 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); | |
2167 | } | 2161 | } | |
2168 | err = 0; | 2162 | err = 0; | |
2169 | } | 2163 | } | |
2170 | 2164 | |||
2171 | splx(s); | 2165 | splx(s); | |
2172 | return err; | 2166 | return err; | |
2173 | } | 2167 | } | |
2174 | 2168 | |||
2175 | static void | 2169 | static void | |
2176 | atu_watchdog(struct ifnet *ifp) | 2170 | atu_watchdog(struct ifnet *ifp) | |
2177 | { | 2171 | { | |
2178 | struct atu_softc *sc = ifp->if_softc; | 2172 | struct atu_softc *sc = ifp->if_softc; | |
2179 | struct atu_chain *c; | 2173 | struct atu_chain *c; | |
2180 | usbd_status stat; | 2174 | usbd_status stat; | |
2181 | int cnt, s; | 2175 | int cnt, s; | |
2182 | 2176 | |||
2183 | DPRINTF(("%s: atu_watchdog\n", device_xname(sc->atu_dev))); | 2177 | DPRINTF(("%s: atu_watchdog\n", device_xname(sc->atu_dev))); | |
2184 | 2178 | |||
2185 | ifp->if_timer = 0; | 2179 | ifp->if_timer = 0; | |
2186 | 2180 | |||
2187 | if (sc->sc_state != ATU_S_OK || (ifp->if_flags & IFF_RUNNING) == 0) | 2181 | if (sc->sc_state != ATU_S_OK || (ifp->if_flags & IFF_RUNNING) == 0) | |
2188 | return; | 2182 | return; | |
2189 | 2183 | |||
2190 | sc = ifp->if_softc; | 2184 | sc = ifp->if_softc; | |
2191 | s = splnet(); | 2185 | s = splnet(); | |
2192 | ifp->if_oerrors++; | 2186 | ifp->if_oerrors++; | |
2193 | DPRINTF(("%s: watchdog timeout\n", device_xname(sc->atu_dev))); | 2187 | DPRINTF(("%s: watchdog timeout\n", device_xname(sc->atu_dev))); | |
2194 | 2188 | |||
2195 | /* | 2189 | /* | |
2196 | * TODO: | 2190 | * TODO: | |
2197 | * we should change this since we have multiple TX tranfers... | 2191 | * we should change this since we have multiple TX tranfers... | |
2198 | */ | 2192 | */ | |
2199 | for (cnt = 0; cnt < ATU_TX_LIST_CNT; cnt++) { | 2193 | for (cnt = 0; cnt < ATU_TX_LIST_CNT; cnt++) { | |
2200 | c = &sc->atu_cdata.atu_tx_chain[cnt]; | 2194 | c = &sc->atu_cdata.atu_tx_chain[cnt]; | |
2201 | if (c->atu_in_xfer) { | 2195 | if (c->atu_in_xfer) { | |
2202 | usbd_get_xfer_status(c->atu_xfer, NULL, NULL, NULL, | 2196 | usbd_get_xfer_status(c->atu_xfer, NULL, NULL, NULL, | |
2203 | &stat); | 2197 | &stat); | |
2204 | atu_txeof(c->atu_xfer, c, stat); | 2198 | atu_txeof(c->atu_xfer, c, stat); | |
2205 | } | 2199 | } | |
2206 | } | 2200 | } | |
2207 | 2201 | |||
2208 | if (!IFQ_IS_EMPTY(&ifp->if_snd)) | 2202 | if (!IFQ_IS_EMPTY(&ifp->if_snd)) | |
2209 | atu_start(ifp); | 2203 | atu_start(ifp); | |
2210 | splx(s); | 2204 | splx(s); | |
2211 | 2205 | |||
2212 | ieee80211_watchdog(&sc->sc_ic); | 2206 | ieee80211_watchdog(&sc->sc_ic); | |
2213 | } | 2207 | } | |
2214 | 2208 | |||
2215 | /* | 2209 | /* | |
2216 | * Stop the adapter and free any mbufs allocated to the | 2210 | * Stop the adapter and free any mbufs allocated to the | |
2217 | * RX and TX lists. | 2211 | * RX and TX lists. | |
2218 | */ | 2212 | */ | |
2219 | static void | 2213 | static void | |
2220 | atu_stop(struct ifnet *ifp, int disable) | 2214 | atu_stop(struct ifnet *ifp, int disable) | |
2221 | { | 2215 | { | |
2222 | struct atu_softc *sc = ifp->if_softc; | 2216 | struct atu_softc *sc = ifp->if_softc; | |
2223 | struct ieee80211com *ic = &sc->sc_ic; | 2217 | struct ieee80211com *ic = &sc->sc_ic; | |
2224 | struct atu_cdata *cd; | 2218 | struct atu_cdata *cd; | |
2225 | usbd_status err; | 2219 | usbd_status err; | |
2226 | int s; | 2220 | int s; | |
2227 | 2221 | |||
2228 | s = splnet(); | 2222 | s = splnet(); | |
2229 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | 2223 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); | |
2230 | ifp->if_timer = 0; | 2224 | ifp->if_timer = 0; | |
2231 | 2225 | |||
2232 | usb_rem_task_wait(sc->atu_udev, &sc->sc_task, USB_TASKQ_DRIVER, NULL); | 2226 | usb_rem_task_wait(sc->atu_udev, &sc->sc_task, USB_TASKQ_DRIVER, NULL); | |
2233 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | 2227 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); | |
2234 | 2228 | |||
2235 | /* Stop transfers. */ | 2229 | /* Stop transfers. */ | |
2236 | if (sc->atu_ep[ATU_ENDPT_RX] != NULL) { | 2230 | if (sc->atu_ep[ATU_ENDPT_RX] != NULL) { | |
2237 | err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_RX]); | 2231 | err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_RX]); | |
2238 | if (err) { | 2232 | if (err) { | |
2239 | DPRINTF(("%s: abort rx pipe failed: %s\n", | 2233 | DPRINTF(("%s: abort rx pipe failed: %s\n", | |
2240 | device_xname(sc->atu_dev), usbd_errstr(err))); | 2234 | device_xname(sc->atu_dev), usbd_errstr(err))); | |
2241 | } | 2235 | } | |
2242 | } | 2236 | } | |
2243 | 2237 | |||
2244 | if (sc->atu_ep[ATU_ENDPT_TX] != NULL) { | 2238 | if (sc->atu_ep[ATU_ENDPT_TX] != NULL) { | |
2245 | err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_TX]); | 2239 | err = usbd_abort_pipe(sc->atu_ep[ATU_ENDPT_TX]); | |
2246 | if (err) { | 2240 | if (err) { | |
2247 | DPRINTF(("%s: abort tx pipe failed: %s\n", | 2241 | DPRINTF(("%s: abort tx pipe failed: %s\n", | |
2248 | device_xname(sc->atu_dev), usbd_errstr(err))); | 2242 | device_xname(sc->atu_dev), usbd_errstr(err))); | |
2249 | } | 2243 | } | |
2250 | } | 2244 | } | |
2251 | 2245 | |||
2252 | /* Free RX/TX/MGMT list resources. */ | 2246 | /* Free RX/TX/MGMT list resources. */ | |
2253 | cd = &sc->atu_cdata; | 2247 | cd = &sc->atu_cdata; | |
2254 | atu_xfer_list_free(sc, cd->atu_rx_chain, ATU_RX_LIST_CNT); | 2248 | atu_xfer_list_free(sc, cd->atu_rx_chain, ATU_RX_LIST_CNT); | |
2255 | atu_xfer_list_free(sc, cd->atu_tx_chain, ATU_TX_LIST_CNT); | 2249 | atu_xfer_list_free(sc, cd->atu_tx_chain, ATU_TX_LIST_CNT); | |
2256 | 2250 | |||
2257 | /* Close pipes */ | 2251 | /* Close pipes */ | |
2258 | if (sc->atu_ep[ATU_ENDPT_RX] != NULL) { | 2252 | if (sc->atu_ep[ATU_ENDPT_RX] != NULL) { | |
2259 | err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_RX]); | 2253 | err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_RX]); | |
2260 | if (err) { | 2254 | if (err) { | |
2261 | DPRINTF(("%s: close rx pipe failed: %s\n", | 2255 | DPRINTF(("%s: close rx pipe failed: %s\n", | |
2262 | device_xname(sc->atu_dev), usbd_errstr(err))); | 2256 | device_xname(sc->atu_dev), usbd_errstr(err))); | |
2263 | } | 2257 | } | |
2264 | sc->atu_ep[ATU_ENDPT_RX] = NULL; | 2258 | sc->atu_ep[ATU_ENDPT_RX] = NULL; | |
2265 | } | 2259 | } | |
2266 | 2260 | |||
2267 | if (sc->atu_ep[ATU_ENDPT_TX] != NULL) { | 2261 | if (sc->atu_ep[ATU_ENDPT_TX] != NULL) { | |
2268 | err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_TX]); | 2262 | err = usbd_close_pipe(sc->atu_ep[ATU_ENDPT_TX]); | |
2269 | if (err) { | 2263 | if (err) { | |
2270 | DPRINTF(("%s: close tx pipe failed: %s\n", | 2264 | DPRINTF(("%s: close tx pipe failed: %s\n", | |
2271 | device_xname(sc->atu_dev), usbd_errstr(err))); | 2265 | device_xname(sc->atu_dev), usbd_errstr(err))); | |
2272 | } | 2266 | } | |
2273 | sc->atu_ep[ATU_ENDPT_TX] = NULL; | 2267 | sc->atu_ep[ATU_ENDPT_TX] = NULL; | |
2274 | } | 2268 | } | |
2275 | 2269 | |||
2276 | /* Let's be nice and turn off the radio before we leave */ | 2270 | /* Let's be nice and turn off the radio before we leave */ | |
2277 | atu_switch_radio(sc, 0); | 2271 | atu_switch_radio(sc, 0); | |
2278 | 2272 | |||
2279 | splx(s); | 2273 | splx(s); | |
2280 | } | 2274 | } |