2 * Copyright (c) 2006 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Sepherosa Ziehau <sepherosa@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $DragonFly: src/sys/dev/netif/acx/acx100.c,v 1.5 2006/10/25 20:55:55 dillon Exp $
37 #include <sys/param.h>
39 #include <sys/endian.h>
41 #include <sys/socket.h>
42 #include <sys/sysctl.h>
45 #include <net/if_arp.h>
46 #include <net/if_media.h>
48 #include <netproto/802_11/ieee80211.h>
49 #include <netproto/802_11/ieee80211_var.h>
51 #include <bus/pci/pcireg.h>
55 #include "if_acxreg.h"
56 #include "if_acxvar.h"
59 #define ACX100_CONF_FW_RING 0x0003
60 #define ACX100_CONF_MEMOPT 0x0005
62 #define ACX100_INTR_ENABLE (ACXRV_INTR_TX_FINI | ACXRV_INTR_RX_FINI)
64 * XXX do we really care about following interrupts?
66 * ACXRV_INTR_INFO | ACXRV_INTR_SCAN_FINI
69 #define ACX100_INTR_DISABLE (uint16_t)~(ACXRV_INTR_UNKN)
71 #define ACX100_RATE(rate) ((rate) * 5)
73 #define ACX100_TXPOWER 18
74 #define ACX100_GPIO_POWER_LED 0x0800
75 #define ACX100_EE_EADDR_OFS 0x1a
77 #define ACX100_FW_TXRING_SIZE (ACX_TX_DESC_CNT * sizeof(struct acx_fw_txdesc))
78 #define ACX100_FW_RXRING_SIZE (ACX_RX_DESC_CNT * sizeof(struct acx_fw_rxdesc))
82 * Following structs' fields are little endian
85 struct acx100_bss_join {
91 struct acx100_conf_fw_ring {
92 struct acx_conf confcom;
93 uint32_t fw_ring_size; /* total size of fw (tx + rx) ring */
94 uint32_t fw_rxring_addr; /* start phyaddr of fw rx desc */
95 uint8_t opt; /* see ACX100_RINGOPT_ */
96 uint8_t fw_txring_num; /* num of TX ring */
97 uint8_t fw_rxdesc_num; /* num of fw rx desc */
99 uint32_t fw_ring_end[2]; /* see ACX100_SET_RING_END() */
100 uint32_t fw_txring_addr; /* start phyaddr of fw tx desc */
101 uint8_t fw_txring_prio; /* see ACX100_TXRING_PRIO_ */
102 uint8_t fw_txdesc_num; /* num of fw tx desc */
106 #define ACX100_RINGOPT_AUTO_RESET 0x1
107 #define ACX100_TXRING_PRIO_DEFAULT 0
108 #define ACX100_SET_RING_END(conf, end) \
110 (conf)->fw_ring_end[0] = htole32(end); \
111 (conf)->fw_ring_end[1] = htole32(end + 8); \
114 struct acx100_conf_memblk_size {
115 struct acx_conf confcom;
116 uint16_t memblk_size; /* size of each mem block */
119 struct acx100_conf_mem {
120 struct acx_conf confcom;
121 uint32_t opt; /* see ACX100_MEMOPT_ */
122 uint32_t h_rxring_paddr; /* host rx desc start phyaddr */
125 * Memory blocks are controled by hardware
126 * once after they are initialized
128 uint32_t rx_memblk_addr; /* start addr of rx mem blocks */
129 uint32_t tx_memblk_addr; /* start addr of tx mem blocks */
130 uint16_t rx_memblk_num; /* num of RX mem block */
131 uint16_t tx_memblk_num; /* num of TX mem block */
134 #define ACX100_MEMOPT_MEM_INSTR 0x00000000 /* memory access instruct */
135 #define ACX100_MEMOPT_HOSTDESC 0x00010000 /* host indirect desc */
136 #define ACX100_MEMOPT_MEMBLOCK 0x00020000 /* local mem block list */
137 #define ACX100_MEMOPT_IO_INSTR 0x00040000 /* IO instruct */
138 #define ACX100_MEMOPT_PCICONF 0x00080000 /* PCI conf space */
140 #define ACX100_MEMBLK_ALIGN 0x20
142 struct acx100_conf_cca_mode {
143 struct acx_conf confcom;
148 struct acx100_conf_ed_thresh {
149 struct acx_conf confcom;
154 struct acx100_conf_wepkey {
155 struct acx_conf confcom;
156 uint8_t action; /* see ACX100_WEPKEY_ACT_ */
159 #define ACX100_WEPKEY_LEN 29
160 uint8_t key[ACX100_WEPKEY_LEN];
163 #define ACX100_WEPKEY_ACT_ADD 1
165 #define ACX100_CONF_FUNC(sg, name) _ACX_CONF_FUNC(sg, name, 100)
166 #define ACX_CONF_fw_ring ACX100_CONF_FW_RING
167 #define ACX_CONF_memblk_size ACX_CONF_MEMBLK_SIZE
168 #define ACX_CONF_mem ACX100_CONF_MEMOPT
169 #define ACX_CONF_cca_mode ACX_CONF_CCA_MODE
170 #define ACX_CONF_ed_thresh ACX_CONF_ED_THRESH
171 #define ACX_CONF_wepkey ACX_CONF_WEPKEY
172 ACX100_CONF_FUNC(set, fw_ring);
173 ACX100_CONF_FUNC(set, memblk_size);
174 ACX100_CONF_FUNC(set, mem);
175 ACX100_CONF_FUNC(get, cca_mode);
176 ACX100_CONF_FUNC(set, cca_mode);
177 ACX100_CONF_FUNC(get, ed_thresh);
178 ACX100_CONF_FUNC(set, ed_thresh);
179 ACX100_CONF_FUNC(set, wepkey);
181 #define ACXCMD_init_mem ACXCMD_INIT_MEM
182 ACX_NOARG_FUNC(init_mem);
184 static const uint16_t acx100_reg[ACXREG_MAX] = {
185 ACXREG(SOFT_RESET, 0x0000),
187 ACXREG(FWMEM_ADDR, 0x0014),
188 ACXREG(FWMEM_DATA, 0x0018),
189 ACXREG(FWMEM_CTRL, 0x001c),
190 ACXREG(FWMEM_START, 0x0020),
192 ACXREG(EVENT_MASK, 0x0034),
194 ACXREG(INTR_TRIG, 0x007c),
195 ACXREG(INTR_MASK, 0x0098),
196 ACXREG(INTR_STATUS, 0x00a4),
197 ACXREG(INTR_STATUS_CLR, 0x00a8),
198 ACXREG(INTR_ACK, 0x00ac),
200 ACXREG(HINTR_TRIG, 0x00b0),
201 ACXREG(RADIO_ENABLE, 0x0104),
203 ACXREG(EEPROM_INIT, 0x02d0),
204 ACXREG(EEPROM_CTRL, 0x0250),
205 ACXREG(EEPROM_ADDR, 0x0254),
206 ACXREG(EEPROM_DATA, 0x0258),
207 ACXREG(EEPROM_CONF, 0x025c),
208 ACXREG(EEPROM_INFO, 0x02ac),
210 ACXREG(PHY_ADDR, 0x0268),
211 ACXREG(PHY_DATA, 0x026c),
212 ACXREG(PHY_CTRL, 0x0270),
214 ACXREG(GPIO_OUT_ENABLE, 0x0290),
215 ACXREG(GPIO_OUT, 0x0298),
217 ACXREG(CMD_REG_OFFSET, 0x02a4),
218 ACXREG(INFO_REG_OFFSET, 0x02a8),
220 ACXREG(RESET_SENSE, 0x02d4),
221 ACXREG(ECPU_CTRL, 0x02d8)
224 static const uint8_t acx100_txpower_maxim[21] = {
233 static const uint8_t acx100_txpower_rfmd[21] = {
242 static int acx100_init(struct acx_softc *);
243 static int acx100_init_wep(struct acx_softc *);
244 static int acx100_init_tmplt(struct acx_softc *);
245 static int acx100_init_fw_ring(struct acx_softc *);
246 static int acx100_init_memory(struct acx_softc *);
248 static void acx100_init_fw_txring(struct acx_softc *, uint32_t);
249 static void acx100_init_fw_rxring(struct acx_softc *, uint32_t);
251 static int acx100_read_config(struct acx_softc *, struct acx_config *);
252 static int acx100_write_config(struct acx_softc *, struct acx_config *);
254 static int acx100_set_txpower(struct acx_softc *);
256 static void acx100_set_fw_txdesc_rate(struct acx_softc *,
258 struct ieee80211_node *, int);
259 static void acx100_tx_complete(struct acx_softc *, struct acx_txbuf *,
261 static void acx100_set_bss_join_param(struct acx_softc *, void *, int);
263 static int acx100_set_wepkey(struct acx_softc *, struct ieee80211_key *,
266 static void acx100_proc_wep_rxbuf(struct acx_softc *, struct mbuf *, int *);
269 acx100_set_param(device_t dev)
271 struct acx_softc *sc = device_get_softc(dev);
272 struct ieee80211com *ic = &sc->sc_ic;
274 sc->chip_mem1_rid = PCIR_BAR(1);
275 sc->chip_mem2_rid = PCIR_BAR(2);
276 sc->chip_ioreg = acx100_reg;
277 sc->chip_hw_crypt = 1;
278 sc->chip_intr_enable = ACX100_INTR_ENABLE;
279 sc->chip_intr_disable = ACX100_INTR_DISABLE;
280 sc->chip_gpio_pled = ACX100_GPIO_POWER_LED;
281 sc->chip_ee_eaddr_ofs = ACX100_EE_EADDR_OFS;
282 sc->chip_txdesc1_len = ACX_FRAME_HDRLEN;
283 sc->chip_fw_txdesc_ctrl = DESC_CTRL_AUTODMA |
285 DESC_CTRL_FIRST_FRAG;
286 sc->chip_short_retry_limit = 7;
288 sc->chip_phymode = IEEE80211_MODE_11B;
289 sc->chip_chan_flags = IEEE80211_CHAN_B;
291 ic->ic_phytype = IEEE80211_T_DS;
292 ic->ic_sup_rates[IEEE80211_MODE_11B] = acx_rates_11b;
294 ic->ic_ratectl.rc_st_ratectl_cap = IEEE80211_RATECTL_CAP_ONOE;
295 ic->ic_ratectl.rc_st_ratectl = IEEE80211_RATECTL_ONOE;
297 sc->chip_init = acx100_init;
298 sc->chip_set_wepkey = acx100_set_wepkey;
299 sc->chip_read_config = acx100_read_config;
300 sc->chip_write_config = acx100_write_config;
301 sc->chip_set_fw_txdesc_rate = acx100_set_fw_txdesc_rate;
302 sc->chip_tx_complete = acx100_tx_complete;
303 sc->chip_set_bss_join_param = acx100_set_bss_join_param;
304 sc->chip_proc_wep_rxbuf = acx100_proc_wep_rxbuf;
308 acx100_init(struct acx_softc *sc)
312 * Order of initialization:
315 * 3) Firmware TX/RX ring
317 * Above order is critical to get a correct memory map
320 if (acx100_init_wep(sc) != 0) {
321 if_printf(&sc->sc_ic.ic_if, "%s can't initialize wep\n",
326 if (acx100_init_tmplt(sc) != 0) {
327 if_printf(&sc->sc_ic.ic_if, "%s can't initialize templates\n",
332 if (acx100_init_fw_ring(sc) != 0) {
333 if_printf(&sc->sc_ic.ic_if, "%s can't initialize fw ring\n",
338 if (acx100_init_memory(sc) != 0) {
339 if_printf(&sc->sc_ic.ic_if, "%s can't initialize hw memory\n",
347 acx100_init_wep(struct acx_softc *sc)
349 struct acx_conf_wepopt wep_opt;
350 struct acx_conf_mmap mem_map;
352 /* Set WEP cache start/end address */
353 if (acx_get_mmap_conf(sc, &mem_map) != 0) {
354 if_printf(&sc->sc_ic.ic_if, "can't get mmap\n");
358 mem_map.wep_cache_start = htole32(le32toh(mem_map.code_end) + 4);
359 mem_map.wep_cache_end = htole32(le32toh(mem_map.code_end) + 4);
360 if (acx_set_mmap_conf(sc, &mem_map) != 0) {
361 if_printf(&sc->sc_ic.ic_if, "can't set mmap\n");
365 /* Set WEP options */
366 wep_opt.nkey = htole16(IEEE80211_WEP_NKID + 10);
367 wep_opt.opt = WEPOPT_HDWEP;
368 if (acx_set_wepopt_conf(sc, &wep_opt) != 0) {
369 if_printf(&sc->sc_ic.ic_if, "can't set wep opt\n");
376 acx100_init_tmplt(struct acx_softc *sc)
378 struct acx_conf_mmap mem_map;
379 struct acx_tmplt_tim tim;
381 /* Set templates start address */
382 if (acx_get_mmap_conf(sc, &mem_map) != 0) {
383 if_printf(&sc->sc_ic.ic_if, "can't get mmap\n");
387 mem_map.pkt_tmplt_start = mem_map.wep_cache_end;
388 if (acx_set_mmap_conf(sc, &mem_map) != 0) {
389 if_printf(&sc->sc_ic.ic_if, "can't set mmap\n");
393 /* Initialize various packet templates */
394 if (acx_init_tmplt_ordered(sc) != 0) {
395 if_printf(&sc->sc_ic.ic_if, "can't init tmplt\n");
399 /* Setup TIM template */
400 bzero(&tim, sizeof(tim));
401 tim.tim_eid = IEEE80211_ELEMID_TIM;
402 tim.tim_len = ACX_TIM_LEN(ACX_TIM_BITMAP_LEN);
403 if (_acx_set_tim_tmplt(sc, &tim,
404 ACX_TMPLT_TIM_SIZ(ACX_TIM_BITMAP_LEN)) != 0) {
405 if_printf(&sc->sc_ic.ic_if, "can't set tim tmplt\n");
412 acx100_init_fw_ring(struct acx_softc *sc)
414 struct acx100_conf_fw_ring ring;
415 struct acx_conf_mmap mem_map;
416 uint32_t txring_start, rxring_start, ring_end;
418 /* Set firmware descriptor ring start address */
419 if (acx_get_mmap_conf(sc, &mem_map) != 0) {
420 if_printf(&sc->sc_ic.ic_if, "can't get mmap\n");
424 txring_start = le32toh(mem_map.pkt_tmplt_end) + 4;
425 rxring_start = txring_start + ACX100_FW_TXRING_SIZE;
426 ring_end = rxring_start + ACX100_FW_RXRING_SIZE;
428 mem_map.fw_desc_start = htole32(txring_start);
429 if (acx_set_mmap_conf(sc, &mem_map) != 0) {
430 if_printf(&sc->sc_ic.ic_if, "can't set mmap\n");
434 /* Set firmware descriptor ring configure */
435 bzero(&ring, sizeof(ring));
436 ring.fw_ring_size = htole32(ACX100_FW_TXRING_SIZE +
437 ACX100_FW_RXRING_SIZE + 8);
439 ring.fw_txring_num = 1;
440 ring.fw_txring_addr = htole32(txring_start);
441 ring.fw_txring_prio = ACX100_TXRING_PRIO_DEFAULT;
442 ring.fw_txdesc_num = 0; /* XXX ignored?? */
444 ring.fw_rxring_addr = htole32(rxring_start);
445 ring.fw_rxdesc_num = 0; /* XXX ignored?? */
447 ring.opt = ACX100_RINGOPT_AUTO_RESET;
448 ACX100_SET_RING_END(&ring, ring_end);
449 if (acx100_set_fw_ring_conf(sc, &ring) != 0) {
450 if_printf(&sc->sc_ic.ic_if, "can't set fw ring configure\n");
454 /* Setup firmware TX/RX descriptor ring */
455 acx100_init_fw_txring(sc, txring_start);
456 acx100_init_fw_rxring(sc, rxring_start);
461 #define MEMBLK_ALIGN(addr) \
462 (((addr) + (ACX100_MEMBLK_ALIGN - 1)) & ~(ACX100_MEMBLK_ALIGN - 1))
465 acx100_init_memory(struct acx_softc *sc)
467 struct acx100_conf_memblk_size memblk_sz;
468 struct acx100_conf_mem mem;
469 struct acx_conf_mmap mem_map;
470 uint32_t memblk_start, memblk_end;
471 int total_memblk, txblk_num, rxblk_num;
473 /* Set memory block start address */
474 if (acx_get_mmap_conf(sc, &mem_map) != 0) {
475 if_printf(&sc->sc_ic.ic_if, "can't get mmap\n");
479 mem_map.memblk_start =
480 htole32(MEMBLK_ALIGN(le32toh(mem_map.fw_desc_end) + 4));
482 if (acx_set_mmap_conf(sc, &mem_map) != 0) {
483 if_printf(&sc->sc_ic.ic_if, "can't set mmap\n");
487 /* Set memory block size */
488 memblk_sz.memblk_size = htole16(ACX_MEMBLOCK_SIZE);
489 if (acx100_set_memblk_size_conf(sc, &memblk_sz) != 0) {
490 if_printf(&sc->sc_ic.ic_if, "can't set mem block size\n");
494 /* Get memory map after setting it */
495 if (acx_get_mmap_conf(sc, &mem_map) != 0) {
496 if_printf(&sc->sc_ic.ic_if, "can't get mmap again\n");
499 memblk_start = le32toh(mem_map.memblk_start);
500 memblk_end = le32toh(mem_map.memblk_end);
502 /* Set memory options */
503 mem.opt = htole32(ACX100_MEMOPT_MEMBLOCK | ACX100_MEMOPT_HOSTDESC);
504 mem.h_rxring_paddr = htole32(sc->sc_ring_data.rx_ring_paddr);
506 total_memblk = (memblk_end - memblk_start) / ACX_MEMBLOCK_SIZE;
508 rxblk_num = total_memblk / 2; /* 50% */
509 txblk_num = total_memblk - rxblk_num; /* 50% */
511 DPRINTF((&sc->sc_ic.ic_if, "\ttotal memory blocks\t%d\n"
512 "\trx memory blocks\t%d\n"
513 "\ttx memory blocks\t%d\n",
514 total_memblk, rxblk_num, txblk_num));
516 mem.rx_memblk_num = htole16(rxblk_num);
517 mem.tx_memblk_num = htole16(txblk_num);
519 mem.rx_memblk_addr = htole32(MEMBLK_ALIGN(memblk_start));
521 htole32(MEMBLK_ALIGN(memblk_start +
522 (ACX_MEMBLOCK_SIZE * rxblk_num)));
524 if (acx100_set_mem_conf(sc, &mem) != 0) {
525 if_printf(&sc->sc_ic.ic_if, "can't set mem options\n");
529 /* Initialize memory */
530 if (acx_init_mem(sc) != 0) {
531 if_printf(&sc->sc_ic.ic_if, "can't init mem\n");
540 acx100_init_fw_txring(struct acx_softc *sc, uint32_t fw_txdesc_start)
542 struct acx_fw_txdesc fw_desc;
543 struct acx_txbuf *tx_buf;
544 uint32_t desc_paddr, fw_desc_offset;
547 bzero(&fw_desc, sizeof(fw_desc));
548 fw_desc.f_tx_ctrl = DESC_CTRL_HOSTOWN |
551 DESC_CTRL_FIRST_FRAG;
553 tx_buf = sc->sc_buf_data.tx_buf;
554 fw_desc_offset = fw_txdesc_start;
555 desc_paddr = sc->sc_ring_data.tx_ring_paddr;
557 for (i = 0; i < ACX_TX_DESC_CNT; ++i) {
558 fw_desc.f_tx_host_desc = htole32(desc_paddr);
560 if (i == ACX_TX_DESC_CNT - 1) {
561 fw_desc.f_tx_next_desc = htole32(fw_txdesc_start);
563 fw_desc.f_tx_next_desc =
564 htole32(fw_desc_offset +
565 sizeof(struct acx_fw_txdesc));
568 tx_buf[i].tb_fwdesc_ofs = fw_desc_offset;
569 DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc,
572 desc_paddr += (2 * sizeof(struct acx_host_desc));
573 fw_desc_offset += sizeof(fw_desc);
578 acx100_init_fw_rxring(struct acx_softc *sc, uint32_t fw_rxdesc_start)
580 struct acx_fw_rxdesc fw_desc;
581 uint32_t fw_desc_offset;
584 bzero(&fw_desc, sizeof(fw_desc));
585 fw_desc.f_rx_ctrl = DESC_CTRL_RECLAIM | DESC_CTRL_AUTODMA;
587 fw_desc_offset = fw_rxdesc_start;
589 for (i = 0; i < ACX_RX_DESC_CNT; ++i) {
590 if (i == ACX_RX_DESC_CNT - 1) {
591 fw_desc.f_rx_next_desc = htole32(fw_rxdesc_start);
593 fw_desc.f_rx_next_desc =
594 htole32(fw_desc_offset +
595 sizeof(struct acx_fw_rxdesc));
598 DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc,
601 fw_desc_offset += sizeof(fw_desc);
606 acx100_read_config(struct acx_softc *sc, struct acx_config *conf)
608 struct acx100_conf_cca_mode cca;
609 struct acx100_conf_ed_thresh ed;
613 * CCA mode and ED threshold MUST be read during initialization
614 * or the acx100 card won't work as expected
618 if (acx100_get_cca_mode_conf(sc, &cca) != 0) {
619 if_printf(&sc->sc_ic.ic_if, "%s can't get cca mode\n",
623 conf->cca_mode = cca.cca_mode;
624 DPRINTF((&sc->sc_ic.ic_if, "cca mode %02x\n", cca.cca_mode));
626 /* Get ED threshold */
627 if (acx100_get_ed_thresh_conf(sc, &ed) != 0) {
628 if_printf(&sc->sc_ic.ic_if, "%s can't get ed threshold\n",
632 conf->ed_thresh = ed.ed_thresh;
633 DPRINTF((&sc->sc_ic.ic_if, "ed threshold %02x\n", ed.ed_thresh));
639 acx100_write_config(struct acx_softc *sc, struct acx_config *conf)
641 struct acx100_conf_cca_mode cca;
642 struct acx100_conf_ed_thresh ed;
645 cca.cca_mode = conf->cca_mode;
646 if (acx100_set_cca_mode_conf(sc, &cca) != 0) {
647 if_printf(&sc->sc_ic.ic_if, "%s can't set cca mode\n",
652 /* Set ED threshold */
653 ed.ed_thresh = conf->ed_thresh;
654 if (acx100_set_ed_thresh_conf(sc, &ed) != 0) {
655 if_printf(&sc->sc_ic.ic_if, "%s can't set ed threshold\n",
661 acx100_set_txpower(sc); /* ignore return value */
667 acx100_set_txpower(struct acx_softc *sc)
671 switch (sc->sc_radio_type) {
672 case ACX_RADIO_TYPE_MAXIM:
673 map = acx100_txpower_maxim;
675 case ACX_RADIO_TYPE_RFMD:
676 case ACX_RADIO_TYPE_RALINK:
677 map = acx100_txpower_rfmd;
680 if_printf(&sc->sc_ic.ic_if, "TX power for radio type 0x%02x "
681 "can't be set yet\n", sc->sc_radio_type);
685 acx_write_phyreg(sc, ACXRV_PHYREG_TXPOWER, map[ACX100_TXPOWER]);
690 acx100_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf,
691 struct ieee80211_node *ni, int data_len)
695 tx_buf->tb_rateidx_len = 1;
697 rate = 2; /* 1Mbit/s */
698 tx_buf->tb_rateidx[0] = 0;
700 ieee80211_ratectl_findrate(ni, data_len,
701 tx_buf->tb_rateidx, 1);
702 rate = IEEE80211_RS_RATE(&ni->ni_rates,
703 tx_buf->tb_rateidx[0]);
705 FW_TXDESC_SETFIELD_1(sc, tx_buf, f_tx_rate100, ACX100_RATE(rate));
709 acx100_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl)
711 struct acx100_bss_join *bj = param;
713 bj->dtim_intvl = dtim_intvl;
714 bj->basic_rates = 15; /* XXX */
715 bj->all_rates = 31; /* XXX */
719 acx100_set_wepkey(struct acx_softc *sc, struct ieee80211_key *wk, int wk_idx)
721 struct acx100_conf_wepkey conf_wk;
723 if (wk->wk_keylen > ACX100_WEPKEY_LEN) {
724 if_printf(&sc->sc_ic.ic_if, "%dth WEP key size beyond %d\n",
725 wk_idx, ACX100_WEPKEY_LEN);
729 conf_wk.action = ACX100_WEPKEY_ACT_ADD;
730 conf_wk.key_len = wk->wk_keylen;
731 conf_wk.key_idx = wk_idx;
732 bcopy(wk->wk_key, conf_wk.key, wk->wk_keylen);
733 if (acx100_set_wepkey_conf(sc, &conf_wk) != 0) {
734 if_printf(&sc->sc_ic.ic_if, "%s set %dth WEP key failed\n",
742 acx100_proc_wep_rxbuf(struct acx_softc *sc, struct mbuf *m, int *len)
745 struct ieee80211_frame *f;
748 * Strip leading IV and KID, and trailing CRC
751 f = mtod(m, struct ieee80211_frame *);
753 if ((f->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
754 mac_hdrlen = sizeof(struct ieee80211_frame_addr4);
756 mac_hdrlen = sizeof(struct ieee80211_frame);
758 #define IEEEWEP_IVLEN (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
759 #define IEEEWEP_EXLEN (IEEEWEP_IVLEN + IEEE80211_WEP_CRCLEN)
761 *len = *len - IEEEWEP_EXLEN;
763 /* Move MAC header toward frame body */
764 ovbcopy(f, (uint8_t *)f + IEEEWEP_IVLEN, mac_hdrlen);
765 m_adj(m, IEEEWEP_IVLEN);
772 acx100_tx_complete(struct acx_softc *sc, struct acx_txbuf *tx_buf,
773 int frame_len, int is_fail)
775 int long_retries, short_retries;
776 struct ieee80211_ratectl_res rc_res;
778 long_retries = FW_TXDESC_GETFIELD_1(sc, tx_buf, f_tx_rts_nretry);
779 short_retries = FW_TXDESC_GETFIELD_1(sc, tx_buf, f_tx_data_nretry);
781 rc_res.rc_res_rateidx = tx_buf->tb_rateidx[0];
782 rc_res.rc_res_tries = short_retries + 1;
784 ieee80211_ratectl_tx_complete(tx_buf->tb_node, frame_len,
785 &rc_res, 1, short_retries, long_retries,