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