summaryrefslogtreecommitdiff
path: root/i386/i386at/gpl/if_hpp.c
diff options
context:
space:
mode:
Diffstat (limited to 'i386/i386at/gpl/if_hpp.c')
-rw-r--r--i386/i386at/gpl/if_hpp.c690
1 files changed, 0 insertions, 690 deletions
diff --git a/i386/i386at/gpl/if_hpp.c b/i386/i386at/gpl/if_hpp.c
deleted file mode 100644
index c177030..0000000
--- a/i386/i386at/gpl/if_hpp.c
+++ /dev/null
@@ -1,690 +0,0 @@
-/*
- Written 1994 by Donald Becker.
-
- This driver is for the Hewlett Packard PC LAN (27***) plus ethercards.
- These cards are sold under several model numbers, usually 2724*.
-
- This software may be used and distributed according to the terms
- of the GNU Public License, incorporated herein by reference.
-
- The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-
- Center of Excellence in Space Data and Information Sciences
- Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-
- As is often the case, a great deal of credit is owed to Russ Nelson.
- The Crynwr packet driver was my primary source of HP-specific
- programming information.
-*/
-
-/*
- * Ported to mach by Stephen Clawson, sclawson@cs.utah.edu
- * University of Utah CSL.
- *
- * Derived from the Linux driver by Donald Becker.
- *
- * Also uses code Shantanu Goel adapted from Donald Becker
- * for ns8930 support.
- *
- */
-
-#include <hpp.h>
-#if NHPP > 0
-
-#include <sys/types.h>
-#include "vm_param.h"
-#include <kern/time_out.h>
-#include <device/device_types.h>
-#include <device/errno.h>
-#include <device/io_req.h>
-#include <device/if_hdr.h>
-#include <device/if_ether.h>
-#include <device/net_status.h>
-#include <device/net_io.h>
-#include <chips/busses.h>
-#include <i386/ipl.h>
-#include <i386/pio.h>
-#include <i386at/gpl/if_nsreg.h>
-
-
-/*
- * XXX - This is some gross glue garbage. The io instructions really
- * should be integrated into pio.h...
- */
-#define IO_DELAY __asm__ __volatile__("outb %al,$0x80")
-#define outb_p(p, v) { outb(p, v); IO_DELAY; }
-#define inb_p(p) ({ unsigned char _v; _v = inb(p); IO_DELAY; _v; })
-
-
-static __inline void
-insw(u_short port, void *addr, int cnt)
-{
- __asm __volatile("cld\n\trepne\n\tinsw" :
- : "d" (port), "D" (addr), "c" (cnt) : "%edi", "%ecx");
-}
-
-static __inline void
-outsw(u_short port, void *addr, int cnt)
-{
- __asm __volatile("cld\n\trepne\n\toutsw" :
- : "d" (port), "S" (addr), "c" (cnt) : "%esi", "%ecx");
-}
-
-
-/*
- The HP EtherTwist chip implementation is a fairly routine DP8390
- implementation. It allows both shared memory and programmed-I/O buffer
- access, using a custom interface for both. The programmed-I/O mode is
- entirely implemented in the HP EtherTwist chip, bypassing the problem
- ridden built-in 8390 facilities used on NE2000 designs. The shared
- memory mode is likewise special, with an offset register used to make
- packets appear at the shared memory base. Both modes use a base and bounds
- page register to hide the Rx ring buffer wrap -- a packet that spans the
- end of physical buffer memory appears continuous to the driver. (c.f. the
- 3c503 and Cabletron E2100)
-
- A special note: the internal buffer of the board is only 8 bits wide.
- This lays several nasty traps for the unaware:
- - the 8390 must be programmed for byte-wide operations
- - all I/O and memory operations must work on whole words (the access
- latches are serially preloaded and have no byte-swapping ability).
-
- This board is laid out in I/O space much like the earlier HP boards:
- the first 16 locations are for the board registers, and the second 16 are
- for the 8390. The board is easy to identify, with both a dedicated 16 bit
- ID register and a constant 0x530* value in the upper bits of the paging
- register.
-*/
-
-#define HP_ID 0x00 /* ID register, always 0x4850. */
-#define HP_PAGING 0x02 /* Registers visible @ 8-f, see PageName. */
-#define HPP_OPTION 0x04 /* Bitmapped options, see HP_Option.*/
-#define HPP_OUT_ADDR 0x08 /* I/O output location in Perf_Page.*/
-#define HPP_IN_ADDR 0x0A /* I/O input location in Perf_Page.*/
-#define HP_DATAPORT 0x0c /* I/O data transfer in Perf_Page.*/
-#define HPP_NIC_OFFSET 0x10 /* Offset to the 8390 registers.*/
-#define HP_IO_EXTENT 32
-
-#define HP_START_PG 0x00 /* First page of TX buffer */
-#define HP_STOP_PG 0x80 /* Last page +1 of RX ring */
-/*#define HP_STOP_PG 0x1f
-
-/* The register set selected in HP_PAGING. */
-enum PageName {
- Perf_Page = 0, /* Normal operation. */
- MAC_Page = 1, /* The ethernet address (+checksum). */
- HW_Page = 2, /* EEPROM-loaded hw parameters. */
- LAN_Page = 4, /* Transciever type, testing, etc. */
- ID_Page = 6 };
-
-/* The bit definitions for the HPP_OPTION register. */
-enum HP_Option {
- NICReset = 1, /* Active low, really UNreset. */
- ChipReset = 2,
- EnableIRQ = 4,
- FakeIntr = 8,
- BootROMEnb = 0x10,
- IOEnb = 0x20,
- MemEnable = 0x40,
- ZeroWait = 0x80,
- MemDisable = 0x1000, };
-
-
-void hpp_reset_8390(struct nssoftc *ns);
-
-void hpp_mem_block_input(struct nssoftc *ns, int, char *, int);
-int hpp_mem_block_output(struct nssoftc *ns, int, char *, int);
-void hpp_io_block_input(struct nssoftc *ns, int, char *, int);
-int hpp_io_block_output(struct nssoftc *ns, int,char *, int);
-
-
-/*
- * Watchdog timer.
- */
-int hppwstart = 0;
-void hppwatch(void);
-
-
-/*
- * Autoconfig structures.
- */
-int hpp_std[] = { 0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0 };
-struct bus_device *hpp_info[NHPP];
-int hpp_probe();
-void hpp_attach();
-struct bus_driver hppdriver = {
- hpp_probe, 0, hpp_attach, 0, hpp_std, "hpp", hpp_info, 0, 0, 0
-};
-
-
-/*
- * ns8390 state.
- */
-struct nssoftc hppnssoftc[NHPP];
-
-
-/*
- * hpp state.
- */
-struct hppsoftc {
- unsigned long rmem_start; /* shmem "recv" start */
- unsigned long rmem_end; /* shmem "recv" end */
- unsigned long mem_start; /* shared mem start */
- unsigned long mem_end; /* shared mem end */
-} hppsoftc[NHPP];
-
-
-/*
- * Probe a list of addresses for the card.
- *
- */
-int hpp_probe(port, dev)
- int port;
- struct bus_device *dev;
-{
- int unit = dev->unit;
- char *str = "hp-plus ethernet board %d out of range.\n";
- caddr_t base = (caddr_t) (dev ? dev->address : 0);
- int i;
-
- if ((unit < 0) || (unit >= NHPP)) {
- printf(str, unit);
- return(0);
- }
-
- /* Check a single specified location. */
- if (base > (caddr_t) 0x1ff)
- return hpp_probe1(dev, base);
- else if (base != 0) /* Don't probe at all. */
- return 0;
-
- for (i = 0; hpp_std[i]; i++) {
- int ioaddr = hpp_std[i];
-
- if ( ioaddr > 0 && hpp_probe1(dev, ioaddr) ) {
- dev->address = ioaddr;
- hpp_std[i] = -1; /* Mark address used */
- return(1);
- }
- }
-
- return 0;
-}
-
-
-
-/*
- * Do the interesting part of the probe at a single address.
- *
- */
-int hpp_probe1(dev, ioaddr)
- struct bus_device *dev;
- int ioaddr;
-{
- int i;
- u_char checksum = 0;
- int mem_start;
-
- struct hppsoftc *hpp = &hppsoftc[dev->unit];
- struct nssoftc *ns = &hppnssoftc[dev->unit];
- struct ifnet *ifp = &ns->sc_if;
-
- /* Check for the HP+ signature, 50 48 0x 53. */
- if (inw(ioaddr + HP_ID) != 0x4850
- || (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300)
- return 0;
-
-
- printf("%s%d: HP PClan plus at %#3x,", dev->name, dev->unit, ioaddr);
- /* Retrieve and checksum the station address. */
- outw(ioaddr + HP_PAGING, MAC_Page);
-
- printf("MAC_Page = %d, ioaddr = %x\n", MAC_Page, ioaddr);
-
- for(i = 0; i < ETHER_ADDR_LEN; i++) {
- u_char inval = inb(ioaddr + 8 + i);
- ns->sc_addr[i] = inval;
- checksum += inval;
- printf(" %2.2x", inval);
- }
- checksum += inb(ioaddr + 14);
-
- if (checksum != 0xff) {
- printf(" bad checksum %2.2x.\n", checksum);
- return 0;
- } else {
- /* Point at the Software Configuration Flags. */
- outw(ioaddr + HP_PAGING, ID_Page);
- printf(" ID %4.4x", inw(ioaddr + 12));
- }
-
-
- /* Read the IRQ line. */
- outw(ioaddr + HP_PAGING, HW_Page);
- {
- int irq = inb(ioaddr + 13) & 0x0f;
- int option = inw(ioaddr + HPP_OPTION);
-
- dev->sysdep1 = irq;
- take_dev_irq(dev);
-
- if (option & MemEnable) {
- mem_start = inw(ioaddr + 9) << 8;
- printf(", IRQ %d, memory address %#x.\n", irq, mem_start);
- } else {
- mem_start = 0;
- printf(", IRQ %d, programmed-I/O mode.\n", irq);
- }
- }
-
- /* Set the wrap registers for string I/O reads. */
- outw( ioaddr + 14, (HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8));
-
- /* Set the base address to point to the NIC, not the "real" base! */
- ns->sc_port = ioaddr + HPP_NIC_OFFSET;
-
- ns->sc_name = dev->name;
- ns->sc_unit = dev->unit;
- ns->sc_pingpong = 0; /* turn off pingpong mode */
- ns->sc_word16 = 0; /* Agggghhhhh! Debug time: 2 days! */
- ns->sc_txstrtpg = HP_START_PG;
- ns->sc_rxstrtpg = HP_START_PG + TX_2X_PAGES;
- ns->sc_stoppg = HP_STOP_PG;
-
-
- ns->sc_reset = hpp_reset_8390;
- ns->sc_input = hpp_io_block_input;
- ns->sc_output = hpp_io_block_output;
-
- /* Check if the memory_enable flag is set in the option register. */
- if (mem_start) {
- ns->sc_input = hpp_mem_block_input;
- ns->sc_output = hpp_mem_block_output;
- hpp->mem_start = mem_start;
- hpp->rmem_start = hpp->mem_start + TX_2X_PAGES * 256;
- hpp->mem_end = hpp->rmem_end
- = hpp->mem_start + (HP_STOP_PG - HP_START_PG) * 256;
- }
-
- outw(ioaddr + HP_PAGING, Perf_Page);
-
- /* Leave the 8390 and HP chip reset. */
- outw( ioaddr + HPP_OPTION, inw(ioaddr + HPP_OPTION) & ~EnableIRQ );
-
- /*
- * Initialize interface header.
- */
- ifp->if_unit = dev->unit;
- ifp->if_mtu = ETHERMTU;
- ifp->if_flags = IFF_BROADCAST;
- ifp->if_header_size = sizeof(struct ether_header);
- ifp->if_header_format = HDR_ETHERNET;
- ifp->if_address_size = ETHER_ADDR_LEN;
- ifp->if_address = ns->sc_addr;
- if_init_queues(ifp);
-
- return (1);
-}
-
-/*
- * XXX
- *
- * this routine really should do the invasive part of the setup.
- */
-void
-hpp_attach(dev)
- struct bus_device *dev;
-{
- /* NULL */
-}
-
-
-
-int
-hppopen(dev, flag)
- dev_t dev;
- int flag;
-{
- int s, unit = minor(dev);
- struct bus_device *bd;
- struct hppsoftc *hpp;
- struct nssoftc *ns = &hppnssoftc[unit];
-
- int ioaddr = ns->sc_port - HPP_NIC_OFFSET;
- int option_reg;
-
- if (unit < 0 || unit >= NHPP ||
- (bd = hpp_info[unit]) == 0 || !(bd->alive))
- return ENXIO;
-
- /*
- * Start watchdog.
- */
- if (!hppwstart) {
- hppwstart++;
- timeout(hppwatch, 0, hz);
- }
- hpp = &hppsoftc[unit];
- ns->sc_if.if_flags |= IFF_UP;
-
- s = splimp();
-
- /* Reset the 8390 and HP chip. */
- option_reg = inw(ioaddr + HPP_OPTION);
- outw( ioaddr + HPP_OPTION, option_reg & ~(NICReset + ChipReset) );
- IO_DELAY; IO_DELAY;
-
- /* Unreset the board and enable interrupts. */
- outw( ioaddr + HPP_OPTION, option_reg | (EnableIRQ + NICReset + ChipReset));
-
- /* Set the wrap registers for programmed-I/O operation. */
- outw( ioaddr + HP_PAGING, HW_Page );
- outw( ioaddr + 14, (HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8) );
-
- /* Select the operational page. */
- outw( ioaddr + HP_PAGING, Perf_Page );
- nsinit(ns);
-
- splx(s);
-
- return (0);
-}
-
-/*
- * needs to be called at splimp()?
- *
- */
-void
-hpp_reset_8390(ns)
- struct nssoftc *ns;
-{
- int ioaddr = ns->sc_port - HPP_NIC_OFFSET;
- int option_reg = inw(ioaddr + HPP_OPTION);
-
- outw( ioaddr + HPP_OPTION, option_reg & ~(NICReset + ChipReset) );
- /* Pause a few cycles for the hardware reset to take place. */
- IO_DELAY;
- IO_DELAY;
- ns->sc_txing = 0;
- outw( ioaddr + HPP_OPTION, option_reg | (EnableIRQ + NICReset + ChipReset) );
-
- /*
- * XXX - I'm not sure there needs to be this many IO_DELAY's...
- */
- IO_DELAY; IO_DELAY;
- IO_DELAY; IO_DELAY;
-
- if ((inb_p(ioaddr + HPP_NIC_OFFSET + EN0_ISR) & ENISR_RESET) == 0)
- printf("%s: hp_reset_8390() did not complete.\n", ns->sc_name);
-
- return;
-}
-
-
-/*
- * Block input and output, similar to the Crynwr packet driver.
- * Note that transfer with the EtherTwist+ must be on word boundaries.
- */
-void
-hpp_io_block_input(ns, count, buf, ring_offset)
- struct nssoftc *ns;
- int count;
- char *buf;
- int ring_offset;
-{
- int ioaddr = ns->sc_port - HPP_NIC_OFFSET;
-
- outw(ioaddr + HPP_IN_ADDR, ring_offset);
-
- insw(ioaddr + HP_DATAPORT, buf, count >> 1 );
-
- if (count & 0x01)
- buf[count-1] = (char) inw(ioaddr + HP_DATAPORT);
-
-}
-
-void
-hpp_mem_block_input(ns, count, buf, ring_offset)
- struct nssoftc *ns;
- int count;
- char *buf;
- int ring_offset;
-{
- int ioaddr = ns->sc_port - HPP_NIC_OFFSET;
- int option_reg = inw(ioaddr + HPP_OPTION);
- char *mem_start = (char *)phystokv(hppsoftc[ns->sc_unit].mem_start);
-
- outw(ioaddr + HPP_IN_ADDR, ring_offset);
- outw(ioaddr + HPP_OPTION, option_reg & ~(MemDisable + BootROMEnb));
-
- /* copy as much as we can straight through */
- bcopy16(mem_start, buf, count & ~1);
-
- /* Now we copy that last byte. */
- if (count & 0x01) {
- u_short savebyte[2];
-
- bcopy16(mem_start + (count & ~1), savebyte, 2);
- buf[count-1] = savebyte[0];
- }
-
- outw(ioaddr + HPP_OPTION, option_reg);
-}
-
-
-/*
- * output data into NIC buffers.
- *
- * NOTE: All transfers must be on word boundaries.
- */
-int
-hpp_io_block_output(ns, count, buf, start_page)
- struct nssoftc *ns;
- int count;
- char *buf;
- int start_page;
-{
- int ioaddr = ns->sc_port - HPP_NIC_OFFSET;
-
- outw(ioaddr + HPP_OUT_ADDR, start_page << 8) ;
-
- if (count > 1) {
- outsw(ioaddr + HP_DATAPORT, buf, count >> 1);
- }
-
- if ( (count & 1) == 1 ) {
- u_char savebyte[2];
-
- savebyte[1] = 0;
- savebyte[0] = buf[count - 1];
- outw(ioaddr + HP_DATAPORT, *(u_short *)savebyte);
- }
-
- if (count < (ETHERMIN + sizeof( struct ether_header )))
- count = ETHERMIN + sizeof( struct ether_header );
-
-
- return (count) ;
-}
-
-
-/* XXX
- *
- * I take great pains to not try and bcopy past the end of the buffer,
- * does this matter? Are the io request buffers the exact byte size?
- */
-int
-hpp_mem_block_output(ns, count, buf, start_page )
- struct nssoftc *ns;
- int count;
- char *buf;
- int start_page;
-{
- int ioaddr = ns->sc_port - HPP_NIC_OFFSET;
- int option_reg = inw(ioaddr + HPP_OPTION);
- struct hppsoftc *hpp = &hppsoftc[ns->sc_unit];
- char *shmem;
-
- outw(ioaddr + HPP_OUT_ADDR, start_page << 8);
- outw(ioaddr + HPP_OPTION, option_reg & ~(MemDisable + BootROMEnb));
-
- shmem = (char *)phystokv(hpp->mem_start);
- bcopy16(buf, shmem, count & ~1);
-
- if ( (count & 1) == 1 ) {
- u_char savebyte[2];
-
- savebyte[1] = 0;
- savebyte[0] = buf[count - 1];
- bcopy16(savebyte, shmem + (count & ~1), 2);
- }
-
- while (count < ETHERMIN + sizeof(struct ether_header)) {
- *(shmem + count) = 0;
- count++;
- }
-
- outw(ioaddr + HPP_OPTION, option_reg);
-
- return count;
-}
-
-
-int
-hppintr(unit)
- int unit;
-{
- nsintr(&hppnssoftc[unit]);
-
- return(0);
-}
-
-void
-hppstart(unit)
- int unit;
-{
- nsstart(&hppnssoftc[unit]);
-}
-
-int hppoutput();
-
-int
-hppoutput(dev, ior)
- dev_t dev;
- io_req_t ior;
-{
- int unit = minor(dev);
- struct bus_device *ui;
-
- if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0)
- return (ENXIO);
-
- return (net_write(&hppnssoftc[unit].sc_if, hppstart, ior));
-}
-
-
-int
-hppsetinput(dev, receive_port, priority, filter, filter_count)
- dev_t dev;
- mach_port_t receive_port;
- int priority;
- filter_t *filter;
- unsigned filter_count;
-{
- int unit = minor(dev);
- struct bus_device *ui;
-
- if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0)
- return (ENXIO);
-
- return (net_set_filter(&hppnssoftc[unit].sc_if, receive_port,
- priority, filter, filter_count));
-}
-
-
-int
-hppgetstat(dev, flavor, status, count)
- dev_t dev;
- int flavor;
- dev_status_t status;
- unsigned *count;
-{
- int unit = minor(dev);
- struct bus_device *ui;
-
- if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0)
- return (ENXIO);
-
- return (net_getstat(&hppnssoftc[unit].sc_if, flavor, status, count));
-}
-
-
-int
-hppsetstat(dev, flavor, status, count)
- dev_t dev;
- int flavor;
- dev_status_t status;
- unsigned count;
-{
- int unit = minor(dev), oflags, s;
- struct bus_device *ui;
- struct ifnet *ifp;
- struct net_status *ns;
-
- if (unit >= NHPP || (ui = hpp_info[unit]) == 0 || ui->alive == 0)
- return (ENXIO);
-
- ifp = &hppnssoftc[unit].sc_if;
-
- switch (flavor) {
-
- case NET_STATUS:
- if (count < NET_STATUS_COUNT)
- return (D_INVALID_SIZE);
- ns = (struct net_status *)status;
- oflags = ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC);
- ifp->if_flags &= ~(IFF_ALLMULTI|IFF_PROMISC);
- ifp->if_flags |= ns->flags & (IFF_ALLMULTI|IFF_PROMISC);
- if ((ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC)) != oflags) {
- s = splimp();
- nsinit(&hppnssoftc[unit]);
- splx(s);
- }
- break;
-
- default:
- return (D_INVALID_OPERATION);
- }
- return (D_SUCCESS);
-}
-
-/*
- * Watchdog.
- * Check for hung transmissions.
- */
-void
-hppwatch()
-{
- int unit, s;
- struct nssoftc *ns;
-
- timeout(hppwatch, 0, hz);
-
- s = splimp();
- for (unit = 0; unit < NHPP; unit++) {
- if (hpp_info[unit] == 0 || hpp_info[unit]->alive == 0)
- continue;
- ns = &hppnssoftc[unit];
- if (ns->sc_timer && --ns->sc_timer == 0) {
- printf("hpp%d: transmission timeout\n", unit);
- (*ns->sc_reset)(ns);
- nsinit(ns);
- }
- }
- splx(s);
-}
-
-
-#endif /* NHPP > 0 */
-
-