Home | History | Annotate | Download | only in netboot
      1 /**************************************************************************
      2 ETHERBOOT -  BOOTP/TFTP Bootstrap Program
      3 
      4 Author: Martin Renters.
      5   Date: Mar 22 1995
      6 
      7  This code is based heavily on David Greenman's if_ed.c driver and
      8   Andres Vega Garcia's if_ep.c driver.
      9 
     10  Copyright (C) 1993-1994, David Greenman, Martin Renters.
     11  Copyright (C) 1993-1995, Andres Vega Garcia.
     12  Copyright (C) 1995, Serge Babkin.
     13   This software may be used, modified, copied, distributed, and sold, in
     14   both source and binary form provided that the above copyright and these
     15   terms are retained. Under no circumstances are the authors responsible for
     16   the proper functioning of this software, nor do the authors assume any
     17   responsibility for damages incurred with its use.
     18 
     19 3c509 support added by Serge Babkin (babkin (at) hq.icb.chel.su)
     20 
     21 $Id: 3c509.c,v 1.4 2002/01/02 21:56:40 okuji Exp $
     22 
     23 ***************************************************************************/
     24 
     25 /* #define EDEBUG */
     26 
     27 #include "etherboot.h"
     28 #include "nic.h"
     29 #include "cards.h"
     30 #include "timer.h"
     31 #include "3c509.h"
     32 
     33 #define	udelay(n)	waiton_timer2(((n)*TICKS_PER_MS)/1000)
     34 
     35 static unsigned short	eth_nic_base;
     36 static enum { none, bnc, utp } connector = none;	/* for 3C509 */
     37 
     38 #ifdef	INCLUDE_3C529
     39 /*
     40  * This table and several other pieces of the MCA support
     41  * code were shamelessly borrowed from the Linux kernel source.
     42  *
     43  * MCA support added by Adam Fritzler (mid (at) auk.cx)
     44  *
     45  */
     46 struct el3_mca_adapters_struct {
     47         const char *name;
     48         int id;
     49 };
     50 static struct el3_mca_adapters_struct el3_mca_adapters[] = {
     51         { "3Com 3c529 EtherLink III (10base2)", 0x627c },
     52         { "3Com 3c529 EtherLink III (10baseT)", 0x627d },
     53         { "3Com 3c529 EtherLink III (test mode)", 0x62db },
     54         { "3Com 3c529 EtherLink III (TP or coax)", 0x62f6 },
     55         { "3Com 3c529 EtherLink III (TP)", 0x62f7 },
     56         { NULL, 0 },
     57 };
     58 #endif
     59 
     60 /**************************************************************************
     61 ETH_RESET - Reset adapter
     62 ***************************************************************************/
     63 static void t509_reset(struct nic *nic)
     64 {
     65 	int i;
     66 
     67 	/***********************************************************
     68 			Reset 3Com 509 card
     69 	*************************************************************/
     70 
     71 	/* stop card */
     72 	outw(RX_DISABLE, BASE + EP_COMMAND);
     73 	outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND);
     74 	while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
     75 		;
     76 	outw(TX_DISABLE, BASE + EP_COMMAND);
     77 	outw(STOP_TRANSCEIVER, BASE + EP_COMMAND);
     78 	udelay(1000);
     79 	outw(RX_RESET, BASE + EP_COMMAND);
     80 	outw(TX_RESET, BASE + EP_COMMAND);
     81 	outw(C_INTR_LATCH, BASE + EP_COMMAND);
     82 	outw(SET_RD_0_MASK, BASE + EP_COMMAND);
     83 	outw(SET_INTR_MASK, BASE + EP_COMMAND);
     84 	outw(SET_RX_FILTER, BASE + EP_COMMAND);
     85 
     86 	/*
     87 	* initialize card
     88 	*/
     89 	while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
     90 		;
     91 
     92 	GO_WINDOW(0);
     93 
     94 	/* Disable the card */
     95 	outw(0, BASE + EP_W0_CONFIG_CTRL);
     96 
     97 	/* Configure IRQ to none */
     98 	outw(SET_IRQ(0), BASE + EP_W0_RESOURCE_CFG);
     99 
    100 	/* Enable the card */
    101 	outw(ENABLE_DRQ_IRQ, BASE + EP_W0_CONFIG_CTRL);
    102 
    103 	GO_WINDOW(2);
    104 
    105 	/* Reload the ether_addr. */
    106 	for (i = 0; i < ETH_ALEN; i++)
    107 		outb(nic->node_addr[i], BASE + EP_W2_ADDR_0 + i);
    108 
    109 	outw(RX_RESET, BASE + EP_COMMAND);
    110 	outw(TX_RESET, BASE + EP_COMMAND);
    111 
    112 	/* Window 1 is operating window */
    113 	GO_WINDOW(1);
    114 	for (i = 0; i < 31; i++)
    115 		inb(BASE + EP_W1_TX_STATUS);
    116 
    117 	/* get rid of stray intr's */
    118 	outw(ACK_INTR | 0xff, BASE + EP_COMMAND);
    119 
    120 	outw(SET_RD_0_MASK | S_5_INTS, BASE + EP_COMMAND);
    121 
    122 	outw(SET_INTR_MASK, BASE + EP_COMMAND);
    123 
    124 	outw(SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST, BASE + EP_COMMAND);
    125 
    126 	/* configure BNC */
    127 	if (connector == bnc) {
    128 		outw(START_TRANSCEIVER, BASE + EP_COMMAND);
    129 		udelay(1000);
    130 	}
    131 	/* configure UTP */
    132 	else if (connector == utp) {
    133 		GO_WINDOW(4);
    134 		outw(ENABLE_UTP, BASE + EP_W4_MEDIA_TYPE);
    135 		sleep(2);	/* Give time for media to negotiate */
    136 		GO_WINDOW(1);
    137 	}
    138 
    139 	/* start transceiver and receiver */
    140 	outw(RX_ENABLE, BASE + EP_COMMAND);
    141 	outw(TX_ENABLE, BASE + EP_COMMAND);
    142 
    143 	/* set early threshold for minimal packet length */
    144 	outw(SET_RX_EARLY_THRESH | ETH_ZLEN, BASE + EP_COMMAND);
    145 	outw(SET_TX_START_THRESH | 16, BASE + EP_COMMAND);
    146 }
    147 
    148 /**************************************************************************
    149 ETH_TRANSMIT - Transmit a frame
    150 ***************************************************************************/
    151 static char padmap[] = {
    152 	0, 3, 2, 1};
    153 
    154 static void t509_transmit(
    155 struct nic *nic,
    156 const char *d,			/* Destination */
    157 unsigned int t,			/* Type */
    158 unsigned int s,			/* size */
    159 const char *p)			/* Packet */
    160 {
    161 	register unsigned int len;
    162 	int pad;
    163 	int status;
    164 
    165 #ifdef	EDEBUG
    166 	printf("{l=%d,t=%hX}",s+ETH_HLEN,t);
    167 #endif
    168 
    169 	/* swap bytes of type */
    170 	t= htons(t);
    171 
    172 	len=s+ETH_HLEN; /* actual length of packet */
    173 	pad = padmap[len & 3];
    174 
    175 	/*
    176 	* The 3c509 automatically pads short packets to minimum ethernet length,
    177 	* but we drop packets that are too large. Perhaps we should truncate
    178 	* them instead?
    179 	*/
    180 	if (len + pad > ETH_FRAME_LEN) {
    181 		return;
    182 	}
    183 
    184 	/* drop acknowledgements */
    185 	while ((status=inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE ) {
    186 		if (status & (TXS_UNDERRUN|TXS_MAX_COLLISION|TXS_STATUS_OVERFLOW)) {
    187 			outw(TX_RESET, BASE + EP_COMMAND);
    188 			outw(TX_ENABLE, BASE + EP_COMMAND);
    189 		}
    190 		outb(0x0, BASE + EP_W1_TX_STATUS);
    191 	}
    192 
    193 	while (inw(BASE + EP_W1_FREE_TX) < (unsigned short)len + pad + 4)
    194 		; /* no room in FIFO */
    195 
    196 	outw(len, BASE + EP_W1_TX_PIO_WR_1);
    197 	outw(0x0, BASE + EP_W1_TX_PIO_WR_1);	/* Second dword meaningless */
    198 
    199 	/* write packet */
    200 	outsw(BASE + EP_W1_TX_PIO_WR_1, d, ETH_ALEN/2);
    201 	outsw(BASE + EP_W1_TX_PIO_WR_1, nic->node_addr, ETH_ALEN/2);
    202 	outw(t, BASE + EP_W1_TX_PIO_WR_1);
    203 	outsw(BASE + EP_W1_TX_PIO_WR_1, p, s / 2);
    204 	if (s & 1)
    205 		outb(*(p+s - 1), BASE + EP_W1_TX_PIO_WR_1);
    206 
    207 	while (pad--)
    208 		outb(0, BASE + EP_W1_TX_PIO_WR_1);	/* Padding */
    209 
    210 	/* wait for Tx complete */
    211 	while((inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) != 0)
    212 		;
    213 }
    214 
    215 /**************************************************************************
    216 ETH_POLL - Wait for a frame
    217 ***************************************************************************/
    218 static int t509_poll(struct nic *nic)
    219 {
    220 	/* common variables */
    221 	unsigned short type = 0;	/* used by EDEBUG */
    222 	/* variables for 3C509 */
    223 	short status, cst;
    224 	register short rx_fifo;
    225 
    226 	cst=inw(BASE + EP_STATUS);
    227 
    228 #ifdef	EDEBUG
    229 	if(cst & 0x1FFF)
    230 		printf("-%hX-",cst);
    231 #endif
    232 
    233 	if( (cst & S_RX_COMPLETE)==0 ) {
    234 		/* acknowledge  everything */
    235 		outw(ACK_INTR| (cst & S_5_INTS), BASE + EP_COMMAND);
    236 		outw(C_INTR_LATCH, BASE + EP_COMMAND);
    237 
    238 		return 0;
    239 	}
    240 
    241 	status = inw(BASE + EP_W1_RX_STATUS);
    242 #ifdef	EDEBUG
    243 	printf("*%hX*",status);
    244 #endif
    245 
    246 	if (status & ERR_RX) {
    247 		outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND);
    248 		return 0;
    249 	}
    250 
    251 	rx_fifo = status & RX_BYTES_MASK;
    252 	if (rx_fifo==0)
    253 		return 0;
    254 
    255 		/* read packet */
    256 #ifdef	EDEBUG
    257 	printf("[l=%d",rx_fifo);
    258 #endif
    259 	insw(BASE + EP_W1_RX_PIO_RD_1, nic->packet, rx_fifo / 2);
    260 	if(rx_fifo & 1)
    261 		nic->packet[rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1);
    262 	nic->packetlen=rx_fifo;
    263 
    264 	while(1) {
    265 		status = inw(BASE + EP_W1_RX_STATUS);
    266 #ifdef	EDEBUG
    267 		printf("*%hX*",status);
    268 #endif
    269 		rx_fifo = status & RX_BYTES_MASK;
    270 		if(rx_fifo>0) {
    271 			insw(BASE + EP_W1_RX_PIO_RD_1, nic->packet+nic->packetlen, rx_fifo / 2);
    272 			if(rx_fifo & 1)
    273 				nic->packet[nic->packetlen+rx_fifo-1]=inb(BASE + EP_W1_RX_PIO_RD_1);
    274 			nic->packetlen+=rx_fifo;
    275 #ifdef	EDEBUG
    276 			printf("+%d",rx_fifo);
    277 #endif
    278 		}
    279 		if(( status & RX_INCOMPLETE )==0) {
    280 #ifdef	EDEBUG
    281 			printf("=%d",nic->packetlen);
    282 #endif
    283 			break;
    284 		}
    285 		udelay(1000);	/* if incomplete wait 1 ms */
    286 	}
    287 	/* acknowledge reception of packet */
    288 	outw(RX_DISCARD_TOP_PACK, BASE + EP_COMMAND);
    289 	while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS)
    290 		;
    291 #ifdef	EDEBUG
    292 	type = (nic->packet[12]<<8) | nic->packet[13];
    293 	if(nic->packet[0]+nic->packet[1]+nic->packet[2]+nic->packet[3]+nic->packet[4]+
    294 	    nic->packet[5] == 0xFF*ETH_ALEN)
    295 		printf(",t=%hX,b]",type);
    296 	else
    297 		printf(",t=%hX]",type);
    298 #endif
    299 	return (1);
    300 }
    301 
    302 /*************************************************************************
    303 	3Com 509 - specific routines
    304 **************************************************************************/
    305 
    306 static int
    307 eeprom_rdy(void)
    308 {
    309 	int i;
    310 
    311 	for (i = 0; is_eeprom_busy(IS_BASE) && i < MAX_EEPROMBUSY; i++);
    312 	if (i >= MAX_EEPROMBUSY) {
    313 		/* printf("3c509: eeprom failed to come ready.\n"); */
    314 		printf("3c509: eeprom busy.\n"); /* memory in EPROM is tight */
    315 		return (0);
    316 	}
    317 	return (1);
    318 }
    319 
    320 /*
    321  * get_e: gets a 16 bits word from the EEPROM. we must have set the window
    322  * before
    323  */
    324 static int
    325 get_e(int offset)
    326 {
    327 	if (!eeprom_rdy())
    328 		return (0xffff);
    329 	outw(EEPROM_CMD_RD | offset, IS_BASE + EP_W0_EEPROM_COMMAND);
    330 	if (!eeprom_rdy())
    331 		return (0xffff);
    332 	return (inw(IS_BASE + EP_W0_EEPROM_DATA));
    333 }
    334 
    335 static int
    336 send_ID_sequence(int port)
    337 {
    338 	int cx, al;
    339 
    340 	for (al = 0xff, cx = 0; cx < 255; cx++) {
    341 		outb(al, port);
    342 		al <<= 1;
    343 		if (al & 0x100)
    344 			al ^= 0xcf;
    345 	}
    346 	return (1);
    347 }
    348 
    349 
    350 /*
    351  * We get eeprom data from the id_port given an offset into the eeprom.
    352  * Basically; after the ID_sequence is sent to all of the cards; they enter
    353  * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
    354  * the eeprom data.  We then read the port 16 times and with every read; the
    355  * cards check for contention (ie: if one card writes a 0 bit and another
    356  * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
    357  * compares the data on the bus; if there is a difference then that card goes
    358  * into ID_WAIT state again). In the meantime; one bit of data is returned in
    359  * the AX register which is conveniently returned to us by inb().  Hence; we
    360  * read 16 times getting one bit of data with each read.
    361  */
    362 static int
    363 get_eeprom_data(int id_port, int offset)
    364 {
    365 	int i, data = 0;
    366 	outb(0x80 + offset, id_port);
    367 	/* Do we really need this wait? Won't be noticeable anyway */
    368 	udelay(10000);
    369 	for (i = 0; i < 16; i++)
    370 		data = (data << 1) | (inw(id_port) & 1);
    371 	return (data);
    372 }
    373 
    374 static void t509_disable(struct nic *nic)
    375 {
    376 	outb(0xc0, EP_ID_PORT);
    377 }
    378 
    379 /**************************************************************************
    380 ETH_PROBE - Look for an adapter
    381 ***************************************************************************/
    382 #ifdef	INCLUDE_3C529
    383 struct nic *t529_probe(struct nic *nic, unsigned short *probe_addrs)
    384 #else
    385 struct nic *t509_probe(struct nic *nic, unsigned short *probe_addrs)
    386 #endif
    387 {
    388 	/* common variables */
    389 	int i;
    390 	int failcount;
    391 
    392 #ifdef	INCLUDE_3C529
    393 	struct el3_mca_adapters_struct *mcafound = NULL;
    394 	int mca_pos4 = 0, mca_pos5 = 0, mca_irq = 0;
    395 #endif
    396 
    397 	t509_disable(nic);		/* in case board was active */
    398 					/* note that nic is not used */
    399 	for (failcount = 0; failcount < 4000; failcount++) {
    400 		int data, j, io_base, id_port;
    401 		unsigned short k;
    402 		int ep_current_tag;
    403 		short *p;
    404 #ifdef	INCLUDE_3C529
    405 		int curboard;
    406 #endif
    407 
    408 		id_port = EP_ID_PORT;
    409 		ep_current_tag = EP_LAST_TAG + 1;
    410 
    411 	/*********************************************************
    412 			Search for 3Com 509 card
    413 	***********************************************************/
    414 #ifdef	INCLUDE_3C529
    415 		/*
    416 		 * XXX: We should really check to make sure we have an MCA
    417 		 * bus controller before going ahead with this...
    418 		 *
    419 		 * For now, we avoid any hassle by making it a compile
    420 		 * time option.
    421 		 *
    422 		 */
    423 		printf("\nWarning: Assuming presence of MCA bus\n");
    424 
    425                 /* Make sure motherboard setup is off */
    426                 outb_p(0xff, MCA_MOTHERBOARD_SETUP_REG);
    427 
    428 		/* Cycle through slots */
    429 		for(curboard=0; curboard<MCA_MAX_SLOT_NR; curboard++) {
    430 			int boardid;
    431 			int curcard;
    432 
    433 			outb_p(0x8|(curboard&0xf), MCA_ADAPTER_SETUP_REG);
    434 
    435 			boardid = inb_p(MCA_POS_REG(0));
    436 			boardid += inb_p(MCA_POS_REG(1)) << 8;
    437 
    438 			curcard = 0;
    439 			while (el3_mca_adapters[curcard].name) {
    440 				if (el3_mca_adapters[curcard].id == boardid) {
    441 					mcafound = &el3_mca_adapters[curcard];
    442 
    443 					mca_pos4 = inb_p(MCA_POS_REG(4));
    444 					mca_pos5 = inb_p(MCA_POS_REG(5));
    445 
    446 					goto donewithdetect;
    447 				}
    448 				else
    449 					curcard++;
    450 			}
    451 
    452 		}
    453 	donewithdetect:
    454 		/* Kill all setup modes */
    455 		outb_p(0, MCA_ADAPTER_SETUP_REG);
    456 
    457 		if (mcafound) {
    458 			eth_nic_base = ((short)((mca_pos4&0xfc)|0x02)) << 8;
    459 			mca_irq = mca_pos5 & 0x0f;
    460 			ep_current_tag--;
    461 		}
    462 		else
    463 			printf("MCA Card not found\n");
    464 #endif
    465 	/* Look for the EISA boards, leave them activated */
    466 	/* search for the first card, ignore all others */
    467 	for(j = 1; j < 16; j++) {
    468 		io_base = (j * EP_EISA_START) | EP_EISA_W0;
    469 		if (inw(io_base + EP_W0_MFG_ID) != MFG_ID)
    470 			continue;
    471 
    472 		/* we must have found 0x1f if the board is EISA configurated */
    473 		if ((inw(io_base + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f)
    474 			continue;
    475 
    476 		/* Reset and Enable the card */
    477 		outb(W0_P4_CMD_RESET_ADAPTER, io_base + EP_W0_CONFIG_CTRL);
    478 		udelay(1000); /* Must wait 800 s, be conservative */
    479 		outb(W0_P4_CMD_ENABLE_ADAPTER, io_base + EP_W0_CONFIG_CTRL);
    480 
    481 		/*
    482 		 * Once activated, all the registers are mapped in the range
    483 		 * x000 - x00F, where x is the slot number.
    484 		 */
    485 		eth_nic_base = j * EP_EISA_START;
    486 		break;
    487 	}
    488 	ep_current_tag--;
    489 
    490 	/* Look for the ISA boards. Init and leave them actived */
    491 	/* search for the first card, ignore all others */
    492 	outb(0xc0, id_port);	/* Global reset */
    493 	udelay(1000);		/* wait 1 ms */
    494 	for (i = 0; i < EP_MAX_BOARDS; i++) {
    495 		outb(0, id_port);
    496 		outb(0, id_port);
    497 		send_ID_sequence(id_port);
    498 
    499 		data = get_eeprom_data(id_port, EEPROM_MFG_ID);
    500 		if (data != MFG_ID)
    501 			break;
    502 
    503 		/* resolve contention using the Ethernet address */
    504 		for (j = 0; j < 3; j++)
    505 			data = get_eeprom_data(id_port, j);
    506 
    507 		eth_nic_base =
    508 		    (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200;
    509 		outb(ep_current_tag, id_port);	/* tags board */
    510 		outb(ACTIVATE_ADAPTER_TO_CONFIG, id_port);
    511 		ep_current_tag--;
    512 		break;
    513 	}
    514 
    515 	if (i >= EP_MAX_BOARDS)
    516 		goto no3c509;
    517 
    518 	/*
    519 	* The iobase was found and MFG_ID was 0x6d50. PROD_ID should be
    520 	* 0x9[0-f]50
    521 	*/
    522 	GO_WINDOW(0);
    523 	k = get_e(EEPROM_PROD_ID);
    524 #ifdef	INCLUDE_3C529
    525 	/*
    526 	 * On MCA, the PROD_ID matches the MCA card ID (POS0+POS1)
    527 	 */
    528 	if (mcafound) {
    529 		if (mcafound->id != k) {
    530 			printf("MCA: PROD_ID in EEPROM does not match MCA card ID! (%hX != %hX)\n", k, mcafound->id);
    531 			goto no3c509;
    532 		}
    533 	} else { /* for ISA/EISA */
    534 		if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
    535 			goto no3c509;
    536 	}
    537 #else
    538 	if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
    539 		goto no3c509;
    540 #endif
    541 
    542 #ifdef	INCLUDE_3C529
    543 	if (mcafound) {
    544 		printf("%s board found on MCA at %#hx IRQ %d -",
    545 		       mcafound->name, eth_nic_base, mca_irq);
    546 	} else {
    547 #endif
    548 		if(eth_nic_base >= EP_EISA_START)
    549 			printf("3C5x9 board on EISA at %#hx - ",eth_nic_base);
    550 		else
    551 			printf("3C5x9 board on ISA at %#hx - ",eth_nic_base);
    552 #ifdef	INCLUDE_3C529
    553 	}
    554 #endif
    555 
    556 	/* test for presence of connectors */
    557 	i = inw(IS_BASE + EP_W0_CONFIG_CTRL);
    558 	j = (inw(IS_BASE + EP_W0_ADDRESS_CFG) >> 14) & 0x3;
    559 
    560 	switch(j) {
    561 		case 0:
    562 			if (i & IS_UTP) {
    563 				printf("10baseT\n");
    564 				connector = utp;
    565 				}
    566 			else {
    567 				printf("10baseT not present\n");
    568 				goto no3c509;
    569 				}
    570 			break;
    571 		case 1:
    572 			if (i & IS_AUI)
    573 				printf("10base5\n");
    574 			else {
    575 				printf("10base5 not present\n");
    576 				goto no3c509;
    577 				}
    578 			break;
    579 		case 3:
    580 			if (i & IS_BNC) {
    581 				printf("10base2\n");
    582 				connector = bnc;
    583 				}
    584 			else {
    585 				printf("10base2 not present\n");
    586 				goto no3c509;
    587 				}
    588 			break;
    589 		default:
    590 			printf("unknown connector\n");
    591 			goto no3c509;
    592 		}
    593 	/*
    594 	* Read the station address from the eeprom
    595 	*/
    596 	p = (unsigned short *) nic->node_addr;
    597 	for (i = 0; i < ETH_ALEN / 2; i++) {
    598 		GO_WINDOW(0);
    599 		p[i] = htons(get_e(i));
    600 		GO_WINDOW(2);
    601 		outw(ntohs(p[i]), BASE + EP_W2_ADDR_0 + (i * 2));
    602 	}
    603 	printf("Ethernet address: %!\n", nic->node_addr);
    604 	t509_reset(nic);
    605 	nic->reset = t509_reset;
    606 	nic->poll = t509_poll;
    607 	nic->transmit = t509_transmit;
    608 	nic->disable = t509_disable;
    609 	return nic;
    610 no3c509:
    611 	printf("(probe fail)");
    612 	}
    613 	return 0;
    614 }
    615 
    616 /*
    617  * Local variables:
    618  *  c-basic-offset: 8
    619  * End:
    620  */
    621