Annotation of Gnu-Mach/linux/src/drivers/net/hp-plus.c, revision 1.1

1.1     ! root        1: /* hp-plus.c: A HP PCLAN/plus ethernet driver for linux. */
        !             2: /*
        !             3:        Written 1994 by Donald Becker.
        !             4: 
        !             5:        This driver is for the Hewlett Packard PC LAN (27***) plus ethercards.
        !             6:        These cards are sold under several model numbers, usually 2724*.
        !             7: 
        !             8:        This software may be used and distributed according to the terms
        !             9:        of the GNU Public License, incorporated herein by reference.
        !            10: 
        !            11:        The author may be reached as [email protected], or C/O
        !            12: 
        !            13:        Center of Excellence in Space Data and Information Sciences
        !            14:                Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
        !            15: 
        !            16:        As is often the case, a great deal of credit is owed to Russ Nelson.
        !            17:        The Crynwr packet driver was my primary source of HP-specific
        !            18:        programming information.
        !            19: */
        !            20: 
        !            21: static const char *version =
        !            22: "hp-plus.c:v1.10 9/24/94 Donald Becker ([email protected])\n";
        !            23: 
        !            24: #include <linux/module.h>
        !            25: 
        !            26: #include <linux/string.h>              /* Important -- this inlines word moves. */
        !            27: #include <linux/kernel.h>
        !            28: #include <linux/sched.h>
        !            29: #include <linux/errno.h>
        !            30: #include <linux/ioport.h>
        !            31: #include <linux/netdevice.h>
        !            32: #include <linux/etherdevice.h>
        !            33: 
        !            34: #include <asm/system.h>
        !            35: #include <asm/io.h>
        !            36: 
        !            37: 
        !            38: #include "8390.h"
        !            39: 
        !            40: /* A zero-terminated list of I/O addresses to be probed. */
        !            41: static unsigned int hpplus_portlist[] =
        !            42: {0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0};
        !            43: 
        !            44: /*
        !            45:    The HP EtherTwist chip implementation is a fairly routine DP8390
        !            46:    implementation.  It allows both shared memory and programmed-I/O buffer
        !            47:    access, using a custom interface for both.  The programmed-I/O mode is
        !            48:    entirely implemented in the HP EtherTwist chip, bypassing the problem
        !            49:    ridden built-in 8390 facilities used on NE2000 designs.  The shared
        !            50:    memory mode is likewise special, with an offset register used to make
        !            51:    packets appear at the shared memory base.  Both modes use a base and bounds
        !            52:    page register to hide the Rx ring buffer wrap -- a packet that spans the
        !            53:    end of physical buffer memory appears continuous to the driver. (c.f. the
        !            54:    3c503 and Cabletron E2100)
        !            55: 
        !            56:    A special note: the internal buffer of the board is only 8 bits wide.
        !            57:    This lays several nasty traps for the unaware:
        !            58:    - the 8390 must be programmed for byte-wide operations
        !            59:    - all I/O and memory operations must work on whole words (the access
        !            60:      latches are serially preloaded and have no byte-swapping ability).
        !            61: 
        !            62:    This board is laid out in I/O space much like the earlier HP boards:
        !            63:    the first 16 locations are for the board registers, and the second 16 are
        !            64:    for the 8390.  The board is easy to identify, with both a dedicated 16 bit
        !            65:    ID register and a constant 0x530* value in the upper bits of the paging
        !            66:    register.
        !            67: */
        !            68: 
        !            69: #define HP_ID                  0x00    /* ID register, always 0x4850. */
        !            70: #define HP_PAGING              0x02    /* Registers visible @ 8-f, see PageName. */ 
        !            71: #define HPP_OPTION             0x04    /* Bitmapped options, see HP_Option.    */
        !            72: #define HPP_OUT_ADDR   0x08    /* I/O output location in Perf_Page.    */
        !            73: #define HPP_IN_ADDR            0x0A    /* I/O input location in Perf_Page.             */
        !            74: #define HP_DATAPORT            0x0c    /* I/O data transfer in Perf_Page.              */
        !            75: #define NIC_OFFSET             0x10    /* Offset to the 8390 registers.                */
        !            76: #define HP_IO_EXTENT   32
        !            77: 
        !            78: #define HP_START_PG            0x00    /* First page of TX buffer */
        !            79: #define HP_STOP_PG             0x80    /* Last page +1 of RX ring */
        !            80: 
        !            81: /* The register set selected in HP_PAGING. */
        !            82: enum PageName {
        !            83:        Perf_Page = 0,                          /* Normal operation. */
        !            84:        MAC_Page = 1,                           /* The ethernet address (+checksum). */
        !            85:        HW_Page = 2,                            /* EEPROM-loaded hardware parameters. */
        !            86:        LAN_Page = 4,                           /* Transceiver selection, testing, etc. */
        !            87:        ID_Page = 6 }; 
        !            88: 
        !            89: /* The bit definitions for the HPP_OPTION register. */
        !            90: enum HP_Option {
        !            91:        NICReset = 1, ChipReset = 2,    /* Active low, really UNreset. */
        !            92:        EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20,
        !            93:        MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, };
        !            94: 
        !            95: int hp_plus_probe(struct device *dev);
        !            96: int hpp_probe1(struct device *dev, int ioaddr);
        !            97: 
        !            98: static void hpp_reset_8390(struct device *dev);
        !            99: static int hpp_open(struct device *dev);
        !           100: static int hpp_close(struct device *dev);
        !           101: static void hpp_mem_block_input(struct device *dev, int count,
        !           102:                                                  struct sk_buff *skb, int ring_offset);
        !           103: static void hpp_mem_block_output(struct device *dev, int count,
        !           104:                                                        const unsigned char *buf, const int start_page);
        !           105: static void hpp_mem_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
        !           106:                                                  int ring_page);
        !           107: static void hpp_io_block_input(struct device *dev, int count,
        !           108:                                                  struct sk_buff *skb, int ring_offset);
        !           109: static void hpp_io_block_output(struct device *dev, int count,
        !           110:                                                        const unsigned char *buf, const int start_page);
        !           111: static void hpp_io_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
        !           112:                                                  int ring_page);
        !           113: 
        !           114: 
        !           115: /*     Probe a list of addresses for an HP LAN+ adaptor.
        !           116:        This routine is almost boilerplate. */
        !           117: #ifdef HAVE_DEVLIST
        !           118: /* Support for a alternate probe manager, which will eliminate the
        !           119:    boilerplate below. */
        !           120: struct netdev_entry hpplus_drv =
        !           121: {"hpplus", hpp_probe1, HP_IO_EXTENT, hpplus_portlist};
        !           122: #else
        !           123: 
        !           124: int hp_plus_probe(struct device *dev)
        !           125: {
        !           126:        int i;
        !           127:        int base_addr = dev ? dev->base_addr : 0;
        !           128: 
        !           129:        if (base_addr > 0x1ff)          /* Check a single specified location. */
        !           130:                return hpp_probe1(dev, base_addr);
        !           131:        else if (base_addr != 0)        /* Don't probe at all. */
        !           132:                return ENXIO;
        !           133: 
        !           134:        for (i = 0; hpplus_portlist[i]; i++) {
        !           135:                int ioaddr = hpplus_portlist[i];
        !           136:                if (check_region(ioaddr, HP_IO_EXTENT))
        !           137:                        continue;
        !           138:                if (hpp_probe1(dev, ioaddr) == 0)
        !           139:                        return 0;
        !           140:        }
        !           141: 
        !           142:        return ENODEV;
        !           143: }
        !           144: #endif
        !           145: 
        !           146: /* Do the interesting part of the probe at a single address. */
        !           147: int hpp_probe1(struct device *dev, int ioaddr)
        !           148: {
        !           149:        int i;
        !           150:        unsigned char checksum = 0;
        !           151:        const char *name = "HP-PC-LAN+";
        !           152:        int mem_start;
        !           153:        static unsigned version_printed = 0;
        !           154: 
        !           155:        /* Check for the HP+ signature, 50 48 0x 53. */
        !           156:        if (inw(ioaddr + HP_ID) != 0x4850
        !           157:                || (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300)
        !           158:                return ENODEV;
        !           159: 
        !           160:        /* We should have a "dev" from Space.c or the static module table. */
        !           161:        if (dev == NULL) {
        !           162:                printk("hp-plus.c: Passed a NULL device.\n");
        !           163:                dev = init_etherdev(0, 0);
        !           164:        }
        !           165: 
        !           166:        if (ei_debug  &&  version_printed++ == 0)
        !           167:                printk(version);
        !           168: 
        !           169:        printk("%s: %s at %#3x,", dev->name, name, ioaddr);
        !           170: 
        !           171:        /* Retrieve and checksum the station address. */
        !           172:        outw(MAC_Page, ioaddr + HP_PAGING);
        !           173: 
        !           174:        for(i = 0; i < ETHER_ADDR_LEN; i++) {
        !           175:                unsigned char inval = inb(ioaddr + 8 + i);
        !           176:                dev->dev_addr[i] = inval;
        !           177:                checksum += inval;
        !           178:                printk(" %2.2x", inval);
        !           179:        }
        !           180:        checksum += inb(ioaddr + 14);
        !           181: 
        !           182:        if (checksum != 0xff) {
        !           183:                printk(" bad checksum %2.2x.\n", checksum);
        !           184:                return ENODEV;
        !           185:        } else {
        !           186:                /* Point at the Software Configuration Flags. */
        !           187:                outw(ID_Page, ioaddr + HP_PAGING);
        !           188:                printk(" ID %4.4x", inw(ioaddr + 12));
        !           189:        }
        !           190: 
        !           191:        /* Allocate dev->priv and fill in 8390 specific dev fields. */
        !           192:        if (ethdev_init(dev)) {
        !           193:                printk ("hp-plus.c: unable to allocate memory for dev->priv.\n");
        !           194:                return -ENOMEM;
        !           195:         }
        !           196: 
        !           197:        /* Grab the region so we can find another board if something fails. */
        !           198:        request_region(ioaddr, HP_IO_EXTENT,"hp-plus");
        !           199: 
        !           200:        /* Read the IRQ line. */
        !           201:        outw(HW_Page, ioaddr + HP_PAGING);
        !           202:        {
        !           203:                int irq = inb(ioaddr + 13) & 0x0f;
        !           204:                int option = inw(ioaddr + HPP_OPTION);
        !           205: 
        !           206:                dev->irq = irq;
        !           207:                if (option & MemEnable) {
        !           208:                        mem_start = inw(ioaddr + 9) << 8;
        !           209:                        printk(", IRQ %d, memory address %#x.\n", irq, mem_start);
        !           210:                } else {
        !           211:                        mem_start = 0;
        !           212:                        printk(", IRQ %d, programmed-I/O mode.\n", irq);
        !           213:                }
        !           214:        }
        !           215: 
        !           216:        /* Set the wrap registers for string I/O reads.   */
        !           217:        outw((HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
        !           218: 
        !           219:        /* Set the base address to point to the NIC, not the "real" base! */
        !           220:        dev->base_addr = ioaddr + NIC_OFFSET;
        !           221: 
        !           222:        dev->open = &hpp_open;
        !           223:        dev->stop = &hpp_close;
        !           224: 
        !           225:        ei_status.name = name;
        !           226:        ei_status.word16 = 0;           /* Agggghhhhh! Debug time: 2 days! */
        !           227:        ei_status.tx_start_page = HP_START_PG;
        !           228:        ei_status.rx_start_page = HP_START_PG + TX_2X_PAGES;
        !           229:        ei_status.stop_page = HP_STOP_PG;
        !           230: 
        !           231:        ei_status.reset_8390 = &hpp_reset_8390;
        !           232:        ei_status.block_input = &hpp_io_block_input;
        !           233:        ei_status.block_output = &hpp_io_block_output;
        !           234:        ei_status.get_8390_hdr = &hpp_io_get_8390_hdr;
        !           235: 
        !           236:        /* Check if the memory_enable flag is set in the option register. */
        !           237:        if (mem_start) {
        !           238:                ei_status.block_input = &hpp_mem_block_input;
        !           239:                ei_status.block_output = &hpp_mem_block_output;
        !           240:                ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr;
        !           241:                dev->mem_start = mem_start;
        !           242:                dev->rmem_start = dev->mem_start + TX_2X_PAGES*256;
        !           243:                dev->mem_end = dev->rmem_end
        !           244:                        = dev->mem_start + (HP_STOP_PG - HP_START_PG)*256;
        !           245:        }
        !           246: 
        !           247:        outw(Perf_Page, ioaddr + HP_PAGING);
        !           248:        NS8390_init(dev, 0);
        !           249:        /* Leave the 8390 and HP chip reset. */
        !           250:        outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION);
        !           251: 
        !           252:        return 0;
        !           253: }
        !           254: 
        !           255: static int
        !           256: hpp_open(struct device *dev)
        !           257: {
        !           258:        int ioaddr = dev->base_addr - NIC_OFFSET;
        !           259:        int option_reg;
        !           260: 
        !           261:        if (request_irq(dev->irq, &ei_interrupt, 0, "hp-plus", NULL)) {
        !           262:            return -EAGAIN;
        !           263:        }
        !           264: 
        !           265:        /* Reset the 8390 and HP chip. */
        !           266:        option_reg = inw(ioaddr + HPP_OPTION);
        !           267:        outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
        !           268:        SLOW_DOWN_IO; SLOW_DOWN_IO;
        !           269:        /* Unreset the board and enable interrupts. */
        !           270:        outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
        !           271: 
        !           272:        /* Set the wrap registers for programmed-I/O operation.   */
        !           273:        outw(HW_Page, ioaddr + HP_PAGING);
        !           274:        outw((HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8), ioaddr + 14);
        !           275: 
        !           276:        /* Select the operational page. */
        !           277:        outw(Perf_Page, ioaddr + HP_PAGING);
        !           278: 
        !           279:        ei_open(dev);
        !           280:        MOD_INC_USE_COUNT;
        !           281:        return 0;
        !           282: }
        !           283: 
        !           284: static int
        !           285: hpp_close(struct device *dev)
        !           286: {
        !           287:        int ioaddr = dev->base_addr - NIC_OFFSET;
        !           288:        int option_reg = inw(ioaddr + HPP_OPTION);
        !           289: 
        !           290:        free_irq(dev->irq, NULL);
        !           291:        irq2dev_map[dev->irq] = NULL;
        !           292:        ei_close(dev);
        !           293:        outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset,
        !           294:                 ioaddr + HPP_OPTION);
        !           295: 
        !           296:        MOD_DEC_USE_COUNT;
        !           297:        return 0;
        !           298: }
        !           299: 
        !           300: static void
        !           301: hpp_reset_8390(struct device *dev)
        !           302: {
        !           303:        int ioaddr = dev->base_addr - NIC_OFFSET;
        !           304:        int option_reg = inw(ioaddr + HPP_OPTION);
        !           305: 
        !           306:        if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
        !           307: 
        !           308:        outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION);
        !           309:        /* Pause a few cycles for the hardware reset to take place. */
        !           310:        SLOW_DOWN_IO;
        !           311:        SLOW_DOWN_IO;
        !           312:        ei_status.txing = 0;
        !           313:        outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION);
        !           314: 
        !           315:        SLOW_DOWN_IO; SLOW_DOWN_IO;
        !           316: 
        !           317: 
        !           318:        if ((inb_p(ioaddr+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
        !           319:                printk("%s: hp_reset_8390() did not complete.\n", dev->name);
        !           320: 
        !           321:        if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
        !           322:        return;
        !           323: }
        !           324: 
        !           325: /* The programmed-I/O version of reading the 4 byte 8390 specific header.
        !           326:    Note that transfer with the EtherTwist+ must be on word boundaries. */
        !           327: 
        !           328: static void
        !           329: hpp_io_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
        !           330: {
        !           331:        int ioaddr = dev->base_addr - NIC_OFFSET;
        !           332: 
        !           333:        outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
        !           334:        insw(ioaddr + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
        !           335: }
        !           336: 
        !           337: /* Block input and output, similar to the Crynwr packet driver. */
        !           338: 
        !           339: static void
        !           340: hpp_io_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
        !           341: {
        !           342:        int ioaddr = dev->base_addr - NIC_OFFSET;
        !           343:        char *buf = skb->data;
        !           344: 
        !           345:        outw(ring_offset, ioaddr + HPP_IN_ADDR);
        !           346:        insw(ioaddr + HP_DATAPORT, buf, count>>1);
        !           347:        if (count & 0x01)
        !           348:         buf[count-1] = inw(ioaddr + HP_DATAPORT);
        !           349: }
        !           350: 
        !           351: /* The corresponding shared memory versions of the above 2 functions. */
        !           352: 
        !           353: static void
        !           354: hpp_mem_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
        !           355: {
        !           356:        int ioaddr = dev->base_addr - NIC_OFFSET;
        !           357:        int option_reg = inw(ioaddr + HPP_OPTION);
        !           358: 
        !           359:        outw((ring_page<<8), ioaddr + HPP_IN_ADDR);
        !           360:        outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
        !           361:        memcpy_fromio(hdr, dev->mem_start, sizeof(struct e8390_pkt_hdr));
        !           362:        outw(option_reg, ioaddr + HPP_OPTION);
        !           363:        hdr->count = (hdr->count + 3) & ~3;     /* Round up allocation. */
        !           364: }
        !           365: 
        !           366: static void
        !           367: hpp_mem_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
        !           368: {
        !           369:        int ioaddr = dev->base_addr - NIC_OFFSET;
        !           370:        int option_reg = inw(ioaddr + HPP_OPTION);
        !           371: 
        !           372:        outw(ring_offset, ioaddr + HPP_IN_ADDR);
        !           373: 
        !           374:        outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
        !           375: 
        !           376:        /* Caution: this relies on get_8390_hdr() rounding up count!
        !           377:           Also note that we *can't* use eth_io_copy_and_sum() because
        !           378:           it will not always copy "count" bytes (e.g. padded IP).  */
        !           379: 
        !           380:        memcpy_fromio(skb->data, dev->mem_start, count);
        !           381:        outw(option_reg, ioaddr + HPP_OPTION);
        !           382: }
        !           383: 
        !           384: /* A special note: we *must* always transfer >=16 bit words.
        !           385:    It's always safe to round up, so we do. */
        !           386: static void
        !           387: hpp_io_block_output(struct device *dev, int count,
        !           388:                                        const unsigned char *buf, const int start_page)
        !           389: {
        !           390:        int ioaddr = dev->base_addr - NIC_OFFSET;
        !           391:        outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
        !           392:        outsl(ioaddr + HP_DATAPORT, buf, (count+3)>>2);
        !           393:        return;
        !           394: }
        !           395: 
        !           396: static void
        !           397: hpp_mem_block_output(struct device *dev, int count,
        !           398:                                const unsigned char *buf, const int start_page)
        !           399: {
        !           400:        int ioaddr = dev->base_addr - NIC_OFFSET;
        !           401:        int option_reg = inw(ioaddr + HPP_OPTION);
        !           402: 
        !           403:        outw(start_page << 8, ioaddr + HPP_OUT_ADDR);
        !           404:        outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION);
        !           405:        memcpy_toio(dev->mem_start, buf, (count + 3) & ~3);
        !           406:        outw(option_reg, ioaddr + HPP_OPTION);
        !           407: 
        !           408:        return;
        !           409: }
        !           410: 
        !           411: 
        !           412: #ifdef MODULE
        !           413: #define MAX_HPP_CARDS  4       /* Max number of HPP cards per module */
        !           414: #define NAMELEN                8       /* # of chars for storing dev->name */
        !           415: static char namelist[NAMELEN * MAX_HPP_CARDS] = { 0, };
        !           416: static struct device dev_hpp[MAX_HPP_CARDS] = {
        !           417:        {
        !           418:                NULL,           /* assign a chunk of namelist[] below */
        !           419:                0, 0, 0, 0,
        !           420:                0, 0,
        !           421:                0, 0, 0, NULL, NULL
        !           422:        },
        !           423: };
        !           424: 
        !           425: static int io[MAX_HPP_CARDS] = { 0, };
        !           426: static int irq[MAX_HPP_CARDS]  = { 0, };
        !           427: 
        !           428: /* This is set up so that only a single autoprobe takes place per call.
        !           429: ISA device autoprobes on a running machine are not recommended. */
        !           430: int
        !           431: init_module(void)
        !           432: {
        !           433:        int this_dev, found = 0;
        !           434: 
        !           435:        for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
        !           436:                struct device *dev = &dev_hpp[this_dev];
        !           437:                dev->name = namelist+(NAMELEN*this_dev);
        !           438:                dev->irq = irq[this_dev];
        !           439:                dev->base_addr = io[this_dev];
        !           440:                dev->init = hp_plus_probe;
        !           441:                if (io[this_dev] == 0)  {
        !           442:                        if (this_dev != 0) break; /* only autoprobe 1st one */
        !           443:                        printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n");
        !           444:                }
        !           445:                if (register_netdev(dev) != 0) {
        !           446:                        printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]);
        !           447:                        if (found != 0) return 0;       /* Got at least one. */
        !           448:                        return -ENXIO;
        !           449:                }
        !           450:                found++;
        !           451:        }
        !           452: 
        !           453:        return 0;
        !           454: }
        !           455: 
        !           456: void
        !           457: cleanup_module(void)
        !           458: {
        !           459:        int this_dev;
        !           460: 
        !           461:        for (this_dev = 0; this_dev < MAX_HPP_CARDS; this_dev++) {
        !           462:                struct device *dev = &dev_hpp[this_dev];
        !           463:                if (dev->priv != NULL) {
        !           464:                        /* NB: hpp_close() handles free_irq + irq2dev map */
        !           465:                        int ioaddr = dev->base_addr - NIC_OFFSET;
        !           466:                        kfree(dev->priv);
        !           467:                        dev->priv = NULL;
        !           468:                        release_region(ioaddr, HP_IO_EXTENT);
        !           469:                        unregister_netdev(dev);
        !           470:                }
        !           471:        }
        !           472: }
        !           473: #endif /* MODULE */
        !           474: 
        !           475: /*
        !           476:  * Local variables:
        !           477:  * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp-plus.c"
        !           478:  * version-control: t
        !           479:  * kept-new-versions: 5
        !           480:  * tab-width: 4
        !           481:  * c-indent-level: 4
        !           482:  * End:
        !           483:  */

unix.superglobalmegacorp.com

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