[BACK]Return to acx100.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/acx100.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: acx100.c,v 1.20 2007/07/18 19:24:21 damien Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2006 Jonathan Gray <jsg@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: /*
        !            20:  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
        !            21:  *
        !            22:  * This code is derived from software contributed to The DragonFly Project
        !            23:  * by Sepherosa Ziehau <sepherosa@gmail.com>
        !            24:  *
        !            25:  * Redistribution and use in source and binary forms, with or without
        !            26:  * modification, are permitted provided that the following conditions
        !            27:  * are met:
        !            28:  *
        !            29:  * 1. Redistributions of source code must retain the above copyright
        !            30:  *    notice, this list of conditions and the following disclaimer.
        !            31:  * 2. Redistributions in binary form must reproduce the above copyright
        !            32:  *    notice, this list of conditions and the following disclaimer in
        !            33:  *    the documentation and/or other materials provided with the
        !            34:  *    distribution.
        !            35:  * 3. Neither the name of The DragonFly Project nor the names of its
        !            36:  *    contributors may be used to endorse or promote products derived
        !            37:  *    from this software without specific, prior written permission.
        !            38:  *
        !            39:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
        !            40:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
        !            41:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
        !            42:  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
        !            43:  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            44:  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
        !            45:  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
        !            46:  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
        !            47:  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
        !            48:  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
        !            49:  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            50:  * SUCH DAMAGE.
        !            51:  */
        !            52:
        !            53: #include <sys/param.h>
        !            54: #include <sys/systm.h>
        !            55: #include <sys/mbuf.h>
        !            56: #include <sys/endian.h>
        !            57: #include <sys/socket.h>
        !            58: #include <sys/sysctl.h>
        !            59: #include <sys/device.h>
        !            60:
        !            61: #include <machine/bus.h>
        !            62:
        !            63: #include <net/if.h>
        !            64: #include <net/if_arp.h>
        !            65: #include <net/if_media.h>
        !            66:
        !            67: #ifdef INET
        !            68: #include <netinet/in.h>
        !            69: #include <netinet/if_ether.h>
        !            70: #endif
        !            71:
        !            72: #include <net80211/ieee80211_var.h>
        !            73: #include <net80211/ieee80211_amrr.h>
        !            74: #include <net80211/ieee80211_radiotap.h>
        !            75:
        !            76: #include <dev/pci/pcireg.h>
        !            77:
        !            78: #include <dev/ic/acxvar.h>
        !            79: #include <dev/ic/acxreg.h>
        !            80:
        !            81: #define ACX100_CONF_FW_RING    0x0003
        !            82: #define ACX100_CONF_MEMOPT     0x0005
        !            83:
        !            84: #define ACX100_INTR_ENABLE     (ACXRV_INTR_TX_FINI | ACXRV_INTR_RX_FINI)
        !            85: /*
        !            86:  * XXX do we really care about following interrupts?
        !            87:  *
        !            88:  * ACXRV_INTR_INFO | ACXRV_INTR_SCAN_FINI
        !            89:  */
        !            90:
        !            91: #define ACX100_INTR_DISABLE    (uint16_t)~(ACXRV_INTR_UNKN)
        !            92:
        !            93: #define ACX100_RATE(rate)      ((rate) * 5)
        !            94:
        !            95: #define ACX100_TXPOWER         18
        !            96: #define ACX100_GPIO_POWER_LED  0x0800
        !            97: #define ACX100_EE_EADDR_OFS    0x1a
        !            98:
        !            99: #define ACX100_FW_TXRING_SIZE  (ACX_TX_DESC_CNT * sizeof(struct acx_fw_txdesc))
        !           100: #define ACX100_FW_RXRING_SIZE  (ACX_RX_DESC_CNT * sizeof(struct acx_fw_rxdesc))
        !           101:
        !           102: int    acx100_init(struct acx_softc *);
        !           103: int    acx100_init_wep(struct acx_softc *);
        !           104: int    acx100_init_tmplt(struct acx_softc *);
        !           105: int    acx100_init_fw_ring(struct acx_softc *);
        !           106: int    acx100_init_memory(struct acx_softc *);
        !           107: void   acx100_init_fw_txring(struct acx_softc *, uint32_t);
        !           108: void   acx100_init_fw_rxring(struct acx_softc *, uint32_t);
        !           109: int    acx100_read_config(struct acx_softc *, struct acx_config *);
        !           110: int    acx100_write_config(struct acx_softc *, struct acx_config *);
        !           111: int    acx100_set_txpower(struct acx_softc *);
        !           112: void   acx100_set_fw_txdesc_rate(struct acx_softc *,
        !           113:            struct acx_txbuf *, int);
        !           114: void   acx100_set_bss_join_param(struct acx_softc *, void *, int);
        !           115: int    acx100_set_wepkey(struct acx_softc *, struct ieee80211_key *, int);
        !           116: void   acx100_proc_wep_rxbuf(struct acx_softc *, struct mbuf *, int *);
        !           117:
        !           118: /*
        !           119:  * NOTE:
        !           120:  * Following structs' fields are little endian
        !           121:  */
        !           122: struct acx100_bss_join {
        !           123:        uint8_t dtim_intvl;
        !           124:        uint8_t basic_rates;
        !           125:        uint8_t all_rates;
        !           126: } __packed;
        !           127:
        !           128: struct acx100_conf_fw_ring {
        !           129:        struct acx_conf confcom;
        !           130:        uint32_t        fw_ring_size;   /* total size of fw (tx + rx) ring */
        !           131:        uint32_t        fw_rxring_addr; /* start phyaddr of fw rx desc */
        !           132:        uint8_t         opt;            /* see ACX100_RINGOPT_ */
        !           133:        uint8_t         fw_txring_num;  /* num of TX ring */
        !           134:        uint8_t         fw_rxdesc_num;  /* num of fw rx desc */
        !           135:        uint8_t         reserved0;
        !           136:        uint32_t        fw_ring_end[2]; /* see ACX100_SET_RING_END() */
        !           137:        uint32_t        fw_txring_addr; /* start phyaddr of fw tx desc */
        !           138:        uint8_t         fw_txring_prio; /* see ACX100_TXRING_PRIO_ */
        !           139:        uint8_t         fw_txdesc_num;  /* num of fw tx desc */
        !           140:        uint16_t        reserved1;
        !           141: } __packed;
        !           142:
        !           143: #define ACX100_RINGOPT_AUTO_RESET      0x1
        !           144: #define ACX100_TXRING_PRIO_DEFAULT     0
        !           145: #define ACX100_SET_RING_END(conf, end)                 \
        !           146: do {                                                   \
        !           147:        (conf)->fw_ring_end[0] = htole32(end);          \
        !           148:        (conf)->fw_ring_end[1] = htole32(end + 8);      \
        !           149: } while (0)
        !           150:
        !           151: struct acx100_conf_memblk_size {
        !           152:        struct acx_conf confcom;
        !           153:        uint16_t        memblk_size;    /* size of each mem block */
        !           154: } __packed;
        !           155:
        !           156: struct acx100_conf_mem {
        !           157:        struct acx_conf confcom;
        !           158:        uint32_t        opt;            /* see ACX100_MEMOPT_ */
        !           159:        uint32_t        h_rxring_paddr; /* host rx desc start phyaddr */
        !           160:
        !           161:        /*
        !           162:         * Memory blocks are controled by hardware
        !           163:         * once after they are initialized
        !           164:         */
        !           165:        uint32_t        rx_memblk_addr; /* start addr of rx mem blocks */
        !           166:        uint32_t        tx_memblk_addr; /* start addr of tx mem blocks */
        !           167:        uint16_t        rx_memblk_num;  /* num of RX mem block */
        !           168:        uint16_t        tx_memblk_num;  /* num of TX mem block */
        !           169: } __packed;
        !           170:
        !           171: #define ACX100_MEMOPT_MEM_INSTR                0x00000000 /* memory access instruct */
        !           172: #define ACX100_MEMOPT_HOSTDESC         0x00010000 /* host indirect desc */
        !           173: #define ACX100_MEMOPT_MEMBLOCK         0x00020000 /* local mem block list */
        !           174: #define ACX100_MEMOPT_IO_INSTR         0x00040000 /* IO instruct */
        !           175: #define ACX100_MEMOPT_PCICONF          0x00080000 /* PCI conf space */
        !           176:
        !           177: #define ACX100_MEMBLK_ALIGN            0x20
        !           178:
        !           179: struct acx100_conf_cca_mode {
        !           180:        struct acx_conf confcom;
        !           181:        uint8_t         cca_mode;
        !           182:        uint8_t         unknown;
        !           183: } __packed;
        !           184:
        !           185: struct acx100_conf_ed_thresh {
        !           186:        struct acx_conf confcom;
        !           187:        uint8_t         ed_thresh;
        !           188:        uint8_t         unknown[3];
        !           189: } __packed;
        !           190:
        !           191: struct acx100_conf_wepkey {
        !           192:        struct acx_conf confcom;
        !           193:        uint8_t         action; /* see ACX100_WEPKEY_ACT_ */
        !           194:        uint8_t         key_len;
        !           195:        uint8_t         key_idx;
        !           196: #define ACX100_WEPKEY_LEN      29
        !           197:        uint8_t         key[ACX100_WEPKEY_LEN];
        !           198: } __packed;
        !           199:
        !           200: #define ACX100_WEPKEY_ACT_ADD  1
        !           201:
        !           202: static const uint16_t  acx100_reg[ACXREG_MAX] = {
        !           203:        ACXREG(SOFT_RESET,              0x0000),
        !           204:
        !           205:        ACXREG(FWMEM_ADDR,              0x0014),
        !           206:        ACXREG(FWMEM_DATA,              0x0018),
        !           207:        ACXREG(FWMEM_CTRL,              0x001c),
        !           208:        ACXREG(FWMEM_START,             0x0020),
        !           209:
        !           210:        ACXREG(EVENT_MASK,              0x0034),
        !           211:
        !           212:        ACXREG(INTR_TRIG,               0x007c),
        !           213:        ACXREG(INTR_MASK,               0x0098),
        !           214:        ACXREG(INTR_STATUS,             0x00a4),
        !           215:        ACXREG(INTR_STATUS_CLR,         0x00a8),
        !           216:        ACXREG(INTR_ACK,                0x00ac),
        !           217:
        !           218:        ACXREG(HINTR_TRIG,              0x00b0),
        !           219:        ACXREG(RADIO_ENABLE,            0x0104),
        !           220:
        !           221:        ACXREG(EEPROM_INIT,             0x02d0),
        !           222:        ACXREG(EEPROM_CTRL,             0x0250),
        !           223:        ACXREG(EEPROM_ADDR,             0x0254),
        !           224:        ACXREG(EEPROM_DATA,             0x0258),
        !           225:        ACXREG(EEPROM_CONF,             0x025c),
        !           226:        ACXREG(EEPROM_INFO,             0x02ac),
        !           227:
        !           228:        ACXREG(PHY_ADDR,                0x0268),
        !           229:        ACXREG(PHY_DATA,                0x026c),
        !           230:        ACXREG(PHY_CTRL,                0x0270),
        !           231:
        !           232:        ACXREG(GPIO_OUT_ENABLE,         0x0290),
        !           233:        ACXREG(GPIO_OUT,                0x0298),
        !           234:
        !           235:        ACXREG(CMD_REG_OFFSET,          0x02a4),
        !           236:        ACXREG(INFO_REG_OFFSET,         0x02a8),
        !           237:
        !           238:        ACXREG(RESET_SENSE,             0x02d4),
        !           239:        ACXREG(ECPU_CTRL,               0x02d8)
        !           240: };
        !           241:
        !           242: static const uint8_t   acx100_txpower_maxim[21] = {
        !           243:        63, 63, 63, 62,
        !           244:        61, 61, 60, 60,
        !           245:        59, 58, 57, 55,
        !           246:        53, 50, 47, 43,
        !           247:        38, 31, 23, 13,
        !           248:        0
        !           249: };
        !           250:
        !           251: static const uint8_t   acx100_txpower_rfmd[21] = {
        !           252:         0,  0,  0,  1,
        !           253:         2,  2,  3,  3,
        !           254:         4,  5,  6,  8,
        !           255:        10, 13, 16, 20,
        !           256:        25, 32, 41, 50,
        !           257:        63
        !           258: };
        !           259:
        !           260: void
        !           261: acx100_set_param(struct acx_softc *sc)
        !           262: {
        !           263:        sc->chip_mem1_rid = PCIR_BAR(1);
        !           264:        sc->chip_mem2_rid = PCIR_BAR(2);
        !           265:        sc->chip_ioreg = acx100_reg;
        !           266:        sc->chip_hw_crypt = 1;
        !           267:        sc->chip_intr_enable = ACX100_INTR_ENABLE;
        !           268:        sc->chip_intr_disable = ACX100_INTR_DISABLE;
        !           269:        sc->chip_gpio_pled = ACX100_GPIO_POWER_LED;
        !           270:        sc->chip_ee_eaddr_ofs = ACX100_EE_EADDR_OFS;
        !           271:        sc->chip_txdesc1_len = ACX_FRAME_HDRLEN;
        !           272:        sc->chip_fw_txdesc_ctrl = DESC_CTRL_AUTODMA |
        !           273:            DESC_CTRL_RECLAIM | DESC_CTRL_FIRST_FRAG;
        !           274:
        !           275:        sc->chip_phymode = IEEE80211_MODE_11B;
        !           276:        sc->chip_chan_flags = IEEE80211_CHAN_B;
        !           277:        sc->sc_ic.ic_phytype = IEEE80211_T_DS;
        !           278:        sc->sc_ic.ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
        !           279:
        !           280:        sc->chip_init = acx100_init;
        !           281:        sc->chip_set_wepkey = acx100_set_wepkey;
        !           282:        sc->chip_read_config = acx100_read_config;
        !           283:        sc->chip_write_config = acx100_write_config;
        !           284:        sc->chip_set_fw_txdesc_rate = acx100_set_fw_txdesc_rate;
        !           285:        sc->chip_set_bss_join_param = acx100_set_bss_join_param;
        !           286:        sc->chip_proc_wep_rxbuf = acx100_proc_wep_rxbuf;
        !           287: }
        !           288:
        !           289: int
        !           290: acx100_init(struct acx_softc *sc)
        !           291: {
        !           292:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !           293:
        !           294:        /*
        !           295:         * NOTE:
        !           296:         * Order of initialization:
        !           297:         * 1) WEP
        !           298:         * 2) Templates
        !           299:         * 3) Firmware TX/RX ring
        !           300:         * 4) Hardware memory
        !           301:         * Above order is critical to get a correct memory map
        !           302:         */
        !           303:        if (acx100_init_wep(sc) != 0) {
        !           304:                printf("%s: %s can't initialize wep\n",
        !           305:                    ifp->if_xname, __func__);
        !           306:                return (ENXIO);
        !           307:        }
        !           308:
        !           309:        if (acx100_init_tmplt(sc) != 0) {
        !           310:                printf("%s: %s can't initialize templates\n",
        !           311:                    ifp->if_xname, __func__);
        !           312:                return (ENXIO);
        !           313:        }
        !           314:
        !           315:        if (acx100_init_fw_ring(sc) != 0) {
        !           316:                printf("%s: %s can't initialize fw ring\n",
        !           317:                    ifp->if_xname, __func__);
        !           318:                return (ENXIO);
        !           319:        }
        !           320:
        !           321:        if (acx100_init_memory(sc) != 0) {
        !           322:                printf("%s: %s can't initialize hw memory\n",
        !           323:                    ifp->if_xname, __func__);
        !           324:                return (ENXIO);
        !           325:        }
        !           326:
        !           327:        return (0);
        !           328: }
        !           329:
        !           330: int
        !           331: acx100_init_wep(struct acx_softc *sc)
        !           332: {
        !           333:        struct acx_conf_wepopt wep_opt;
        !           334:        struct acx_conf_mmap mem_map;
        !           335:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !           336:
        !           337:        /* Set WEP cache start/end address */
        !           338:        if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
        !           339:                printf("%s: can't get mmap\n", ifp->if_xname);
        !           340:                return (1);
        !           341:        }
        !           342:
        !           343:        mem_map.wep_cache_start = htole32(letoh32(mem_map.code_end) + 4);
        !           344:        mem_map.wep_cache_end = htole32(letoh32(mem_map.code_end) + 4);
        !           345:        if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
        !           346:                printf("%s: can't set mmap\n", ifp->if_xname);
        !           347:                return (1);
        !           348:        }
        !           349:
        !           350:        /* Set WEP options */
        !           351:        wep_opt.nkey = htole16(IEEE80211_WEP_NKID + 10);
        !           352:        wep_opt.opt = WEPOPT_HDWEP;
        !           353:        if (acx_set_conf(sc, ACX_CONF_WEPOPT, &wep_opt, sizeof(wep_opt)) != 0) {
        !           354:                printf("%s: can't set wep opt\n", ifp->if_xname);
        !           355:                return (1);
        !           356:        }
        !           357:
        !           358:        return (0);
        !           359: }
        !           360:
        !           361: int
        !           362: acx100_init_tmplt(struct acx_softc *sc)
        !           363: {
        !           364:        struct acx_conf_mmap mem_map;
        !           365:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !           366:
        !           367:        /* Set templates start address */
        !           368:        if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
        !           369:                printf("%s: can't get mmap\n", ifp->if_xname);
        !           370:                return (1);
        !           371:        }
        !           372:
        !           373:        mem_map.pkt_tmplt_start = mem_map.wep_cache_end;
        !           374:        if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
        !           375:                printf("%s: can't set mmap\n", ifp->if_xname);
        !           376:                return (1);
        !           377:        }
        !           378:
        !           379:        /* Initialize various packet templates */
        !           380:        if (acx_init_tmplt_ordered(sc) != 0) {
        !           381:                printf("%s: can't init tmplt\n", ifp->if_xname);
        !           382:                return (1);
        !           383:        }
        !           384:
        !           385:        return (0);
        !           386: }
        !           387:
        !           388: int
        !           389: acx100_init_fw_ring(struct acx_softc *sc)
        !           390: {
        !           391:        struct acx100_conf_fw_ring ring;
        !           392:        struct acx_conf_mmap mem_map;
        !           393:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !           394:        uint32_t txring_start, rxring_start, ring_end;
        !           395:
        !           396:        /* Set firmware descriptor ring start address */
        !           397:        if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
        !           398:                printf("%s: can't get mmap\n", ifp->if_xname);
        !           399:                return (1);
        !           400:        }
        !           401:
        !           402:        txring_start = letoh32(mem_map.pkt_tmplt_end) + 4;
        !           403:        rxring_start = txring_start + ACX100_FW_TXRING_SIZE;
        !           404:        ring_end = rxring_start + ACX100_FW_RXRING_SIZE;
        !           405:
        !           406:        mem_map.fw_desc_start = htole32(txring_start);
        !           407:        if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
        !           408:                printf("%s: can't set mmap\n", ifp->if_xname);
        !           409:                return (1);
        !           410:        }
        !           411:
        !           412:        /* Set firmware descriptor ring configure */
        !           413:        bzero(&ring, sizeof(ring));
        !           414:        ring.fw_ring_size = htole32(ACX100_FW_TXRING_SIZE +
        !           415:            ACX100_FW_RXRING_SIZE + 8);
        !           416:
        !           417:        ring.fw_txring_num = 1;
        !           418:        ring.fw_txring_addr = htole32(txring_start);
        !           419:        ring.fw_txring_prio = ACX100_TXRING_PRIO_DEFAULT;
        !           420:        ring.fw_txdesc_num = 0; /* XXX ignored?? */
        !           421:
        !           422:        ring.fw_rxring_addr = htole32(rxring_start);
        !           423:        ring.fw_rxdesc_num = 0; /* XXX ignored?? */
        !           424:
        !           425:        ring.opt = ACX100_RINGOPT_AUTO_RESET;
        !           426:        ACX100_SET_RING_END(&ring, ring_end);
        !           427:        if (acx_set_conf(sc, ACX100_CONF_FW_RING, &ring, sizeof(ring)) != 0) {
        !           428:                printf("%s: can't set fw ring configure\n", ifp->if_xname);
        !           429:                return (1);
        !           430:        }
        !           431:
        !           432:        /* Setup firmware TX/RX descriptor ring */
        !           433:        acx100_init_fw_txring(sc, txring_start);
        !           434:        acx100_init_fw_rxring(sc, rxring_start);
        !           435:
        !           436:        return (0);
        !           437: }
        !           438:
        !           439: #define MEMBLK_ALIGN(addr)     \
        !           440:     (((addr) + (ACX100_MEMBLK_ALIGN - 1)) & ~(ACX100_MEMBLK_ALIGN - 1))
        !           441:
        !           442: int
        !           443: acx100_init_memory(struct acx_softc *sc)
        !           444: {
        !           445:        struct acx100_conf_memblk_size memblk_sz;
        !           446:        struct acx100_conf_mem mem;
        !           447:        struct acx_conf_mmap mem_map;
        !           448:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !           449:        uint32_t memblk_start, memblk_end;
        !           450:        int total_memblk, txblk_num, rxblk_num;
        !           451:
        !           452:        /* Set memory block start address */
        !           453:        if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
        !           454:                printf("%s: can't get mmap\n", ifp->if_xname);
        !           455:                return (1);
        !           456:        }
        !           457:
        !           458:        mem_map.memblk_start =
        !           459:            htole32(MEMBLK_ALIGN(letoh32(mem_map.fw_desc_end) + 4));
        !           460:
        !           461:        if (acx_set_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
        !           462:                printf("%s: can't set mmap\n", ifp->if_xname);
        !           463:                return (1);
        !           464:        }
        !           465:
        !           466:        /* Set memory block size */
        !           467:        memblk_sz.memblk_size = htole16(ACX_MEMBLOCK_SIZE);
        !           468:        if (acx_set_conf(sc, ACX_CONF_MEMBLK_SIZE, &memblk_sz,
        !           469:            sizeof(memblk_sz)) != 0) {
        !           470:                printf("%s: can't set mem block size\n", ifp->if_xname);
        !           471:                return (1);
        !           472:        }
        !           473:
        !           474:        /* Get memory map after setting it */
        !           475:        if (acx_get_conf(sc, ACX_CONF_MMAP, &mem_map, sizeof(mem_map)) != 0) {
        !           476:                printf("%s: can't get mmap again\n", ifp->if_xname);
        !           477:                return (1);
        !           478:        }
        !           479:        memblk_start = letoh32(mem_map.memblk_start);
        !           480:        memblk_end = letoh32(mem_map.memblk_end);
        !           481:
        !           482:        /* Set memory options */
        !           483:        mem.opt = htole32(ACX100_MEMOPT_MEMBLOCK | ACX100_MEMOPT_HOSTDESC);
        !           484:        mem.h_rxring_paddr = htole32(sc->sc_ring_data.rx_ring_paddr);
        !           485:
        !           486:        total_memblk = (memblk_end - memblk_start) / ACX_MEMBLOCK_SIZE;
        !           487:
        !           488:        rxblk_num = total_memblk / 2;           /* 50% */
        !           489:        txblk_num = total_memblk - rxblk_num;   /* 50% */
        !           490:
        !           491:        DPRINTF(("%s: \ttotal memory blocks\t%d\n"
        !           492:            "\trx memory blocks\t%d\n"
        !           493:            "\ttx memory blocks\t%d\n",
        !           494:            ifp->if_xname, total_memblk, rxblk_num, txblk_num));
        !           495:
        !           496:        mem.rx_memblk_num = htole16(rxblk_num);
        !           497:        mem.tx_memblk_num = htole16(txblk_num);
        !           498:
        !           499:        mem.rx_memblk_addr = htole32(MEMBLK_ALIGN(memblk_start));
        !           500:        mem.tx_memblk_addr = htole32(MEMBLK_ALIGN(memblk_start +
        !           501:            (ACX_MEMBLOCK_SIZE * rxblk_num)));
        !           502:
        !           503:        if (acx_set_conf(sc, ACX100_CONF_MEMOPT, &mem, sizeof(mem)) != 0) {
        !           504:                printf("%s: can't set mem options\n", ifp->if_xname);
        !           505:                return (1);
        !           506:        }
        !           507:
        !           508:        /* Initialize memory */
        !           509:        if (acx_exec_command(sc, ACXCMD_INIT_MEM, NULL, 0, NULL, 0) != 0) {
        !           510:                printf("%s: can't init mem\n", ifp->if_xname);
        !           511:                return (1);
        !           512:        }
        !           513:
        !           514:        return (0);
        !           515: }
        !           516:
        !           517: #undef MEMBLK_ALIGN
        !           518:
        !           519: void
        !           520: acx100_init_fw_txring(struct acx_softc *sc, uint32_t fw_txdesc_start)
        !           521: {
        !           522:        struct acx_fw_txdesc fw_desc;
        !           523:        struct acx_txbuf *tx_buf;
        !           524:        uint32_t desc_paddr, fw_desc_offset;
        !           525:        int i;
        !           526:
        !           527:        bzero(&fw_desc, sizeof(fw_desc));
        !           528:        fw_desc.f_tx_ctrl = DESC_CTRL_HOSTOWN | DESC_CTRL_RECLAIM |
        !           529:            DESC_CTRL_AUTODMA | DESC_CTRL_FIRST_FRAG;
        !           530:
        !           531:        tx_buf = sc->sc_buf_data.tx_buf;
        !           532:        fw_desc_offset = fw_txdesc_start;
        !           533:        desc_paddr = sc->sc_ring_data.tx_ring_paddr;
        !           534:
        !           535:        for (i = 0; i < ACX_TX_DESC_CNT; ++i) {
        !           536:                fw_desc.f_tx_host_desc = htole32(desc_paddr);
        !           537:
        !           538:                if (i == ACX_TX_DESC_CNT - 1) {
        !           539:                        fw_desc.f_tx_next_desc = htole32(fw_txdesc_start);
        !           540:                } else {
        !           541:                        fw_desc.f_tx_next_desc = htole32(fw_desc_offset +
        !           542:                            sizeof(struct acx_fw_txdesc));
        !           543:                }
        !           544:
        !           545:                tx_buf[i].tb_fwdesc_ofs = fw_desc_offset;
        !           546:                DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc,
        !           547:                    sizeof(fw_desc));
        !           548:
        !           549:                desc_paddr += (2 * sizeof(struct acx_host_desc));
        !           550:                fw_desc_offset += sizeof(fw_desc);
        !           551:        }
        !           552: }
        !           553:
        !           554: void
        !           555: acx100_init_fw_rxring(struct acx_softc *sc, uint32_t fw_rxdesc_start)
        !           556: {
        !           557:        struct acx_fw_rxdesc fw_desc;
        !           558:        uint32_t fw_desc_offset;
        !           559:        int i;
        !           560:
        !           561:        bzero(&fw_desc, sizeof(fw_desc));
        !           562:        fw_desc.f_rx_ctrl = DESC_CTRL_RECLAIM | DESC_CTRL_AUTODMA;
        !           563:
        !           564:        fw_desc_offset = fw_rxdesc_start;
        !           565:
        !           566:        for (i = 0; i < ACX_RX_DESC_CNT; ++i) {
        !           567:                if (i == ACX_RX_DESC_CNT - 1) {
        !           568:                        fw_desc.f_rx_next_desc = htole32(fw_rxdesc_start);
        !           569:                } else {
        !           570:                        fw_desc.f_rx_next_desc =
        !           571:                            htole32(fw_desc_offset +
        !           572:                            sizeof(struct acx_fw_rxdesc));
        !           573:                }
        !           574:
        !           575:                DESC_WRITE_REGION_1(sc, fw_desc_offset, &fw_desc,
        !           576:                    sizeof(fw_desc));
        !           577:
        !           578:                fw_desc_offset += sizeof(fw_desc);
        !           579:        }
        !           580: }
        !           581:
        !           582: int
        !           583: acx100_read_config(struct acx_softc *sc, struct acx_config *conf)
        !           584: {
        !           585:        struct acx100_conf_cca_mode cca;
        !           586:        struct acx100_conf_ed_thresh ed;
        !           587:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !           588:
        !           589:        /*
        !           590:         * NOTE:
        !           591:         * CCA mode and ED threshold MUST be read during initialization
        !           592:         * or the acx100 card won't work as expected
        !           593:         */
        !           594:
        !           595:        /* Get CCA mode */
        !           596:        if (acx_get_conf(sc, ACX_CONF_CCA_MODE, &cca, sizeof(cca)) != 0) {
        !           597:                printf("%s: %s can't get cca mode\n",
        !           598:                    ifp->if_xname, __func__);
        !           599:                return (ENXIO);
        !           600:        }
        !           601:        conf->cca_mode = cca.cca_mode;
        !           602:        DPRINTF(("%s: cca mode %02x\n", ifp->if_xname, cca.cca_mode));
        !           603:
        !           604:        /* Get ED threshold */
        !           605:        if (acx_get_conf(sc, ACX_CONF_ED_THRESH, &ed, sizeof(ed)) != 0) {
        !           606:                printf("%s: %s can't get ed threshold\n",
        !           607:                    ifp->if_xname, __func__);
        !           608:                return (ENXIO);
        !           609:        }
        !           610:        conf->ed_thresh = ed.ed_thresh;
        !           611:        DPRINTF(("%s: ed threshold %02x\n", ifp->if_xname, ed.ed_thresh));
        !           612:
        !           613:        return (0);
        !           614: }
        !           615:
        !           616: int
        !           617: acx100_write_config(struct acx_softc *sc, struct acx_config *conf)
        !           618: {
        !           619:        struct acx100_conf_cca_mode cca;
        !           620:        struct acx100_conf_ed_thresh ed;
        !           621:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !           622:
        !           623:        /* Set CCA mode */
        !           624:        cca.cca_mode = conf->cca_mode;
        !           625:        if (acx_set_conf(sc, ACX_CONF_CCA_MODE, &cca, sizeof(cca)) != 0) {
        !           626:                printf("%s: %s can't set cca mode\n",
        !           627:                    ifp->if_xname, __func__);
        !           628:                return (ENXIO);
        !           629:        }
        !           630:
        !           631:        /* Set ED threshold */
        !           632:        ed.ed_thresh = conf->ed_thresh;
        !           633:        if (acx_set_conf(sc, ACX_CONF_ED_THRESH, &ed, sizeof(ed)) != 0) {
        !           634:                printf("%s: %s can't set ed threshold\n",
        !           635:                    ifp->if_xname, __func__);
        !           636:                return (ENXIO);
        !           637:        }
        !           638:
        !           639:        /* Set TX power */
        !           640:        acx100_set_txpower(sc); /* ignore return value */
        !           641:
        !           642:        return (0);
        !           643: }
        !           644:
        !           645: int
        !           646: acx100_set_txpower(struct acx_softc *sc)
        !           647: {
        !           648:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !           649:        const uint8_t *map;
        !           650:
        !           651:        switch (sc->sc_radio_type) {
        !           652:        case ACX_RADIO_TYPE_MAXIM:
        !           653:                map = acx100_txpower_maxim;
        !           654:                break;
        !           655:        case ACX_RADIO_TYPE_RFMD:
        !           656:        case ACX_RADIO_TYPE_RALINK:
        !           657:                map = acx100_txpower_rfmd;
        !           658:                break;
        !           659:        default:
        !           660:                printf("%s: TX power for radio type 0x%02x can't be set yet\n",
        !           661:                    ifp->if_xname, sc->sc_radio_type);
        !           662:                return (1);
        !           663:        }
        !           664:
        !           665:        acx_write_phyreg(sc, ACXRV_PHYREG_TXPOWER, map[ACX100_TXPOWER]);
        !           666:
        !           667:        return (0);
        !           668: }
        !           669:
        !           670: void
        !           671: acx100_set_fw_txdesc_rate(struct acx_softc *sc, struct acx_txbuf *tx_buf,
        !           672:     int rate)
        !           673: {
        !           674:        FW_TXDESC_SETFIELD_1(sc, tx_buf, f_tx_rate100, ACX100_RATE(rate));
        !           675: }
        !           676:
        !           677: void
        !           678: acx100_set_bss_join_param(struct acx_softc *sc, void *param, int dtim_intvl)
        !           679: {
        !           680:        struct acx100_bss_join *bj = param;
        !           681:
        !           682:        bj->dtim_intvl = dtim_intvl;
        !           683:        bj->basic_rates = 15;   /* XXX */
        !           684:        bj->all_rates = 31;     /* XXX */
        !           685: }
        !           686:
        !           687: int
        !           688: acx100_set_wepkey(struct acx_softc *sc, struct ieee80211_key *k, int k_idx)
        !           689: {
        !           690:        struct acx100_conf_wepkey conf_wk;
        !           691:        struct ifnet *ifp = &sc->sc_ic.ic_if;
        !           692:
        !           693:        if (k->k_len > ACX100_WEPKEY_LEN) {
        !           694:                printf("%s: %dth WEP key size beyond %d\n",
        !           695:                    ifp->if_xname, k_idx, ACX100_WEPKEY_LEN);
        !           696:                return EINVAL;
        !           697:        }
        !           698:
        !           699:        conf_wk.action = ACX100_WEPKEY_ACT_ADD;
        !           700:        conf_wk.key_len = k->k_len;
        !           701:        conf_wk.key_idx = k_idx;
        !           702:        bcopy(k->k_key, conf_wk.key, k->k_len);
        !           703:        if (acx_set_conf(sc, ACX_CONF_WEPKEY, &conf_wk, sizeof(conf_wk)) != 0) {
        !           704:                printf("%s: %s set %dth WEP key failed\n",
        !           705:                    ifp->if_xname, __func__, k_idx);
        !           706:                return ENXIO;
        !           707:        }
        !           708:        return 0;
        !           709: }
        !           710:
        !           711: void
        !           712: acx100_proc_wep_rxbuf(struct acx_softc *sc, struct mbuf *m, int *len)
        !           713: {
        !           714:        int mac_hdrlen;
        !           715:        struct ieee80211_frame *f;
        !           716:
        !           717:        /*
        !           718:         * Strip leading IV and KID, and trailing CRC
        !           719:         */
        !           720:        f = mtod(m, struct ieee80211_frame *);
        !           721:
        !           722:        if ((f->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
        !           723:                mac_hdrlen = sizeof(struct ieee80211_frame_addr4);
        !           724:        else
        !           725:                mac_hdrlen = sizeof(struct ieee80211_frame);
        !           726:
        !           727: #define IEEEWEP_IVLEN  (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN)
        !           728: #define IEEEWEP_EXLEN  (IEEEWEP_IVLEN + IEEE80211_WEP_CRCLEN)
        !           729:
        !           730:        *len = *len - IEEEWEP_EXLEN;
        !           731:
        !           732:        /* Move MAC header toward frame body */
        !           733:        ovbcopy(f, (uint8_t *)f + IEEEWEP_IVLEN, mac_hdrlen);
        !           734:        m_adj(m, IEEEWEP_IVLEN);
        !           735:
        !           736: #undef IEEEWEP_EXLEN
        !           737: #undef IEEEWEP_IVLEN
        !           738: }

CVSweb