if_ed_pccard.c revision 69964
1/* 2 * Copyright (c) 1995, David Greenman 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD: head/sys/dev/ed/if_ed_pccard.c 69964 2000-12-13 06:27:23Z imp $ 28 */ 29 30#include <sys/param.h> 31#include <sys/systm.h> 32#include <sys/socket.h> 33#include <sys/kernel.h> 34#include <sys/conf.h> 35#include <sys/uio.h> 36#include <sys/select.h> 37 38#include <sys/module.h> 39#include <sys/bus.h> 40#include <machine/bus.h> 41#include <sys/rman.h> 42#include <machine/resource.h> 43 44#include <net/ethernet.h> 45#include <net/if.h> 46#include <net/if_arp.h> 47#include <net/if_mib.h> 48 49#include <dev/ed/if_edreg.h> 50#include <dev/ed/if_edvar.h> 51#include <dev/pccard/pccardvar.h> 52#include <dev/pccard/pccarddevs.h> 53 54#include "card_if.h" 55 56/* 57 * PC-Card (PCMCIA) specific code. 58 */ 59static int ed_pccard_match(device_t); 60static int ed_pccard_probe(device_t); 61static int ed_pccard_attach(device_t); 62static int ed_pccard_detach(device_t); 63 64static void ax88190_geteprom(struct ed_softc *); 65static int ed_pccard_memwrite(device_t dev, off_t offset, u_char byte); 66static int linksys; 67 68static device_method_t ed_pccard_methods[] = { 69 /* Device interface */ 70 DEVMETHOD(device_probe, pccard_compat_probe), 71 DEVMETHOD(device_attach, pccard_compat_attach), 72 DEVMETHOD(device_detach, ed_pccard_detach), 73 74 /* Card interface */ 75 DEVMETHOD(card_compat_match, ed_pccard_match), 76 DEVMETHOD(card_compat_probe, ed_pccard_probe), 77 DEVMETHOD(card_compat_attach, ed_pccard_attach), 78 { 0, 0 } 79}; 80 81static driver_t ed_pccard_driver = { 82 "ed", 83 ed_pccard_methods, 84 sizeof(struct ed_softc) 85}; 86 87static devclass_t ed_pccard_devclass; 88 89DRIVER_MODULE(if_ed, pccard, ed_pccard_driver, ed_pccard_devclass, 0, 0); 90 91/* 92 * ed_pccard_detach - unload the driver and clear the table. 93 * XXX TODO: 94 * This is usually called when the card is ejected, but 95 * can be caused by a modunload of a controller driver. 96 * The idea is to reset the driver's view of the device 97 * and ensure that any driver entry points such as 98 * read and write do not hang. 99 */ 100static int 101ed_pccard_detach(device_t dev) 102{ 103 struct ed_softc *sc = device_get_softc(dev); 104 struct ifnet *ifp = &sc->arpcom.ac_if; 105 106 if (sc->gone) { 107 device_printf(dev, "already unloaded\n"); 108 return (0); 109 } 110 ed_stop(sc); 111 ifp->if_flags &= ~IFF_RUNNING; 112 ether_ifdetach(ifp, ETHER_BPF_SUPPORTED); 113 sc->gone = 1; 114 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 115 ed_release_resources(dev); 116 return (0); 117} 118 119static const struct pccard_product ed_pccard_products[] = { 120 { PCCARD_STR_KINGSTON_KNE2, PCCARD_VENDOR_KINGSTON, 121 PCCARD_PRODUCT_KINGSTON_KNE2, 0, NULL, NULL }, 122 { NULL } 123}; 124 125static int 126ed_pccard_match(device_t dev) 127{ 128 const struct pccard_product *pp; 129 130 if ((pp = pccard_product_lookup(dev, ed_pccard_products, 131 sizeof(ed_pccard_products[0]), NULL)) != NULL) { 132 device_set_desc(dev, pp->pp_name); 133 return 0; 134 } 135 return EIO; 136} 137 138/* 139 * Probe framework for pccards. Replicates the standard framework, 140 * minus the pccard driver registration and ignores the ether address 141 * supplied (from the CIS), relying on the probe to find it instead. 142 */ 143static int 144ed_pccard_probe(device_t dev) 145{ 146 struct ed_softc *sc = device_get_softc(dev); 147 int flags = device_get_flags(dev); 148 int error; 149 150 if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_AX88190) { 151 /* Special setup for AX88190 */ 152 int iobase; 153 154 /* Allocate the port resource during setup. */ 155 error = ed_alloc_port(dev, 0, ED_NOVELL_IO_PORTS); 156 if (error) 157 return (error); 158 159 sc->asic_offset = ED_NOVELL_ASIC_OFFSET; 160 sc->nic_offset = ED_NOVELL_NIC_OFFSET; 161 162 sc->chip_type = ED_CHIP_TYPE_AX88190; 163 164 /* 165 * Set Attribute Memory IOBASE Register 166 */ 167 iobase = rman_get_start(sc->port_res); 168 ed_pccard_memwrite(dev, ED_AX88190_IOBASE0, 169 iobase & 0xff); 170 ed_pccard_memwrite(dev, ED_AX88190_IOBASE1, 171 (iobase >> 8) & 0xff); 172 ax88190_geteprom(sc); 173 174 ed_release_resources(dev); 175 goto end2; 176 } 177 178 error = ed_probe_Novell(dev, 0, flags); 179 if (error == 0) 180 goto end; 181 ed_release_resources(dev); 182 183 error = ed_probe_WD80x3(dev, 0, flags); 184 if (error == 0) 185 goto end; 186 ed_release_resources(dev); 187 goto end2; 188 189end: 190 linksys = ed_get_Linksys(dev); 191end2: 192 if (error == 0) 193 error = ed_alloc_irq(dev, 0, 0); 194 195 ed_release_resources(dev); 196 return (error); 197} 198 199static int 200ed_pccard_attach(device_t dev) 201{ 202 struct ed_softc *sc = device_get_softc(dev); 203 int flags = device_get_flags(dev); 204 int error; 205 int i; 206 u_char sum; 207 u_char ether_addr[ETHER_ADDR_LEN]; 208 209 if (sc->port_used > 0) 210 ed_alloc_port(dev, sc->port_rid, sc->port_used); 211 if (sc->mem_used) 212 ed_alloc_memory(dev, sc->mem_rid, sc->mem_used); 213 ed_alloc_irq(dev, sc->irq_rid, 0); 214 215 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET, 216 edintr, sc, &sc->irq_handle); 217 if (error) { 218 printf("setup intr failed %d \n", error); 219 ed_release_resources(dev); 220 return (error); 221 } 222 223 if (linksys == 0) { 224 pccard_get_ether(dev, ether_addr); 225 for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) 226 sum |= ether_addr[i]; 227 if (sum) 228 bcopy(ether_addr, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN); 229 } 230 231 error = ed_attach(sc, device_get_unit(dev), flags); 232 return (error); 233} 234 235static void 236ax88190_geteprom(struct ed_softc *sc) 237{ 238 int prom[16],i; 239 u_char tmp; 240 struct { 241 unsigned char offset, value; 242 } pg_seq[] = { 243 {ED_P0_CR, ED_CR_RD2|ED_CR_STP}, /* Select Page0 */ 244 {ED_P0_DCR, 0x01}, 245 {ED_P0_RBCR0, 0x00}, /* Clear the count regs. */ 246 {ED_P0_RBCR1, 0x00}, 247 {ED_P0_IMR, 0x00}, /* Mask completion irq. */ 248 {ED_P0_ISR, 0xff}, 249 {ED_P0_RCR, ED_RCR_MON | ED_RCR_INTT}, /* Set To Monitor */ 250 {ED_P0_TCR, ED_TCR_LB0}, /* loopback mode. */ 251 {ED_P0_RBCR0, 32}, 252 {ED_P0_RBCR1, 0x00}, 253 {ED_P0_RSAR0, 0x00}, 254 {ED_P0_RSAR1, 0x04}, 255 {ED_P0_CR ,ED_CR_RD0 | ED_CR_STA}, 256 }; 257 258 /* Reset Card */ 259 tmp = ed_asic_inb(sc, ED_NOVELL_RESET); 260 ed_asic_outb(sc, ED_NOVELL_RESET, tmp); 261 DELAY(5000); 262 ed_asic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP); 263 DELAY(5000); 264 265 /* Card Settings */ 266 for (i = 0; i < sizeof(pg_seq) / sizeof(pg_seq[0]); i++) 267 ed_nic_outb(sc, pg_seq[i].offset, pg_seq[i].value); 268 269 /* Get Data */ 270 for (i = 0; i < 16; i++) 271 prom[i] = ed_asic_inb(sc, 0); 272/* 273 for (i = 0; i < 16; i++) 274 printf("ax88190 eprom [%02d] %02x %02x\n", 275 i,prom[i] & 0xff,prom[i] >> 8); 276*/ 277 sc->arpcom.ac_enaddr[0] = prom[0] & 0xff; 278 sc->arpcom.ac_enaddr[1] = prom[0] >> 8; 279 sc->arpcom.ac_enaddr[2] = prom[1] & 0xff; 280 sc->arpcom.ac_enaddr[3] = prom[1] >> 8; 281 sc->arpcom.ac_enaddr[4] = prom[2] & 0xff; 282 sc->arpcom.ac_enaddr[5] = prom[2] >> 8; 283} 284 285static int 286ed_pccard_memwrite(device_t dev, off_t offset, u_char byte) 287{ 288 int cis_rid; 289 struct resource *cis; 290 291 cis_rid = 0; 292 cis = bus_alloc_resource(dev, SYS_RES_MEMORY, &cis_rid, 0, ~0, 4 << 10, RF_ACTIVE | RF_SHAREABLE); 293 if (cis == NULL) 294 return (ENXIO); 295 CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, cis_rid, PCCARD_A_MEM_ATTR); 296 297 bus_space_write_1(rman_get_bustag(cis), rman_get_bushandle(cis), offset, byte); 298 299 bus_deactivate_resource(dev, SYS_RES_MEMORY, cis_rid, cis); 300 bus_release_resource(dev, SYS_RES_MEMORY, cis_rid, cis); 301 302 return (0); 303} 304