xref: /netbsd/sys/arch/i386/stand/lib/netif/3c509.c (revision 6550d01e)
1 /*	$NetBSD: 3c509.c,v 1.10 2008/12/14 18:46:33 christos 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 unsigned ether_medium;
44 unsigned short eth_base;
45 
46 extern void epreset(void);
47 extern int ep_get_e(int);
48 
49 static int send_ID_sequence(int);
50 static int get_eeprom_data(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(void);
70 #endif
71 
72 /**************************************************************************
73 ETH_PROBE - Look for an adapter
74 ***************************************************************************/
75 int
76 EtherInit(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 	u_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)
130 		return 0;
131 */
132 
133 	/*
134 	* The iobase was found and MFG_ID was 0x6d50. PROD_ID should be
135 	* 0x9[0-f]50
136 	*/
137 	GO_WINDOW(0);
138 	k = (u_int)ep_get_e(EEPROM_PROD_ID);
139 	if ((k & 0xf0ff) != (PROD_ID & 0xf0ff))
140 		return 0;
141 
142 	printf("3C5x9 board on ISA at 0x%x - ", eth_base);
143 
144 	/* test for presence of connectors */
145 	i = inw(IS_BASE + EP_W0_CONFIG_CTRL);
146 	j = inw(IS_BASE + EP_W0_ADDRESS_CFG) >> 14;
147 
148 	for (ether_medium = 0, m = mediatab;
149 	    ether_medium < sizeof(mediatab) / sizeof(mediatab[0]);
150 	    ether_medium++, m++) {
151 	    if (j == m->address_cfg) {
152 		if (!(i & m->config_bit)) {
153 		    printf("%s not present\n", m->name);
154 		    return 0;
155 		}
156 		printf("using %s\n", m->name);
157 		goto ok;
158 	    }
159 	}
160 	printf("unknown connector\n");
161 	return 0;
162 
163 ok:
164 	/*
165 	* Read the station address from the eeprom
166 	*/
167 	p = (u_short *) eth_myaddr;
168 	for (i = 0; i < 3; i++) {
169 	  u_short help;
170 	  GO_WINDOW(0);
171 	  help = ep_get_e(i);
172 	  p[i] = ((help & 0xff) << 8) | ((help & 0xff00) >> 8);
173 	  GO_WINDOW(2);
174 	  outw(BASE + EP_W2_ADDR_0 + (i * 2), help);
175 	}
176 	for (i = 0; i < 6; i++)
177 		myadr[i] = eth_myaddr[i];
178 
179 	epreset();
180 
181 #ifdef _STANDALONE
182 	strncpy(bi_netif.ifname, "ep", sizeof(bi_netif.ifname));
183 	bi_netif.bus = BI_BUS_ISA;
184 	bi_netif.addr.iobase = eth_base;
185 
186 	BI_ADD(&bi_netif, BTINFO_NETIF, sizeof(bi_netif));
187 #endif
188 
189 	return 1;
190 }
191 
192 static int
193 send_ID_sequence(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(int id_port, int offset)
220 {
221 	int i, data = 0;
222 	outb(id_port, 0x80 + offset);
223 	delay(1000);
224 	for (i = 0; i < 16; i++)
225 		data = (data << 1) | (inw(id_port) & 1);
226 	return data;
227 }
228