xref: /openbsd-src/sys/dev/ic/acx100.c (revision 4b1a56afb1a28c97103da3911d326d1216798a6e)
1*4b1a56afSjsg /*	$OpenBSD: acx100.c,v 1.28 2022/01/09 05:42:38 jsg Exp $ */
295339239Smglocker 
395339239Smglocker /*
495339239Smglocker  * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
595339239Smglocker  *
695339239Smglocker  * Permission to use, copy, modify, and distribute this software for any
795339239Smglocker  * purpose with or without fee is hereby granted, provided that the above
895339239Smglocker  * copyright notice and this permission notice appear in all copies.
995339239Smglocker  *
1095339239Smglocker  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1195339239Smglocker  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1295339239Smglocker  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1395339239Smglocker  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495339239Smglocker  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595339239Smglocker  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695339239Smglocker  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795339239Smglocker  */
180f91cf57Smglocker 
190f91cf57Smglocker /*
200f91cf57Smglocker  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
210f91cf57Smglocker  *
220f91cf57Smglocker  * This code is derived from software contributed to The DragonFly Project
230f91cf57Smglocker  * by Sepherosa Ziehau <sepherosa@gmail.com>
240f91cf57Smglocker  *
250f91cf57Smglocker  * Redistribution and use in source and binary forms, with or without
260f91cf57Smglocker  * modification, are permitted provided that the following conditions
270f91cf57Smglocker  * are met:
280f91cf57Smglocker  *
290f91cf57Smglocker  * 1. Redistributions of source code must retain the above copyright
300f91cf57Smglocker  *    notice, this list of conditions and the following disclaimer.
310f91cf57Smglocker  * 2. Redistributions in binary form must reproduce the above copyright
320f91cf57Smglocker  *    notice, this list of conditions and the following disclaimer in
330f91cf57Smglocker  *    the documentation and/or other materials provided with the
340f91cf57Smglocker  *    distribution.
350f91cf57Smglocker  * 3. Neither the name of The DragonFly Project nor the names of its
360f91cf57Smglocker  *    contributors may be used to endorse or promote products derived
370f91cf57Smglocker  *    from this software without specific, prior written permission.
380f91cf57Smglocker  *
390f91cf57Smglocker  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
400f91cf57Smglocker  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
410f91cf57Smglocker  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
420f91cf57Smglocker  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
430f91cf57Smglocker  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
440f91cf57Smglocker  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
450f91cf57Smglocker  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
460f91cf57Smglocker  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
470f91cf57Smglocker  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
480f91cf57Smglocker  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
490f91cf57Smglocker  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
500f91cf57Smglocker  * SUCH DAMAGE.
510f91cf57Smglocker  */
520f91cf57Smglocker 
535f82ccb0Sjsg #include "bpfilter.h"
545f82ccb0Sjsg 
550f91cf57Smglocker #include <sys/param.h>
560f91cf57Smglocker #include <sys/systm.h>
570f91cf57Smglocker #include <sys/mbuf.h>
580f91cf57Smglocker #include <sys/endian.h>
590f91cf57Smglocker #include <sys/socket.h>
60da8183c8Sbrad #include <sys/device.h>
610f91cf57Smglocker 
620f91cf57Smglocker #include <machine/bus.h>
630f91cf57Smglocker 
640f91cf57Smglocker #include <net/if.h>
650f91cf57Smglocker #include <net/if_media.h>
660f91cf57Smglocker 
670f91cf57Smglocker #include <netinet/in.h>
680f91cf57Smglocker #include <netinet/if_ether.h>
690f91cf57Smglocker 
700f91cf57Smglocker #include <net80211/ieee80211_var.h>
71960b9804Smglocker #include <net80211/ieee80211_amrr.h>
72172cbfceSmglocker #include <net80211/ieee80211_radiotap.h>
730f91cf57Smglocker 
740f91cf57Smglocker #include <dev/pci/pcireg.h>
750f91cf57Smglocker 
760f91cf57Smglocker #include <dev/ic/acxvar.h>
770f91cf57Smglocker #include <dev/ic/acxreg.h>
780f91cf57Smglocker 
790f91cf57Smglocker #define ACX100_CONF_FW_RING	0x0003
800f91cf57Smglocker #define ACX100_CONF_MEMOPT	0x0005
810f91cf57Smglocker 
820f91cf57Smglocker #define ACX100_INTR_ENABLE	(ACXRV_INTR_TX_FINI | ACXRV_INTR_RX_FINI)
830f91cf57Smglocker /*
840f91cf57Smglocker  * XXX do we really care about following interrupts?
850f91cf57Smglocker  *
860f91cf57Smglocker  * ACXRV_INTR_INFO | ACXRV_INTR_SCAN_FINI
870f91cf57Smglocker  */
880f91cf57Smglocker 
890f91cf57Smglocker #define ACX100_INTR_DISABLE	(uint16_t)~(ACXRV_INTR_UNKN)
900f91cf57Smglocker 
910f91cf57Smglocker #define ACX100_RATE(rate)	((rate) * 5)
920f91cf57Smglocker 
930f91cf57Smglocker #define ACX100_TXPOWER		18
940f91cf57Smglocker #define ACX100_GPIO_POWER_LED	0x0800
950f91cf57Smglocker #define ACX100_EE_EADDR_OFS	0x1a
960f91cf57Smglocker 
970f91cf57Smglocker #define ACX100_FW_TXRING_SIZE	(ACX_TX_DESC_CNT * sizeof(struct acx_fw_txdesc))
980f91cf57Smglocker #define ACX100_FW_RXRING_SIZE	(ACX_RX_DESC_CNT * sizeof(struct acx_fw_rxdesc))
990f91cf57Smglocker 
100793d9a9fSmglocker int	acx100_init(struct acx_softc *);
101793d9a9fSmglocker int	acx100_init_wep(struct acx_softc *);
102793d9a9fSmglocker int	acx100_init_tmplt(struct acx_softc *);
103793d9a9fSmglocker int	acx100_init_fw_ring(struct acx_softc *);
104793d9a9fSmglocker int	acx100_init_memory(struct acx_softc *);
105793d9a9fSmglocker void	acx100_init_fw_txring(struct acx_softc *, uint32_t);
106793d9a9fSmglocker void	acx100_init_fw_rxring(struct acx_softc *, uint32_t);
107793d9a9fSmglocker int	acx100_read_config(struct acx_softc *, struct acx_config *);
108793d9a9fSmglocker int	acx100_write_config(struct acx_softc *, struct acx_config *);
109793d9a9fSmglocker int	acx100_set_txpower(struct acx_softc *);
110793d9a9fSmglocker void	acx100_set_fw_txdesc_rate(struct acx_softc *,
111793d9a9fSmglocker 	    struct acx_txbuf *, int);
112793d9a9fSmglocker void	acx100_set_bss_join_param(struct acx_softc *, void *, int);
11383da4af0Sdamien int	acx100_set_wepkey(struct acx_softc *, struct ieee80211_key *, int);
114793d9a9fSmglocker void	acx100_proc_wep_rxbuf(struct acx_softc *, struct mbuf *, int *);
115793d9a9fSmglocker 
1160f91cf57Smglocker /*
1170f91cf57Smglocker  * NOTE:
1180f91cf57Smglocker  * Following structs' fields are little endian
1190f91cf57Smglocker  */
1200f91cf57Smglocker struct acx100_bss_join {
1210f91cf57Smglocker 	uint8_t	dtim_intvl;
1220f91cf57Smglocker 	uint8_t	basic_rates;
1230f91cf57Smglocker 	uint8_t	all_rates;
1240f91cf57Smglocker } __packed;
1250f91cf57Smglocker 
1260f91cf57Smglocker struct acx100_conf_fw_ring {
1270f91cf57Smglocker 	struct acx_conf	confcom;
1280f91cf57Smglocker 	uint32_t	fw_ring_size;	/* total size of fw (tx + rx) ring */
1290f91cf57Smglocker 	uint32_t	fw_rxring_addr;	/* start phyaddr of fw rx desc */
1300f91cf57Smglocker 	uint8_t		opt;		/* see ACX100_RINGOPT_ */
1310f91cf57Smglocker 	uint8_t		fw_txring_num;	/* num of TX ring */
1320f91cf57Smglocker 	uint8_t		fw_rxdesc_num;	/* num of fw rx desc */
1330f91cf57Smglocker 	uint8_t		reserved0;
1340f91cf57Smglocker 	uint32_t	fw_ring_end[2];	/* see ACX100_SET_RING_END() */
1350f91cf57Smglocker 	uint32_t	fw_txring_addr;	/* start phyaddr of fw tx desc */
1360f91cf57Smglocker 	uint8_t		fw_txring_prio;	/* see ACX100_TXRING_PRIO_ */
1370f91cf57Smglocker 	uint8_t		fw_txdesc_num;	/* num of fw tx desc */
1380f91cf57Smglocker 	uint16_t	reserved1;
1390f91cf57Smglocker } __packed;
1400f91cf57Smglocker 
1410f91cf57Smglocker #define ACX100_RINGOPT_AUTO_RESET	0x1
1420f91cf57Smglocker #define ACX100_TXRING_PRIO_DEFAULT	0
1430f91cf57Smglocker #define ACX100_SET_RING_END(conf, end)			\
1440f91cf57Smglocker do {							\
1450f91cf57Smglocker 	(conf)->fw_ring_end[0] = htole32(end);		\
1460f91cf57Smglocker 	(conf)->fw_ring_end[1] = htole32(end + 8);	\
1470f91cf57Smglocker } while (0)
1480f91cf57Smglocker 
1490f91cf57Smglocker struct acx100_conf_memblk_size {
1500f91cf57Smglocker 	struct acx_conf	confcom;
1510f91cf57Smglocker 	uint16_t	memblk_size;	/* size of each mem block */
1520f91cf57Smglocker } __packed;
1530f91cf57Smglocker 
1540f91cf57Smglocker struct acx100_conf_mem {
1550f91cf57Smglocker 	struct acx_conf	confcom;
1560f91cf57Smglocker 	uint32_t	opt;		/* see ACX100_MEMOPT_ */
1570f91cf57Smglocker 	uint32_t	h_rxring_paddr;	/* host rx desc start phyaddr */
1580f91cf57Smglocker 
1590f91cf57Smglocker 	/*
160*4b1a56afSjsg 	 * Memory blocks are controlled by hardware
1610f91cf57Smglocker 	 * once after they are initialized
1620f91cf57Smglocker 	 */
1630f91cf57Smglocker 	uint32_t	rx_memblk_addr;	/* start addr of rx mem blocks */
1640f91cf57Smglocker 	uint32_t	tx_memblk_addr;	/* start addr of tx mem blocks */
1650f91cf57Smglocker 	uint16_t	rx_memblk_num;	/* num of RX mem block */
1660f91cf57Smglocker 	uint16_t	tx_memblk_num;	/* num of TX mem block */
1670f91cf57Smglocker } __packed;
1680f91cf57Smglocker 
1690f91cf57Smglocker #define ACX100_MEMOPT_MEM_INSTR		0x00000000 /* memory access instruct */
1700f91cf57Smglocker #define ACX100_MEMOPT_HOSTDESC		0x00010000 /* host indirect desc */
1710f91cf57Smglocker #define ACX100_MEMOPT_MEMBLOCK		0x00020000 /* local mem block list */
1720f91cf57Smglocker #define ACX100_MEMOPT_IO_INSTR		0x00040000 /* IO instruct */
1730f91cf57Smglocker #define ACX100_MEMOPT_PCICONF		0x00080000 /* PCI conf space */
1740f91cf57Smglocker 
1750f91cf57Smglocker #define ACX100_MEMBLK_ALIGN		0x20
1760f91cf57Smglocker 
1770f91cf57Smglocker struct acx100_conf_cca_mode {
1780f91cf57Smglocker 	struct acx_conf	confcom;
1790f91cf57Smglocker 	uint8_t		cca_mode;
1800f91cf57Smglocker 	uint8_t		unknown;
1810f91cf57Smglocker } __packed;
1820f91cf57Smglocker 
1830f91cf57Smglocker struct acx100_conf_ed_thresh {
1840f91cf57Smglocker 	struct acx_conf	confcom;
1850f91cf57Smglocker 	uint8_t		ed_thresh;
1860f91cf57Smglocker 	uint8_t		unknown[3];
1870f91cf57Smglocker } __packed;
1880f91cf57Smglocker 
1890f91cf57Smglocker struct acx100_conf_wepkey {
1900f91cf57Smglocker 	struct acx_conf	confcom;
1910f91cf57Smglocker 	uint8_t		action;	/* see ACX100_WEPKEY_ACT_ */
1920f91cf57Smglocker 	uint8_t		key_len;
1930f91cf57Smglocker 	uint8_t		key_idx;
1940f91cf57Smglocker #define ACX100_WEPKEY_LEN	29
1950f91cf57Smglocker 	uint8_t		key[ACX100_WEPKEY_LEN];
1960f91cf57Smglocker } __packed;
1970f91cf57Smglocker 
1980f91cf57Smglocker #define ACX100_WEPKEY_ACT_ADD	1
1990f91cf57Smglocker 
2000f91cf57Smglocker static const uint16_t	acx100_reg[ACXREG_MAX] = {
2010f91cf57Smglocker 	ACXREG(SOFT_RESET,		0x0000),
2020f91cf57Smglocker 
2030f91cf57Smglocker 	ACXREG(FWMEM_ADDR,		0x0014),
2040f91cf57Smglocker 	ACXREG(FWMEM_DATA,		0x0018),
2050f91cf57Smglocker 	ACXREG(FWMEM_CTRL,		0x001c),
2060f91cf57Smglocker 	ACXREG(FWMEM_START,		0x0020),
2070f91cf57Smglocker 
2080f91cf57Smglocker 	ACXREG(EVENT_MASK,		0x0034),
2090f91cf57Smglocker 
2100f91cf57Smglocker 	ACXREG(INTR_TRIG,		0x007c),
2110f91cf57Smglocker 	ACXREG(INTR_MASK,		0x0098),
2120f91cf57Smglocker 	ACXREG(INTR_STATUS,		0x00a4),
2130f91cf57Smglocker 	ACXREG(INTR_STATUS_CLR,		0x00a8),
2140f91cf57Smglocker 	ACXREG(INTR_ACK,		0x00ac),
2150f91cf57Smglocker 
2160f91cf57Smglocker 	ACXREG(HINTR_TRIG,		0x00b0),
2170f91cf57Smglocker 	ACXREG(RADIO_ENABLE,		0x0104),
2180f91cf57Smglocker 
2190f91cf57Smglocker 	ACXREG(EEPROM_INIT,		0x02d0),
2200f91cf57Smglocker 	ACXREG(EEPROM_CTRL,		0x0250),
2210f91cf57Smglocker 	ACXREG(EEPROM_ADDR,		0x0254),
2220f91cf57Smglocker 	ACXREG(EEPROM_DATA,		0x0258),
2230f91cf57Smglocker 	ACXREG(EEPROM_CONF,		0x025c),
2240f91cf57Smglocker 	ACXREG(EEPROM_INFO,		0x02ac),
2250f91cf57Smglocker 
2260f91cf57Smglocker 	ACXREG(PHY_ADDR,		0x0268),
2270f91cf57Smglocker 	ACXREG(PHY_DATA,		0x026c),
2280f91cf57Smglocker 	ACXREG(PHY_CTRL,		0x0270),
2290f91cf57Smglocker 
2300f91cf57Smglocker 	ACXREG(GPIO_OUT_ENABLE,		0x0290),
2310f91cf57Smglocker 	ACXREG(GPIO_OUT,		0x0298),
2320f91cf57Smglocker 
2330f91cf57Smglocker 	ACXREG(CMD_REG_OFFSET,		0x02a4),
2340f91cf57Smglocker 	ACXREG(INFO_REG_OFFSET,		0x02a8),
2350f91cf57Smglocker 
2360f91cf57Smglocker 	ACXREG(RESET_SENSE,		0x02d4),
2370f91cf57Smglocker 	ACXREG(ECPU_CTRL,		0x02d8)
2380f91cf57Smglocker };
2390f91cf57Smglocker 
2400f91cf57Smglocker static const uint8_t	acx100_txpower_maxim[21] = {
2410f91cf57Smglocker 	63, 63, 63, 62,
2420f91cf57Smglocker 	61, 61, 60, 60,
2430f91cf57Smglocker 	59, 58, 57, 55,
2440f91cf57Smglocker 	53, 50, 47, 43,
2450f91cf57Smglocker 	38, 31, 23, 13,
2460f91cf57Smglocker 	0
2470f91cf57Smglocker };
2480f91cf57Smglocker 
2490f91cf57Smglocker static const uint8_t	acx100_txpower_rfmd[21] = {
2500f91cf57Smglocker 	 0,  0,  0,  1,
2510f91cf57Smglocker 	 2,  2,  3,  3,
2520f91cf57Smglocker 	 4,  5,  6,  8,
2530f91cf57Smglocker 	10, 13, 16, 20,
2540f91cf57Smglocker 	25, 32, 41, 50,
2550f91cf57Smglocker 	63
2560f91cf57Smglocker };
2570f91cf57Smglocker 
2580f91cf57Smglocker void
acx100_set_param(struct acx_softc * sc)2590f91cf57Smglocker acx100_set_param(struct acx_softc *sc)
2600f91cf57Smglocker {
2610f91cf57Smglocker 	sc->chip_mem1_rid = PCIR_BAR(1);
2620f91cf57Smglocker 	sc->chip_mem2_rid = PCIR_BAR(2);
2630f91cf57Smglocker 	sc->chip_ioreg = acx100_reg;
2640f91cf57Smglocker 	sc->chip_hw_crypt = 1;
2650f91cf57Smglocker 	sc->chip_intr_enable = ACX100_INTR_ENABLE;
266a0de3126Sclaudio #ifndef IEEE80211_STA_ONLY
267a0de3126Sclaudio 	sc->chip_intr_enable |= ACXRV_INTR_DTIM;
268a0de3126Sclaudio #endif
2690f91cf57Smglocker 	sc->chip_intr_disable = ACX100_INTR_DISABLE;
2700f91cf57Smglocker 	sc->chip_gpio_pled = ACX100_GPIO_POWER_LED;
2710f91cf57Smglocker 	sc->chip_ee_eaddr_ofs = ACX100_EE_EADDR_OFS;
2720f91cf57Smglocker 	sc->chip_txdesc1_len = ACX_FRAME_HDRLEN;
2730f91cf57Smglocker 	sc->chip_fw_txdesc_ctrl = DESC_CTRL_AUTODMA |
274bb966e7aSclaudio 	    DESC_CTRL_RECLAIM | DESC_CTRL_FIRST_FRAG;
2750f91cf57Smglocker 
2760f91cf57Smglocker 	sc->chip_phymode = IEEE80211_MODE_11B;
2770f91cf57Smglocker 	sc->chip_chan_flags = IEEE80211_CHAN_B;
2780f91cf57Smglocker 	sc->sc_ic.ic_phytype = IEEE80211_T_DS;
2798f0d61e1Sjsg 	sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
2800f91cf57Smglocker 
2810f91cf57Smglocker 	sc->chip_init = acx100_init;
2820f91cf57Smglocker 	sc->chip_set_wepkey = acx100_set_wepkey;
2830f91cf57Smglocker 	sc->chip_read_config = acx100_read_config;
2840f91cf57Smglocker 	sc->chip_write_config = acx100_write_config;
2850f91cf57Smglocker 	sc->chip_set_fw_txdesc_rate = acx100_set_fw_txdesc_rate;
2860f91cf57Smglocker 	sc->chip_set_bss_join_param = acx100_set_bss_join_param;
2870f91cf57Smglocker 	sc->chip_proc_wep_rxbuf = acx100_proc_wep_rxbuf;
2880f91cf57Smglocker }
2890f91cf57Smglocker 
2900f91cf57Smglocker int
acx100_init(struct acx_softc * sc)2910f91cf57Smglocker acx100_init(struct acx_softc *sc)
2920f91cf57Smglocker {
2930f91cf57Smglocker 	struct ifnet *ifp = &sc->sc_ic.ic_if;
2940f91cf57Smglocker 
2950f91cf57Smglocker 	/*
2960f91cf57Smglocker 	 * NOTE:
2970f91cf57Smglocker 	 * Order of initialization:
2980f91cf57Smglocker 	 * 1) WEP
2990f91cf57Smglocker 	 * 2) Templates
3000f91cf57Smglocker 	 * 3) Firmware TX/RX ring
3010f91cf57Smglocker 	 * 4) Hardware memory
3020f91cf57Smglocker 	 * Above order is critical to get a correct memory map
3030f91cf57Smglocker 	 */
3040f91cf57Smglocker 	if (acx100_init_wep(sc) != 0) {
3050f91cf57Smglocker 		printf("%s: %s can't initialize wep\n",
3060f91cf57Smglocker 		    ifp->if_xname, __func__);
307793d9a9fSmglocker 		return (ENXIO);
3080f91cf57Smglocker 	}
3090f91cf57Smglocker 
3100f91cf57Smglocker 	if (acx100_init_tmplt(sc) != 0) {
3110f91cf57Smglocker 		printf("%s: %s can't initialize templates\n",
3120f91cf57Smglocker 		    ifp->if_xname, __func__);
313793d9a9fSmglocker 		return (ENXIO);
3140f91cf57Smglocker 	}
3150f91cf57Smglocker 
3160f91cf57Smglocker 	if (acx100_init_fw_ring(sc) != 0) {
3170f91cf57Smglocker 		printf("%s: %s can't initialize fw ring\n",
3180f91cf57Smglocker 		    ifp->if_xname, __func__);
319793d9a9fSmglocker 		return (ENXIO);
3200f91cf57Smglocker 	}
3210f91cf57Smglocker 
3220f91cf57Smglocker 	if (acx100_init_memory(sc) != 0) {
3230f91cf57Smglocker 		printf("%s: %s can't initialize hw memory\n",
3240f91cf57Smglocker 		    ifp->if_xname, __func__);
325793d9a9fSmglocker 		return (ENXIO);
3260f91cf57Smglocker 	}
327793d9a9fSmglocker 
328793d9a9fSmglocker 	return (0);
3290f91cf57Smglocker }
3300f91cf57Smglocker 
3310f91cf57Smglocker int
acx100_init_wep(struct acx_softc * sc)3320f91cf57Smglocker acx100_init_wep(struct acx_softc *sc)
3330f91cf57Smglocker {
3340f91cf57Smglocker 	struct acx_conf_wepopt wep_opt;
3350f91cf57Smglocker 	struct acx_conf_mmap mem_map;
3360f91cf57Smglocker 	struct ifnet *ifp = &sc->sc_ic.ic_if;
3370f91cf57Smglocker 
3380f91cf57Smglocker 	/* Set WEP cache start/end address */
339bb966e7aSclaudio 	if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
3400f91cf57Smglocker 		printf("%s: can't get mmap\n", ifp->if_xname);
341793d9a9fSmglocker 		return (1);
3420f91cf57Smglocker 	}
3430f91cf57Smglocker 
3440f91cf57Smglocker 	mem_map.wep_cache_start = htole32(letoh32(mem_map.code_end) + 4);
3450f91cf57Smglocker 	mem_map.wep_cache_end = htole32(letoh32(mem_map.code_end) + 4);
346bb966e7aSclaudio 	if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
3470f91cf57Smglocker 		printf("%s: can't set mmap\n", ifp->if_xname);
348793d9a9fSmglocker 		return (1);
3490f91cf57Smglocker 	}
3500f91cf57Smglocker 
3510f91cf57Smglocker 	/* Set WEP options */
3520f91cf57Smglocker 	wep_opt.nkey = htole16(IEEE80211_WEP_NKID + 10);
3530f91cf57Smglocker 	wep_opt.opt = WEPOPT_HDWEP;
354bb966e7aSclaudio 	if (acx_set_conf(sc, ACX_CONF_WEPOPT, &wep_opt, sizeof(wep_opt)) != 0) {
3550f91cf57Smglocker 		printf("%s: can't set wep opt\n", ifp->if_xname);
356793d9a9fSmglocker 		return (1);
3570f91cf57Smglocker 	}
358793d9a9fSmglocker 
359793d9a9fSmglocker 	return (0);
3600f91cf57Smglocker }
3610f91cf57Smglocker 
3620f91cf57Smglocker int
acx100_init_tmplt(struct acx_softc * sc)3630f91cf57Smglocker acx100_init_tmplt(struct acx_softc *sc)
3640f91cf57Smglocker {
3650f91cf57Smglocker 	struct acx_conf_mmap mem_map;
3660f91cf57Smglocker 	struct ifnet *ifp = &sc->sc_ic.ic_if;
3670f91cf57Smglocker 
3680f91cf57Smglocker 	/* Set templates start address */
369bb966e7aSclaudio 	if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
3700f91cf57Smglocker 		printf("%s: can't get mmap\n", ifp->if_xname);
371793d9a9fSmglocker 		return (1);
3720f91cf57Smglocker 	}
3730f91cf57Smglocker 
3740f91cf57Smglocker 	mem_map.pkt_tmplt_start = mem_map.wep_cache_end;
375bb966e7aSclaudio 	if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
3760f91cf57Smglocker 		printf("%s: can't set mmap\n", ifp->if_xname);
377793d9a9fSmglocker 		return (1);
3780f91cf57Smglocker 	}
3790f91cf57Smglocker 
3800f91cf57Smglocker 	/* Initialize various packet templates */
3810f91cf57Smglocker 	if (acx_init_tmplt_ordered(sc) != 0) {
3820f91cf57Smglocker 		printf("%s: can't init tmplt\n", ifp->if_xname);
383793d9a9fSmglocker 		return (1);
3840f91cf57Smglocker 	}
3850f91cf57Smglocker 
386793d9a9fSmglocker 	return (0);
3870f91cf57Smglocker }
3880f91cf57Smglocker 
3890f91cf57Smglocker int
acx100_init_fw_ring(struct acx_softc * sc)3900f91cf57Smglocker acx100_init_fw_ring(struct acx_softc *sc)
3910f91cf57Smglocker {
3920f91cf57Smglocker 	struct acx100_conf_fw_ring ring;
3930f91cf57Smglocker 	struct acx_conf_mmap mem_map;
3940f91cf57Smglocker 	struct ifnet *ifp = &sc->sc_ic.ic_if;
3950f91cf57Smglocker 	uint32_t txring_start, rxring_start, ring_end;
3960f91cf57Smglocker 
3970f91cf57Smglocker 	/* Set firmware descriptor ring start address */
398bb966e7aSclaudio 	if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
3990f91cf57Smglocker 		printf("%s: can't get mmap\n", ifp->if_xname);
400793d9a9fSmglocker 		return (1);
4010f91cf57Smglocker 	}
4020f91cf57Smglocker 
4030f91cf57Smglocker 	txring_start = letoh32(mem_map.pkt_tmplt_end) + 4;
4040f91cf57Smglocker 	rxring_start = txring_start + ACX100_FW_TXRING_SIZE;
4050f91cf57Smglocker 	ring_end = rxring_start + ACX100_FW_RXRING_SIZE;
4060f91cf57Smglocker 
4070f91cf57Smglocker 	mem_map.fw_desc_start = htole32(txring_start);
408bb966e7aSclaudio 	if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
4090f91cf57Smglocker 		printf("%s: can't set mmap\n", ifp->if_xname);
410793d9a9fSmglocker 		return (1);
4110f91cf57Smglocker 	}
4120f91cf57Smglocker 
4130f91cf57Smglocker 	/* Set firmware descriptor ring configure */
4140f91cf57Smglocker 	bzero(&ring, sizeof(ring));
4150f91cf57Smglocker 	ring.fw_ring_size = htole32(ACX100_FW_TXRING_SIZE +
4160f91cf57Smglocker 	    ACX100_FW_RXRING_SIZE + 8);
4170f91cf57Smglocker 
4180f91cf57Smglocker 	ring.fw_txring_num = 1;
4190f91cf57Smglocker 	ring.fw_txring_addr = htole32(txring_start);
4200f91cf57Smglocker 	ring.fw_txring_prio = ACX100_TXRING_PRIO_DEFAULT;
4210f91cf57Smglocker 	ring.fw_txdesc_num = 0; /* XXX ignored?? */
4220f91cf57Smglocker 
4230f91cf57Smglocker 	ring.fw_rxring_addr = htole32(rxring_start);
4240f91cf57Smglocker 	ring.fw_rxdesc_num = 0; /* XXX ignored?? */
4250f91cf57Smglocker 
4260f91cf57Smglocker 	ring.opt = ACX100_RINGOPT_AUTO_RESET;
4270f91cf57Smglocker 	ACX100_SET_RING_END(&ring, ring_end);
428bb966e7aSclaudio 	if (acx_set_conf(sc, ACX100_CONF_FW_RING, &ring, sizeof(ring)) != 0) {
4290f91cf57Smglocker 		printf("%s: can't set fw ring configure\n", ifp->if_xname);
430793d9a9fSmglocker 		return (1);
4310f91cf57Smglocker 	}
4320f91cf57Smglocker 
4330f91cf57Smglocker 	/* Setup firmware TX/RX descriptor ring */
4340f91cf57Smglocker 	acx100_init_fw_txring(sc, txring_start);
4350f91cf57Smglocker 	acx100_init_fw_rxring(sc, rxring_start);
4360f91cf57Smglocker 
437793d9a9fSmglocker 	return (0);
4380f91cf57Smglocker }
4390f91cf57Smglocker 
4400f91cf57Smglocker #define MEMBLK_ALIGN(addr)	\
4410f91cf57Smglocker     (((addr) + (ACX100_MEMBLK_ALIGN - 1)) & ~(ACX100_MEMBLK_ALIGN - 1))
4420f91cf57Smglocker 
4430f91cf57Smglocker int
acx100_init_memory(struct acx_softc * sc)4440f91cf57Smglocker acx100_init_memory(struct acx_softc *sc)
4450f91cf57Smglocker {
4460f91cf57Smglocker 	struct acx100_conf_memblk_size memblk_sz;
4470f91cf57Smglocker 	struct acx100_conf_mem mem;
4480f91cf57Smglocker 	struct acx_conf_mmap mem_map;
4490f91cf57Smglocker 	struct ifnet *ifp = &sc->sc_ic.ic_if;
4500f91cf57Smglocker 	uint32_t memblk_start, memblk_end;
4510f91cf57Smglocker 	int total_memblk, txblk_num, rxblk_num;
4520f91cf57Smglocker 
4530f91cf57Smglocker 	/* Set memory block start address */
454bb966e7aSclaudio 	if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
4550f91cf57Smglocker 		printf("%s: can't get mmap\n", ifp->if_xname);
456793d9a9fSmglocker 		return (1);
4570f91cf57Smglocker 	}
4580f91cf57Smglocker 
4590f91cf57Smglocker 	mem_map.memblk_start =
4600f91cf57Smglocker 	    htole32(MEMBLK_ALIGN(letoh32(mem_map.fw_desc_end) + 4));
4610f91cf57Smglocker 
462bb966e7aSclaudio 	if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
4630f91cf57Smglocker 		printf("%s: can't set mmap\n", ifp->if_xname);
464793d9a9fSmglocker 		return (1);
4650f91cf57Smglocker 	}
4660f91cf57Smglocker 
4670f91cf57Smglocker 	/* Set memory block size */
4680f91cf57Smglocker 	memblk_sz.memblk_size = htole16(ACX_MEMBLOCK_SIZE);
469bb966e7aSclaudio 	if (acx_set_conf(sc, ACX_CONF_MEMBLK_SIZE, &memblk_sz,
470bb966e7aSclaudio 	    sizeof(memblk_sz)) != 0) {
4710f91cf57Smglocker 		printf("%s: can't set mem block size\n", ifp->if_xname);
472793d9a9fSmglocker 		return (1);
4730f91cf57Smglocker 	}
4740f91cf57Smglocker 
4750f91cf57Smglocker 	/* Get memory map after setting it */
476bb966e7aSclaudio 	if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
4770f91cf57Smglocker 		printf("%s: can't get mmap again\n", ifp->if_xname);
478793d9a9fSmglocker 		return (1);
4790f91cf57Smglocker 	}
4800f91cf57Smglocker 	memblk_start = letoh32(mem_map.memblk_start);
4810f91cf57Smglocker 	memblk_end = letoh32(mem_map.memblk_end);
4820f91cf57Smglocker 
4830f91cf57Smglocker 	/* Set memory options */
4840f91cf57Smglocker 	mem.opt = htole32(ACX100_MEMOPT_MEMBLOCK | ACX100_MEMOPT_HOSTDESC);
4850f91cf57Smglocker 	mem.h_rxring_paddr = htole32(sc->sc_ring_data.rx_ring_paddr);
4860f91cf57Smglocker 
4870f91cf57Smglocker 	total_memblk = (memblk_end - memblk_start) / ACX_MEMBLOCK_SIZE;
4880f91cf57Smglocker 
4890f91cf57Smglocker 	rxblk_num = total_memblk / 2;		/* 50% */
4900f91cf57Smglocker 	txblk_num = total_memblk - rxblk_num;	/* 50% */
4910f91cf57Smglocker 
4920f91cf57Smglocker 	DPRINTF(("%s: \ttotal memory blocks\t%d\n"
4930f91cf57Smglocker 	    "\trx memory blocks\t%d\n"
4940f91cf57Smglocker 	    "\ttx memory blocks\t%d\n",
4950f91cf57Smglocker 	    ifp->if_xname, total_memblk, rxblk_num, txblk_num));
4960f91cf57Smglocker 
4970f91cf57Smglocker 	mem.rx_memblk_num = htole16(rxblk_num);
4980f91cf57Smglocker 	mem.tx_memblk_num = htole16(txblk_num);
4990f91cf57Smglocker 
5000f91cf57Smglocker 	mem.rx_memblk_addr = htole32(MEMBLK_ALIGN(memblk_start));
501793d9a9fSmglocker 	mem.tx_memblk_addr = htole32(MEMBLK_ALIGN(memblk_start +
5020f91cf57Smglocker 	    (ACX_MEMBLOCK_SIZE * rxblk_num)));
5030f91cf57Smglocker 
504bb966e7aSclaudio 	if (acx_set_conf(sc, ACX100_CONF_MEMOPT, &mem, sizeof(mem)) != 0) {
5050f91cf57Smglocker 		printf("%s: can't set mem options\n", ifp->if_xname);
506793d9a9fSmglocker 		return (1);
5070f91cf57Smglocker 	}
5080f91cf57Smglocker 
5090f91cf57Smglocker 	/* Initialize memory */
510f7407174Sclaudio 	if (acx_exec_command(sc, ACXCMD_INIT_MEM, NULL, 0, NULL, 0) != 0) {
5110f91cf57Smglocker 		printf("%s: can't init mem\n", ifp->if_xname);
512793d9a9fSmglocker 		return (1);
5130f91cf57Smglocker 	}
514793d9a9fSmglocker 
515793d9a9fSmglocker 	return (0);
5160f91cf57Smglocker }
5170f91cf57Smglocker 
5180f91cf57Smglocker #undef MEMBLK_ALIGN
5190f91cf57Smglocker 
5200f91cf57Smglocker void
acx100_init_fw_txring(struct acx_softc * sc,uint32_t fw_txdesc_start)5210f91cf57Smglocker acx100_init_fw_txring(struct acx_softc *sc, uint32_t fw_txdesc_start)
5220f91cf57Smglocker {
5230f91cf57Smglocker 	struct acx_fw_txdesc fw_desc;
5240f91cf57Smglocker 	struct acx_txbuf *tx_buf;
5250f91cf57Smglocker 	uint32_t desc_paddr, fw_desc_offset;
5260f91cf57Smglocker 	int i;
5270f91cf57Smglocker 
5280f91cf57Smglocker 	bzero(&fw_desc, sizeof(fw_desc));
529bb966e7aSclaudio 	fw_desc.f_tx_ctrl = DESC_CTRL_HOSTOWN | DESC_CTRL_RECLAIM |
530bb966e7aSclaudio 	    DESC_CTRL_AUTODMA | DESC_CTRL_FIRST_FRAG;
5310f91cf57Smglocker 
5320f91cf57Smglocker 	tx_buf = sc->sc_buf_data.tx_buf;
5330f91cf57Smglocker 	fw_desc_offset = fw_txdesc_start;
5340f91cf57Smglocker 	desc_paddr = sc->sc_ring_data.tx_ring_paddr;
5350f91cf57Smglocker 
5360f91cf57Smglocker 	for (i = 0; i < ACX_TX_DESC_CNT; ++i) {
5370f91cf57Smglocker 		fw_desc.f_tx_host_desc = htole32(desc_paddr);
5380f91cf57Smglocker 
5390f91cf57Smglocker 		if (i == ACX_TX_DESC_CNT - 1) {
5400f91cf57Smglocker 			fw_desc.f_tx_next_desc = htole32(fw_txdesc_start);
5410f91cf57Smglocker 		} else {
542793d9a9fSmglocker 			fw_desc.f_tx_next_desc = htole32(fw_desc_offset +
5430f91cf57Smglocker 			    sizeof(struct acx_fw_txdesc));
5440f91cf57Smglocker 		}
5450f91cf57Smglocker 
5460f91cf57Smglocker 		tx_buf[i].tb_fwdesc_ofs = fw_desc_offset;
5470f91cf57Smglocker 		DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc,
5480f91cf57Smglocker 		    sizeof(fw_desc));
5490f91cf57Smglocker 
5500f91cf57Smglocker 		desc_paddr += (2 * sizeof(struct acx_host_desc));
5510f91cf57Smglocker 		fw_desc_offset += sizeof(fw_desc);
5520f91cf57Smglocker 	}
5530f91cf57Smglocker }
5540f91cf57Smglocker 
5550f91cf57Smglocker void
acx100_init_fw_rxring(struct acx_softc * sc,uint32_t fw_rxdesc_start)5560f91cf57Smglocker acx100_init_fw_rxring(struct acx_softc *sc, uint32_t fw_rxdesc_start)
5570f91cf57Smglocker {
5580f91cf57Smglocker 	struct acx_fw_rxdesc fw_desc;
5590f91cf57Smglocker 	uint32_t fw_desc_offset;
5600f91cf57Smglocker 	int i;
5610f91cf57Smglocker 
5620f91cf57Smglocker 	bzero(&fw_desc, sizeof(fw_desc));
5630f91cf57Smglocker 	fw_desc.f_rx_ctrl = DESC_CTRL_RECLAIM | DESC_CTRL_AUTODMA;
5640f91cf57Smglocker 
5650f91cf57Smglocker 	fw_desc_offset = fw_rxdesc_start;
5660f91cf57Smglocker 
5670f91cf57Smglocker 	for (i = 0; i < ACX_RX_DESC_CNT; ++i) {
5680f91cf57Smglocker 		if (i == ACX_RX_DESC_CNT - 1) {
5690f91cf57Smglocker 			fw_desc.f_rx_next_desc = htole32(fw_rxdesc_start);
5700f91cf57Smglocker 		} else {
5710f91cf57Smglocker 			fw_desc.f_rx_next_desc =
5720f91cf57Smglocker 			    htole32(fw_desc_offset +
5730f91cf57Smglocker 			    sizeof(struct acx_fw_rxdesc));
5740f91cf57Smglocker 		}
5750f91cf57Smglocker 
5760f91cf57Smglocker 		DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc,
5770f91cf57Smglocker 		    sizeof(fw_desc));
5780f91cf57Smglocker 
5790f91cf57Smglocker 		fw_desc_offset += sizeof(fw_desc);
5800f91cf57Smglocker 	}
5810f91cf57Smglocker }
5820f91cf57Smglocker 
5830f91cf57Smglocker int
acx100_read_config(struct acx_softc * sc,struct acx_config * conf)5840f91cf57Smglocker acx100_read_config(struct acx_softc *sc, struct acx_config *conf)
5850f91cf57Smglocker {
5860f91cf57Smglocker 	struct acx100_conf_cca_mode cca;
5870f91cf57Smglocker 	struct acx100_conf_ed_thresh ed;
5880f91cf57Smglocker 	struct ifnet *ifp = &sc->sc_ic.ic_if;
5890f91cf57Smglocker 
5900f91cf57Smglocker 	/*
5910f91cf57Smglocker 	 * NOTE:
5920f91cf57Smglocker 	 * CCA mode and ED threshold MUST be read during initialization
5930f91cf57Smglocker 	 * or the acx100 card won't work as expected
5940f91cf57Smglocker 	 */
5950f91cf57Smglocker 
5960f91cf57Smglocker 	/* Get CCA mode */
597bb966e7aSclaudio 	if (acx_get_conf(sc, ACX_CONF_CCA_MODE, &cca, sizeof(cca)) != 0) {
5980f91cf57Smglocker 		printf("%s: %s can't get cca mode\n",
5990f91cf57Smglocker 		    ifp->if_xname, __func__);
600793d9a9fSmglocker 		return (ENXIO);
6010f91cf57Smglocker 	}
6020f91cf57Smglocker 	conf->cca_mode = cca.cca_mode;
6030f91cf57Smglocker 	DPRINTF(("%s: cca mode %02x\n", ifp->if_xname, cca.cca_mode));
6040f91cf57Smglocker 
6050f91cf57Smglocker 	/* Get ED threshold */
606bb966e7aSclaudio 	if (acx_get_conf(sc, ACX_CONF_ED_THRESH, &ed, sizeof(ed)) != 0) {
6070f91cf57Smglocker 		printf("%s: %s can't get ed threshold\n",
6080f91cf57Smglocker 		    ifp->if_xname, __func__);
609793d9a9fSmglocker 		return (ENXIO);
6100f91cf57Smglocker 	}
6110f91cf57Smglocker 	conf->ed_thresh = ed.ed_thresh;
6120f91cf57Smglocker 	DPRINTF(("%s: ed threshold %02x\n", ifp->if_xname, ed.ed_thresh));
6130f91cf57Smglocker 
614793d9a9fSmglocker 	return (0);
6150f91cf57Smglocker }
6160f91cf57Smglocker 
6170f91cf57Smglocker int
acx100_write_config(struct acx_softc * sc,struct acx_config * conf)6180f91cf57Smglocker acx100_write_config(struct acx_softc *sc, struct acx_config *conf)
6190f91cf57Smglocker {
6200f91cf57Smglocker 	struct acx100_conf_cca_mode cca;
6210f91cf57Smglocker 	struct acx100_conf_ed_thresh ed;
6220f91cf57Smglocker 	struct ifnet *ifp = &sc->sc_ic.ic_if;
6230f91cf57Smglocker 
6240f91cf57Smglocker 	/* Set CCA mode */
6250f91cf57Smglocker 	cca.cca_mode = conf->cca_mode;
626bb966e7aSclaudio 	if (acx_set_conf(sc, ACX_CONF_CCA_MODE, &cca, sizeof(cca)) != 0) {
6270f91cf57Smglocker 		printf("%s: %s can't set cca mode\n",
6280f91cf57Smglocker 		    ifp->if_xname, __func__);
629793d9a9fSmglocker 		return (ENXIO);
6300f91cf57Smglocker 	}
6310f91cf57Smglocker 
6320f91cf57Smglocker 	/* Set ED threshold */
6330f91cf57Smglocker 	ed.ed_thresh = conf->ed_thresh;
634bb966e7aSclaudio 	if (acx_set_conf(sc, ACX_CONF_ED_THRESH, &ed, sizeof(ed)) != 0) {
6350f91cf57Smglocker 		printf("%s: %s can't set ed threshold\n",
6360f91cf57Smglocker 		    ifp->if_xname, __func__);
637793d9a9fSmglocker 		return (ENXIO);
6380f91cf57Smglocker 	}
6390f91cf57Smglocker 
6400f91cf57Smglocker 	/* Set TX power */
6410f91cf57Smglocker 	acx100_set_txpower(sc);	/* ignore return value */
6420f91cf57Smglocker 
643793d9a9fSmglocker 	return (0);
6440f91cf57Smglocker }
6450f91cf57Smglocker 
6460f91cf57Smglocker int
acx100_set_txpower(struct acx_softc * sc)6470f91cf57Smglocker acx100_set_txpower(struct acx_softc *sc)
6480f91cf57Smglocker {
6490f91cf57Smglocker 	struct ifnet *ifp = &sc->sc_ic.ic_if;
6500f91cf57Smglocker 	const uint8_t *map;
6510f91cf57Smglocker 
6520f91cf57Smglocker 	switch (sc->sc_radio_type) {
6530f91cf57Smglocker 	case ACX_RADIO_TYPE_MAXIM:
6540f91cf57Smglocker 		map = acx100_txpower_maxim;
6550f91cf57Smglocker 		break;
6560f91cf57Smglocker 	case ACX_RADIO_TYPE_RFMD:
6570f91cf57Smglocker 	case ACX_RADIO_TYPE_RALINK:
6580f91cf57Smglocker 		map = acx100_txpower_rfmd;
6590f91cf57Smglocker 		break;
6600f91cf57Smglocker 	default:
661793d9a9fSmglocker 		printf("%s: TX power for radio type 0x%02x can't be set yet\n",
662793d9a9fSmglocker 		    ifp->if_xname, sc->sc_radio_type);
663793d9a9fSmglocker 		return (1);
6640f91cf57Smglocker 	}
6650f91cf57Smglocker 
6660f91cf57Smglocker 	acx_write_phyreg(sc, ACXRV_PHYREG_TXPOWER, map[ACX100_TXPOWER]);
667793d9a9fSmglocker 
668793d9a9fSmglocker 	return (0);
6690f91cf57Smglocker }
6700f91cf57Smglocker 
6710f91cf57Smglocker void
acx100_set_fw_txdesc_rate(struct acx_softc * sc,struct acx_txbuf * tx_buf,int rate)6720f91cf57Smglocker acx100_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf,
6730f91cf57Smglocker     int rate)
6740f91cf57Smglocker {
6750f91cf57Smglocker 	FW_TXDESC_SETFIELD_1(sc, tx_buf, f_tx_rate100, ACX100_RATE(rate));
6760f91cf57Smglocker }
6770f91cf57Smglocker 
6780f91cf57Smglocker void
acx100_set_bss_join_param(struct acx_softc * sc,void * param,int dtim_intvl)6790f91cf57Smglocker acx100_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl)
6800f91cf57Smglocker {
6810f91cf57Smglocker 	struct acx100_bss_join *bj = param;
6820f91cf57Smglocker 
6830f91cf57Smglocker 	bj->dtim_intvl = dtim_intvl;
6840f91cf57Smglocker 	bj->basic_rates = 15;	/* XXX */
6850f91cf57Smglocker 	bj->all_rates = 31;	/* XXX */
6860f91cf57Smglocker }
6870f91cf57Smglocker 
6880f91cf57Smglocker int
acx100_set_wepkey(struct acx_softc * sc,struct ieee80211_key * k,int k_idx)68983da4af0Sdamien acx100_set_wepkey(struct acx_softc *sc, struct ieee80211_key *k, int k_idx)
6900f91cf57Smglocker {
6910f91cf57Smglocker 	struct acx100_conf_wepkey conf_wk;
6920f91cf57Smglocker 	struct ifnet *ifp = &sc->sc_ic.ic_if;
6930f91cf57Smglocker 
69483da4af0Sdamien 	if (k->k_len > ACX100_WEPKEY_LEN) {
6950f91cf57Smglocker 		printf("%s: %dth WEP key size beyond %d\n",
69665b39e71Sdamien 		    ifp->if_xname, k_idx, ACX100_WEPKEY_LEN);
6970f91cf57Smglocker 		return EINVAL;
6980f91cf57Smglocker 	}
6990f91cf57Smglocker 
7000f91cf57Smglocker 	conf_wk.action = ACX100_WEPKEY_ACT_ADD;
70183da4af0Sdamien 	conf_wk.key_len = k->k_len;
70283da4af0Sdamien 	conf_wk.key_idx = k_idx;
70383da4af0Sdamien 	bcopy(k->k_key, conf_wk.key, k->k_len);
704bb966e7aSclaudio 	if (acx_set_conf(sc, ACX_CONF_WEPKEY, &conf_wk, sizeof(conf_wk)) != 0) {
7050f91cf57Smglocker 		printf("%s: %s set %dth WEP key failed\n",
70683da4af0Sdamien 		    ifp->if_xname, __func__, k_idx);
7070f91cf57Smglocker 		return ENXIO;
7080f91cf57Smglocker 	}
7090f91cf57Smglocker 	return 0;
7100f91cf57Smglocker }
7110f91cf57Smglocker 
7120f91cf57Smglocker void
acx100_proc_wep_rxbuf(struct acx_softc * sc,struct mbuf * m,int * len)7130f91cf57Smglocker acx100_proc_wep_rxbuf(struct acx_softc *sc, struct mbuf *m, int *len)
7140f91cf57Smglocker {
7150f91cf57Smglocker 	int mac_hdrlen;
7160f91cf57Smglocker 	struct ieee80211_frame *f;
7170f91cf57Smglocker 
7180f91cf57Smglocker 	/*
7190f91cf57Smglocker 	 * Strip leading IV and KID, and trailing CRC
7200f91cf57Smglocker 	 */
7210f91cf57Smglocker 	f = mtod(m, struct ieee80211_frame *);
7220f91cf57Smglocker 
7232a9fd578Skevlo 	if (ieee80211_has_addr4(f))
7240f91cf57Smglocker 		mac_hdrlen = sizeof(struct ieee80211_frame_addr4);
7250f91cf57Smglocker 	else
7260f91cf57Smglocker 		mac_hdrlen = sizeof(struct ieee80211_frame);
7270f91cf57Smglocker 
7280f91cf57Smglocker #define IEEEWEP_IVLEN	(IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
7290f91cf57Smglocker #define IEEEWEP_EXLEN	(IEEEWEP_IVLEN + IEEE80211_WEP_CRCLEN)
7300f91cf57Smglocker 
7310f91cf57Smglocker 	*len = *len - IEEEWEP_EXLEN;
7320f91cf57Smglocker 
7330f91cf57Smglocker 	/* Move MAC header toward frame body */
7348f51fbe3Sderaadt 	memmove((uint8_t *)f + IEEEWEP_IVLEN, f, mac_hdrlen);
7350f91cf57Smglocker 	m_adj(m, IEEEWEP_IVLEN);
7360f91cf57Smglocker 
7370f91cf57Smglocker #undef IEEEWEP_EXLEN
7380f91cf57Smglocker #undef IEEEWEP_IVLEN
7390f91cf57Smglocker }
740