1 | /* $NetBSD: malo.c,v 1.8 2016/06/10 13:27:13 ozaki-r Exp $ */ |
2 | /* $OpenBSD: malo.c,v 1.92 2010/08/27 17:08:00 jsg Exp $ */ |
3 | |
4 | /* |
5 | * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org> |
6 | * Copyright (c) 2006 Marcus Glocker <mglocker@openbsd.org> |
7 | * |
8 | * Permission to use, copy, modify, and distribute this software for any |
9 | * purpose with or without fee is hereby granted, provided that the above |
10 | * copyright notice and this permission notice appear in all copies. |
11 | * |
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
13 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
14 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
15 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
16 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
17 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
18 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
19 | */ |
20 | |
21 | #include <sys/cdefs.h> |
22 | __KERNEL_RCSID(0, "$NetBSD: malo.c,v 1.8 2016/06/10 13:27:13 ozaki-r Exp $" ); |
23 | |
24 | #include <sys/param.h> |
25 | #include <sys/types.h> |
26 | |
27 | #include <sys/device.h> |
28 | #include <sys/kernel.h> |
29 | #include <sys/malloc.h> |
30 | #include <sys/mbuf.h> |
31 | #include <sys/proc.h> |
32 | #include <sys/socket.h> |
33 | #include <sys/sockio.h> |
34 | #include <sys/systm.h> |
35 | #include <sys/bus.h> |
36 | |
37 | #include <machine/endian.h> |
38 | #include <machine/intr.h> |
39 | |
40 | #include <net/if.h> |
41 | #include <net/if_media.h> |
42 | #include <net/if_ether.h> |
43 | |
44 | #include <net/bpf.h> |
45 | |
46 | #include <netinet/in.h> |
47 | #include <netinet/in_systm.h> |
48 | |
49 | #include <net80211/ieee80211_var.h> |
50 | #include <net80211/ieee80211_radiotap.h> |
51 | |
52 | #include <dev/firmload.h> |
53 | |
54 | #include <dev/ic/malovar.h> |
55 | #include <dev/ic/maloreg.h> |
56 | |
57 | #ifdef MALO_DEBUG |
58 | int malo_d = 2; |
59 | #define DPRINTF(l, x...) do { if ((l) <= malo_d) printf(x); } while (0) |
60 | #else |
61 | #define DPRINTF(l, x...) |
62 | #endif |
63 | |
64 | /* internal structures and defines */ |
65 | struct malo_node { |
66 | struct ieee80211_node ni; |
67 | }; |
68 | |
69 | struct malo_rx_data { |
70 | bus_dmamap_t map; |
71 | struct mbuf *m; |
72 | }; |
73 | |
74 | struct malo_tx_data { |
75 | bus_dmamap_t map; |
76 | struct mbuf *m; |
77 | uint32_t softstat; |
78 | struct ieee80211_node *ni; |
79 | }; |
80 | |
81 | /* RX descriptor used by HW */ |
82 | struct malo_rx_desc { |
83 | uint8_t rxctrl; |
84 | uint8_t ; |
85 | uint8_t status; |
86 | uint8_t channel; |
87 | uint16_t len; |
88 | uint8_t reserved1; /* actually unused */ |
89 | uint8_t datarate; |
90 | uint32_t physdata; /* DMA address of data */ |
91 | uint32_t physnext; /* DMA address of next control block */ |
92 | uint16_t qosctrl; |
93 | uint16_t reserved2; |
94 | } __packed; |
95 | |
96 | /* TX descriptor used by HW */ |
97 | struct malo_tx_desc { |
98 | uint32_t status; |
99 | #define MALO_TXD_STATUS_IDLE 0x00000000 |
100 | #define MALO_TXD_STATUS_USED 0x00000001 |
101 | #define MALO_TXD_STATUS_OK 0x00000001 |
102 | #define MALO_TXD_STATUS_OK_RETRY 0x00000002 |
103 | #define MALO_TXD_STATUS_OK_MORE_RETRY 0x00000004 |
104 | #define MALO_TXD_STATUS_MULTICAST_TX 0x00000008 |
105 | #define MALO_TXD_STATUS_BROADCAST_TX 0x00000010 |
106 | #define MALO_TXD_STATUS_FAILED_LINK_ERROR 0x00000020 |
107 | #define MALO_TXD_STATUS_FAILED_EXCEED_LIMIT 0x00000040 |
108 | #define MALO_TXD_STATUS_FAILED_XRETRY MALO_TXD_STATUS_FAILED_EXCEED_LIMIT |
109 | #define MALO_TXD_STATUS_FAILED_AGING 0x00000080 |
110 | #define MALO_TXD_STATUS_FW_OWNED 0x80000000 |
111 | uint8_t datarate; |
112 | uint8_t txpriority; |
113 | uint16_t qosctrl; |
114 | uint32_t physdata; /* DMA address of data */ |
115 | uint16_t len; |
116 | uint8_t destaddr[6]; |
117 | uint32_t physnext; /* DMA address of next control block */ |
118 | uint32_t reserved1; /* SAP packet info ??? */ |
119 | uint32_t reserved2; |
120 | } __packed; |
121 | |
122 | #define MALO_RX_RING_COUNT 256 |
123 | #define MALO_TX_RING_COUNT 256 |
124 | #define MALO_MAX_SCATTER 8 /* XXX unknown, wild guess */ |
125 | #define MALO_CMD_TIMEOUT 50 /* MALO_CMD_TIMEOUT * 100us */ |
126 | |
127 | /* |
128 | * Firmware commands |
129 | */ |
130 | #define MALO_CMD_GET_HW_SPEC 0x0003 |
131 | #define MALO_CMD_SET_RADIO 0x001c |
132 | #define MALO_CMD_SET_AID 0x010d |
133 | #define MALO_CMD_SET_TXPOWER 0x001e |
134 | #define MALO_CMD_SET_ANTENNA 0x0020 |
135 | #define MALO_CMD_SET_PRESCAN 0x0107 |
136 | #define MALO_CMD_SET_POSTSCAN 0x0108 |
137 | #define MALO_CMD_SET_RATE 0x0110 |
138 | #define MALO_CMD_SET_CHANNEL 0x010a |
139 | #define MALO_CMD_SET_RTS 0x0113 |
140 | #define MALO_CMD_SET_SLOT 0x0114 |
141 | #define MALO_CMD_RESPONSE 0x8000 |
142 | |
143 | #define MALO_CMD_RESULT_OK 0x0000 /* everything is fine */ |
144 | #define MALO_CMD_RESULT_ERROR 0x0001 /* general error */ |
145 | #define MALO_CMD_RESULT_NOSUPPORT 0x0002 /* command not valid */ |
146 | #define MALO_CMD_RESULT_PENDING 0x0003 /* will be processed */ |
147 | #define MALO_CMD_RESULT_BUSY 0x0004 /* command ignored */ |
148 | #define MALO_CMD_RESULT_PARTIALDATA 0x0005 /* buffer too small */ |
149 | |
150 | struct { |
151 | uint16_t ; |
152 | uint16_t ; /* size of the command, incl. header */ |
153 | uint16_t ; /* seems not to matter that much */ |
154 | uint16_t ; /* set to 0 on request */ |
155 | /* following the data payload, up to 256 bytes */ |
156 | }; |
157 | |
158 | struct malo_hw_spec { |
159 | uint16_t HwVersion; |
160 | uint16_t NumOfWCB; |
161 | uint16_t NumOfMCastAdr; |
162 | uint8_t PermanentAddress[6]; |
163 | uint16_t RegionCode; |
164 | uint16_t NumberOfAntenna; |
165 | uint32_t FWReleaseNumber; |
166 | uint32_t WcbBase0; |
167 | uint32_t RxPdWrPtr; |
168 | uint32_t RxPdRdPtr; |
169 | uint32_t CookiePtr; |
170 | uint32_t WcbBase1; |
171 | uint32_t WcbBase2; |
172 | uint32_t WcbBase3; |
173 | } __packed; |
174 | |
175 | struct malo_cmd_radio { |
176 | uint16_t action; |
177 | uint16_t preamble_mode; |
178 | uint16_t enable; |
179 | } __packed; |
180 | |
181 | struct malo_cmd_aid { |
182 | uint16_t associd; |
183 | uint8_t macaddr[6]; |
184 | uint32_t gprotection; |
185 | uint8_t aprates[14]; |
186 | } __packed; |
187 | |
188 | struct malo_cmd_txpower { |
189 | uint16_t action; |
190 | uint16_t supportpowerlvl; |
191 | uint16_t currentpowerlvl; |
192 | uint16_t reserved; |
193 | uint16_t powerlvllist[8]; |
194 | } __packed; |
195 | |
196 | struct malo_cmd_antenna { |
197 | uint16_t action; |
198 | uint16_t mode; |
199 | } __packed; |
200 | |
201 | struct malo_cmd_postscan { |
202 | uint32_t isibss; |
203 | uint8_t bssid[6]; |
204 | } __packed; |
205 | |
206 | struct malo_cmd_channel { |
207 | uint16_t action; |
208 | uint8_t channel; |
209 | } __packed; |
210 | |
211 | struct malo_cmd_rate { |
212 | uint8_t dataratetype; |
213 | uint8_t rateindex; |
214 | uint8_t aprates[14]; |
215 | } __packed; |
216 | |
217 | struct malo_cmd_rts { |
218 | uint16_t action; |
219 | uint32_t threshold; |
220 | } __packed; |
221 | |
222 | struct malo_cmd_slot { |
223 | uint16_t action; |
224 | uint8_t slot; |
225 | } __packed; |
226 | |
227 | #define malo_mem_write4(sc, off, x) \ |
228 | bus_space_write_4((sc)->sc_mem1_bt, (sc)->sc_mem1_bh, (off), (x)) |
229 | #define malo_mem_write2(sc, off, x) \ |
230 | bus_space_write_2((sc)->sc_mem1_bt, (sc)->sc_mem1_bh, (off), (x)) |
231 | #define malo_mem_write1(sc, off, x) \ |
232 | bus_space_write_1((sc)->sc_mem1_bt, (sc)->sc_mem1_bh, (off), (x)) |
233 | |
234 | #define malo_mem_read4(sc, off) \ |
235 | bus_space_read_4((sc)->sc_mem1_bt, (sc)->sc_mem1_bh, (off)) |
236 | #define malo_mem_read1(sc, off) \ |
237 | bus_space_read_1((sc)->sc_mem1_bt, (sc)->sc_mem1_bh, (off)) |
238 | |
239 | #define malo_ctl_write4(sc, off, x) \ |
240 | bus_space_write_4((sc)->sc_mem2_bt, (sc)->sc_mem2_bh, (off), (x)) |
241 | #define malo_ctl_read4(sc, off) \ |
242 | bus_space_read_4((sc)->sc_mem2_bt, (sc)->sc_mem2_bh, (off)) |
243 | #define malo_ctl_read1(sc, off) \ |
244 | bus_space_read_1((sc)->sc_mem2_bt, (sc)->sc_mem2_bh, (off)) |
245 | |
246 | #define malo_ctl_barrier(sc, t) \ |
247 | bus_space_barrier((sc)->sc_mem2_bt, (sc)->sc_mem2_bh, 0x0c00, 0xff, (t)) |
248 | |
249 | static int malo_alloc_cmd(struct malo_softc *sc); |
250 | static void malo_free_cmd(struct malo_softc *sc); |
251 | static void malo_send_cmd(struct malo_softc *sc, bus_addr_t addr); |
252 | static int malo_send_cmd_dma(struct malo_softc *sc, bus_addr_t addr); |
253 | static int malo_alloc_rx_ring(struct malo_softc *sc, struct malo_rx_ring *ring, |
254 | int count); |
255 | static void malo_reset_rx_ring(struct malo_softc *sc, struct malo_rx_ring *ring); |
256 | static void malo_free_rx_ring(struct malo_softc *sc, struct malo_rx_ring *ring); |
257 | static int malo_alloc_tx_ring(struct malo_softc *sc, struct malo_tx_ring *ring, |
258 | int count); |
259 | static void malo_reset_tx_ring(struct malo_softc *sc, struct malo_tx_ring *ring); |
260 | static void malo_free_tx_ring(struct malo_softc *sc, struct malo_tx_ring *ring); |
261 | static int malo_ioctl(struct ifnet *ifp, u_long cmd, void* data); |
262 | static void malo_start(struct ifnet *ifp); |
263 | static void malo_watchdog(struct ifnet *ifp); |
264 | static int malo_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, |
265 | int arg); |
266 | static void malo_newassoc(struct ieee80211_node *ni, int isnew); |
267 | static struct ieee80211_node * |
268 | malo_node_alloc(struct ieee80211_node_table *nt); |
269 | static int malo_media_change(struct ifnet *ifp); |
270 | static void malo_media_status(struct ifnet *ifp, struct ifmediareq *imr); |
271 | static int malo_chip2rate(int chip_rate); |
272 | static int malo_fix2rate(int fix_rate); |
273 | static void malo_next_scan(void *arg); |
274 | static void malo_tx_intr(struct malo_softc *sc); |
275 | static int malo_tx_data(struct malo_softc *sc, struct mbuf *m0, |
276 | struct ieee80211_node *ni); |
277 | static void malo_tx_setup_desc(struct malo_softc *sc, struct malo_tx_desc *desc, |
278 | int len, int rate, const bus_dma_segment_t *segs, int nsegs); |
279 | static void malo_rx_intr(struct malo_softc *sc); |
280 | static int malo_load_bootimg(struct malo_softc *sc); |
281 | static int malo_load_firmware(struct malo_softc *sc); |
282 | |
283 | static int malo_set_slot(struct malo_softc *sc); |
284 | static void malo_update_slot(struct ifnet* ifp); |
285 | #ifdef MALO_DEBUG |
286 | static void malo_hexdump(void *buf, int len); |
287 | #endif |
288 | static const char *malo_cmd_string(uint16_t cmd); |
289 | static const char *malo_cmd_string_result(uint16_t result); |
290 | static int malo_cmd_get_spec(struct malo_softc *sc); |
291 | static int malo_cmd_set_prescan(struct malo_softc *sc); |
292 | static int malo_cmd_set_postscan(struct malo_softc *sc, uint8_t *macaddr, |
293 | uint8_t ibsson); |
294 | static int malo_cmd_set_channel(struct malo_softc *sc, struct ieee80211_channel *chan); |
295 | static int malo_cmd_set_antenna(struct malo_softc *sc, uint16_t antenna_type); |
296 | static int malo_cmd_set_radio(struct malo_softc *sc, uint16_t mode, |
297 | uint16_t preamble); |
298 | static int malo_cmd_set_aid(struct malo_softc *sc, uint8_t *bssid, |
299 | uint16_t associd); |
300 | static int malo_cmd_set_txpower(struct malo_softc *sc, unsigned int powerlevel); |
301 | static int malo_cmd_set_rts(struct malo_softc *sc, uint32_t threshold); |
302 | static int malo_cmd_set_slot(struct malo_softc *sc, uint8_t slot); |
303 | static int malo_cmd_set_rate(struct malo_softc *sc, uint8_t rate); |
304 | static void malo_cmd_response(struct malo_softc *sc); |
305 | |
306 | int |
307 | malo_intr(void *arg) |
308 | { |
309 | struct malo_softc *sc = arg; |
310 | uint32_t status; |
311 | |
312 | status = malo_ctl_read4(sc, MALO_REG_A2H_INTERRUPT_CAUSE); |
313 | if (status == 0xffffffff || status == 0) |
314 | /* not for us */ |
315 | return (0); |
316 | |
317 | if (status & MALO_A2HRIC_BIT_TX_DONE) |
318 | malo_tx_intr(sc); |
319 | if (status & MALO_A2HRIC_BIT_RX_RDY) |
320 | malo_rx_intr(sc); |
321 | if (status & MALO_A2HRIC_BIT_OPC_DONE) { |
322 | /* XXX cmd done interrupt handling doesn't work yet */ |
323 | DPRINTF(1, "%s: got cmd done interrupt\n" , device_xname(sc->sc_dev)); |
324 | //malo_cmd_response(sc); |
325 | } |
326 | |
327 | if (status & ~0x7) { |
328 | DPRINTF(1, "%s: unknown interrupt %x\n" , |
329 | device_xname(sc->sc_dev), status); |
330 | } |
331 | |
332 | /* just ack the interrupt */ |
333 | malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_CAUSE, 0); |
334 | |
335 | return (1); |
336 | } |
337 | |
338 | int |
339 | malo_attach(struct malo_softc *sc) |
340 | { |
341 | struct ieee80211com *ic = &sc->sc_ic; |
342 | struct ifnet *ifp = &sc->sc_if; |
343 | int i; |
344 | |
345 | /* initialize channel scanning timer */ |
346 | callout_init(&sc->sc_scan_to, 0); |
347 | callout_setfunc(&sc->sc_scan_to, malo_next_scan, sc); |
348 | |
349 | /* allocate DMA structures */ |
350 | malo_alloc_cmd(sc); |
351 | malo_alloc_rx_ring(sc, &sc->sc_rxring, MALO_RX_RING_COUNT); |
352 | malo_alloc_tx_ring(sc, &sc->sc_txring, MALO_TX_RING_COUNT); |
353 | |
354 | /* setup interface */ |
355 | ifp->if_softc = sc; |
356 | ifp->if_init = malo_init; |
357 | ifp->if_stop = malo_stop; |
358 | ifp->if_ioctl = malo_ioctl; |
359 | ifp->if_start = malo_start; |
360 | ifp->if_watchdog = malo_watchdog; |
361 | ifp->if_flags = IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST; |
362 | memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ); |
363 | IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN); |
364 | IFQ_SET_READY(&ifp->if_snd); |
365 | |
366 | /* set supported rates */ |
367 | ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; |
368 | ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g; |
369 | sc->sc_last_txrate = -1; |
370 | |
371 | /* set channels */ |
372 | for (i = 1; i <= 14; i++) { |
373 | ic->ic_channels[i].ic_freq = |
374 | ieee80211_ieee2mhz(i, IEEE80211_CHAN_2GHZ); |
375 | ic->ic_channels[i].ic_flags = |
376 | IEEE80211_CHAN_CCK | IEEE80211_CHAN_OFDM | |
377 | IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ; |
378 | } |
379 | |
380 | /* OpenBSD supports IEEE80211_C_RSN too */ |
381 | /* set the rest */ |
382 | ic->ic_ifp = ifp; |
383 | ic->ic_caps = |
384 | IEEE80211_C_IBSS | |
385 | IEEE80211_C_MONITOR | |
386 | IEEE80211_C_SHPREAMBLE | |
387 | IEEE80211_C_SHSLOT | |
388 | IEEE80211_C_WEP | |
389 | IEEE80211_C_WPA; |
390 | ic->ic_opmode = IEEE80211_M_STA; |
391 | ic->ic_state = IEEE80211_S_INIT; |
392 | for (i = 0; i < 6; i++) |
393 | ic->ic_myaddr[i] = malo_ctl_read1(sc, 0xa528 + i); |
394 | |
395 | /* show our mac address */ |
396 | aprint_normal(", address %s\n" , ether_sprintf(ic->ic_myaddr)); |
397 | |
398 | /* attach interface */ |
399 | if_attach(ifp); |
400 | ieee80211_ifattach(ic); |
401 | |
402 | /* post attach vector functions */ |
403 | sc->sc_newstate = ic->ic_newstate; |
404 | ic->ic_newstate = malo_newstate; |
405 | ic->ic_newassoc = malo_newassoc; |
406 | ic->ic_node_alloc = malo_node_alloc; |
407 | ic->ic_updateslot = malo_update_slot; |
408 | |
409 | ieee80211_media_init(ic, malo_media_change, malo_media_status); |
410 | |
411 | bpf_attach2(ifp, DLT_IEEE802_11_RADIO, |
412 | sizeof(struct ieee80211_frame) + IEEE80211_RADIOTAP_HDRLEN, |
413 | &sc->sc_drvbpf); |
414 | |
415 | sc->sc_rxtap_len = sizeof(sc->sc_rxtapu); |
416 | sc->sc_rxtap.wr_ihdr.it_len = htole16(sc->sc_rxtap_len); |
417 | sc->sc_rxtap.wr_ihdr.it_present = htole32(MALO_RX_RADIOTAP_PRESENT); |
418 | |
419 | sc->sc_txtap_len = sizeof(sc->sc_txtapu); |
420 | sc->sc_txtap.wt_ihdr.it_len = htole16(sc->sc_txtap_len); |
421 | sc->sc_txtap.wt_ihdr.it_present = htole32(MALO_TX_RADIOTAP_PRESENT); |
422 | |
423 | ieee80211_announce(ic); |
424 | |
425 | return (0); |
426 | } |
427 | |
428 | int |
429 | malo_detach(void *arg) |
430 | { |
431 | struct malo_softc *sc = arg; |
432 | struct ieee80211com *ic = &sc->sc_ic; |
433 | struct ifnet *ifp = &sc->sc_if; |
434 | |
435 | /* remove channel scanning timer */ |
436 | callout_stop(&sc->sc_scan_to); |
437 | |
438 | malo_stop(ifp, 1); |
439 | ieee80211_ifdetach(ic); |
440 | if_detach(ifp); |
441 | malo_free_cmd(sc); |
442 | malo_free_rx_ring(sc, &sc->sc_rxring); |
443 | malo_free_tx_ring(sc, &sc->sc_txring); |
444 | |
445 | return (0); |
446 | } |
447 | |
448 | static int |
449 | malo_alloc_cmd(struct malo_softc *sc) |
450 | { |
451 | int error, nsegs; |
452 | |
453 | error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, |
454 | PAGE_SIZE, 0, BUS_DMA_ALLOCNOW, &sc->sc_cmd_dmam); |
455 | if (error != 0) { |
456 | aprint_error_dev(sc->sc_dev, "can not create DMA tag\n" ); |
457 | return (-1); |
458 | } |
459 | |
460 | error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, |
461 | 0, &sc->sc_cmd_dmas, 1, &nsegs, BUS_DMA_WAITOK); |
462 | if (error != 0) { |
463 | aprint_error_dev(sc->sc_dev, "error alloc dma memory\n" ); |
464 | return (-1); |
465 | } |
466 | |
467 | error = bus_dmamem_map(sc->sc_dmat, &sc->sc_cmd_dmas, nsegs, |
468 | PAGE_SIZE, (void **)&sc->sc_cmd_mem, BUS_DMA_WAITOK); |
469 | if (error != 0) { |
470 | aprint_error_dev(sc->sc_dev, "error map dma memory\n" ); |
471 | return (-1); |
472 | } |
473 | |
474 | error = bus_dmamap_load(sc->sc_dmat, sc->sc_cmd_dmam, |
475 | sc->sc_cmd_mem, PAGE_SIZE, NULL, BUS_DMA_NOWAIT); |
476 | if (error != 0) { |
477 | aprint_error_dev(sc->sc_dev, "error load dma memory\n" ); |
478 | bus_dmamem_free(sc->sc_dmat, &sc->sc_cmd_dmas, nsegs); |
479 | return (-1); |
480 | } |
481 | |
482 | sc->sc_cookie = sc->sc_cmd_mem; |
483 | *sc->sc_cookie = htole32(0xaa55aa55); |
484 | sc->sc_cmd_mem = ((char*)sc->sc_cmd_mem) + sizeof(uint32_t); |
485 | sc->sc_cookie_dmaaddr = sc->sc_cmd_dmam->dm_segs[0].ds_addr; |
486 | sc->sc_cmd_dmaaddr = sc->sc_cmd_dmam->dm_segs[0].ds_addr + |
487 | sizeof(uint32_t); |
488 | |
489 | return (0); |
490 | } |
491 | |
492 | static void |
493 | malo_free_cmd(struct malo_softc *sc) |
494 | { |
495 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
496 | BUS_DMASYNC_POSTWRITE); |
497 | bus_dmamap_unload(sc->sc_dmat, sc->sc_cmd_dmam); |
498 | bus_dmamem_unmap(sc->sc_dmat, sc->sc_cookie, PAGE_SIZE); |
499 | bus_dmamem_free(sc->sc_dmat, &sc->sc_cmd_dmas, 1); |
500 | } |
501 | |
502 | static void |
503 | malo_send_cmd(struct malo_softc *sc, bus_addr_t addr) |
504 | { |
505 | malo_ctl_write4(sc, MALO_REG_GEN_PTR, (uint32_t)addr); |
506 | malo_ctl_barrier(sc, BUS_SPACE_BARRIER_WRITE); |
507 | malo_ctl_write4(sc, MALO_REG_H2A_INTERRUPT_EVENTS, 2); /* CPU_TRANSFER_CMD */ |
508 | malo_ctl_barrier(sc, BUS_SPACE_BARRIER_WRITE); |
509 | } |
510 | |
511 | static int |
512 | malo_send_cmd_dma(struct malo_softc *sc, bus_addr_t addr) |
513 | { |
514 | int i; |
515 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
516 | |
517 | malo_send_cmd(sc, addr); |
518 | |
519 | for (i = 0; i < MALO_CMD_TIMEOUT; i++) { |
520 | delay(100); |
521 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
522 | BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); |
523 | if (hdr->cmd & htole16(0x8000)) |
524 | break; |
525 | } |
526 | if (i == MALO_CMD_TIMEOUT) { |
527 | aprint_error_dev(sc->sc_dev, "timeout while waiting for cmd response!\n" ); |
528 | return (ETIMEDOUT); |
529 | } |
530 | |
531 | malo_cmd_response(sc); |
532 | |
533 | return (0); |
534 | } |
535 | |
536 | static int |
537 | malo_alloc_rx_ring(struct malo_softc *sc, struct malo_rx_ring *ring, int count) |
538 | { |
539 | struct malo_rx_desc *desc; |
540 | struct malo_rx_data *data; |
541 | int i, nsegs, error; |
542 | |
543 | ring->count = count; |
544 | ring->cur = ring->next = 0; |
545 | |
546 | error = bus_dmamap_create(sc->sc_dmat, |
547 | count * sizeof(struct malo_rx_desc), 1, |
548 | count * sizeof(struct malo_rx_desc), 0, |
549 | BUS_DMA_NOWAIT, &ring->map); |
550 | if (error != 0) { |
551 | aprint_error_dev(sc->sc_dev, "could not create desc DMA map\n" ); |
552 | goto fail; |
553 | } |
554 | |
555 | error = bus_dmamem_alloc(sc->sc_dmat, |
556 | count * sizeof(struct malo_rx_desc), |
557 | PAGE_SIZE, 0, &ring->seg, 1, &nsegs, BUS_DMA_NOWAIT); |
558 | |
559 | if (error != 0) { |
560 | aprint_error_dev(sc->sc_dev, "could not allocate DMA memory\n" ); |
561 | goto fail; |
562 | } |
563 | |
564 | error = bus_dmamem_map(sc->sc_dmat, &ring->seg, nsegs, |
565 | count * sizeof(struct malo_rx_desc), (void **)&ring->desc, |
566 | BUS_DMA_NOWAIT); |
567 | if (error != 0) { |
568 | aprint_error_dev(sc->sc_dev, "can't map desc DMA memory\n" ); |
569 | goto fail; |
570 | } |
571 | |
572 | error = bus_dmamap_load(sc->sc_dmat, ring->map, ring->desc, |
573 | count * sizeof(struct malo_rx_desc), NULL, BUS_DMA_NOWAIT); |
574 | if (error != 0) { |
575 | aprint_error_dev(sc->sc_dev, "could not load desc DMA map\n" ); |
576 | goto fail; |
577 | } |
578 | |
579 | ring->physaddr = ring->map->dm_segs->ds_addr; |
580 | |
581 | ring->data = malloc(count * sizeof (struct malo_rx_data), M_DEVBUF, |
582 | M_NOWAIT); |
583 | if (ring->data == NULL) { |
584 | aprint_error_dev(sc->sc_dev, "could not allocate soft data\n" ); |
585 | error = ENOMEM; |
586 | goto fail; |
587 | } |
588 | |
589 | /* |
590 | * Pre-allocate Rx buffers and populate Rx ring. |
591 | */ |
592 | memset(ring->data, 0, count * sizeof (struct malo_rx_data)); |
593 | for (i = 0; i < count; i++) { |
594 | desc = &ring->desc[i]; |
595 | data = &ring->data[i]; |
596 | |
597 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, |
598 | 0, BUS_DMA_NOWAIT, &data->map); |
599 | if (error != 0) { |
600 | aprint_error_dev(sc->sc_dev, "could not create DMA map\n" ); |
601 | goto fail; |
602 | } |
603 | |
604 | MGETHDR(data->m, M_DONTWAIT, MT_DATA); |
605 | if (data->m == NULL) { |
606 | aprint_error_dev(sc->sc_dev, "could not allocate rx mbuf\n" ); |
607 | error = ENOMEM; |
608 | goto fail; |
609 | } |
610 | |
611 | MCLGET(data->m, M_DONTWAIT); |
612 | if (!(data->m->m_flags & M_EXT)) { |
613 | aprint_error_dev(sc->sc_dev, "could not allocate rx mbuf cluster\n" ); |
614 | error = ENOMEM; |
615 | goto fail; |
616 | } |
617 | |
618 | error = bus_dmamap_load(sc->sc_dmat, data->map, |
619 | mtod(data->m, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); |
620 | if (error != 0) { |
621 | aprint_error_dev(sc->sc_dev, "could not load rx buf DMA map" ); |
622 | goto fail; |
623 | } |
624 | |
625 | desc->status = 1; |
626 | desc->physdata = htole32(data->map->dm_segs->ds_addr); |
627 | desc->physnext = htole32(ring->physaddr + |
628 | (i + 1) % count * sizeof(struct malo_rx_desc)); |
629 | } |
630 | |
631 | bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize, |
632 | BUS_DMASYNC_PREWRITE); |
633 | |
634 | return (0); |
635 | |
636 | fail: malo_free_rx_ring(sc, ring); |
637 | return (error); |
638 | } |
639 | |
640 | static void |
641 | malo_reset_rx_ring(struct malo_softc *sc, struct malo_rx_ring *ring) |
642 | { |
643 | int i; |
644 | |
645 | for (i = 0; i < ring->count; i++) |
646 | ring->desc[i].status = 0; |
647 | |
648 | bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize, |
649 | BUS_DMASYNC_PREWRITE); |
650 | |
651 | ring->cur = ring->next = 0; |
652 | } |
653 | |
654 | static void |
655 | malo_free_rx_ring(struct malo_softc *sc, struct malo_rx_ring *ring) |
656 | { |
657 | struct malo_rx_data *data; |
658 | int i; |
659 | |
660 | if (ring->desc != NULL) { |
661 | bus_dmamap_sync(sc->sc_dmat, ring->map, 0, |
662 | ring->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); |
663 | bus_dmamap_unload(sc->sc_dmat, ring->map); |
664 | bus_dmamem_unmap(sc->sc_dmat, ring->desc, |
665 | ring->count * sizeof(struct malo_rx_desc)); |
666 | bus_dmamem_free(sc->sc_dmat, &ring->seg, 1); |
667 | } |
668 | |
669 | if (ring->data != NULL) { |
670 | for (i = 0; i < ring->count; i++) { |
671 | data = &ring->data[i]; |
672 | |
673 | if (data->m != NULL) { |
674 | bus_dmamap_sync(sc->sc_dmat, data->map, 0, |
675 | data->map->dm_mapsize, |
676 | BUS_DMASYNC_POSTREAD); |
677 | bus_dmamap_unload(sc->sc_dmat, data->map); |
678 | m_freem(data->m); |
679 | } |
680 | |
681 | if (data->map != NULL) |
682 | bus_dmamap_destroy(sc->sc_dmat, data->map); |
683 | } |
684 | free(ring->data, M_DEVBUF); |
685 | } |
686 | } |
687 | |
688 | static int |
689 | malo_alloc_tx_ring(struct malo_softc *sc, struct malo_tx_ring *ring, |
690 | int count) |
691 | { |
692 | int i, nsegs, error; |
693 | |
694 | ring->count = count; |
695 | ring->queued = 0; |
696 | ring->cur = ring->next = ring->stat = 0; |
697 | |
698 | error = bus_dmamap_create(sc->sc_dmat, |
699 | count * sizeof(struct malo_tx_desc), 1, |
700 | count * sizeof(struct malo_tx_desc), 0, BUS_DMA_NOWAIT, &ring->map); |
701 | if (error != 0) { |
702 | aprint_error_dev(sc->sc_dev, "could not create desc DMA map\n" ); |
703 | goto fail; |
704 | } |
705 | |
706 | error = bus_dmamem_alloc(sc->sc_dmat, |
707 | count * sizeof(struct malo_tx_desc), PAGE_SIZE, 0, |
708 | &ring->seg, 1, &nsegs, BUS_DMA_NOWAIT); |
709 | if (error != 0) { |
710 | aprint_error_dev(sc->sc_dev, "could not allocate DMA memory\n" ); |
711 | goto fail; |
712 | } |
713 | |
714 | error = bus_dmamem_map(sc->sc_dmat, &ring->seg, nsegs, |
715 | count * sizeof(struct malo_tx_desc), (void **)&ring->desc, |
716 | BUS_DMA_NOWAIT); |
717 | if (error != 0) { |
718 | aprint_error_dev(sc->sc_dev, "can't map desc DMA memory\n" ); |
719 | goto fail; |
720 | } |
721 | |
722 | error = bus_dmamap_load(sc->sc_dmat, ring->map, ring->desc, |
723 | count * sizeof(struct malo_tx_desc), NULL, BUS_DMA_NOWAIT); |
724 | if (error != 0) { |
725 | aprint_error_dev(sc->sc_dev, "could not load desc DMA map\n" ); |
726 | goto fail; |
727 | } |
728 | |
729 | ring->physaddr = ring->map->dm_segs->ds_addr; |
730 | |
731 | ring->data = malloc(count * sizeof(struct malo_tx_data), M_DEVBUF, |
732 | M_NOWAIT); |
733 | if (ring->data == NULL) { |
734 | aprint_error_dev(sc->sc_dev, "could not allocate soft data\n" ); |
735 | error = ENOMEM; |
736 | goto fail; |
737 | } |
738 | |
739 | memset(ring->data, 0, count * sizeof(struct malo_tx_data)); |
740 | for (i = 0; i < count; i++) { |
741 | error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, |
742 | MALO_MAX_SCATTER, MCLBYTES, 0, BUS_DMA_NOWAIT, |
743 | &ring->data[i].map); |
744 | if (error != 0) { |
745 | aprint_error_dev(sc->sc_dev, "could not create DMA map\n" ); |
746 | goto fail; |
747 | } |
748 | ring->desc[i].physnext = htole32(ring->physaddr + |
749 | (i + 1) % count * sizeof(struct malo_tx_desc)); |
750 | } |
751 | |
752 | return (0); |
753 | |
754 | fail: malo_free_tx_ring(sc, ring); |
755 | return (error); |
756 | } |
757 | |
758 | static void |
759 | malo_reset_tx_ring(struct malo_softc *sc, struct malo_tx_ring *ring) |
760 | { |
761 | struct malo_tx_desc *desc; |
762 | struct malo_tx_data *data; |
763 | int i; |
764 | |
765 | for (i = 0; i < ring->count; i++) { |
766 | desc = &ring->desc[i]; |
767 | data = &ring->data[i]; |
768 | |
769 | if (data->m != NULL) { |
770 | bus_dmamap_sync(sc->sc_dmat, data->map, 0, |
771 | data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); |
772 | bus_dmamap_unload(sc->sc_dmat, data->map); |
773 | m_freem(data->m); |
774 | data->m = NULL; |
775 | } |
776 | |
777 | /* |
778 | * The node has already been freed at that point so don't call |
779 | * ieee80211_release_node() here. |
780 | */ |
781 | data->ni = NULL; |
782 | |
783 | desc->status = 0; |
784 | } |
785 | |
786 | bus_dmamap_sync(sc->sc_dmat, ring->map, 0, ring->map->dm_mapsize, |
787 | BUS_DMASYNC_PREWRITE); |
788 | |
789 | ring->queued = 0; |
790 | ring->cur = ring->next = ring->stat = 0; |
791 | } |
792 | |
793 | static void |
794 | malo_free_tx_ring(struct malo_softc *sc, struct malo_tx_ring *ring) |
795 | { |
796 | struct malo_tx_data *data; |
797 | int i; |
798 | |
799 | if (ring->desc != NULL) { |
800 | bus_dmamap_sync(sc->sc_dmat, ring->map, 0, |
801 | ring->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); |
802 | bus_dmamap_unload(sc->sc_dmat, ring->map); |
803 | bus_dmamem_unmap(sc->sc_dmat, ring->desc, |
804 | ring->count * sizeof(struct malo_tx_desc)); |
805 | bus_dmamem_free(sc->sc_dmat, &ring->seg, 1); |
806 | } |
807 | |
808 | if (ring->data != NULL) { |
809 | for (i = 0; i < ring->count; i++) { |
810 | data = &ring->data[i]; |
811 | |
812 | if (data->m != NULL) { |
813 | bus_dmamap_sync(sc->sc_dmat, data->map, 0, |
814 | data->map->dm_mapsize, |
815 | BUS_DMASYNC_POSTWRITE); |
816 | bus_dmamap_unload(sc->sc_dmat, data->map); |
817 | m_freem(data->m); |
818 | } |
819 | |
820 | /* |
821 | * The node has already been freed at that point so |
822 | * don't call ieee80211_release_node() here. |
823 | */ |
824 | data->ni = NULL; |
825 | |
826 | if (data->map != NULL) |
827 | bus_dmamap_destroy(sc->sc_dmat, data->map); |
828 | } |
829 | free(ring->data, M_DEVBUF); |
830 | } |
831 | } |
832 | |
833 | int |
834 | malo_init(struct ifnet *ifp) |
835 | { |
836 | struct malo_softc *sc = ifp->if_softc; |
837 | struct ieee80211com *ic = &sc->sc_ic; |
838 | int error; |
839 | |
840 | DPRINTF(1, "%s: %s\n" , ifp->if_xname, __func__); |
841 | |
842 | /* if interface already runs stop it first */ |
843 | if (ifp->if_flags & IFF_RUNNING) |
844 | malo_stop(ifp, 1); |
845 | |
846 | /* power on cardbus socket */ |
847 | if (sc->sc_enable) |
848 | sc->sc_enable(sc); |
849 | |
850 | /* disable interrupts */ |
851 | malo_ctl_read4(sc, MALO_REG_A2H_INTERRUPT_CAUSE); |
852 | malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_CAUSE, 0); |
853 | malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_MASK, 0); |
854 | malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_STATUS_MASK, 0); |
855 | |
856 | /* load firmware */ |
857 | if ((error = malo_load_bootimg(sc))) |
858 | goto fail; |
859 | if ((error = malo_load_firmware(sc))) |
860 | goto fail; |
861 | |
862 | /* enable interrupts */ |
863 | malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_MASK, 0x1f); |
864 | malo_ctl_barrier(sc, BUS_SPACE_BARRIER_WRITE); |
865 | malo_ctl_write4(sc, MALO_REG_A2H_INTERRUPT_STATUS_MASK, 0x1f); |
866 | malo_ctl_barrier(sc, BUS_SPACE_BARRIER_WRITE); |
867 | |
868 | if ((error = malo_cmd_get_spec(sc))) |
869 | goto fail; |
870 | |
871 | /* select default channel */ |
872 | ic->ic_bss->ni_chan = ic->ic_ibss_chan; |
873 | |
874 | /* initialize hardware */ |
875 | if ((error = malo_cmd_set_channel(sc, ic->ic_bss->ni_chan))) { |
876 | aprint_error_dev(sc->sc_dev, "setting channel failed!\n" ); |
877 | goto fail; |
878 | } |
879 | if ((error = malo_cmd_set_antenna(sc, 1))) { |
880 | aprint_error_dev(sc->sc_dev, "setting RX antenna failed!\n" ); |
881 | goto fail; |
882 | } |
883 | if ((error = malo_cmd_set_antenna(sc, 2))) { |
884 | aprint_error_dev(sc->sc_dev, "setting TX antenna failed!\n" ); |
885 | goto fail; |
886 | } |
887 | if ((error = malo_cmd_set_radio(sc, 1, 5))) { |
888 | aprint_error_dev(sc->sc_dev, "turn radio on failed!\n" ); |
889 | goto fail; |
890 | } |
891 | if ((error = malo_cmd_set_txpower(sc, 100))) { |
892 | aprint_error_dev(sc->sc_dev, "setting TX power failed!\n" ); |
893 | goto fail; |
894 | } |
895 | if ((error = malo_cmd_set_rts(sc, IEEE80211_RTS_MAX))) { |
896 | aprint_error_dev(sc->sc_dev, "setting RTS failed!\n" ); |
897 | goto fail; |
898 | } |
899 | |
900 | ifp->if_flags |= IFF_RUNNING; |
901 | |
902 | if (ic->ic_opmode != IEEE80211_M_MONITOR) |
903 | /* start background scanning */ |
904 | ieee80211_new_state(ic, IEEE80211_S_SCAN, -1); |
905 | else |
906 | /* in monitor mode change directly into run state */ |
907 | ieee80211_new_state(ic, IEEE80211_S_RUN, -1); |
908 | |
909 | return (0); |
910 | |
911 | fail: |
912 | /* reset adapter */ |
913 | DPRINTF(1, "%s: malo_init failed, resetting card\n" , |
914 | device_xname(sc->sc_dev)); |
915 | malo_stop(ifp, 1); |
916 | return (error); |
917 | } |
918 | |
919 | static int |
920 | malo_ioctl(struct ifnet *ifp, u_long cmd, void* data) |
921 | { |
922 | struct malo_softc *sc = ifp->if_softc; |
923 | struct ieee80211com *ic = &sc->sc_ic; |
924 | int s, error = 0; |
925 | |
926 | s = splnet(); |
927 | |
928 | switch (cmd) { |
929 | case SIOCSIFFLAGS: |
930 | if ((error = ifioctl_common(ifp, cmd, data)) != 0) |
931 | break; |
932 | if (ifp->if_flags & IFF_UP) { |
933 | if ((ifp->if_flags & IFF_RUNNING) == 0) |
934 | malo_init(ifp); |
935 | } else { |
936 | if (ifp->if_flags & IFF_RUNNING) |
937 | malo_stop(ifp, 1); |
938 | } |
939 | break; |
940 | case SIOCADDMULTI: |
941 | case SIOCDELMULTI: |
942 | if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) { |
943 | /* setup multicast filter, etc */ |
944 | error = 0; |
945 | } |
946 | break; |
947 | case SIOCS80211CHANNEL: |
948 | /* allow fast channel switching in monitor mode */ |
949 | error = ieee80211_ioctl(ic, cmd, data); |
950 | if (error == ENETRESET && |
951 | ic->ic_opmode == IEEE80211_M_MONITOR) { |
952 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == |
953 | (IFF_UP | IFF_RUNNING)) { |
954 | ic->ic_bss->ni_chan = ic->ic_ibss_chan; |
955 | malo_cmd_set_channel(sc, ic->ic_bss->ni_chan); |
956 | } |
957 | error = 0; |
958 | } |
959 | break; |
960 | default: |
961 | error = ieee80211_ioctl(ic, cmd, data); |
962 | break; |
963 | } |
964 | |
965 | if (error == ENETRESET) { |
966 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == |
967 | (IFF_UP | IFF_RUNNING)) |
968 | malo_init(ifp); |
969 | error = 0; |
970 | } |
971 | |
972 | splx(s); |
973 | |
974 | return (error); |
975 | } |
976 | |
977 | static void |
978 | malo_start(struct ifnet *ifp) |
979 | { |
980 | struct malo_softc *sc = ifp->if_softc; |
981 | struct ieee80211com *ic = &sc->sc_ic; |
982 | struct mbuf *m0; |
983 | struct ether_header *eh; |
984 | struct ieee80211_node *ni = NULL; |
985 | |
986 | DPRINTF(2, "%s: %s\n" , device_xname(sc->sc_dev), __func__); |
987 | |
988 | if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) |
989 | return; |
990 | |
991 | for (;;) { |
992 | IF_POLL(&ic->ic_mgtq, m0); |
993 | if (m0 != NULL) { |
994 | if (sc->sc_txring.queued >= MALO_TX_RING_COUNT) { |
995 | ifp->if_flags |= IFF_OACTIVE; |
996 | break; |
997 | } |
998 | IF_DEQUEUE(&ic->ic_mgtq, m0); |
999 | |
1000 | ni = M_GETCTX(m0, struct ieee80211_node *); |
1001 | M_CLEARCTX(m0); |
1002 | |
1003 | bpf_mtap3(ic->ic_rawbpf, m0); |
1004 | |
1005 | if (malo_tx_data(sc, m0, ni) != 0) |
1006 | break; |
1007 | } else { |
1008 | if (ic->ic_state != IEEE80211_S_RUN) |
1009 | break; |
1010 | IFQ_POLL(&ifp->if_snd, m0); |
1011 | if (m0 == NULL) |
1012 | break; |
1013 | if (sc->sc_txring.queued >= MALO_TX_RING_COUNT - 1) { |
1014 | ifp->if_flags |= IFF_OACTIVE; |
1015 | break; |
1016 | } |
1017 | |
1018 | if (m0->m_len < sizeof (*eh) && |
1019 | (m0 = m_pullup(m0, sizeof (*eh))) == NULL) { |
1020 | ifp->if_oerrors++; |
1021 | continue; |
1022 | } |
1023 | eh = mtod(m0, struct ether_header *); |
1024 | ni = ieee80211_find_txnode(ic, eh->ether_dhost); |
1025 | if (ni == NULL) { |
1026 | m_freem(m0); |
1027 | ifp->if_oerrors++; |
1028 | continue; |
1029 | } |
1030 | |
1031 | // XXX must I call ieee_classify at this point ? |
1032 | |
1033 | IFQ_DEQUEUE(&ifp->if_snd, m0); |
1034 | bpf_mtap(ifp, m0); |
1035 | |
1036 | m0 = ieee80211_encap(ic, m0, ni); |
1037 | if (m0 == NULL) |
1038 | continue; |
1039 | bpf_mtap(ifp, m0); |
1040 | |
1041 | if (malo_tx_data(sc, m0, ni) != 0) { |
1042 | ieee80211_free_node(ni); |
1043 | ifp->if_oerrors++; |
1044 | break; |
1045 | } |
1046 | } |
1047 | } |
1048 | } |
1049 | |
1050 | void |
1051 | malo_stop(struct ifnet* ifp, int disable) |
1052 | { |
1053 | struct malo_softc *sc = ifp->if_softc; |
1054 | struct ieee80211com *ic = &sc->sc_ic; |
1055 | |
1056 | DPRINTF(1, "%s: %s\n" , ifp->if_xname, __func__); |
1057 | |
1058 | /* reset adapter */ |
1059 | if (ifp->if_flags & IFF_RUNNING) |
1060 | malo_ctl_write4(sc, MALO_REG_H2A_INTERRUPT_EVENTS, (1 << 15)); |
1061 | |
1062 | /* device is not running anymore */ |
1063 | ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); |
1064 | |
1065 | /* change back to initial state */ |
1066 | ieee80211_new_state(ic, IEEE80211_S_INIT, -1); |
1067 | |
1068 | /* reset RX / TX rings */ |
1069 | malo_reset_tx_ring(sc, &sc->sc_txring); |
1070 | malo_reset_rx_ring(sc, &sc->sc_rxring); |
1071 | |
1072 | /* set initial rate */ |
1073 | sc->sc_last_txrate = -1; |
1074 | |
1075 | /* power off cardbus socket */ |
1076 | if (sc->sc_disable) |
1077 | sc->sc_disable(sc); |
1078 | } |
1079 | |
1080 | static void |
1081 | malo_watchdog(struct ifnet *ifp) |
1082 | { |
1083 | |
1084 | } |
1085 | |
1086 | static int |
1087 | malo_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) |
1088 | { |
1089 | struct ifnet *ifp = ic->ic_ifp; |
1090 | struct malo_softc *sc = ifp->if_softc; |
1091 | enum ieee80211_state ostate; |
1092 | int rate; |
1093 | |
1094 | DPRINTF(2, "%s: %s\n" , device_xname(sc->sc_dev), __func__); |
1095 | |
1096 | ostate = ic->ic_state; |
1097 | callout_stop(&sc->sc_scan_to); |
1098 | |
1099 | switch (nstate) { |
1100 | case IEEE80211_S_INIT: |
1101 | DPRINTF(1, "%s: newstate INIT\n" , device_xname(sc->sc_dev)); |
1102 | break; |
1103 | case IEEE80211_S_SCAN: |
1104 | DPRINTF(1, "%s: newstate SCAN\n" , device_xname(sc->sc_dev)); |
1105 | if (ostate == IEEE80211_S_INIT) { |
1106 | if (malo_cmd_set_prescan(sc) != 0) { |
1107 | DPRINTF(1, "%s: can't set prescan\n" , |
1108 | device_xname(sc->sc_dev)); |
1109 | } |
1110 | } else { |
1111 | malo_cmd_set_channel(sc, ic->ic_curchan); |
1112 | } |
1113 | callout_schedule(&sc->sc_scan_to, hz/2); |
1114 | break; |
1115 | case IEEE80211_S_AUTH: |
1116 | DPRINTF(1, "%s: newstate AUTH\n" , device_xname(sc->sc_dev)); |
1117 | malo_cmd_set_postscan(sc, ic->ic_myaddr, 1); |
1118 | malo_cmd_set_channel(sc, ic->ic_curchan); |
1119 | break; |
1120 | case IEEE80211_S_ASSOC: |
1121 | DPRINTF(1, "%s: newstate ASSOC\n" , device_xname(sc->sc_dev)); |
1122 | malo_cmd_set_channel(sc, ic->ic_curchan); |
1123 | if (ic->ic_flags & IEEE80211_F_SHPREAMBLE) |
1124 | malo_cmd_set_radio(sc, 1, 3); /* short preamble */ |
1125 | else |
1126 | malo_cmd_set_radio(sc, 1, 1); /* long preamble */ |
1127 | |
1128 | malo_cmd_set_aid(sc, ic->ic_bss->ni_bssid, |
1129 | ic->ic_bss->ni_associd); |
1130 | |
1131 | if (ic->ic_fixed_rate == -1) |
1132 | /* automatic rate adaption */ |
1133 | malo_cmd_set_rate(sc, 0); |
1134 | else { |
1135 | /* fixed rate */ |
1136 | rate = malo_fix2rate(ic->ic_fixed_rate); |
1137 | malo_cmd_set_rate(sc, rate); |
1138 | } |
1139 | |
1140 | malo_set_slot(sc); |
1141 | break; |
1142 | case IEEE80211_S_RUN: |
1143 | DPRINTF(1, "%s: newstate RUN\n" , device_xname(sc->sc_dev)); |
1144 | break; |
1145 | default: |
1146 | break; |
1147 | } |
1148 | |
1149 | return (sc->sc_newstate(ic, nstate, arg)); |
1150 | } |
1151 | |
1152 | static void |
1153 | malo_newassoc(struct ieee80211_node *ni, int isnew) |
1154 | { |
1155 | } |
1156 | |
1157 | static struct ieee80211_node * |
1158 | malo_node_alloc(struct ieee80211_node_table *nt) |
1159 | { |
1160 | struct malo_node *wn; |
1161 | |
1162 | wn = malloc(sizeof(*wn), M_DEVBUF, M_NOWAIT | M_ZERO); |
1163 | if (wn == NULL) |
1164 | return (NULL); |
1165 | |
1166 | return ((struct ieee80211_node *)wn); |
1167 | } |
1168 | |
1169 | static int |
1170 | malo_media_change(struct ifnet *ifp) |
1171 | { |
1172 | int error; |
1173 | |
1174 | DPRINTF(1, "%s: %s\n" , ifp->if_xname, __func__); |
1175 | |
1176 | error = ieee80211_media_change(ifp); |
1177 | if (error != ENETRESET) |
1178 | return (error); |
1179 | |
1180 | if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == (IFF_UP | IFF_RUNNING)) |
1181 | malo_init(ifp); |
1182 | |
1183 | return (0); |
1184 | } |
1185 | |
1186 | static void |
1187 | malo_media_status(struct ifnet *ifp, struct ifmediareq *imr) |
1188 | { |
1189 | struct malo_softc *sc = ifp->if_softc; |
1190 | struct ieee80211com *ic = &sc->sc_ic; |
1191 | |
1192 | imr->ifm_status = IFM_AVALID; |
1193 | imr->ifm_active = IFM_IEEE80211; |
1194 | if (ic->ic_state == IEEE80211_S_RUN) |
1195 | imr->ifm_status |= IFM_ACTIVE; |
1196 | |
1197 | /* report last TX rate used by chip */ |
1198 | imr->ifm_active |= ieee80211_rate2media(ic, sc->sc_last_txrate, |
1199 | ic->ic_curmode); |
1200 | |
1201 | switch (ic->ic_opmode) { |
1202 | case IEEE80211_M_STA: |
1203 | break; |
1204 | case IEEE80211_M_IBSS: |
1205 | imr->ifm_active |= IFM_IEEE80211_ADHOC; |
1206 | break; |
1207 | case IEEE80211_M_AHDEMO: |
1208 | break; |
1209 | case IEEE80211_M_HOSTAP: |
1210 | break; |
1211 | case IEEE80211_M_MONITOR: |
1212 | imr->ifm_active |= IFM_IEEE80211_MONITOR; |
1213 | break; |
1214 | default: |
1215 | break; |
1216 | } |
1217 | |
1218 | switch (ic->ic_curmode) { |
1219 | case IEEE80211_MODE_11B: |
1220 | imr->ifm_active |= IFM_IEEE80211_11B; |
1221 | break; |
1222 | case IEEE80211_MODE_11G: |
1223 | imr->ifm_active |= IFM_IEEE80211_11G; |
1224 | break; |
1225 | } |
1226 | } |
1227 | |
1228 | static int |
1229 | malo_chip2rate(int chip_rate) |
1230 | { |
1231 | switch (chip_rate) { |
1232 | /* CCK rates */ |
1233 | case 0: return (2); |
1234 | case 1: return (4); |
1235 | case 2: return (11); |
1236 | case 3: return (22); |
1237 | |
1238 | /* OFDM rates */ |
1239 | case 4: return (0); /* reserved */ |
1240 | case 5: return (12); |
1241 | case 6: return (18); |
1242 | case 7: return (24); |
1243 | case 8: return (36); |
1244 | case 9: return (48); |
1245 | case 10: return (72); |
1246 | case 11: return (96); |
1247 | case 12: return (108); |
1248 | |
1249 | /* no rate select yet or unknown rate */ |
1250 | default: return (-1); |
1251 | } |
1252 | } |
1253 | |
1254 | static int |
1255 | malo_fix2rate(int fix_rate) |
1256 | { |
1257 | switch (fix_rate) { |
1258 | /* CCK rates */ |
1259 | case 0: return (2); |
1260 | case 1: return (4); |
1261 | case 2: return (11); |
1262 | case 3: return (22); |
1263 | |
1264 | /* OFDM rates */ |
1265 | case 4: return (12); |
1266 | case 5: return (18); |
1267 | case 6: return (24); |
1268 | case 7: return (36); |
1269 | case 8: return (48); |
1270 | case 9: return (72); |
1271 | case 10: return (96); |
1272 | case 11: return (108); |
1273 | |
1274 | /* unknown rate: should not happen */ |
1275 | default: return (0); |
1276 | } |
1277 | } |
1278 | |
1279 | static void |
1280 | malo_next_scan(void *arg) |
1281 | { |
1282 | struct malo_softc *sc = arg; |
1283 | struct ieee80211com *ic = &sc->sc_ic; |
1284 | int s; |
1285 | |
1286 | DPRINTF(1, "%s: %s\n" , sc->sc_if.if_xname, __func__); |
1287 | |
1288 | s = splnet(); |
1289 | |
1290 | if (ic->ic_state == IEEE80211_S_SCAN) |
1291 | ieee80211_next_scan(ic); |
1292 | |
1293 | splx(s); |
1294 | } |
1295 | |
1296 | static void |
1297 | malo_tx_intr(struct malo_softc *sc) |
1298 | { |
1299 | struct ifnet *ifp = &sc->sc_if; |
1300 | struct malo_tx_desc *desc; |
1301 | struct malo_tx_data *data; |
1302 | struct malo_node *rn; |
1303 | int stat; |
1304 | |
1305 | DPRINTF(2, "%s: %s\n" , device_xname(sc->sc_dev), __func__); |
1306 | |
1307 | stat = sc->sc_txring.stat; |
1308 | for (;;) { |
1309 | desc = &sc->sc_txring.desc[sc->sc_txring.stat]; |
1310 | data = &sc->sc_txring.data[sc->sc_txring.stat]; |
1311 | rn = (struct malo_node *)data->ni; |
1312 | |
1313 | /* check if TX descriptor is not owned by FW anymore */ |
1314 | if ((le32toh(desc->status) & MALO_TXD_STATUS_FW_OWNED) || |
1315 | !(le32toh(data->softstat) & MALO_TXD_STATUS_FAILED_AGING)) |
1316 | break; |
1317 | |
1318 | /* if no frame has been sent, ignore */ |
1319 | if (rn == NULL) |
1320 | goto next; |
1321 | |
1322 | /* check TX state */ |
1323 | switch (le32toh(desc->status) & MALO_TXD_STATUS_USED) { |
1324 | case MALO_TXD_STATUS_OK: |
1325 | DPRINTF(2, "%s: data frame was sent successfully\n" , |
1326 | device_xname(sc->sc_dev)); |
1327 | ifp->if_opackets++; |
1328 | break; |
1329 | default: |
1330 | DPRINTF(1, "%s: data frame sending error\n" , |
1331 | device_xname(sc->sc_dev)); |
1332 | ifp->if_oerrors++; |
1333 | break; |
1334 | } |
1335 | |
1336 | /* save last used TX rate */ |
1337 | sc->sc_last_txrate = malo_chip2rate(desc->datarate); |
1338 | |
1339 | /* cleanup TX data and TX descriptor */ |
1340 | bus_dmamap_sync(sc->sc_dmat, data->map, 0, |
1341 | data->map->dm_mapsize, BUS_DMASYNC_POSTWRITE); |
1342 | bus_dmamap_unload(sc->sc_dmat, data->map); |
1343 | m_freem(data->m); |
1344 | ieee80211_free_node(data->ni); |
1345 | data->m = NULL; |
1346 | data->ni = NULL; |
1347 | data->softstat &= htole32(~0x80); |
1348 | desc->status = 0; |
1349 | desc->len = 0; |
1350 | |
1351 | DPRINTF(2, "%s: tx done idx=%u\n" , |
1352 | device_xname(sc->sc_dev), sc->sc_txring.stat); |
1353 | |
1354 | sc->sc_txring.queued--; |
1355 | next: |
1356 | if (++sc->sc_txring.stat >= sc->sc_txring.count) |
1357 | sc->sc_txring.stat = 0; |
1358 | if (sc->sc_txring.stat == stat) |
1359 | break; |
1360 | } |
1361 | |
1362 | sc->sc_tx_timer = 0; |
1363 | ifp->if_flags &= ~IFF_OACTIVE; |
1364 | malo_start(ifp); |
1365 | } |
1366 | |
1367 | static int |
1368 | malo_tx_data(struct malo_softc *sc, struct mbuf *m0, |
1369 | struct ieee80211_node *ni) |
1370 | { |
1371 | struct ieee80211com *ic = &sc->sc_ic; |
1372 | struct ifnet *ifp = &sc->sc_if; |
1373 | struct malo_tx_desc *desc; |
1374 | struct malo_tx_data *data; |
1375 | struct ieee80211_frame *wh; |
1376 | struct ieee80211_key *k; |
1377 | struct mbuf *mnew; |
1378 | int error; |
1379 | |
1380 | DPRINTF(2, "%s: %s\n" , device_xname(sc->sc_dev), __func__); |
1381 | |
1382 | desc = &sc->sc_txring.desc[sc->sc_txring.cur]; |
1383 | data = &sc->sc_txring.data[sc->sc_txring.cur]; |
1384 | |
1385 | if (m0->m_len < sizeof(struct ieee80211_frame)) { |
1386 | m0 = m_pullup(m0, sizeof(struct ieee80211_frame)); |
1387 | if (m0 == NULL) { |
1388 | ifp->if_ierrors++; |
1389 | return (ENOBUFS); |
1390 | } |
1391 | } |
1392 | wh = mtod(m0, struct ieee80211_frame *); |
1393 | |
1394 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) { |
1395 | k = ieee80211_crypto_encap(ic, ni, m0); |
1396 | if (k == NULL) { |
1397 | m_freem(m0); |
1398 | return ENOBUFS; |
1399 | } |
1400 | |
1401 | /* packet header may have moved, reset our local pointer */ |
1402 | wh = mtod(m0, struct ieee80211_frame *); |
1403 | } |
1404 | |
1405 | if (sc->sc_drvbpf != NULL) { |
1406 | struct malo_tx_radiotap_hdr *tap = &sc->sc_txtap; |
1407 | |
1408 | tap->wt_flags = 0; |
1409 | tap->wt_chan_freq = htole16(ni->ni_chan->ic_freq); |
1410 | tap->wt_chan_flags = htole16(ni->ni_chan->ic_flags); |
1411 | tap->wt_rate = sc->sc_last_txrate; |
1412 | if (wh->i_fc[1] & IEEE80211_FC1_WEP) |
1413 | tap->wt_flags |= IEEE80211_RADIOTAP_F_WEP; |
1414 | |
1415 | bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_txtap_len, m0); |
1416 | } |
1417 | |
1418 | /* |
1419 | * inject FW specific fields into the 802.11 frame |
1420 | * |
1421 | * 2 bytes FW len (inject) |
1422 | * 24 bytes 802.11 frame header |
1423 | * 6 bytes addr4 (inject) |
1424 | * n bytes 802.11 frame body |
1425 | * |
1426 | * For now copy all into a new mcluster. |
1427 | */ |
1428 | MGETHDR(mnew, M_DONTWAIT, MT_DATA); |
1429 | if (mnew == NULL) |
1430 | return (ENOBUFS); |
1431 | MCLGET(mnew, M_DONTWAIT); |
1432 | if (!(mnew->m_flags & M_EXT)) { |
1433 | m_free(mnew); |
1434 | return (ENOBUFS); |
1435 | } |
1436 | |
1437 | *mtod(mnew, uint16_t *) = htole16(m0->m_pkthdr.len - 24); /* FW len */ |
1438 | memmove(mtod(mnew, char*) + 2, wh, sizeof(*wh)); |
1439 | memset(mtod(mnew, char*) + 26, 0, 6); |
1440 | m_copydata(m0, sizeof(*wh), m0->m_pkthdr.len - sizeof(*wh), |
1441 | mtod(mnew, char*) + 32); |
1442 | mnew->m_pkthdr.len = mnew->m_len = m0->m_pkthdr.len + 8; |
1443 | m_freem(m0); |
1444 | m0 = mnew; |
1445 | |
1446 | error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m0, |
1447 | BUS_DMA_NOWAIT); |
1448 | if (error != 0) { |
1449 | aprint_error_dev(sc->sc_dev, "can't map mbuf (error %d)\n" , error); |
1450 | m_freem(m0); |
1451 | return (error); |
1452 | } |
1453 | |
1454 | data->m = m0; |
1455 | data->ni = ni; |
1456 | data->softstat |= htole32(0x80); |
1457 | |
1458 | malo_tx_setup_desc(sc, desc, m0->m_pkthdr.len, 1, |
1459 | data->map->dm_segs, data->map->dm_nsegs); |
1460 | |
1461 | bus_dmamap_sync(sc->sc_dmat, data->map, 0, data->map->dm_mapsize, |
1462 | BUS_DMASYNC_PREWRITE); |
1463 | bus_dmamap_sync(sc->sc_dmat, sc->sc_txring.map, |
1464 | sc->sc_txring.cur * sizeof(struct malo_tx_desc), |
1465 | sizeof(struct malo_tx_desc), BUS_DMASYNC_PREWRITE); |
1466 | |
1467 | DPRINTF(2, "%s: sending frame, pktlen=%u, idx=%u\n" , |
1468 | device_xname(sc->sc_dev), m0->m_pkthdr.len, sc->sc_txring.cur); |
1469 | |
1470 | sc->sc_txring.queued++; |
1471 | sc->sc_txring.cur = (sc->sc_txring.cur + 1) % MALO_TX_RING_COUNT; |
1472 | |
1473 | /* kick data TX */ |
1474 | malo_ctl_write4(sc, MALO_REG_H2A_INTERRUPT_EVENTS, 1); |
1475 | malo_ctl_barrier(sc, BUS_SPACE_BARRIER_WRITE); |
1476 | |
1477 | return (0); |
1478 | } |
1479 | |
1480 | static void |
1481 | malo_tx_setup_desc(struct malo_softc *sc, struct malo_tx_desc *desc, |
1482 | int len, int rate, const bus_dma_segment_t *segs, int nsegs) |
1483 | { |
1484 | desc->len = htole16(segs[0].ds_len); |
1485 | desc->datarate = rate; /* 0 = mgmt frame, 1 = data frame */ |
1486 | desc->physdata = htole32(segs[0].ds_addr); |
1487 | desc->status = htole32(MALO_TXD_STATUS_OK | MALO_TXD_STATUS_FW_OWNED); |
1488 | } |
1489 | |
1490 | static void |
1491 | malo_rx_intr(struct malo_softc *sc) |
1492 | { |
1493 | struct ieee80211com *ic = &sc->sc_ic; |
1494 | struct ifnet *ifp = &sc->sc_if; |
1495 | struct malo_rx_desc *desc; |
1496 | struct malo_rx_data *data; |
1497 | struct ieee80211_frame *wh; |
1498 | struct ieee80211_node *ni; |
1499 | struct mbuf *mnew, *m; |
1500 | uint32_t rxRdPtr, rxWrPtr; |
1501 | int error, i; |
1502 | |
1503 | rxRdPtr = malo_mem_read4(sc, sc->sc_RxPdRdPtr); |
1504 | rxWrPtr = malo_mem_read4(sc, sc->sc_RxPdWrPtr); |
1505 | |
1506 | for (i = 0; i < MALO_RX_RING_COUNT && rxRdPtr != rxWrPtr; i++) { |
1507 | desc = &sc->sc_rxring.desc[sc->sc_rxring.cur]; |
1508 | data = &sc->sc_rxring.data[sc->sc_rxring.cur]; |
1509 | |
1510 | bus_dmamap_sync(sc->sc_dmat, sc->sc_rxring.map, |
1511 | sc->sc_rxring.cur * sizeof(struct malo_rx_desc), |
1512 | sizeof(struct malo_rx_desc), BUS_DMASYNC_POSTREAD); |
1513 | |
1514 | DPRINTF(3, "%s: rx intr idx=%d, rxctrl=0x%02x, rssi=%d, " |
1515 | "status=0x%02x, channel=%d, len=%d, res1=%02x, rate=%d, " |
1516 | "physdata=0x%04x, physnext=0x%04x, qosctrl=%02x, res2=%d\n" , |
1517 | device_xname(sc->sc_dev), |
1518 | sc->sc_rxring.cur, desc->rxctrl, desc->rssi, desc->status, |
1519 | desc->channel, le16toh(desc->len), desc->reserved1, |
1520 | desc->datarate, le32toh(desc->physdata), |
1521 | le32toh(desc->physnext), desc->qosctrl, desc->reserved2); |
1522 | |
1523 | if ((desc->rxctrl & 0x80) == 0) |
1524 | break; |
1525 | |
1526 | MGETHDR(mnew, M_DONTWAIT, MT_DATA); |
1527 | if (mnew == NULL) { |
1528 | ifp->if_ierrors++; |
1529 | goto skip; |
1530 | } |
1531 | |
1532 | MCLGET(mnew, M_DONTWAIT); |
1533 | if (!(mnew->m_flags & M_EXT)) { |
1534 | m_freem(mnew); |
1535 | ifp->if_ierrors++; |
1536 | goto skip; |
1537 | } |
1538 | |
1539 | bus_dmamap_sync(sc->sc_dmat, data->map, 0, |
1540 | data->map->dm_mapsize, BUS_DMASYNC_POSTREAD); |
1541 | bus_dmamap_unload(sc->sc_dmat, data->map); |
1542 | |
1543 | error = bus_dmamap_load(sc->sc_dmat, data->map, |
1544 | mtod(mnew, void *), MCLBYTES, NULL, BUS_DMA_NOWAIT); |
1545 | if (error != 0) { |
1546 | m_freem(mnew); |
1547 | |
1548 | error = bus_dmamap_load(sc->sc_dmat, data->map, |
1549 | mtod(data->m, void *), MCLBYTES, NULL, |
1550 | BUS_DMA_NOWAIT); |
1551 | if (error != 0) { |
1552 | panic("%s: could not load old rx mbuf" , |
1553 | device_xname(sc->sc_dev)); |
1554 | } |
1555 | ifp->if_ierrors++; |
1556 | goto skip; |
1557 | } |
1558 | |
1559 | /* |
1560 | * New mbuf mbuf successfully loaded |
1561 | */ |
1562 | m = data->m; |
1563 | data->m = mnew; |
1564 | desc->physdata = htole32(data->map->dm_segs->ds_addr); |
1565 | |
1566 | /* finalize mbuf */ |
1567 | m_set_rcvif(m, ifp); |
1568 | m->m_pkthdr.len = m->m_len = le16toh(desc->len); |
1569 | |
1570 | /* |
1571 | * cut out FW specific fields from the 802.11 frame |
1572 | * |
1573 | * 2 bytes FW len (cut out) |
1574 | * 24 bytes 802.11 frame header |
1575 | * 6 bytes addr4 (cut out) |
1576 | * n bytes 802.11 frame data |
1577 | */ |
1578 | memmove(m->m_data +6, m->m_data, 26); |
1579 | m_adj(m, 8); |
1580 | |
1581 | if (sc->sc_drvbpf != NULL) { |
1582 | struct malo_rx_radiotap_hdr *tap = &sc->sc_rxtap; |
1583 | |
1584 | tap->wr_flags = 0; |
1585 | tap->wr_chan_freq = |
1586 | htole16(ic->ic_bss->ni_chan->ic_freq); |
1587 | tap->wr_chan_flags = |
1588 | htole16(ic->ic_bss->ni_chan->ic_flags); |
1589 | |
1590 | bpf_mtap2(sc->sc_drvbpf, tap, sc->sc_rxtap_len, m); |
1591 | } |
1592 | |
1593 | wh = mtod(m, struct ieee80211_frame *); |
1594 | ni = ieee80211_find_rxnode(ic, (struct ieee80211_frame_min *)wh); |
1595 | |
1596 | /* send the frame to the 802.11 layer */ |
1597 | ieee80211_input(ic, m, ni, desc->rssi, 0); |
1598 | |
1599 | /* node is no longer needed */ |
1600 | ieee80211_free_node(ni); |
1601 | |
1602 | skip: |
1603 | desc->rxctrl = 0; |
1604 | rxRdPtr = le32toh(desc->physnext); |
1605 | |
1606 | bus_dmamap_sync(sc->sc_dmat, sc->sc_rxring.map, |
1607 | sc->sc_rxring.cur * sizeof(struct malo_rx_desc), |
1608 | sizeof(struct malo_rx_desc), BUS_DMASYNC_PREWRITE); |
1609 | |
1610 | sc->sc_rxring.cur = (sc->sc_rxring.cur + 1) % |
1611 | MALO_RX_RING_COUNT; |
1612 | } |
1613 | |
1614 | malo_mem_write4(sc, sc->sc_RxPdRdPtr, rxRdPtr); |
1615 | } |
1616 | |
1617 | static int |
1618 | malo_get_firmware(struct malo_softc *sc, const char *name, |
1619 | uint8_t** firmware_image, size_t* size) |
1620 | { |
1621 | firmware_handle_t fw; |
1622 | int error; |
1623 | |
1624 | |
1625 | /* load firmware image from disk */ |
1626 | if ((error = firmware_open("malo" , name, &fw)) != 0) { |
1627 | aprint_error_dev(sc->sc_dev, "could not read firmware file\n" ); |
1628 | return error; |
1629 | } |
1630 | |
1631 | *size = firmware_get_size(fw); |
1632 | |
1633 | *firmware_image = firmware_malloc(*size); |
1634 | if (*firmware_image == NULL) { |
1635 | aprint_error_dev(sc->sc_dev, "not enough memory to stock firmware\n" ); |
1636 | error = ENOMEM; |
1637 | goto fail1; |
1638 | } |
1639 | |
1640 | if ((error = firmware_read(fw, 0, *firmware_image, *size)) != 0) { |
1641 | aprint_error_dev(sc->sc_dev, "can't get firmware\n" ); |
1642 | goto fail2; |
1643 | } |
1644 | |
1645 | firmware_close(fw); |
1646 | |
1647 | return 0; |
1648 | fail2: |
1649 | firmware_free(*firmware_image, *size); |
1650 | fail1: |
1651 | firmware_close(fw); |
1652 | return error; |
1653 | } |
1654 | |
1655 | static int |
1656 | malo_load_bootimg(struct malo_softc *sc) |
1657 | { |
1658 | const char *name = "malo8335-h" ; |
1659 | uint8_t *ucode; |
1660 | size_t size; |
1661 | int error, i; |
1662 | |
1663 | /* load boot firmware */ |
1664 | if ((error = malo_get_firmware(sc, name, &ucode, &size)) != 0) { |
1665 | aprint_error_dev(sc->sc_dev, "error %d, could not read firmware %s\n" , |
1666 | error, name); |
1667 | return (EIO); |
1668 | } |
1669 | |
1670 | /* |
1671 | * It seems we are putting this code directly onto the stack of |
1672 | * the ARM cpu. I don't know why we need to instruct the DMA |
1673 | * engine to move the code. This is a big riddle without docu. |
1674 | */ |
1675 | DPRINTF(1, "%s: loading boot firmware\n" , device_xname(sc->sc_dev)); |
1676 | malo_mem_write2(sc, 0xbef8, 0x001); |
1677 | malo_mem_write2(sc, 0xbefa, size); |
1678 | malo_mem_write4(sc, 0xbefc, 0); |
1679 | |
1680 | bus_space_write_region_1(sc->sc_mem1_bt, sc->sc_mem1_bh, 0xbf00, |
1681 | ucode, size); |
1682 | |
1683 | /* |
1684 | * we loaded the firmware into card memory now tell the CPU |
1685 | * to fetch the code and execute it. The memory mapped via the |
1686 | * first bar is internaly mapped to 0xc0000000. |
1687 | */ |
1688 | malo_send_cmd(sc, 0xc000bef8); |
1689 | |
1690 | /* wait for the device to go into FW loading mode */ |
1691 | for (i = 0; i < 10; i++) { |
1692 | delay(50); |
1693 | malo_ctl_barrier(sc, BUS_SPACE_BARRIER_READ); |
1694 | if (malo_ctl_read4(sc, 0x0c14) == 0x5) |
1695 | break; |
1696 | } |
1697 | if (i == 10) { |
1698 | aprint_error_dev(sc->sc_dev, "timeout at boot firmware load!\n" ); |
1699 | free(ucode, M_DEVBUF); |
1700 | return (ETIMEDOUT); |
1701 | } |
1702 | firmware_free(ucode, size); |
1703 | |
1704 | /* tell the card we're done and... */ |
1705 | malo_mem_write2(sc, 0xbef8, 0x001); |
1706 | malo_mem_write2(sc, 0xbefa, 0); |
1707 | malo_mem_write4(sc, 0xbefc, 0); |
1708 | malo_send_cmd(sc, 0xc000bef8); |
1709 | |
1710 | DPRINTF(1, "%s: boot firmware loaded\n" , device_xname(sc->sc_dev)); |
1711 | |
1712 | return (0); |
1713 | } |
1714 | |
1715 | |
1716 | static int |
1717 | malo_load_firmware(struct malo_softc *sc) |
1718 | { |
1719 | struct malo_cmdheader *hdr; |
1720 | const char *name = "malo8335-m" ; |
1721 | void *data; |
1722 | uint8_t *ucode; |
1723 | size_t size, count, bsize; |
1724 | int i, sn, error; |
1725 | |
1726 | /* load real firmware now */ |
1727 | if ((error = malo_get_firmware(sc, name, &ucode, &size)) != 0) { |
1728 | aprint_error_dev(sc->sc_dev, "error %d, could not read firmware %s\n" , |
1729 | error, name); |
1730 | return (EIO); |
1731 | } |
1732 | |
1733 | DPRINTF(1, "%s: uploading firmware\n" , device_xname(sc->sc_dev)); |
1734 | |
1735 | hdr = sc->sc_cmd_mem; |
1736 | data = hdr + 1; |
1737 | sn = 1; |
1738 | for (count = 0; count < size; count += bsize) { |
1739 | bsize = MIN(256, size - count); |
1740 | |
1741 | hdr->cmd = htole16(0x0001); |
1742 | hdr->size = htole16(bsize); |
1743 | hdr->seqnum = htole16(sn++); |
1744 | hdr->result = 0; |
1745 | |
1746 | memcpy(data, ucode + count, bsize); |
1747 | |
1748 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
1749 | BUS_DMASYNC_PREWRITE); |
1750 | malo_send_cmd(sc, sc->sc_cmd_dmaaddr); |
1751 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
1752 | BUS_DMASYNC_POSTWRITE); |
1753 | delay(500); |
1754 | } |
1755 | firmware_free(ucode, size); |
1756 | |
1757 | DPRINTF(1, "%s: firmware upload finished\n" , device_xname(sc->sc_dev)); |
1758 | |
1759 | /* |
1760 | * send a command with size 0 to tell that the firmware has been |
1761 | * uploaded |
1762 | */ |
1763 | hdr->cmd = htole16(0x0001); |
1764 | hdr->size = 0; |
1765 | hdr->seqnum = htole16(sn++); |
1766 | hdr->result = 0; |
1767 | |
1768 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
1769 | BUS_DMASYNC_PREWRITE); |
1770 | malo_send_cmd(sc, sc->sc_cmd_dmaaddr); |
1771 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
1772 | BUS_DMASYNC_POSTWRITE); |
1773 | delay(100); |
1774 | |
1775 | DPRINTF(1, "%s: loading firmware\n" , device_xname(sc->sc_dev)); |
1776 | |
1777 | /* wait until firmware has been loaded */ |
1778 | for (i = 0; i < 200; i++) { |
1779 | malo_ctl_write4(sc, 0x0c10, 0x5a); |
1780 | delay(500); |
1781 | malo_ctl_barrier(sc, BUS_SPACE_BARRIER_WRITE | |
1782 | BUS_SPACE_BARRIER_READ); |
1783 | if (malo_ctl_read4(sc, 0x0c14) == 0xf0f1f2f4) |
1784 | break; |
1785 | } |
1786 | if (i == 200) { |
1787 | aprint_error_dev(sc->sc_dev, "timeout at firmware load!\n" ); |
1788 | return (ETIMEDOUT); |
1789 | } |
1790 | |
1791 | DPRINTF(1, "%s: firmware loaded\n" , device_xname(sc->sc_dev)); |
1792 | |
1793 | return (0); |
1794 | } |
1795 | |
1796 | static int |
1797 | malo_set_slot(struct malo_softc *sc) |
1798 | { |
1799 | struct ieee80211com *ic = &sc->sc_ic; |
1800 | |
1801 | if (ic->ic_flags & IEEE80211_F_SHSLOT) { |
1802 | /* set short slot */ |
1803 | if (malo_cmd_set_slot(sc, 1)) { |
1804 | aprint_error_dev(sc->sc_dev, "setting short slot failed\n" ); |
1805 | return (ENXIO); |
1806 | } |
1807 | } else { |
1808 | /* set long slot */ |
1809 | if (malo_cmd_set_slot(sc, 0)) { |
1810 | aprint_error_dev(sc->sc_dev, "setting long slot failed\n" ); |
1811 | return (ENXIO); |
1812 | } |
1813 | } |
1814 | |
1815 | return (0); |
1816 | } |
1817 | |
1818 | static void |
1819 | malo_update_slot(struct ifnet* ifp) |
1820 | { |
1821 | struct malo_softc *sc = ifp->if_softc; |
1822 | struct ieee80211com *ic = &sc->sc_ic; |
1823 | |
1824 | malo_set_slot(sc); |
1825 | |
1826 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) { |
1827 | /* TODO */ |
1828 | } |
1829 | } |
1830 | |
1831 | #ifdef MALO_DEBUG |
1832 | static void |
1833 | malo_hexdump(void *buf, int len) |
1834 | { |
1835 | u_char b[16]; |
1836 | int i, j, l; |
1837 | |
1838 | for (i = 0; i < len; i += l) { |
1839 | printf("%4i:" , i); |
1840 | l = min(sizeof(b), len - i); |
1841 | memcpy(b, (char*)buf + i, l); |
1842 | |
1843 | for (j = 0; j < sizeof(b); j++) { |
1844 | if (j % 2 == 0) |
1845 | printf(" " ); |
1846 | if (j % 8 == 0) |
1847 | printf(" " ); |
1848 | if (j < l) |
1849 | printf("%02x" , (int)b[j]); |
1850 | else |
1851 | printf(" " ); |
1852 | } |
1853 | printf(" |" ); |
1854 | for (j = 0; j < l; j++) { |
1855 | if (b[j] >= 0x20 && b[j] <= 0x7e) |
1856 | printf("%c" , b[j]); |
1857 | else |
1858 | printf("." ); |
1859 | } |
1860 | printf("|\n" ); |
1861 | } |
1862 | } |
1863 | #endif |
1864 | |
1865 | static const char * |
1866 | malo_cmd_string(uint16_t cmd) |
1867 | { |
1868 | int i; |
1869 | static char cmd_buf[16]; |
1870 | static const struct { |
1871 | uint16_t cmd_code; |
1872 | const char *cmd_string; |
1873 | } cmds[] = { |
1874 | { MALO_CMD_GET_HW_SPEC, "GetHwSpecifications" }, |
1875 | { MALO_CMD_SET_RADIO, "SetRadio" }, |
1876 | { MALO_CMD_SET_AID, "SetAid" }, |
1877 | { MALO_CMD_SET_TXPOWER, "SetTxPower" }, |
1878 | { MALO_CMD_SET_ANTENNA, "SetAntenna" }, |
1879 | { MALO_CMD_SET_PRESCAN, "SetPrescan" }, |
1880 | { MALO_CMD_SET_POSTSCAN, "SetPostscan" }, |
1881 | { MALO_CMD_SET_RATE, "SetRate" }, |
1882 | { MALO_CMD_SET_CHANNEL, "SetChannel" }, |
1883 | { MALO_CMD_SET_RTS, "SetRTS" }, |
1884 | { MALO_CMD_SET_SLOT, "SetSlot" }, |
1885 | }; |
1886 | |
1887 | for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) |
1888 | if ((le16toh(cmd) & 0x7fff) == cmds[i].cmd_code) |
1889 | return (cmds[i].cmd_string); |
1890 | |
1891 | snprintf(cmd_buf, sizeof(cmd_buf), "unknown %#x" , cmd); |
1892 | return (cmd_buf); |
1893 | } |
1894 | |
1895 | static const char * |
1896 | malo_cmd_string_result(uint16_t result) |
1897 | { |
1898 | int i; |
1899 | static const struct { |
1900 | uint16_t result_code; |
1901 | const char *result_string; |
1902 | } results[] = { |
1903 | { MALO_CMD_RESULT_OK, "OK" }, |
1904 | { MALO_CMD_RESULT_ERROR, "general error" }, |
1905 | { MALO_CMD_RESULT_NOSUPPORT, "not supported" }, |
1906 | { MALO_CMD_RESULT_PENDING, "pending" }, |
1907 | { MALO_CMD_RESULT_BUSY, "ignored" }, |
1908 | { MALO_CMD_RESULT_PARTIALDATA, "incomplete" }, |
1909 | }; |
1910 | |
1911 | for (i = 0; i < sizeof(results) / sizeof(results[0]); i++) |
1912 | if (le16toh(result) == results[i].result_code) |
1913 | return (results[i].result_string); |
1914 | |
1915 | return ("unknown" ); |
1916 | } |
1917 | |
1918 | static int |
1919 | malo_cmd_get_spec(struct malo_softc *sc) |
1920 | { |
1921 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
1922 | struct malo_hw_spec *spec; |
1923 | |
1924 | hdr->cmd = htole16(MALO_CMD_GET_HW_SPEC); |
1925 | hdr->size = htole16(sizeof(*hdr) + sizeof(*spec)); |
1926 | hdr->seqnum = htole16(42); /* the one and only */ |
1927 | hdr->result = 0; |
1928 | spec = (struct malo_hw_spec *)(hdr + 1); |
1929 | |
1930 | memset(spec, 0, sizeof(*spec)); |
1931 | memset(spec->PermanentAddress, 0xff, ETHER_ADDR_LEN); |
1932 | spec->CookiePtr = htole32(sc->sc_cookie_dmaaddr); |
1933 | |
1934 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
1935 | BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD); |
1936 | |
1937 | if (malo_send_cmd_dma(sc, sc->sc_cmd_dmaaddr) != 0) |
1938 | return (ETIMEDOUT); |
1939 | |
1940 | /* get the data from the buffer */ |
1941 | DPRINTF(1, "%s: get_hw_spec: V%x R%x, #WCB %d, #Mcast %d, Regcode %d, " |
1942 | "#Ant %d\n" , device_xname(sc->sc_dev), htole16(spec->HwVersion), |
1943 | htole32(spec->FWReleaseNumber), htole16(spec->NumOfWCB), |
1944 | htole16(spec->NumOfMCastAdr), htole16(spec->RegionCode), |
1945 | htole16(spec->NumberOfAntenna)); |
1946 | |
1947 | /* tell the DMA engine where our rings are */ |
1948 | malo_mem_write4(sc, le32toh(spec->RxPdRdPtr) & 0xffff, |
1949 | sc->sc_rxring.physaddr); |
1950 | malo_mem_write4(sc, le32toh(spec->RxPdWrPtr) & 0xffff, |
1951 | sc->sc_rxring.physaddr); |
1952 | malo_mem_write4(sc, le32toh(spec->WcbBase0) & 0xffff, |
1953 | sc->sc_txring.physaddr); |
1954 | |
1955 | /* save DMA RX pointers for later use */ |
1956 | sc->sc_RxPdRdPtr = le32toh(spec->RxPdRdPtr) & 0xffff; |
1957 | sc->sc_RxPdWrPtr = le32toh(spec->RxPdWrPtr) & 0xffff; |
1958 | |
1959 | return (0); |
1960 | } |
1961 | |
1962 | static int |
1963 | malo_cmd_set_prescan(struct malo_softc *sc) |
1964 | { |
1965 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
1966 | |
1967 | hdr->cmd = htole16(MALO_CMD_SET_PRESCAN); |
1968 | hdr->size = htole16(sizeof(*hdr)); |
1969 | hdr->seqnum = 1; |
1970 | hdr->result = 0; |
1971 | |
1972 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
1973 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
1974 | |
1975 | return (malo_send_cmd_dma(sc, sc->sc_cmd_dmaaddr)); |
1976 | } |
1977 | |
1978 | static int |
1979 | malo_cmd_set_postscan(struct malo_softc *sc, uint8_t *macaddr, uint8_t ibsson) |
1980 | { |
1981 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
1982 | struct malo_cmd_postscan *body; |
1983 | |
1984 | hdr->cmd = htole16(MALO_CMD_SET_POSTSCAN); |
1985 | hdr->size = htole16(sizeof(*hdr) + sizeof(*body)); |
1986 | hdr->seqnum = 1; |
1987 | hdr->result = 0; |
1988 | body = (struct malo_cmd_postscan *)(hdr + 1); |
1989 | |
1990 | memset(body, 0, sizeof(*body)); |
1991 | memcpy(&body->bssid, macaddr, ETHER_ADDR_LEN); |
1992 | body->isibss = htole32(ibsson); |
1993 | |
1994 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
1995 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
1996 | |
1997 | return (malo_send_cmd_dma(sc, sc->sc_cmd_dmaaddr)); |
1998 | } |
1999 | |
2000 | static int |
2001 | malo_cmd_set_channel(struct malo_softc *sc, struct ieee80211_channel* chan) |
2002 | { |
2003 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
2004 | struct ieee80211com *ic = &sc->sc_ic; |
2005 | struct malo_cmd_channel *body; |
2006 | uint8_t channel; |
2007 | |
2008 | channel = ieee80211_chan2ieee(ic, chan); |
2009 | |
2010 | hdr->cmd = htole16(MALO_CMD_SET_CHANNEL); |
2011 | hdr->size = htole16(sizeof(*hdr) + sizeof(*body)); |
2012 | hdr->seqnum = 1; |
2013 | hdr->result = 0; |
2014 | body = (struct malo_cmd_channel *)(hdr + 1); |
2015 | |
2016 | memset(body, 0, sizeof(*body)); |
2017 | body->action = htole16(1); |
2018 | body->channel = channel; |
2019 | |
2020 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
2021 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2022 | |
2023 | return (malo_send_cmd_dma(sc, sc->sc_cmd_dmaaddr)); |
2024 | } |
2025 | |
2026 | static int |
2027 | malo_cmd_set_antenna(struct malo_softc *sc, uint16_t antenna) |
2028 | { |
2029 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
2030 | struct malo_cmd_antenna *body; |
2031 | |
2032 | hdr->cmd = htole16(MALO_CMD_SET_ANTENNA); |
2033 | hdr->size = htole16(sizeof(*hdr) + sizeof(*body)); |
2034 | hdr->seqnum = 1; |
2035 | hdr->result = 0; |
2036 | body = (struct malo_cmd_antenna *)(hdr + 1); |
2037 | |
2038 | memset(body, 0, sizeof(*body)); |
2039 | body->action = htole16(antenna); |
2040 | if (antenna == 1) |
2041 | body->mode = htole16(0xffff); |
2042 | else |
2043 | body->mode = htole16(2); |
2044 | |
2045 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
2046 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2047 | |
2048 | return (malo_send_cmd_dma(sc, sc->sc_cmd_dmaaddr)); |
2049 | } |
2050 | |
2051 | static int |
2052 | malo_cmd_set_radio(struct malo_softc *sc, uint16_t enable, |
2053 | uint16_t preamble_mode) |
2054 | { |
2055 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
2056 | struct malo_cmd_radio *body; |
2057 | |
2058 | hdr->cmd = htole16(MALO_CMD_SET_RADIO); |
2059 | hdr->size = htole16(sizeof(*hdr) + sizeof(*body)); |
2060 | hdr->seqnum = 1; |
2061 | hdr->result = 0; |
2062 | body = (struct malo_cmd_radio *)(hdr + 1); |
2063 | |
2064 | memset(body, 0, sizeof(*body)); |
2065 | body->action = htole16(1); |
2066 | body->preamble_mode = htole16(preamble_mode); |
2067 | body->enable = htole16(enable); |
2068 | |
2069 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
2070 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2071 | |
2072 | return (malo_send_cmd_dma(sc, sc->sc_cmd_dmaaddr)); |
2073 | } |
2074 | |
2075 | static int |
2076 | malo_cmd_set_aid(struct malo_softc *sc, uint8_t *bssid, uint16_t associd) |
2077 | { |
2078 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
2079 | struct malo_cmd_aid *body; |
2080 | |
2081 | hdr->cmd = htole16(MALO_CMD_SET_AID); |
2082 | hdr->size = htole16(sizeof(*hdr) + sizeof(*body)); |
2083 | hdr->seqnum = 1; |
2084 | hdr->result = 0; |
2085 | body = (struct malo_cmd_aid *)(hdr + 1); |
2086 | |
2087 | memset(body, 0, sizeof(*body)); |
2088 | body->associd = htole16(associd); |
2089 | memcpy(&body->macaddr[0], bssid, IEEE80211_ADDR_LEN); |
2090 | |
2091 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
2092 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2093 | |
2094 | return (malo_send_cmd_dma(sc, sc->sc_cmd_dmaaddr)); |
2095 | } |
2096 | |
2097 | static int |
2098 | malo_cmd_set_txpower(struct malo_softc *sc, unsigned int powerlevel) |
2099 | { |
2100 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
2101 | struct malo_cmd_txpower *body; |
2102 | |
2103 | hdr->cmd = htole16(MALO_CMD_SET_TXPOWER); |
2104 | hdr->size = htole16(sizeof(*hdr) + sizeof(*body)); |
2105 | hdr->seqnum = 1; |
2106 | hdr->result = 0; |
2107 | body = (struct malo_cmd_txpower *)(hdr + 1); |
2108 | |
2109 | memset(body, 0, sizeof(*body)); |
2110 | body->action = htole16(1); |
2111 | if (powerlevel < 30) |
2112 | body->supportpowerlvl = htole16(5); /* LOW */ |
2113 | else if (powerlevel >= 30 && powerlevel < 60) |
2114 | body->supportpowerlvl = htole16(10); /* MEDIUM */ |
2115 | else |
2116 | body->supportpowerlvl = htole16(15); /* HIGH */ |
2117 | |
2118 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
2119 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2120 | |
2121 | return (malo_send_cmd_dma(sc, sc->sc_cmd_dmaaddr)); |
2122 | } |
2123 | |
2124 | static int |
2125 | malo_cmd_set_rts(struct malo_softc *sc, uint32_t threshold) |
2126 | { |
2127 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
2128 | struct malo_cmd_rts *body; |
2129 | |
2130 | hdr->cmd = htole16(MALO_CMD_SET_RTS); |
2131 | hdr->size = htole16(sizeof(*hdr) + sizeof(*body)); |
2132 | hdr->seqnum = 1; |
2133 | hdr->result = 0; |
2134 | body = (struct malo_cmd_rts *)(hdr + 1); |
2135 | |
2136 | memset(body, 0, sizeof(*body)); |
2137 | body->action = htole16(1); |
2138 | body->threshold = htole32(threshold); |
2139 | |
2140 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
2141 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2142 | |
2143 | return (malo_send_cmd_dma(sc, sc->sc_cmd_dmaaddr)); |
2144 | } |
2145 | |
2146 | static int |
2147 | malo_cmd_set_slot(struct malo_softc *sc, uint8_t slot) |
2148 | { |
2149 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
2150 | struct malo_cmd_slot *body; |
2151 | |
2152 | hdr->cmd = htole16(MALO_CMD_SET_SLOT); |
2153 | hdr->size = htole16(sizeof(*hdr) + sizeof(*body)); |
2154 | hdr->seqnum = 1; |
2155 | hdr->result = 0; |
2156 | body = (struct malo_cmd_slot *)(hdr + 1); |
2157 | |
2158 | memset(body, 0, sizeof(*body)); |
2159 | body->action = htole16(1); |
2160 | body->slot = slot; |
2161 | |
2162 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
2163 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2164 | |
2165 | return (malo_send_cmd_dma(sc, sc->sc_cmd_dmaaddr)); |
2166 | } |
2167 | |
2168 | static int |
2169 | malo_cmd_set_rate(struct malo_softc *sc, uint8_t rate) |
2170 | { |
2171 | struct ieee80211com *ic = &sc->sc_ic; |
2172 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
2173 | struct malo_cmd_rate *body; |
2174 | int i; |
2175 | |
2176 | hdr->cmd = htole16(MALO_CMD_SET_RATE); |
2177 | hdr->size = htole16(sizeof(*hdr) + sizeof(*body)); |
2178 | hdr->seqnum = 1; |
2179 | hdr->result = 0; |
2180 | body = (struct malo_cmd_rate *)(hdr + 1); |
2181 | |
2182 | memset(body, 0,sizeof(*body)); |
2183 | |
2184 | if (ic->ic_opmode == IEEE80211_M_HOSTAP) { |
2185 | /* TODO */ |
2186 | } else |
2187 | { |
2188 | body->aprates[0] = 2; |
2189 | body->aprates[1] = 4; |
2190 | body->aprates[2] = 11; |
2191 | body->aprates[3] = 22; |
2192 | if (ic->ic_curmode == IEEE80211_MODE_11G) { |
2193 | body->aprates[4] = 0; |
2194 | body->aprates[5] = 12; |
2195 | body->aprates[6] = 18; |
2196 | body->aprates[7] = 24; |
2197 | body->aprates[8] = 36; |
2198 | body->aprates[9] = 48; |
2199 | body->aprates[10] = 72; |
2200 | body->aprates[11] = 96; |
2201 | body->aprates[12] = 108; |
2202 | } |
2203 | } |
2204 | |
2205 | if (rate != 0) { |
2206 | /* fixed rate */ |
2207 | for (i = 0; i < 13; i++) { |
2208 | if (body->aprates[i] == rate) { |
2209 | body->rateindex = i; |
2210 | body->dataratetype = 1; |
2211 | break; |
2212 | } |
2213 | } |
2214 | } |
2215 | |
2216 | bus_dmamap_sync(sc->sc_dmat, sc->sc_cmd_dmam, 0, PAGE_SIZE, |
2217 | BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); |
2218 | |
2219 | return (malo_send_cmd_dma(sc, sc->sc_cmd_dmaaddr)); |
2220 | } |
2221 | |
2222 | static void |
2223 | malo_cmd_response(struct malo_softc *sc) |
2224 | { |
2225 | struct malo_cmdheader *hdr = sc->sc_cmd_mem; |
2226 | |
2227 | if (le16toh(hdr->result) != MALO_CMD_RESULT_OK) { |
2228 | aprint_error_dev(sc->sc_dev, "firmware cmd %s failed with %s\n" , |
2229 | malo_cmd_string(hdr->cmd), |
2230 | malo_cmd_string_result(hdr->result)); |
2231 | } |
2232 | |
2233 | #ifdef MALO_DEBUG |
2234 | aprint_error_dev(sc->sc_dev, "cmd answer for %s=%s\n" , |
2235 | malo_cmd_string(hdr->cmd), |
2236 | malo_cmd_string_result(hdr->result)); |
2237 | |
2238 | if (malo_d > 2) |
2239 | malo_hexdump(hdr, le16toh(hdr->size)); |
2240 | #endif |
2241 | } |
2242 | |