if_ep_eisa.c revision 50477
1/* 2 * Product specific probe and attach routines for: 3 * 3COM 3C579 and 3C509(in eisa config mode) ethernet controllers 4 * 5 * Copyright (c) 1996 Justin T. Gibbs 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice immediately at the beginning of the file, without modification, 13 * this list of conditions, and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Absolutely no warranty of function or purpose is made by the author 18 * Justin T. Gibbs. 19 * 4. Modifications may be freely made to this file if the above conditions 20 * are met. 21 * 22 * $FreeBSD: head/sys/dev/ep/if_ep_eisa.c 50477 1999-08-28 01:08:13Z peter $ 23 */ 24 25#include "eisa.h" 26#if NEISA > 0 27 28#include <sys/param.h> 29#include <sys/systm.h> 30#include <sys/kernel.h> 31#include <sys/socket.h> 32#include <sys/module.h> 33#include <sys/bus.h> 34 35#include <machine/clock.h> 36#include <machine/bus.h> 37#include <machine/resource.h> 38#include <sys/rman.h> 39 40#include <net/if.h> 41 42#include <netinet/in.h> 43#include <netinet/if_ether.h> 44 45#include <i386/isa/if_epreg.h> 46#include <i386/eisa/eisaconf.h> 47 48#define EISA_DEVICE_ID_3COM_3C509_TP 0x506d5090 49#define EISA_DEVICE_ID_3COM_3C509_BNC 0x506d5091 50#define EISA_DEVICE_ID_3COM_3C579_TP 0x506d5092 51#define EISA_DEVICE_ID_3COM_3C579_BNC 0x506d5093 52#define EISA_DEVICE_ID_3COM_3C509_COMBO 0x506d5094 53#define EISA_DEVICE_ID_3COM_3C509_TPO 0x506d5095 54 55#define EP_EISA_SLOT_OFFSET 0x0c80 56#define EP_EISA_IOSIZE 0x000a 57 58#define EISA_IOCONF 0x0008 59#define IRQ_CHANNEL 0xf000 60#define INT_3 0x3000 61#define INT_5 0x5000 62#define INT_7 0x7000 63#define INT_9 0x9000 64#define INT_10 0xa000 65#define INT_11 0xb000 66#define INT_12 0xc000 67#define INT_15 0xf000 68#define EISA_BPROM_MEDIA_CONF 0x0006 69#define TRANS_TYPE 0xc000 70#define TRANS_TP 0x0000 71#define TRANS_AUI 0x4000 72#define TRANS_BNC 0xc000 73 74static const char *ep_match __P((eisa_id_t type)); 75 76static const char* 77ep_match(eisa_id_t type) 78{ 79 switch(type) { 80 case EISA_DEVICE_ID_3COM_3C509_TP: 81 return "3Com 3C509-TP Network Adapter"; 82 break; 83 case EISA_DEVICE_ID_3COM_3C509_BNC: 84 return "3Com 3C509-BNC Network Adapter"; 85 break; 86 case EISA_DEVICE_ID_3COM_3C579_TP: 87 return "3Com 3C579-TP EISA Network Adapter"; 88 break; 89 case EISA_DEVICE_ID_3COM_3C579_BNC: 90 return "3Com 3C579-BNC EISA Network Adapter"; 91 break; 92 case EISA_DEVICE_ID_3COM_3C509_COMBO: 93 return "3Com 3C509-Combo Network Adapter"; 94 break; 95 case EISA_DEVICE_ID_3COM_3C509_TPO: 96 return "3Com 3C509-TPO Network Adapter"; 97 break; 98 default: 99 break; 100 } 101 return (NULL); 102} 103 104static int 105ep_eisa_probe(device_t dev) 106{ 107 const char *desc; 108 u_long iobase; 109 u_short conf; 110 u_long port; 111 int irq; 112 113 desc = ep_match(eisa_get_id(dev)); 114 if (!desc) 115 return (ENXIO); 116 device_set_desc(dev, desc); 117 118 port = (eisa_get_slot(dev) * EISA_SLOT_SIZE); 119 iobase = port + EP_EISA_SLOT_OFFSET; 120 121 /* We must be in EISA configuration mode */ 122 if ((inw(iobase + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f) 123 return ENXIO; 124 125 eisa_add_iospace(dev, iobase, EP_EISA_IOSIZE, RESVADDR_NONE); 126 eisa_add_iospace(dev, port, EP_IOSIZE, RESVADDR_NONE); 127 128 conf = inw(iobase + EISA_IOCONF); 129 /* Determine our IRQ */ 130 switch (conf & IRQ_CHANNEL) { 131 case INT_3: 132 irq = 3; 133 break; 134 case INT_5: 135 irq = 5; 136 break; 137 case INT_7: 138 irq = 7; 139 break; 140 case INT_9: 141 irq = 9; 142 break; 143 case INT_10: 144 irq = 10; 145 break; 146 case INT_11: 147 irq = 11; 148 break; 149 case INT_12: 150 irq = 12; 151 break; 152 case INT_15: 153 irq = 15; 154 break; 155 default: 156 /* Disabled */ 157 printf("ep: 3COM Network Adapter at " 158 "slot %d has its IRQ disabled. " 159 "Probe failed.\n", 160 eisa_get_slot(dev)); 161 return ENXIO; 162 } 163 eisa_add_intr(dev, irq, EISA_TRIGGER_EDGE); 164 165 return 0; 166} 167 168static int 169ep_eisa_attach(device_t dev) 170{ 171 struct ep_softc *sc; 172 struct ep_board *epb; 173 struct resource *io = 0; 174 struct resource *eisa_io = 0; 175 struct resource *irq = 0; 176 int unit = device_get_unit(dev); 177 u_char level_intr; 178 int i, rid, shared; 179 void *ih; 180 181 /* 182 * The addresses are sorted in increasing order 183 * so we know the port to pass to the core ep 184 * driver comes first. 185 */ 186 rid = 0; 187 io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 188 0, ~0, 1, RF_ACTIVE); 189 if (!io) { 190 device_printf(dev, "No I/O space?!\n"); 191 goto bad; 192 } 193 194 rid = 1; 195 eisa_io = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 196 0, ~0, 1, RF_ACTIVE); 197 if (!eisa_io) { 198 device_printf(dev, "No I/O space?!\n"); 199 goto bad; 200 } 201 202 epb = &ep_board[ep_boards]; 203 204 epb->epb_addr = rman_get_start(io); 205 epb->epb_used = 1; 206 207 if(!(sc = ep_alloc(unit, epb))) 208 goto bad; 209 210 ep_boards++; 211 212 sc->stat = 0; 213 level_intr = FALSE; 214 switch(eisa_get_id(dev)) { 215 case EISA_DEVICE_ID_3COM_3C509_TP: 216 sc->ep_connectors = UTP|AUI; 217 break; 218 case EISA_DEVICE_ID_3COM_3C509_BNC: 219 sc->ep_connectors = BNC|AUI; 220 break; 221 case EISA_DEVICE_ID_3COM_3C579_TP: 222 sc->ep_connectors = UTP|AUI; 223 sc->stat = F_ACCESS_32_BITS; 224 level_intr = TRUE; 225 break; 226 case EISA_DEVICE_ID_3COM_3C579_BNC: 227 sc->ep_connectors = BNC|AUI; 228 sc->stat = F_ACCESS_32_BITS; 229 level_intr = TRUE; 230 break; 231 case EISA_DEVICE_ID_3COM_3C509_COMBO: 232 sc->ep_connectors = UTP|BNC|AUI; 233 break; 234 case EISA_DEVICE_ID_3COM_3C509_TPO: 235 sc->ep_connectors = UTP; 236 break; 237 default: 238 break; 239 } 240 /* 241 * Set the eisa config selected media type 242 */ 243 sc->ep_connector = inw(rman_get_start(eisa_io) + EISA_BPROM_MEDIA_CONF) 244 >> ACF_CONNECTOR_BITS; 245 246 shared = level_intr ? RF_SHAREABLE : 0; 247 rid = 0; 248 irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 249 0, ~0, 1, shared | RF_ACTIVE); 250 if (!irq) { 251 device_printf(dev, "No irq?!\n"); 252 goto bad; 253 } 254 255 /* Reset and Enable the card */ 256 outb(rman_get_start(eisa_io) + EP_W0_CONFIG_CTRL, W0_P4_CMD_RESET_ADAPTER); 257 DELAY(1000); /* we must wait at least 1 ms */ 258 outb(rman_get_start(eisa_io) + EP_W0_CONFIG_CTRL, W0_P4_CMD_ENABLE_ADAPTER); 259 260 /* Now the registers are availible through the lower ioport */ 261 262 /* 263 * Retrieve our ethernet address 264 */ 265 GO_WINDOW(0); 266 for(i = 0; i < 3; i++) 267 sc->epb->eth_addr[i] = get_e(sc, i); 268 269 /* Even we get irq number from board, we should tell him.. 270 Otherwise we never get a H/W interrupt anymore...*/ 271 if ( rman_get_start(irq) == 9 ) 272 rman_get_start(irq) = 2; 273 SET_IRQ(rman_get_start(eisa_io), rman_get_start(irq)); 274 275 ep_attach(sc); 276 277 bus_setup_intr(dev, irq, INTR_TYPE_NET, ep_intr, sc, &ih); 278 279 return 0; 280 281 bad: 282 if (io) 283 bus_release_resource(dev, SYS_RES_IOPORT, 0, io); 284 if (eisa_io) 285 bus_release_resource(dev, SYS_RES_IOPORT, 0, eisa_io); 286 if (irq) 287 bus_release_resource(dev, SYS_RES_IRQ, 0, irq); 288 return -1; 289} 290 291static device_method_t ep_eisa_methods[] = { 292 /* Device interface */ 293 DEVMETHOD(device_probe, ep_eisa_probe), 294 DEVMETHOD(device_attach, ep_eisa_attach), 295 296 { 0, 0 } 297}; 298 299static driver_t ep_eisa_driver = { 300 "ep", 301 ep_eisa_methods, 302 1, /* unused */ 303}; 304 305static devclass_t ep_devclass; 306 307DRIVER_MODULE(ep, eisa, ep_eisa_driver, ep_devclass, 0, 0); 308 309#endif /* NEISA > 0 */ 310