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

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)
1.1.1.2 ! root      167:                printk("%s", version);
1.1       root      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.