diff options
author | Poul-Henning Kamp <phk@FreeBSD.org> | 1995-10-10 09:52:55 +0000 |
---|---|---|
committer | Poul-Henning Kamp <phk@FreeBSD.org> | 1995-10-10 09:52:55 +0000 |
commit | 14a288e58bb1de57e5f3a41fd7fb7abc934ca4e0 (patch) | |
tree | 107cc4de7776258abc2229b986efbb12009500ad /sys/dev/ed/if_ed.c | |
parent | 573d3a2d0d30b2fe3777aa9ff100e39ff8361889 (diff) | |
download | src-14a288e58bb1de57e5f3a41fd7fb7abc934ca4e0.tar.gz src-14a288e58bb1de57e5f3a41fd7fb7abc934ca4e0.zip |
PCCARD support.
Notes
Notes:
svn path=/head/; revision=11409
Diffstat (limited to 'sys/dev/ed/if_ed.c')
-rw-r--r-- | sys/dev/ed/if_ed.c | 314 |
1 files changed, 281 insertions, 33 deletions
diff --git a/sys/dev/ed/if_ed.c b/sys/dev/ed/if_ed.c index 2e1b11d5542d..8d086b9cb64a 100644 --- a/sys/dev/ed/if_ed.c +++ b/sys/dev/ed/if_ed.c @@ -13,7 +13,7 @@ * the SMC Elite Ultra (8216), the 3Com 3c503, the NE1000 and NE2000, * and a variety of similar clones. * - * $Id: if_ed.c,v 1.75 1995/07/28 12:15:16 davidg Exp $ + * $Id: if_ed.c,v 1.76 1995/08/25 19:50:15 bde Exp $ */ #include "ed.h" @@ -71,6 +71,7 @@ struct ed_softc { char *type_str; /* pointer to type string */ u_char vendor; /* interface vendor */ u_char type; /* interface type code */ + u_char gone; /* HW missing, presumed having a good time */ u_short asic_addr; /* ASIC I/O bus address */ u_short nic_addr; /* NIC (DS8390) I/O bus address */ @@ -118,6 +119,7 @@ int ed_probe_generic8390(struct ed_softc *); int ed_probe_WD80x3(struct isa_device *); int ed_probe_3Com(struct isa_device *); int ed_probe_Novell(struct isa_device *); +int ed_probe_pccard(struct isa_device *, u_char *); void ds_getmcaf(); @@ -133,6 +135,112 @@ u_short ed_pio_write_mbufs(); void ed_setrcr(struct ifnet *, struct ed_softc *); +#include "crd.h" +#if NCRD > 0 +#include <sys/select.h> +#include <pccard/card.h> +#include <pccard/slot.h> +/* + * PC-Card (PCMCIA) specific code. + */ +static int card_intr(struct pccard_dev *); /* Interrupt handler */ +void edunload(struct pccard_dev *); /* Disable driver */ +void edsuspend(struct pccard_dev *); /* Suspend driver */ +static int edinit(struct pccard_dev *, int); /* init device */ + +static struct pccard_drv ed_info = + { + "ed", + card_intr, + edunload, + edsuspend, + edinit, + 0, /* Attributes - presently unused */ + &net_imask /* Interrupt mask for device */ + /* This should also include net_imask?? */ + }; +/* + * Called when a power down is wanted. Shuts down the + * device and configures the device as unavailable (but + * still loaded...). A resume is done by calling + * edinit with first=0. This is called when the user suspends + * the system, or the APM code suspends the system. + */ +void +edsuspend(struct pccard_dev *dp) +{ + printf("ed%d: suspending\n", dp->isahd.id_unit); +} +/* + * Initialize the device - called from Slot manager. + * if first is set, then initially check for + * the device's existence before initialising it. + * Once initialised, the device table may be set up. + */ +int +edinit(struct pccard_dev *dp, int first) +{ + int s; + struct ed_softc *sc = &ed_softc[dp->isahd.id_unit]; +/* + * validate unit number. + */ + if (first) { + if (dp->isahd.id_unit >= NED) + return(ENODEV); +/* + * Probe the device. If a value is returned, the + * device was found at the location. + */ + + sc->gone = 0; + if (ed_probe_pccard(&dp->isahd,dp->misc)==0) { + return(ENXIO); + } + if (ed_attach(&dp->isahd)==0) { + return(ENXIO); + } + } +/* + * XXX TODO: + * If it was already inited before, the device structure + * should be already initialised. Here we should + * reset (and possibly restart) the hardware, but + * I am not sure of the best way to do this... + */ + return(0); +} +/* + * edunload - unload the driver and clear the table. + * XXX TODO: + * This is called usually when the card is ejected, but + * can be caused by the modunload of a controller driver. + * The idea is reset the driver's view of the device + * and ensure that any driver entry points such as + * read and write do not hang. + */ +void +edunload(struct pccard_dev *dp) +{ + struct ed_softc *sc = &ed_softc[dp->isahd.id_unit]; + sc->kdc.kdc_state = DC_UNCONFIGURED; + if_down(&sc->arpcom.ac_if); + sc->gone = 1; + printf("ed%d: unload\n", dp->isahd.id_unit); +} + +/* + * card_intr - Shared interrupt called from + * front end of PC-Card handler. + */ +static int +card_intr(struct pccard_dev *dp) +{ + edintr(dp->isahd.id_unit); + return(1); +} +#endif /* NCRD > 0 */ + struct isa_driver eddriver = { ed_probe, ed_attach, @@ -211,6 +319,13 @@ ed_probe(isa_dev) struct isa_device *isa_dev; { int nports; +#if NCRD > 0 +/* + * If PC-Card probe required, then register driver with + * slot manager. + */ + pccard_add_driver(&ed_info); +#endif /* NCRD > 0 */ #ifndef DEV_LKM ed_registerdev(isa_dev, "Ethernet adapter"); @@ -548,19 +663,18 @@ ed_probe_WD80x3(isa_dev) /* * allocate one xmit buffer if < 16k, two buffers otherwise */ - if ((memsize < 16384) || (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)) { - sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE); + if ((memsize < 16384) || + (isa_dev->id_flags & ED_FLAGS_NO_MULTI_BUFFERING)) { sc->txb_cnt = 1; - sc->rec_page_start = ED_TXBUF_SIZE; } else { - sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE * 2); sc->txb_cnt = 2; - sc->rec_page_start = ED_TXBUF_SIZE * 2; } + sc->tx_page_start = ED_WD_PAGE_OFFSET; + sc->rec_page_start = ED_WD_PAGE_OFFSET + ED_TXBUF_SIZE * sc->txb_cnt; + sc->rec_page_stop = ED_WD_PAGE_OFFSET + memsize / ED_PAGE_SIZE; + sc->mem_ring = sc->mem_start + (ED_PAGE_SIZE * sc->rec_page_start); sc->mem_size = memsize; sc->mem_end = sc->mem_start + memsize; - sc->rec_page_stop = memsize / ED_PAGE_SIZE; - sc->tx_page_start = ED_WD_PAGE_OFFSET; /* * Get station address from on-board ROM @@ -1153,6 +1267,115 @@ ed_probe_Novell(isa_dev) return (ED_NOVELL_IO_PORTS); } + +/* + * Probe and vendor-specific initialization routine for PCCARDs + */ +int +ed_probe_pccard(isa_dev, ether) + struct isa_device *isa_dev; + u_char *ether; +{ + struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; + int i; + u_int memsize; + u_char iptr, isa16bit, sum; + + sc->nic_addr = isa_dev->id_iobase; + sc->gone = 0; + sc->is790 = 0; + sc->cr_proto = ED_CR_RD2; + sc->vendor = ED_VENDOR_PCCARD; + sc->type = 0; + sc->type_str = "PCCARD"; + sc->kdc.kdc_description = "PCCARD Ethernet"; + sc->mem_size = isa_dev->id_msize = memsize = 16384; + sc->isa16bit = isa16bit = 1; + + for (i = 0; i < ETHER_ADDR_LEN; ++i) + sc->arpcom.ac_enaddr[i] = ether[i]; + +#if ED_DEBUG + printf("type = %x type_str=%s isa16bit=%d memsize=%d id_msize=%d\n", + sc->type, sc->type_str, isa16bit, memsize, isa_dev->id_msize); +#endif + + i = inb(sc->nic_addr + ED_PC_RESET); + DELAY(100000); + outb(sc->nic_addr + ED_PC_RESET,i); + DELAY(100000); + i = inb(sc->nic_addr + ED_PC_MISC); + if (!i) { + int j; + printf("ed_probe_pccard: possible failure\n"); + for (j=0;j<20 && !i;j++) { + printf("."); + DELAY(100000); + i = inb(sc->nic_addr + ED_PC_MISC); + } + if (!i) { + printf("dead :-(\n"); + return 0; + } + printf("\n"); + } + /* + * Set initial values for width/size. + */ + + /* Make sure that we really have an 8390 based board */ + if (!ed_probe_generic8390(sc)) { + printf("ed_probe_generic8390 failed\n"); + return (0); + } + sc->txb_cnt = 2; + sc->tx_page_start = ED_PC_PAGE_OFFSET; + sc->rec_page_start = sc->tx_page_start + ED_TXBUF_SIZE * sc->txb_cnt; + sc->rec_page_stop = sc->tx_page_start + memsize / ED_PAGE_SIZE; + + sc->mem_shared = 1; + sc->mem_start = (caddr_t) isa_dev->id_maddr; + sc->mem_size = memsize; + sc->mem_end = sc->mem_start + memsize; + + sc->mem_ring = sc->mem_start + + sc->txb_cnt * ED_PAGE_SIZE * ED_TXBUF_SIZE; + + /* + * Now zero memory and verify that it is clear + */ + bzero(sc->mem_start, memsize); + + for (i = 0; i < memsize; ++i) { + if (sc->mem_start[i]) { + printf("ed%d: failed to clear shared memory at %lx - check configuration\n", + isa_dev->id_unit, kvtop(sc->mem_start + i)); + + return (0); + } + sc->mem_start[i] = (i - 5) & 0xff; + } + for (i = 0; i < memsize; ++i) { + if ((sc->mem_start[i] & 0xff) != ((i - 5) & 0xff)) { + printf("ed%d: shared memory failed at %lx (%x != %x) - check configuration\n", + isa_dev->id_unit, kvtop(sc->mem_start + i), + sc->mem_start[i], (i-5) & 0xff); + return (0); + + } + } + + i = inb(sc->nic_addr + ED_PC_MISC); + if (!i) { + printf("ed_probe_pccard: possible failure(2)\n"); + } + + /* clear any pending interupts that we may have caused */ + outb(sc->nic_addr + ED_P0_ISR, 0xff); + + return (ED_PC_IO_PORTS); +} + /* * Install interface into kernel networking data structures */ @@ -1168,33 +1391,37 @@ ed_attach(isa_dev) */ ed_stop(isa_dev->id_unit); - /* - * Initialize ifnet structure - */ - ifp->if_unit = isa_dev->id_unit; - ifp->if_name = "ed"; - ifp->if_init = ed_init; - ifp->if_output = ether_output; - ifp->if_start = ed_start; - ifp->if_ioctl = ed_ioctl; - ifp->if_reset = ed_reset; - ifp->if_watchdog = ed_watchdog; + if (!ifp->if_name) { + /* + * Initialize ifnet structure + */ + ifp->if_unit = isa_dev->id_unit; + ifp->if_name = "ed"; + ifp->if_init = ed_init; + ifp->if_output = ether_output; + ifp->if_start = ed_start; + ifp->if_ioctl = ed_ioctl; + ifp->if_reset = ed_reset; + ifp->if_watchdog = ed_watchdog; + ifp->if_snd.ifq_maxlen = IFQ_MAXLEN; - /* - * Set default state for ALTPHYS flag (used to disable the tranceiver - * for AUI operation), based on compile-time config option. - */ - if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER) - ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | - IFF_MULTICAST | IFF_ALTPHYS); - else - ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | - IFF_MULTICAST); + /* + * Set default state for ALTPHYS flag (used to disable the + * tranceiver for AUI operation), based on compile-time + * config option. + */ + if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER) + ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | + IFF_NOTRAILERS | IFF_MULTICAST | IFF_ALTPHYS); + else + ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | + IFF_NOTRAILERS | IFF_MULTICAST); - /* - * Attach the interface - */ - if_attach(ifp); + /* + * Attach the interface + */ + if_attach(ifp); + } /* device attach does transition from UNCONFIGURED to IDLE state */ sc->kdc.kdc_state = DC_IDLE; @@ -1232,6 +1459,8 @@ ed_reset(unit) { int s; + if (ed_softc[unit].gone) + return; s = splimp(); /* @@ -1253,6 +1482,8 @@ ed_stop(unit) struct ed_softc *sc = &ed_softc[unit]; int n = 5000; + if (sc->gone) + return; /* * Stop everything on the interface, and select page 0 registers. */ @@ -1276,6 +1507,8 @@ ed_watchdog(unit) { struct ed_softc *sc = &ed_softc[unit]; + if (sc->gone) + return; log(LOG_ERR, "ed%d: device timeout\n", unit); ++sc->arpcom.ac_if.if_oerrors; @@ -1293,6 +1526,8 @@ ed_init(unit) struct ifnet *ifp = &sc->arpcom.ac_if; int i, s; + if (sc->gone) + return; /* address not known */ if (ifp->if_addrlist == (struct ifaddr *) 0) @@ -1445,6 +1680,8 @@ ed_xmit(ifp) struct ed_softc *sc = &ed_softc[ifp->if_unit]; unsigned short len; + if (sc->gone) + return; len = sc->txb_len[sc->txb_next_tx]; /* @@ -1501,6 +1738,10 @@ ed_start(ifp) caddr_t buffer; int len; + if (sc->gone) { + printf("ed_start(%p) GONE\n",ifp); + return; + } outloop: /* @@ -1653,6 +1894,9 @@ ed_rint(unit) struct ed_ring packet_hdr; char *packet_ptr; + if (sc->gone) + return; + /* * Set NIC to page 1 registers to get 'current' pointer */ @@ -1770,6 +2014,8 @@ edintr(unit) struct ed_softc *sc = &ed_softc[unit]; u_char isr; + if (sc->gone) + return; /* * Set NIC to page 0 registers */ @@ -1985,6 +2231,8 @@ ed_ioctl(ifp, command, data) struct ifreq *ifr = (struct ifreq *) data; int s, error = 0; + if (sc->gone) + return -1; s = splimp(); switch (command) { |