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