if_ep_eisa.c revision 17223
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 * $Id: 3c5x9.c,v 1.3 1996/06/12 05:02:39 gpalmer Exp $ 23 */ 24 25#include "eisa.h" 26#if NEISA > 0 27 28#include <sys/param.h> 29#include <sys/systm.h> 30#include <sys/devconf.h> 31#include <sys/kernel.h> 32 33#include <machine/clock.h> 34 35#include <net/if.h> 36 37#include <netinet/in.h> 38#include <netinet/if_ether.h> 39 40#include <i386/isa/if_epreg.h> 41#include <i386/isa/isa_device.h> /* For kdc_isa0 */ 42#include <i386/eisa/eisaconf.h> 43 44#define EISA_DEVICE_ID_3COM_3C509_TP 0x506d5090 45#define EISA_DEVICE_ID_3COM_3C509_BNC 0x506d5091 46#define EISA_DEVICE_ID_3COM_3C579_TP 0x506d5092 47#define EISA_DEVICE_ID_3COM_3C579_BNC 0x506d5093 48#define EISA_DEVICE_ID_3COM_3C509_COMBO 0x506d5094 49#define EISA_DEVICE_ID_3COM_3C509_TPO 0x506d5095 50 51#define EP_EISA_SLOT_OFFSET 0x0c80 52#define EP_EISA_IOSIZE 0x000a 53 54#define EISA_IOCONF 0x0008 55#define IRQ_CHANNEL 0xf000 56#define INT_3 0x3000 57#define INT_5 0x5000 58#define INT_7 0x7000 59#define INT_9 0x9000 60#define INT_10 0xa000 61#define INT_11 0xb000 62#define INT_12 0xc000 63#define INT_15 0xf000 64#define EISA_BPROM_MEDIA_CONF 0x0006 65#define TRANS_TYPE 0xc000 66#define TRANS_TP 0x0000 67#define TRANS_AUI 0x4000 68#define TRANS_BNC 0xc000 69 70static int ep_eisa_probe __P((void)); 71static int ep_eisa_attach __P((struct eisa_device *e_dev)); 72 73struct eisa_driver ep_eisa_driver = { 74 "ep", 75 ep_eisa_probe, 76 ep_eisa_attach, 77 /*shutdown*/NULL, 78 &ep_unit 79 }; 80 81DATA_SET (eisadriver_set, ep_eisa_driver); 82 83static struct kern_devconf kdc_eisa_ep = { 84 0, 0, 0, /* filled in by dev_attach */ 85 "ep", 0, { MDDT_EISA, 0, "net" }, 86 eisa_generic_externalize, 0, 0, EISA_EXTERNALLEN, 87 &kdc_eisa0, /* parent */ 88 0, /* parentdata */ 89 DC_UNCONFIGURED, /* always start out here */ 90 NULL, 91 DC_CLS_MISC /* host adapters aren't special */ 92}; 93 94static char *ep_match __P((eisa_id_t type)); 95 96static char* 97ep_match(type) 98 eisa_id_t type; 99{ 100 switch(type) { 101 case EISA_DEVICE_ID_3COM_3C509_TP: 102 return "3Com 3C509-TP Network Adapter"; 103 break; 104 case EISA_DEVICE_ID_3COM_3C509_BNC: 105 return "3Com 3C509-BNC Network Adapter"; 106 break; 107 case EISA_DEVICE_ID_3COM_3C579_TP: 108 return "3Com 3C579-TP EISA Network Adapter"; 109 break; 110 case EISA_DEVICE_ID_3COM_3C579_BNC: 111 return "3Com 3C579-BNC EISA Network Adapter"; 112 break; 113 case EISA_DEVICE_ID_3COM_3C509_COMBO: 114 return "3Com 3C509-Combo Network Adapter"; 115 break; 116 case EISA_DEVICE_ID_3COM_3C509_TPO: 117 return "3Com 3C509-TPO Network Adapter"; 118 break; 119 default: 120 break; 121 } 122 return (NULL); 123} 124 125static int 126ep_eisa_probe(void) 127{ 128 u_long iobase; 129 struct eisa_device *e_dev = NULL; 130 int count; 131 132 count = 0; 133 while ((e_dev = eisa_match_dev(e_dev, ep_match))) { 134 u_short conf; 135 u_long port; 136 int irq; 137 138 port = (e_dev->ioconf.slot * EISA_SLOT_SIZE); 139 iobase = port + EP_EISA_SLOT_OFFSET; 140 141 /* We must be in EISA configuration mode */ 142 if ((inw(iobase + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f) 143 continue; 144 145 eisa_add_iospace(e_dev, iobase, EP_EISA_IOSIZE, RESVADDR_NONE); 146 eisa_add_iospace(e_dev, port, EP_IOSIZE, RESVADDR_NONE); 147 148 conf = inw(iobase + EISA_IOCONF); 149 /* Determine our IRQ */ 150 switch (conf & IRQ_CHANNEL) { 151 case INT_3: 152 irq = 3; 153 break; 154 case INT_5: 155 irq = 5; 156 break; 157 case INT_7: 158 irq = 7; 159 break; 160 case INT_9: 161 irq = 9; 162 break; 163 case INT_10: 164 irq = 10; 165 break; 166 case INT_11: 167 irq = 11; 168 break; 169 case INT_12: 170 irq = 12; 171 break; 172 case INT_15: 173 irq = 15; 174 break; 175 default: 176 /* Disabled */ 177 printf("ep: 3COM Network Adapter at " 178 "slot %d has its IRQ disabled. " 179 "Probe failed.\n", 180 e_dev->ioconf.slot); 181 continue; 182 } 183 eisa_add_intr(e_dev, irq); 184 eisa_registerdev(e_dev, &ep_eisa_driver, &kdc_eisa_ep); 185 if(e_dev->id != EISA_DEVICE_ID_3COM_3C579_TP && 186 e_dev->id != EISA_DEVICE_ID_3COM_3C579_BNC) { 187 /* Our real parent is the isa bus. Say so. */ 188 e_dev->kdc->kdc_parent = &kdc_isa0; 189 } 190 count++; 191 } 192 return count; 193} 194 195static int 196ep_eisa_attach(e_dev) 197 struct eisa_device *e_dev; 198{ 199 struct ep_softc *sc; 200 struct ep_board *epb; 201 int unit = e_dev->unit; 202 int irq = ffs(e_dev->ioconf.irq) - 1; 203 resvaddr_t *ioport; 204 resvaddr_t *eisa_ioport; 205 u_char level_intr; 206 int i; 207 208 /* 209 * The addresses are sorted in increasing order 210 * so we know the port to pass to the core ep 211 * driver comes first. 212 */ 213 ioport = e_dev->ioconf.ioaddrs.lh_first; 214 215 if(!ioport) 216 return -1; 217 218 eisa_ioport = ioport->links.le_next; 219 220 if(!eisa_ioport) 221 return -1; 222 223 eisa_reg_start(e_dev); 224 if(eisa_reg_iospace(e_dev, ioport)) 225 return -1; 226 227 if(eisa_reg_iospace(e_dev, eisa_ioport)) 228 return -1; 229 230 epb = &ep_board[ep_boards]; 231 232 epb->epb_addr = ioport->addr; 233 epb->epb_used = 1; 234 235 if(!(sc = ep_alloc(unit, epb))) 236 return -1; 237 238 ep_boards++; 239 240 sc->stat = 0; 241 sc->kdc = e_dev->kdc; 242 level_intr = FALSE; 243 switch(e_dev->id) { 244 case EISA_DEVICE_ID_3COM_3C509_TP: 245 sc->ep_connectors = UTP|AUI; 246 break; 247 case EISA_DEVICE_ID_3COM_3C509_BNC: 248 sc->ep_connectors = BNC|AUI; 249 break; 250 case EISA_DEVICE_ID_3COM_3C579_TP: 251 sc->ep_connectors = UTP|AUI; 252 sc->stat = F_ACCESS_32_BITS; 253 level_intr = TRUE; 254 break; 255 case EISA_DEVICE_ID_3COM_3C579_BNC: 256 sc->ep_connectors = BNC|AUI; 257 sc->stat = F_ACCESS_32_BITS; 258 level_intr = TRUE; 259 break; 260 case EISA_DEVICE_ID_3COM_3C509_COMBO: 261 sc->ep_connectors = UTP|BNC|AUI; 262 break; 263 case EISA_DEVICE_ID_3COM_3C509_TPO: 264 sc->ep_connectors = UTP; 265 break; 266 default: 267 break; 268 } 269 /* 270 * Set the eisa config selected media type 271 */ 272 sc->ep_connector = inw(eisa_ioport->addr + EISA_BPROM_MEDIA_CONF) 273 >> ACF_CONNECTOR_BITS; 274 275 if(eisa_reg_intr(e_dev, irq, ep_intr, (void *)sc, &net_imask, 276 /*shared ==*/level_intr)) { 277 ep_free(sc); 278 return -1; 279 } 280 eisa_reg_end(e_dev); 281 282 /* Reset and Enable the card */ 283 outb(eisa_ioport->addr + EP_W0_CONFIG_CTRL, W0_P4_CMD_RESET_ADAPTER); 284 DELAY(1000); /* we must wait at least 1 ms */ 285 outb(eisa_ioport->addr + EP_W0_CONFIG_CTRL, W0_P4_CMD_ENABLE_ADAPTER); 286 287 /* Now the registers are availible through the lower ioport */ 288 289 /* 290 * Retrieve our ethernet address 291 */ 292 GO_WINDOW(0); 293 for(i = 0; i < 3; i++) 294 sc->epb->eth_addr[i] = get_e(sc, i); 295 296 /* Even we get irq number from board, we should tell him.. 297 Otherwise we never get a H/W interrupt anymore...*/ 298 if ( irq == 9 ) 299 irq = 2; 300 SET_IRQ(eisa_ioport->addr, irq); 301 302 ep_attach(sc); 303 304 if(eisa_enable_intr(e_dev, irq)) { 305 ep_free(sc); 306 eisa_release_intr(e_dev, irq, ep_intr); 307 return -1; 308 } 309 310 return 0; 311} 312 313#endif /* NEISA > 0 */ 314