xref: /minix3/sys/arch/i386/stand/lib/netif/3c509.c (revision 58a2b0008e28f606a7f7f5faaeaba4faac57a1ea)
1*58a2b000SEvgeniy Ivanov /*	$NetBSD: 3c509.c,v 1.10 2008/12/14 18:46:33 christos Exp $	*/
2*58a2b000SEvgeniy Ivanov 
3*58a2b000SEvgeniy Ivanov /* stripped down from freebsd:sys/i386/netboot/3c509.c */
4*58a2b000SEvgeniy Ivanov 
5*58a2b000SEvgeniy Ivanov /**************************************************************************
6*58a2b000SEvgeniy Ivanov NETBOOT -  BOOTP/TFTP Bootstrap Program
7*58a2b000SEvgeniy Ivanov 
8*58a2b000SEvgeniy Ivanov Author: Martin Renters.
9*58a2b000SEvgeniy Ivanov   Date: Mar 22 1995
10*58a2b000SEvgeniy Ivanov 
11*58a2b000SEvgeniy Ivanov  This code is based heavily on David Greenman's if_ed.c driver and
12*58a2b000SEvgeniy Ivanov   Andres Vega Garcia's if_ep.c driver.
13*58a2b000SEvgeniy Ivanov 
14*58a2b000SEvgeniy Ivanov  Copyright (C) 1993-1994, David Greenman, Martin Renters.
15*58a2b000SEvgeniy Ivanov  Copyright (C) 1993-1995, Andres Vega Garcia.
16*58a2b000SEvgeniy Ivanov  Copyright (C) 1995, Serge Babkin.
17*58a2b000SEvgeniy Ivanov   This software may be used, modified, copied, distributed, and sold, in
18*58a2b000SEvgeniy Ivanov   both source and binary form provided that the above copyright and these
19*58a2b000SEvgeniy Ivanov   terms are retained. Under no circumstances are the authors responsible for
20*58a2b000SEvgeniy Ivanov   the proper functioning of this software, nor do the authors assume any
21*58a2b000SEvgeniy Ivanov   responsibility for damages incurred with its use.
22*58a2b000SEvgeniy Ivanov 
23*58a2b000SEvgeniy Ivanov 3c509 support added by Serge Babkin (babkin@hq.icb.chel.su)
24*58a2b000SEvgeniy Ivanov 
25*58a2b000SEvgeniy Ivanov 3c509.c,v 1.2 1995/05/30 07:58:52 rgrimes Exp
26*58a2b000SEvgeniy Ivanov 
27*58a2b000SEvgeniy Ivanov ***************************************************************************/
28*58a2b000SEvgeniy Ivanov 
29*58a2b000SEvgeniy Ivanov #include <sys/types.h>
30*58a2b000SEvgeniy Ivanov #include <machine/pio.h>
31*58a2b000SEvgeniy Ivanov 
32*58a2b000SEvgeniy Ivanov #include <lib/libsa/stand.h>
33*58a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
34*58a2b000SEvgeniy Ivanov 
35*58a2b000SEvgeniy Ivanov #include <libi386.h>
36*58a2b000SEvgeniy Ivanov #ifdef _STANDALONE
37*58a2b000SEvgeniy Ivanov #include <bootinfo.h>
38*58a2b000SEvgeniy Ivanov #endif
39*58a2b000SEvgeniy Ivanov 
40*58a2b000SEvgeniy Ivanov #include "etherdrv.h"
41*58a2b000SEvgeniy Ivanov #include "3c509.h"
42*58a2b000SEvgeniy Ivanov 
43*58a2b000SEvgeniy Ivanov unsigned ether_medium;
44*58a2b000SEvgeniy Ivanov unsigned short eth_base;
45*58a2b000SEvgeniy Ivanov 
46*58a2b000SEvgeniy Ivanov extern void epreset(void);
47*58a2b000SEvgeniy Ivanov extern int ep_get_e(int);
48*58a2b000SEvgeniy Ivanov 
49*58a2b000SEvgeniy Ivanov static int send_ID_sequence(int);
50*58a2b000SEvgeniy Ivanov static int get_eeprom_data(int, int);
51*58a2b000SEvgeniy Ivanov 
52*58a2b000SEvgeniy Ivanov u_char eth_myaddr[6];
53*58a2b000SEvgeniy Ivanov 
54*58a2b000SEvgeniy Ivanov static struct mtabentry {
55*58a2b000SEvgeniy Ivanov     int address_cfg; /* configured connector */
56*58a2b000SEvgeniy Ivanov     int config_bit; /* connector present */
57*58a2b000SEvgeniy Ivanov     char *name;
58*58a2b000SEvgeniy Ivanov } mediatab[] = { /* indexed by media type - etherdrv.h */
59*58a2b000SEvgeniy Ivanov     {3, IS_BNC, "BNC"},
60*58a2b000SEvgeniy Ivanov     {0, IS_UTP, "UTP"},
61*58a2b000SEvgeniy Ivanov     {1, IS_AUI, "AUI"},
62*58a2b000SEvgeniy Ivanov };
63*58a2b000SEvgeniy Ivanov 
64*58a2b000SEvgeniy Ivanov #ifdef _STANDALONE
65*58a2b000SEvgeniy Ivanov static struct btinfo_netif bi_netif;
66*58a2b000SEvgeniy Ivanov #endif
67*58a2b000SEvgeniy Ivanov 
68*58a2b000SEvgeniy Ivanov #ifndef _STANDALONE
69*58a2b000SEvgeniy Ivanov extern int mapio(void);
70*58a2b000SEvgeniy Ivanov #endif
71*58a2b000SEvgeniy Ivanov 
72*58a2b000SEvgeniy Ivanov /**************************************************************************
73*58a2b000SEvgeniy Ivanov ETH_PROBE - Look for an adapter
74*58a2b000SEvgeniy Ivanov ***************************************************************************/
75*58a2b000SEvgeniy Ivanov int
EtherInit(unsigned char * myadr)76*58a2b000SEvgeniy Ivanov EtherInit(unsigned char *myadr)
77*58a2b000SEvgeniy Ivanov {
78*58a2b000SEvgeniy Ivanov 	/* common variables */
79*58a2b000SEvgeniy Ivanov 	int i;
80*58a2b000SEvgeniy Ivanov 	/* variables for 3C509 */
81*58a2b000SEvgeniy Ivanov 	int data, j, id_port = EP_ID_PORT;
82*58a2b000SEvgeniy Ivanov 	u_short k;
83*58a2b000SEvgeniy Ivanov /*	int ep_current_tag = EP_LAST_TAG + 1; */
84*58a2b000SEvgeniy Ivanov 	u_short *p;
85*58a2b000SEvgeniy Ivanov 	struct mtabentry *m;
86*58a2b000SEvgeniy Ivanov 
87*58a2b000SEvgeniy Ivanov #ifndef _STANDALONE
88*58a2b000SEvgeniy Ivanov 	if (mapio()) {
89*58a2b000SEvgeniy Ivanov 		printf("no IO access\n");
90*58a2b000SEvgeniy Ivanov 		return 0;
91*58a2b000SEvgeniy Ivanov 	}
92*58a2b000SEvgeniy Ivanov #endif
93*58a2b000SEvgeniy Ivanov 
94*58a2b000SEvgeniy Ivanov 	/*********************************************************
95*58a2b000SEvgeniy Ivanov 			Search for 3Com 509 card
96*58a2b000SEvgeniy Ivanov 	***********************************************************/
97*58a2b000SEvgeniy Ivanov /*
98*58a2b000SEvgeniy Ivanov 	ep_current_tag--;
99*58a2b000SEvgeniy Ivanov */
100*58a2b000SEvgeniy Ivanov 
101*58a2b000SEvgeniy Ivanov 	/* Look for the ISA boards. Init and leave them actived */
102*58a2b000SEvgeniy Ivanov 	/* search for the first card, ignore all others */
103*58a2b000SEvgeniy Ivanov 	outb(id_port, 0xc0);	/* Global reset */
104*58a2b000SEvgeniy Ivanov 	delay(1000);
105*58a2b000SEvgeniy Ivanov /*
106*58a2b000SEvgeniy Ivanov 	for (i = 0; i < EP_MAX_BOARDS; i++) {
107*58a2b000SEvgeniy Ivanov */
108*58a2b000SEvgeniy Ivanov 		outb(id_port, 0);
109*58a2b000SEvgeniy Ivanov 		outb(id_port, 0);
110*58a2b000SEvgeniy Ivanov 		send_ID_sequence(id_port);
111*58a2b000SEvgeniy Ivanov 
112*58a2b000SEvgeniy Ivanov 		data = get_eeprom_data(id_port, EEPROM_MFG_ID);
113*58a2b000SEvgeniy Ivanov 		if (data != MFG_ID)
114*58a2b000SEvgeniy Ivanov 			return 0;
115*58a2b000SEvgeniy Ivanov 
116*58a2b000SEvgeniy Ivanov 		/* resolve contention using the Ethernet address */
117*58a2b000SEvgeniy Ivanov 		for (j = 0; j < 3; j++)
118*58a2b000SEvgeniy Ivanov 			data = get_eeprom_data(id_port, j);
119*58a2b000SEvgeniy Ivanov 
120*58a2b000SEvgeniy Ivanov 		eth_base =
121*58a2b000SEvgeniy Ivanov 		    (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200;
122*58a2b000SEvgeniy Ivanov 		outb(id_port, EP_LAST_TAG);	/* tags board */
123*58a2b000SEvgeniy Ivanov 		outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG);
124*58a2b000SEvgeniy Ivanov /*
125*58a2b000SEvgeniy Ivanov 		ep_current_tag--;
126*58a2b000SEvgeniy Ivanov 		break;
127*58a2b000SEvgeniy Ivanov 	}
128*58a2b000SEvgeniy Ivanov 
129*58a2b000SEvgeniy Ivanov 	if (i == EP_MAX_BOARDS)
130*58a2b000SEvgeniy Ivanov 		return 0;
131*58a2b000SEvgeniy Ivanov */
132*58a2b000SEvgeniy Ivanov 
133*58a2b000SEvgeniy Ivanov 	/*
134*58a2b000SEvgeniy Ivanov 	* The iobase was found and MFG_ID was 0x6d50. PROD_ID should be
135*58a2b000SEvgeniy Ivanov 	* 0x9[0-f]50
136*58a2b000SEvgeniy Ivanov 	*/
137*58a2b000SEvgeniy Ivanov 	GO_WINDOW(0);
138*58a2b000SEvgeniy Ivanov 	k = (u_int)ep_get_e(EEPROM_PROD_ID);
139*58a2b000SEvgeniy Ivanov 	if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
140*58a2b000SEvgeniy Ivanov 		return 0;
141*58a2b000SEvgeniy Ivanov 
142*58a2b000SEvgeniy Ivanov 	printf("3C5x9 board on ISA at 0x%x - ", eth_base);
143*58a2b000SEvgeniy Ivanov 
144*58a2b000SEvgeniy Ivanov 	/* test for presence of connectors */
145*58a2b000SEvgeniy Ivanov 	i = inw(IS_BASE + EP_W0_CONFIG_CTRL);
146*58a2b000SEvgeniy Ivanov 	j = inw(IS_BASE + EP_W0_ADDRESS_CFG) >> 14;
147*58a2b000SEvgeniy Ivanov 
148*58a2b000SEvgeniy Ivanov 	for (ether_medium = 0, m = mediatab;
149*58a2b000SEvgeniy Ivanov 	    ether_medium < sizeof(mediatab) / sizeof(mediatab[0]);
150*58a2b000SEvgeniy Ivanov 	    ether_medium++, m++) {
151*58a2b000SEvgeniy Ivanov 	    if (j == m->address_cfg) {
152*58a2b000SEvgeniy Ivanov 		if (!(i & m->config_bit)) {
153*58a2b000SEvgeniy Ivanov 		    printf("%s not present\n", m->name);
154*58a2b000SEvgeniy Ivanov 		    return 0;
155*58a2b000SEvgeniy Ivanov 		}
156*58a2b000SEvgeniy Ivanov 		printf("using %s\n", m->name);
157*58a2b000SEvgeniy Ivanov 		goto ok;
158*58a2b000SEvgeniy Ivanov 	    }
159*58a2b000SEvgeniy Ivanov 	}
160*58a2b000SEvgeniy Ivanov 	printf("unknown connector\n");
161*58a2b000SEvgeniy Ivanov 	return 0;
162*58a2b000SEvgeniy Ivanov 
163*58a2b000SEvgeniy Ivanov ok:
164*58a2b000SEvgeniy Ivanov 	/*
165*58a2b000SEvgeniy Ivanov 	* Read the station address from the eeprom
166*58a2b000SEvgeniy Ivanov 	*/
167*58a2b000SEvgeniy Ivanov 	p = (u_short *) eth_myaddr;
168*58a2b000SEvgeniy Ivanov 	for (i = 0; i < 3; i++) {
169*58a2b000SEvgeniy Ivanov 	  u_short help;
170*58a2b000SEvgeniy Ivanov 	  GO_WINDOW(0);
171*58a2b000SEvgeniy Ivanov 	  help = ep_get_e(i);
172*58a2b000SEvgeniy Ivanov 	  p[i] = ((help & 0xff) << 8) | ((help & 0xff00) >> 8);
173*58a2b000SEvgeniy Ivanov 	  GO_WINDOW(2);
174*58a2b000SEvgeniy Ivanov 	  outw(BASE + EP_W2_ADDR_0 + (i * 2), help);
175*58a2b000SEvgeniy Ivanov 	}
176*58a2b000SEvgeniy Ivanov 	for (i = 0; i < 6; i++)
177*58a2b000SEvgeniy Ivanov 		myadr[i] = eth_myaddr[i];
178*58a2b000SEvgeniy Ivanov 
179*58a2b000SEvgeniy Ivanov 	epreset();
180*58a2b000SEvgeniy Ivanov 
181*58a2b000SEvgeniy Ivanov #ifdef _STANDALONE
182*58a2b000SEvgeniy Ivanov 	strncpy(bi_netif.ifname, "ep", sizeof(bi_netif.ifname));
183*58a2b000SEvgeniy Ivanov 	bi_netif.bus = BI_BUS_ISA;
184*58a2b000SEvgeniy Ivanov 	bi_netif.addr.iobase = eth_base;
185*58a2b000SEvgeniy Ivanov 
186*58a2b000SEvgeniy Ivanov 	BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
187*58a2b000SEvgeniy Ivanov #endif
188*58a2b000SEvgeniy Ivanov 
189*58a2b000SEvgeniy Ivanov 	return 1;
190*58a2b000SEvgeniy Ivanov }
191*58a2b000SEvgeniy Ivanov 
192*58a2b000SEvgeniy Ivanov static int
send_ID_sequence(int port)193*58a2b000SEvgeniy Ivanov send_ID_sequence(int port)
194*58a2b000SEvgeniy Ivanov {
195*58a2b000SEvgeniy Ivanov 	int cx, al;
196*58a2b000SEvgeniy Ivanov 
197*58a2b000SEvgeniy Ivanov 	for (al = 0xff, cx = 0; cx < 255; cx++) {
198*58a2b000SEvgeniy Ivanov 		outb(port, al);
199*58a2b000SEvgeniy Ivanov 		al <<= 1;
200*58a2b000SEvgeniy Ivanov 		if (al & 0x100)
201*58a2b000SEvgeniy Ivanov 			al ^= 0xcf;
202*58a2b000SEvgeniy Ivanov 	}
203*58a2b000SEvgeniy Ivanov 	return 1;
204*58a2b000SEvgeniy Ivanov }
205*58a2b000SEvgeniy Ivanov 
206*58a2b000SEvgeniy Ivanov /*
207*58a2b000SEvgeniy Ivanov  * We get eeprom data from the id_port given an offset into the eeprom.
208*58a2b000SEvgeniy Ivanov  * Basically; after the ID_sequence is sent to all of the cards; they enter
209*58a2b000SEvgeniy Ivanov  * the ID_CMD state where they will accept command requests. 0x80-0xbf loads
210*58a2b000SEvgeniy Ivanov  * the eeprom data.  We then read the port 16 times and with every read; the
211*58a2b000SEvgeniy Ivanov  * cards check for contention (ie: if one card writes a 0 bit and another
212*58a2b000SEvgeniy Ivanov  * writes a 1 bit then the host sees a 0. At the end of the cycle; each card
213*58a2b000SEvgeniy Ivanov  * compares the data on the bus; if there is a difference then that card goes
214*58a2b000SEvgeniy Ivanov  * into ID_WAIT state again). In the meantime; one bit of data is returned in
215*58a2b000SEvgeniy Ivanov  * the AX register which is conveniently returned to us by inb().  Hence; we
216*58a2b000SEvgeniy Ivanov  * read 16 times getting one bit of data with each read.
217*58a2b000SEvgeniy Ivanov  */
218*58a2b000SEvgeniy Ivanov static int
get_eeprom_data(int id_port,int offset)219*58a2b000SEvgeniy Ivanov get_eeprom_data(int id_port, int offset)
220*58a2b000SEvgeniy Ivanov {
221*58a2b000SEvgeniy Ivanov 	int i, data = 0;
222*58a2b000SEvgeniy Ivanov 	outb(id_port, 0x80 + offset);
223*58a2b000SEvgeniy Ivanov 	delay(1000);
224*58a2b000SEvgeniy Ivanov 	for (i = 0; i < 16; i++)
225*58a2b000SEvgeniy Ivanov 		data = (data << 1) | (inw(id_port) & 1);
226*58a2b000SEvgeniy Ivanov 	return data;
227*58a2b000SEvgeniy Ivanov }
228