Annotation of Gnu-Mach/linux/pcmcia-cs/wireless/hermes.c, revision 1.1.1.1

1.1       root        1: /* hermes.c
                      2:  *
                      3:  * Driver core for the "Hermes" wireless MAC controller, as used in
                      4:  * the Lucent Orinoco and Cabletron RoamAbout cards. It should also
                      5:  * work on the hfa3841 and hfa3842 MAC controller chips used in the
                      6:  * Prism II chipsets.
                      7:  *
                      8:  * This is not a complete driver, just low-level access routines for
                      9:  * the MAC controller itself.
                     10:  *
                     11:  * Based on the prism2 driver from Absolute Value Systems' linux-wlan
                     12:  * project, the Linux wvlan_cs driver, Lucent's HCF-Light
                     13:  * (wvlan_hcf.c) library, and the NetBSD wireless driver (in no
                     14:  * particular order).
                     15:  *
                     16:  * Copyright (C) 2000, David Gibson, Linuxcare Australia <[email protected]>
                     17:  * Copyright (C) 2001, David Gibson, IBM <[email protected]>
                     18:  * 
                     19:  * The contents of this file are subject to the Mozilla Public License
                     20:  * Version 1.1 (the "License"); you may not use this file except in
                     21:  * compliance with the License. You may obtain a copy of the License
                     22:  * at http://www.mozilla.org/MPL/
                     23:  *
                     24:  * Software distributed under the License is distributed on an "AS IS"
                     25:  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
                     26:  * the License for the specific language governing rights and
                     27:  * limitations under the License.
                     28:  *
                     29:  * Alternatively, the contents of this file may be used under the
                     30:  * terms of the GNU General Public License version 2 (the "GPL"), in
                     31:  * which case the provisions of the GPL are applicable instead of the
                     32:  * above.  If you wish to allow the use of your version of this file
                     33:  * only under the terms of the GPL and not to allow others to use your
                     34:  * version of this file under the MPL, indicate your decision by
                     35:  * deleting the provisions above and replace them with the notice and
                     36:  * other provisions required by the GPL.  If you do not delete the
                     37:  * provisions above, a recipient may use your version of this file
                     38:  * under either the MPL or the GPL.
                     39:  */
                     40: 
                     41: #include <linux/config.h>
                     42: 
                     43: #include <linux/module.h>
                     44: #include <linux/types.h>
                     45: #include <linux/threads.h>
                     46: #include <linux/smp.h>
                     47: #include <asm/io.h>
                     48: #include <linux/delay.h>
                     49: #include <linux/init.h>
                     50: #include <linux/kernel.h>
                     51: #include <asm/errno.h>
                     52: 
                     53: #include "hermes.h"
                     54: 
                     55: MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
                     56: MODULE_AUTHOR("David Gibson <[email protected]>");
                     57: #ifdef MODULE_LICENSE
                     58: MODULE_LICENSE("Dual MPL/GPL");
                     59: #endif
                     60: 
                     61: /* These are maximum timeouts. Most often, card wil react much faster */
                     62: #define CMD_BUSY_TIMEOUT (100) /* In iterations of ~1us */
                     63: #define CMD_INIT_TIMEOUT (50000) /* in iterations of ~10us */
                     64: #define CMD_COMPL_TIMEOUT (20000) /* in iterations of ~10us */
                     65: #define ALLOC_COMPL_TIMEOUT (1000) /* in iterations of ~10us */
                     66: 
                     67: /*
                     68:  * Debugging helpers
                     69:  */
                     70: 
                     71: #define IO_TYPE(hw)    ((hw)->io_space ? "IO " : "MEM ")
                     72: #define DMSG(stuff...) do {printk(KERN_DEBUG "hermes @ %s0x%x: " , IO_TYPE(hw), hw->iobase); \
                     73:                        printk(stuff);} while (0)
                     74: 
                     75: #undef HERMES_DEBUG
                     76: #ifdef HERMES_DEBUG
                     77: #include <stdarg.h>
                     78: 
                     79: #define DEBUG(lvl, stuff...) if ( (lvl) <= HERMES_DEBUG) DMSG(stuff)
                     80: 
                     81: #else /* ! HERMES_DEBUG */
                     82: 
                     83: #define DEBUG(lvl, stuff...) do { } while (0)
                     84: 
                     85: #endif /* ! HERMES_DEBUG */
                     86: 
                     87: 
                     88: /*
                     89:  * Internal functions
                     90:  */
                     91: 
                     92: /* Issue a command to the chip. Waiting for it to complete is the caller's
                     93:    problem.
                     94: 
                     95:    Returns -EBUSY if the command register is busy, 0 on success.
                     96: 
                     97:    Callable from any context.
                     98: */
                     99: static int hermes_issue_cmd(hermes_t *hw, u16 cmd, u16 param0)
                    100: {
                    101:        int k = CMD_BUSY_TIMEOUT;
                    102:        u16 reg;
                    103: 
                    104:        /* First wait for the command register to unbusy */
                    105:        reg = hermes_read_regn(hw, CMD);
                    106:        while ( (reg & HERMES_CMD_BUSY) && k ) {
                    107:                k--;
                    108:                udelay(1);
                    109:                reg = hermes_read_regn(hw, CMD);
                    110:        }
                    111:        if (reg & HERMES_CMD_BUSY) {
                    112:                return -EBUSY;
                    113:        }
                    114: 
                    115:        hermes_write_regn(hw, PARAM2, 0);
                    116:        hermes_write_regn(hw, PARAM1, 0);
                    117:        hermes_write_regn(hw, PARAM0, param0);
                    118:        hermes_write_regn(hw, CMD, cmd);
                    119:        
                    120:        return 0;
                    121: }
                    122: 
                    123: /*
                    124:  * Function definitions
                    125:  */
                    126: 
                    127: void hermes_struct_init(hermes_t *hw, ulong address,
                    128:                        int io_space, int reg_spacing)
                    129: {
                    130:        hw->iobase = address;
                    131:        hw->io_space = io_space;
                    132:        hw->reg_spacing = reg_spacing;
                    133:        hw->inten = 0x0;
                    134: 
                    135: #ifdef HERMES_DEBUG_BUFFER
                    136:        hw->dbufp = 0;
                    137:        memset(&hw->dbuf, 0xff, sizeof(hw->dbuf));
                    138:        memset(&hw->profile, 0, sizeof(hw->profile));
                    139: #endif
                    140: }
                    141: 
                    142: int hermes_init(hermes_t *hw)
                    143: {
                    144:        u16 status, reg;
                    145:        int err = 0;
                    146:        int k;
                    147: 
                    148:        /* We don't want to be interrupted while resetting the chipset */
                    149:        hw->inten = 0x0;
                    150:        hermes_write_regn(hw, INTEN, 0);
                    151:        hermes_write_regn(hw, EVACK, 0xffff);
                    152: 
                    153:        /* Normally it's a "can't happen" for the command register to
                    154:            be busy when we go to issue a command because we are
                    155:            serializing all commands.  However we want to have some
                    156:            chance of resetting the card even if it gets into a stupid
                    157:            state, so we actually wait to see if the command register
                    158:            will unbusy itself here. */
                    159:        k = CMD_BUSY_TIMEOUT;
                    160:        reg = hermes_read_regn(hw, CMD);
                    161:        while (k && (reg & HERMES_CMD_BUSY)) {
                    162:                if (reg == 0xffff) /* Special case - the card has probably been removed,
                    163:                                      so don't wait for the timeout */
                    164:                        return -ENODEV;
                    165: 
                    166:                k--;
                    167:                udelay(1);
                    168:                reg = hermes_read_regn(hw, CMD);
                    169:        }
                    170:        
                    171:        /* No need to explicitly handle the timeout - if we've timed
                    172:           out hermes_issue_cmd() will probably return -EBUSY below */
                    173: 
                    174:        /* According to the documentation, EVSTAT may contain
                    175:           obsolete event occurrence information.  We have to acknowledge
                    176:           it by writing EVACK. */
                    177:        reg = hermes_read_regn(hw, EVSTAT);
                    178:        hermes_write_regn(hw, EVACK, reg);
                    179: 
                    180:        /* We don't use hermes_docmd_wait here, because the reset wipes
                    181:           the magic constant in SWSUPPORT0 away, and it gets confused */
                    182:        err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0);
                    183:        if (err)
                    184:                return err;
                    185: 
                    186:        reg = hermes_read_regn(hw, EVSTAT);
                    187:        k = CMD_INIT_TIMEOUT;
                    188:        while ( (! (reg & HERMES_EV_CMD)) && k) {
                    189:                k--;
                    190:                udelay(10);
                    191:                reg = hermes_read_regn(hw, EVSTAT);
                    192:        }
                    193: 
                    194:        hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC);
                    195: 
                    196:        if (! hermes_present(hw)) {
                    197:                DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n",
                    198:                       hw->iobase);
                    199:                err = -ENODEV;
                    200:                goto out;
                    201:        }
                    202:                
                    203:        if (! (reg & HERMES_EV_CMD)) {
                    204:                printk(KERN_ERR "hermes @ %s0x%lx: " 
                    205:                       "Timeout waiting for card to reset (reg=0x%04x)!\n",
                    206:                       IO_TYPE(hw), hw->iobase, reg);
                    207:                err = -ETIMEDOUT;
                    208:                goto out;
                    209:        }
                    210: 
                    211:        status = hermes_read_regn(hw, STATUS);
                    212: 
                    213:        hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
                    214: 
                    215:        if (status & HERMES_STATUS_RESULT)
                    216:                err = -EIO;
                    217: 
                    218:  out:
                    219:        return err;
                    220: }
                    221: 
                    222: /* Issue a command to the chip, and (busy!) wait for it to
                    223:  * complete.
                    224:  *
                    225:  * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
                    226:  *
                    227:  * Callable from any context, but locking is your problem. */
                    228: int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
                    229:                      hermes_response_t *resp)
                    230: {
                    231:        int err;
                    232:        int k;
                    233:        u16 reg;
                    234:        u16 status;
                    235: 
                    236:        err = hermes_issue_cmd(hw, cmd, parm0);
                    237:        if (err) {
                    238:                if (! hermes_present(hw)) {
                    239:                        printk(KERN_WARNING "hermes @ %s0x%lx: "
                    240:                               "Card removed while issuing command.\n",
                    241:                               IO_TYPE(hw), hw->iobase);
                    242:                        err = -ENODEV;
                    243:                } else 
                    244:                        printk(KERN_ERR "hermes @ %s0x%lx: Error %d issuing command.\n",
                    245:                               IO_TYPE(hw), hw->iobase, err);
                    246:                goto out;
                    247:        }
                    248: 
                    249:        reg = hermes_read_regn(hw, EVSTAT);
                    250:        k = CMD_COMPL_TIMEOUT;
                    251:        while ( (! (reg & HERMES_EV_CMD)) && k) {
                    252:                k--;
                    253:                udelay(10);
                    254:                reg = hermes_read_regn(hw, EVSTAT);
                    255:        }
                    256: 
                    257:        if (! hermes_present(hw)) {
                    258:                printk(KERN_WARNING "hermes @ %s0x%lx: "
                    259:                       "Card removed while waiting for command completion.\n",
                    260:                       IO_TYPE(hw), hw->iobase);
                    261:                err = -ENODEV;
                    262:                goto out;
                    263:        }
                    264:                
                    265:        if (! (reg & HERMES_EV_CMD)) {
                    266:                printk(KERN_ERR "hermes @ %s0x%lx: "
                    267:                       "Timeout waiting for command completion.\n",
                    268:                       IO_TYPE(hw), hw->iobase);
                    269:                err = -ETIMEDOUT;
                    270:                goto out;
                    271:        }
                    272: 
                    273:        status = hermes_read_regn(hw, STATUS);
                    274:        if (resp) {
                    275:                resp->status = status;
                    276:                resp->resp0 = hermes_read_regn(hw, RESP0);
                    277:                resp->resp1 = hermes_read_regn(hw, RESP1);
                    278:                resp->resp2 = hermes_read_regn(hw, RESP2);
                    279:        }
                    280: 
                    281:        hermes_write_regn(hw, EVACK, HERMES_EV_CMD);
                    282: 
                    283:        if (status & HERMES_STATUS_RESULT)
                    284:                err = -EIO;
                    285: 
                    286:  out:
                    287:        return err;
                    288: }
                    289: 
                    290: int hermes_allocate(hermes_t *hw, u16 size, u16 *fid)
                    291: {
                    292:        int err = 0;
                    293:        int k;
                    294:        u16 reg;
                    295:        
                    296:        if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) )
                    297:                return -EINVAL;
                    298: 
                    299:        err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL);
                    300:        if (err) {
                    301:                return err;
                    302:        }
                    303: 
                    304:        reg = hermes_read_regn(hw, EVSTAT);
                    305:        k = ALLOC_COMPL_TIMEOUT;
                    306:        while ( (! (reg & HERMES_EV_ALLOC)) && k) {
                    307:                k--;
                    308:                udelay(10);
                    309:                reg = hermes_read_regn(hw, EVSTAT);
                    310:        }
                    311:        
                    312:        if (! hermes_present(hw)) {
                    313:                printk(KERN_WARNING "hermes @ %s0x%lx: "
                    314:                       "Card removed waiting for frame allocation.\n",
                    315:                       IO_TYPE(hw), hw->iobase);
                    316:                return -ENODEV;
                    317:        }
                    318:                
                    319:        if (! (reg & HERMES_EV_ALLOC)) {
                    320:                printk(KERN_ERR "hermes @ %s0x%lx: "
                    321:                       "Timeout waiting for frame allocation\n",
                    322:                       IO_TYPE(hw), hw->iobase);
                    323:                return -ETIMEDOUT;
                    324:        }
                    325: 
                    326:        *fid = hermes_read_regn(hw, ALLOCFID);
                    327:        hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC);
                    328:        
                    329:        return 0;
                    330: }
                    331: 
                    332: 
                    333: /* Set up a BAP to read a particular chunk of data from card's internal buffer.
                    334:  *
                    335:  * Returns: < 0 on internal failure (errno), 0 on success, >0 on error
                    336:  * from firmware
                    337:  *
                    338:  * Callable from any context */
                    339: static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
                    340: {
                    341:        int sreg = bap ? HERMES_SELECT1 : HERMES_SELECT0;
                    342:        int oreg = bap ? HERMES_OFFSET1 : HERMES_OFFSET0;
                    343:        int k;
                    344:        u16 reg;
                    345: 
                    346:        /* Paranoia.. */
                    347:        if ( (offset > HERMES_BAP_OFFSET_MAX) || (offset % 2) )
                    348:                return -EINVAL;
                    349: 
                    350:        k = HERMES_BAP_BUSY_TIMEOUT;
                    351:        reg = hermes_read_reg(hw, oreg);
                    352:        while ((reg & HERMES_OFFSET_BUSY) && k) {
                    353:                k--;
                    354:                udelay(1);
                    355:                reg = hermes_read_reg(hw, oreg);
                    356:        }
                    357: 
                    358: #ifdef HERMES_DEBUG_BUFFER
                    359:        hw->profile[HERMES_BAP_BUSY_TIMEOUT - k]++;
                    360: 
                    361:        if (k < HERMES_BAP_BUSY_TIMEOUT) {
                    362:                struct hermes_debug_entry *e = 
                    363:                        &hw->dbuf[(hw->dbufp++) % HERMES_DEBUG_BUFSIZE];
                    364:                e->bap = bap;
                    365:                e->id = id;
                    366:                e->offset = offset;
                    367:                e->cycles = HERMES_BAP_BUSY_TIMEOUT - k;
                    368:        }
                    369: #endif
                    370: 
                    371:        if (reg & HERMES_OFFSET_BUSY)
                    372:                return -ETIMEDOUT;
                    373: 
                    374:        /* Now we actually set up the transfer */
                    375:        hermes_write_reg(hw, sreg, id);
                    376:        hermes_write_reg(hw, oreg, offset);
                    377: 
                    378:        /* Wait for the BAP to be ready */
                    379:        k = HERMES_BAP_BUSY_TIMEOUT;
                    380:        reg = hermes_read_reg(hw, oreg);
                    381:        while ( (reg & (HERMES_OFFSET_BUSY | HERMES_OFFSET_ERR)) && k) {
                    382:                k--;
                    383:                udelay(1);
                    384:                reg = hermes_read_reg(hw, oreg);
                    385:        }
                    386: 
                    387:        if (reg & HERMES_OFFSET_BUSY) {
                    388:                return -ETIMEDOUT;
                    389:        }
                    390: 
                    391:        if (reg & HERMES_OFFSET_ERR) {
                    392:                return -EIO;
                    393:        }
                    394: 
                    395: 
                    396:        return 0;
                    397: }
                    398: 
                    399: /* Read a block of data from the chip's buffer, via the
                    400:  * BAP. Synchronization/serialization is the caller's problem.  len
                    401:  * must be even.
                    402:  *
                    403:  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
                    404:  */
                    405: int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len,
                    406:                     u16 id, u16 offset)
                    407: {
                    408:        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
                    409:        int err = 0;
                    410: 
                    411:        if ( (len < 0) || (len % 2) )
                    412:                return -EINVAL;
                    413: 
                    414:        err = hermes_bap_seek(hw, bap, id, offset);
                    415:        if (err)
                    416:                goto out;
                    417: 
                    418:        /* Actually do the transfer */
                    419:        hermes_read_words(hw, dreg, buf, len/2);
                    420: 
                    421:  out:
                    422:        return err;
                    423: }
                    424: 
                    425: /* Write a block of data to the chip's buffer, via the
                    426:  * BAP. Synchronization/serialization is the caller's problem. len
                    427:  * must be even.
                    428:  *
                    429:  * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
                    430:  */
                    431: int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
                    432:                      u16 id, u16 offset)
                    433: {
                    434:        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
                    435:        int err = 0;
                    436: 
                    437:        if ( (len < 0) || (len % 2) )
                    438:                return -EINVAL;
                    439: 
                    440:        err = hermes_bap_seek(hw, bap, id, offset);
                    441:        if (err)
                    442:                goto out;
                    443:        
                    444:        /* Actually do the transfer */
                    445:        hermes_write_words(hw, dreg, buf, len/2);
                    446: 
                    447:  out:  
                    448:        return err;
                    449: }
                    450: 
                    451: /* Read a Length-Type-Value record from the card.
                    452:  *
                    453:  * If length is NULL, we ignore the length read from the card, and
                    454:  * read the entire buffer regardless. This is useful because some of
                    455:  * the configuration records appear to have incorrect lengths in
                    456:  * practice.
                    457:  *
                    458:  * Callable from user or bh context.  */
                    459: int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
                    460:                    u16 *length, void *buf)
                    461: {
                    462:        int err = 0;
                    463:        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
                    464:        u16 rlength, rtype;
                    465:        unsigned nwords;
                    466: 
                    467:        if ( (bufsize < 0) || (bufsize % 2) )
                    468:                return -EINVAL;
                    469: 
                    470:        err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
                    471:        if (err)
                    472:                return err;
                    473: 
                    474:        err = hermes_bap_seek(hw, bap, rid, 0);
                    475:        if (err)
                    476:                return err;
                    477: 
                    478:        rlength = hermes_read_reg(hw, dreg);
                    479: 
                    480:        if (! rlength)
                    481:                return -ENOENT;
                    482: 
                    483:        rtype = hermes_read_reg(hw, dreg);
                    484: 
                    485:        if (length)
                    486:                *length = rlength;
                    487: 
                    488:        if (rtype != rid)
                    489:                printk(KERN_WARNING "hermes @ %s0x%lx: "
                    490:                       "hermes_read_ltv(): rid  (0x%04x) does not match type (0x%04x)\n",
                    491:                       IO_TYPE(hw), hw->iobase, rid, rtype);
                    492:        if (HERMES_RECLEN_TO_BYTES(rlength) > bufsize)
                    493:                printk(KERN_WARNING "hermes @ %s0x%lx: "
                    494:                       "Truncating LTV record from %d to %d bytes. "
                    495:                       "(rid=0x%04x, len=0x%04x)\n",
                    496:                       IO_TYPE(hw), hw->iobase,
                    497:                       HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
                    498: 
                    499:        nwords = min((unsigned)rlength - 1, bufsize / 2);
                    500:        hermes_read_words(hw, dreg, buf, nwords);
                    501: 
                    502:        return 0;
                    503: }
                    504: 
                    505: int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, 
                    506:                     u16 length, const void *value)
                    507: {
                    508:        int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
                    509:        int err = 0;
                    510:        unsigned count;
                    511: 
                    512:        if (length == 0)
                    513:                return -EINVAL;
                    514: 
                    515:        err = hermes_bap_seek(hw, bap, rid, 0);
                    516:        if (err)
                    517:                return err;
                    518: 
                    519:        hermes_write_reg(hw, dreg, length);
                    520:        hermes_write_reg(hw, dreg, rid);
                    521: 
                    522:        count = length - 1;
                    523: 
                    524:        hermes_write_words(hw, dreg, value, count);
                    525: 
                    526:        err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, 
                    527:                                rid, NULL);
                    528: 
                    529:        return err;
                    530: }
                    531: 
                    532: EXPORT_SYMBOL(hermes_struct_init);
                    533: EXPORT_SYMBOL(hermes_init);
                    534: EXPORT_SYMBOL(hermes_docmd_wait);
                    535: EXPORT_SYMBOL(hermes_allocate);
                    536: 
                    537: EXPORT_SYMBOL(hermes_bap_pread);
                    538: EXPORT_SYMBOL(hermes_bap_pwrite);
                    539: EXPORT_SYMBOL(hermes_read_ltv);
                    540: EXPORT_SYMBOL(hermes_write_ltv);
                    541: 
                    542: static int __init init_hermes(void)
                    543: {
                    544:        return 0;
                    545: }
                    546: 
                    547: static void __exit exit_hermes(void)
                    548: {
                    549: }
                    550: 
                    551: module_init(init_hermes);
                    552: module_exit(exit_hermes);

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.