Annotation of Gnu-Mach/linux/pcmcia-cs/wireless/hermes.c, revision 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.