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

1.1     ! root        1: /* hp.c: A HP LAN ethernet driver for linux. */
        !             2: /*
        !             3:        Written 1993-94 by Donald Becker.
        !             4: 
        !             5:        Copyright 1993 United States Government as represented by the
        !             6:        Director, National Security Agency.
        !             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:        Center of Excellence in Space Data and Information Sciences
        !            13:           Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
        !            14: 
        !            15:        This is a driver for the HP PC-LAN adaptors.
        !            16: 
        !            17:        Sources:
        !            18:          The Crynwr packet driver.
        !            19: */
        !            20: 
        !            21: static const char *version =
        !            22:        "hp.c:v1.10 9/23/94 Donald Becker ([email protected])\n";
        !            23: 
        !            24: 
        !            25: #include <linux/module.h>
        !            26: 
        !            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: #include "8390.h"
        !            38: 
        !            39: /* A zero-terminated list of I/O addresses to be probed. */
        !            40: static unsigned int hppclan_portlist[] =
        !            41: { 0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
        !            42: 
        !            43: #define HP_IO_EXTENT   32
        !            44: 
        !            45: #define HP_DATAPORT            0x0c    /* "Remote DMA" data port. */
        !            46: #define HP_ID                  0x07
        !            47: #define HP_CONFIGURE   0x08    /* Configuration register. */
        !            48: #define         HP_RUN                 0x01    /* 1 == Run, 0 == reset. */
        !            49: #define         HP_IRQ                 0x0E    /* Mask for software-configured IRQ line. */
        !            50: #define         HP_DATAON              0x10    /* Turn on dataport */
        !            51: #define NIC_OFFSET             0x10    /* Offset the 8390 registers. */
        !            52: 
        !            53: #define HP_START_PG            0x00    /* First page of TX buffer */
        !            54: #define HP_8BSTOP_PG   0x80    /* Last page +1 of RX ring */
        !            55: #define HP_16BSTOP_PG  0xFF    /* Same, for 16 bit cards. */
        !            56: 
        !            57: int hp_probe(struct device *dev);
        !            58: int hp_probe1(struct device *dev, int ioaddr);
        !            59: 
        !            60: static int hp_open(struct device *dev);
        !            61: static int hp_close(struct device *dev);
        !            62: static void hp_reset_8390(struct device *dev);
        !            63: static void hp_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
        !            64:                                        int ring_page);
        !            65: static void hp_block_input(struct device *dev, int count,
        !            66:                                        struct sk_buff *skb , int ring_offset);
        !            67: static void hp_block_output(struct device *dev, int count,
        !            68:                                                        const unsigned char *buf, const int start_page);
        !            69: 
        !            70: static void hp_init_card(struct device *dev);
        !            71: 
        !            72: /* The map from IRQ number to HP_CONFIGURE register setting. */
        !            73: /* My default is IRQ5     0  1  2  3  4  5  6  7  8  9 10 11 */
        !            74: static char irqmap[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0};
        !            75: 
        !            76: 
        !            77: /*     Probe for an HP LAN adaptor.
        !            78:        Also initialize the card and fill in STATION_ADDR with the station
        !            79:        address. */
        !            80: #ifdef HAVE_DEVLIST
        !            81: struct netdev_entry netcard_drv =
        !            82: {"hp", hp_probe1, HP_IO_EXTENT, hppclan_portlist};
        !            83: #else
        !            84: 
        !            85: int hp_probe(struct device *dev)
        !            86: {
        !            87:        int i;
        !            88:        int base_addr = dev ? dev->base_addr : 0;
        !            89: 
        !            90:        if (base_addr > 0x1ff)          /* Check a single specified location. */
        !            91:                return hp_probe1(dev, base_addr);
        !            92:        else if (base_addr != 0)        /* Don't probe at all. */
        !            93:                return ENXIO;
        !            94: 
        !            95:        for (i = 0; hppclan_portlist[i]; i++) {
        !            96:                int ioaddr = hppclan_portlist[i];
        !            97:                if (check_region(ioaddr, HP_IO_EXTENT))
        !            98:                        continue;
        !            99:                if (hp_probe1(dev, ioaddr) == 0)
        !           100:                        return 0;
        !           101:        }
        !           102: 
        !           103:        return ENODEV;
        !           104: }
        !           105: #endif
        !           106: 
        !           107: int hp_probe1(struct device *dev, int ioaddr)
        !           108: {
        !           109:        int i, board_id, wordmode;
        !           110:        const char *name;
        !           111:        static unsigned version_printed = 0;
        !           112: 
        !           113:        /* Check for the HP physical address, 08 00 09 xx xx xx. */
        !           114:        /* This really isn't good enough: we may pick up HP LANCE boards
        !           115:           also!  Avoid the lance 0x5757 signature. */
        !           116:        if (inb(ioaddr) != 0x08
        !           117:                || inb(ioaddr+1) != 0x00
        !           118:                || inb(ioaddr+2) != 0x09
        !           119:                || inb(ioaddr+14) == 0x57)
        !           120:                return ENODEV;
        !           121: 
        !           122:        /* Set up the parameters based on the board ID.
        !           123:           If you have additional mappings, please mail them to me -djb. */
        !           124:        if ((board_id = inb(ioaddr + HP_ID)) & 0x80) {
        !           125:                name = "HP27247";
        !           126:                wordmode = 1;
        !           127:        } else {
        !           128:                name = "HP27250";
        !           129:                wordmode = 0;
        !           130:        }
        !           131: 
        !           132:        /* We should have a "dev" from Space.c or the static module table. */
        !           133:        if (dev == NULL) {
        !           134:                printk("hp.c: Passed a NULL device.\n");
        !           135:                dev = init_etherdev(0, 0);
        !           136:        }
        !           137: 
        !           138:        if (ei_debug  &&  version_printed++ == 0)
        !           139:                printk(version);
        !           140:  
        !           141:        printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr);
        !           142: 
        !           143:        for(i = 0; i < ETHER_ADDR_LEN; i++)
        !           144:                printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
        !           145: 
        !           146:        /* Snarf the interrupt now.  Someday this could be moved to open(). */
        !           147:        if (dev->irq < 2) {
        !           148:                int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
        !           149:                int irq_8list[] = { 7, 5, 3, 4, 9, 0};
        !           150:                int *irqp = wordmode ? irq_16list : irq_8list;
        !           151:                do {
        !           152:                        int irq = *irqp;
        !           153:                        if (request_irq (irq, NULL, 0, "bogus", NULL) != -EBUSY) {
        !           154:                                autoirq_setup(0);
        !           155:                                /* Twinkle the interrupt, and check if it's seen. */
        !           156:                                outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE);
        !           157:                                outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE);
        !           158:                                if (irq == autoirq_report(0)             /* It's a good IRQ line! */
        !           159:                                        && request_irq (irq, &ei_interrupt, 0, "hp", NULL) == 0) {
        !           160:                                        printk(" selecting IRQ %d.\n", irq);
        !           161:                                        dev->irq = *irqp;
        !           162:                                        break;
        !           163:                                }
        !           164:                        }
        !           165:                } while (*++irqp);
        !           166:                if (*irqp == 0) {
        !           167:                        printk(" no free IRQ lines.\n");
        !           168:                        return EBUSY;
        !           169:                }
        !           170:        } else {
        !           171:                if (dev->irq == 2)
        !           172:                        dev->irq = 9;
        !           173:                if (request_irq(dev->irq, ei_interrupt, 0, "hp", NULL)) {
        !           174:                        printk (" unable to get IRQ %d.\n", dev->irq);
        !           175:                        return EBUSY;
        !           176:                }
        !           177:        }
        !           178: 
        !           179:        /* Allocate dev->priv and fill in 8390 specific dev fields. */
        !           180:        if (ethdev_init(dev)) {
        !           181:                printk (" unable to get memory for dev->priv.\n");
        !           182:                free_irq(dev->irq, NULL);
        !           183:                return -ENOMEM;
        !           184:        }
        !           185: 
        !           186:        /* Grab the region so we can find another board if something fails. */
        !           187:        request_region(ioaddr, HP_IO_EXTENT,"hp");
        !           188: 
        !           189:        /* Set the base address to point to the NIC, not the "real" base! */
        !           190:        dev->base_addr = ioaddr + NIC_OFFSET;
        !           191:        dev->open = &hp_open;
        !           192:        dev->stop = &hp_close;
        !           193: 
        !           194:        ei_status.name = name;
        !           195:        ei_status.word16 = wordmode;
        !           196:        ei_status.tx_start_page = HP_START_PG;
        !           197:        ei_status.rx_start_page = HP_START_PG + TX_PAGES;
        !           198:        ei_status.stop_page = wordmode ? HP_16BSTOP_PG : HP_8BSTOP_PG;
        !           199: 
        !           200:        ei_status.reset_8390 = &hp_reset_8390;
        !           201:        ei_status.get_8390_hdr = &hp_get_8390_hdr;
        !           202:        ei_status.block_input = &hp_block_input;
        !           203:        ei_status.block_output = &hp_block_output;
        !           204:        hp_init_card(dev);
        !           205: 
        !           206:        return 0;
        !           207: }
        !           208: 
        !           209: static int
        !           210: hp_open(struct device *dev)
        !           211: {
        !           212:        ei_open(dev);
        !           213:        MOD_INC_USE_COUNT;
        !           214:        return 0;
        !           215: }
        !           216: 
        !           217: static int
        !           218: hp_close(struct device *dev)
        !           219: {
        !           220:        ei_close(dev);
        !           221:        MOD_DEC_USE_COUNT;
        !           222:        return 0;
        !           223: }
        !           224: 
        !           225: static void
        !           226: hp_reset_8390(struct device *dev)
        !           227: {
        !           228:        int hp_base = dev->base_addr - NIC_OFFSET;
        !           229:        int saved_config = inb_p(hp_base + HP_CONFIGURE);
        !           230: 
        !           231:        if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies);
        !           232:        outb_p(0x00, hp_base + HP_CONFIGURE);
        !           233:        ei_status.txing = 0;
        !           234:        /* Pause just a few cycles for the hardware reset to take place. */
        !           235:        SLOW_DOWN_IO;
        !           236:        SLOW_DOWN_IO;
        !           237: 
        !           238:        outb_p(saved_config, hp_base + HP_CONFIGURE);
        !           239:        SLOW_DOWN_IO; SLOW_DOWN_IO;
        !           240:        
        !           241:        if ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0)
        !           242:                printk("%s: hp_reset_8390() did not complete.\n", dev->name);
        !           243: 
        !           244:        if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies);
        !           245:        return;
        !           246: }
        !           247: 
        !           248: static void
        !           249: hp_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
        !           250: {
        !           251:        int nic_base = dev->base_addr;
        !           252:        int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
        !           253: 
        !           254:        outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
        !           255:        outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
        !           256:        outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
        !           257:        outb_p(0, nic_base + EN0_RCNTHI);
        !           258:        outb_p(0, nic_base + EN0_RSARLO);       /* On page boundary */
        !           259:        outb_p(ring_page, nic_base + EN0_RSARHI);
        !           260:        outb_p(E8390_RREAD+E8390_START, nic_base);
        !           261: 
        !           262:        if (ei_status.word16) 
        !           263:          insw(nic_base - NIC_OFFSET + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr)>>1);
        !           264:        else 
        !           265:          insb(nic_base - NIC_OFFSET + HP_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr));
        !           266: 
        !           267:        outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
        !           268: }
        !           269:        
        !           270: /* Block input and output, similar to the Crynwr packet driver. If you are
        !           271:    porting to a new ethercard look at the packet driver source for hints.
        !           272:    The HP LAN doesn't use shared memory -- we put the packet
        !           273:    out through the "remote DMA" dataport. */
        !           274: 
        !           275: static void
        !           276: hp_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
        !           277: {
        !           278:        int nic_base = dev->base_addr;
        !           279:        int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
        !           280:        int xfer_count = count;
        !           281:        char *buf = skb->data;
        !           282: 
        !           283:        outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
        !           284:        outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base);
        !           285:        outb_p(count & 0xff, nic_base + EN0_RCNTLO);
        !           286:        outb_p(count >> 8, nic_base + EN0_RCNTHI);
        !           287:        outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
        !           288:        outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
        !           289:        outb_p(E8390_RREAD+E8390_START, nic_base);
        !           290:        if (ei_status.word16) {
        !           291:          insw(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1);
        !           292:          if (count & 0x01)
        !           293:                buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++;
        !           294:        } else {
        !           295:                insb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
        !           296:        }
        !           297:        /* This is for the ALPHA version only, remove for later releases. */
        !           298:        if (ei_debug > 0) {                     /* DMA termination address check... */
        !           299:          int high = inb_p(nic_base + EN0_RSARHI);
        !           300:          int low = inb_p(nic_base + EN0_RSARLO);
        !           301:          int addr = (high << 8) + low;
        !           302:          /* Check only the lower 8 bits so we can ignore ring wrap. */
        !           303:          if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff))
        !           304:                printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n",
        !           305:                           dev->name, ring_offset + xfer_count, addr);
        !           306:        }
        !           307:        outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
        !           308: }
        !           309: 
        !           310: static void
        !           311: hp_block_output(struct device *dev, int count,
        !           312:                                const unsigned char *buf, const int start_page)
        !           313: {
        !           314:        int nic_base = dev->base_addr;
        !           315:        int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE);
        !           316: 
        !           317:        outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE);
        !           318:        /* Round the count up for word writes.  Do we need to do this?
        !           319:           What effect will an odd byte count have on the 8390?
        !           320:           I should check someday. */
        !           321:        if (ei_status.word16 && (count & 0x01))
        !           322:          count++;
        !           323:        /* We should already be in page 0, but to be safe... */
        !           324:        outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base);
        !           325: 
        !           326: #ifdef NE8390_RW_BUGFIX
        !           327:        /* Handle the read-before-write bug the same way as the
        !           328:           Crynwr packet driver -- the NatSemi method doesn't work. */
        !           329:        outb_p(0x42, nic_base + EN0_RCNTLO);
        !           330:        outb_p(0,       nic_base + EN0_RCNTHI);
        !           331:        outb_p(0xff, nic_base + EN0_RSARLO);
        !           332:        outb_p(0x00, nic_base + EN0_RSARHI);
        !           333: #define NE_CMD         0x00
        !           334:        outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD);
        !           335:        /* Make certain that the dummy read has occurred. */
        !           336:        inb_p(0x61);
        !           337:        inb_p(0x61);
        !           338: #endif
        !           339: 
        !           340:        outb_p(count & 0xff, nic_base + EN0_RCNTLO);
        !           341:        outb_p(count >> 8,       nic_base + EN0_RCNTHI);
        !           342:        outb_p(0x00, nic_base + EN0_RSARLO);
        !           343:        outb_p(start_page, nic_base + EN0_RSARHI);
        !           344: 
        !           345:        outb_p(E8390_RWRITE+E8390_START, nic_base);
        !           346:        if (ei_status.word16) {
        !           347:                /* Use the 'rep' sequence for 16 bit boards. */
        !           348:                outsw(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1);
        !           349:        } else {
        !           350:                outsb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count);
        !           351:        }
        !           352: 
        !           353:        /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */
        !           354: 
        !           355:        /* This is for the ALPHA version only, remove for later releases. */
        !           356:        if (ei_debug > 0) {                     /* DMA termination address check... */
        !           357:          int high = inb_p(nic_base + EN0_RSARHI);
        !           358:          int low  = inb_p(nic_base + EN0_RSARLO);
        !           359:          int addr = (high << 8) + low;
        !           360:          if ((start_page << 8) + count != addr)
        !           361:                printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n",
        !           362:                           dev->name, (start_page << 8) + count, addr);
        !           363:        }
        !           364:        outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE);
        !           365:        return;
        !           366: }
        !           367: 
        !           368: /* This function resets the ethercard if something screws up. */
        !           369: static void
        !           370: hp_init_card(struct device *dev)
        !           371: {
        !           372:        int irq = dev->irq;
        !           373:        NS8390_init(dev, 0);
        !           374:        outb_p(irqmap[irq&0x0f] | HP_RUN,
        !           375:                   dev->base_addr - NIC_OFFSET + HP_CONFIGURE);
        !           376:        return;
        !           377: }
        !           378: 
        !           379: #ifdef MODULE
        !           380: #define MAX_HP_CARDS   4       /* Max number of HP cards per module */
        !           381: #define NAMELEN                8       /* # of chars for storing dev->name */
        !           382: static char namelist[NAMELEN * MAX_HP_CARDS] = { 0, };
        !           383: static struct device dev_hp[MAX_HP_CARDS] = {
        !           384:        {
        !           385:                NULL,           /* assign a chunk of namelist[] below */
        !           386:                0, 0, 0, 0,
        !           387:                0, 0,
        !           388:                0, 0, 0, NULL, NULL
        !           389:        },
        !           390: };
        !           391: 
        !           392: static int io[MAX_HP_CARDS] = { 0, };
        !           393: static int irq[MAX_HP_CARDS]  = { 0, };
        !           394: 
        !           395: /* This is set up so that only a single autoprobe takes place per call.
        !           396: ISA device autoprobes on a running machine are not recommended. */
        !           397: int
        !           398: init_module(void)
        !           399: {
        !           400:        int this_dev, found = 0;
        !           401: 
        !           402:        for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
        !           403:                struct device *dev = &dev_hp[this_dev];
        !           404:                dev->name = namelist+(NAMELEN*this_dev);
        !           405:                dev->irq = irq[this_dev];
        !           406:                dev->base_addr = io[this_dev];
        !           407:                dev->init = hp_probe;
        !           408:                if (io[this_dev] == 0)  {
        !           409:                        if (this_dev != 0) break; /* only autoprobe 1st one */
        !           410:                        printk(KERN_NOTICE "hp.c: Presently autoprobing (not recommended) for a single card.\n");
        !           411:                }
        !           412:                if (register_netdev(dev) != 0) {
        !           413:                        printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]);
        !           414:                        if (found != 0) return 0;       /* Got at least one. */
        !           415:                        return -ENXIO;
        !           416:                }
        !           417:                found++;
        !           418:        }
        !           419: 
        !           420:        return 0;
        !           421: }
        !           422: 
        !           423: void
        !           424: cleanup_module(void)
        !           425: {
        !           426:        int this_dev;
        !           427: 
        !           428:        for (this_dev = 0; this_dev < MAX_HP_CARDS; this_dev++) {
        !           429:                struct device *dev = &dev_hp[this_dev];
        !           430:                if (dev->priv != NULL) {
        !           431:                        int ioaddr = dev->base_addr - NIC_OFFSET;
        !           432:                        kfree(dev->priv);
        !           433:                        dev->priv = NULL;
        !           434:                        free_irq(dev->irq, NULL);
        !           435:                        irq2dev_map[dev->irq] = NULL;
        !           436:                        release_region(ioaddr, HP_IO_EXTENT);
        !           437:                        unregister_netdev(dev);
        !           438:                }
        !           439:        }
        !           440: }
        !           441: #endif /* MODULE */
        !           442: 
        !           443: /*
        !           444:  * Local variables:
        !           445:  * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c"
        !           446:  * version-control: t
        !           447:  * kept-new-versions: 5
        !           448:  * tab-width: 4
        !           449:  * c-indent-level: 4
        !           450:  * End:
        !           451:  */

unix.superglobalmegacorp.com

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