Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "../port/lib.h"
3
#include "mem.h"
4
#include "dat.h"
5
#include "fns.h"
6
#include "io.h"
7
#include "../port/error.h"
8
#include "../port/netif.h"
9
 
10
#include "etherif.h"
11
#include "ether8390.h"
12
 
13
/*
14
 * Driver written for the 'Notebook Computer Ethernet LAN Adapter',
15
 * a plug-in to the bus-slot on the rear of the Gateway NOMAD 425DXL
16
 * laptop. The manual says NE2000 compatible.
17
 * The interface appears to be pretty well described in the National
18
 * Semiconductor Local Area Network Databook (1992) as one of the
19
 * AT evaluation cards.
20
 *
21
 * The NE2000 is really just a DP8390[12] plus a data port
22
 * and a reset port.
23
 */
24
enum {
25
	Data		= 0x10,		/* offset from I/O base of data port */
26
	Reset		= 0x1F,		/* offset from I/O base of reset port */
27
};
28
 
29
typedef struct Ctlr Ctlr;
30
typedef struct Ctlr {
31
	Pcidev*	pcidev;
32
	Ctlr*	next;
33
	int	active;
34
} Ctlr;
35
 
36
static Ctlr* ctlrhead;
37
static Ctlr* ctlrtail;
38
 
39
static struct {
40
	char*	name;
41
	int	id;
42
} ne2000pci[] = {
43
	{ "Realtek 8029",	(0x8029<<16)|0x10EC, },
44
	{ "Winbond 89C940",	(0x0940<<16)|0x1050, },
45
	{ nil },
46
};
47
 
48
static Ctlr*
49
ne2000match(Ether* edev, int id)
50
{
51
	int port;
52
	Pcidev *p;
53
	Ctlr *ctlr;
54
 
55
	/*
56
	 * Any adapter matches if no edev->port is supplied,
57
	 * otherwise the ports must match.
58
	 */
59
	for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){
60
		if(ctlr->active)
61
			continue;
62
		p = ctlr->pcidev;
63
		if(((p->did<<16)|p->vid) != id)
64
			continue;
65
		port = p->mem[0].bar & ~0x01;
66
		if(edev->port != 0 && edev->port != port)
67
			continue;
68
 
69
		/*
70
		 * It suffices to fill these in,
71
		 * the rest is gleaned from the card.
72
		 */
73
		edev->port = port;
74
		edev->irq = p->intl;
75
 
76
		ctlr->active = 1;
77
 
78
		return ctlr;
79
	}
80
 
81
	return nil;
82
}
83
 
84
static void
85
ne2000pnp(Ether* edev)
86
{
87
	int i, id;
88
	Pcidev *p;
89
	Ctlr *ctlr;
90
 
91
	/*
92
	 * Make a list of all ethernet controllers
93
	 * if not already done.
94
	 */
95
	if(ctlrhead == nil){
96
		p = nil;
97
		while(p = pcimatch(p, 0, 0)){
98
			if(p->ccrb != 0x02 || p->ccru != 0)
99
				continue;
100
			ctlr = malloc(sizeof(Ctlr));
101
			if(ctlr == nil)
102
				error(Enomem);
103
			ctlr->pcidev = p;
104
 
105
			if(ctlrhead != nil)
106
				ctlrtail->next = ctlr;
107
			else
108
				ctlrhead = ctlr;
109
			ctlrtail = ctlr;
110
		}
111
	}
112
 
113
	/*
114
	 * Is it a card with an unrecognised vid+did?
115
	 * Normally a search is made through all the found controllers
116
	 * for one which matches any of the known vid+did pairs.
117
	 * If a vid+did pair is specified a search is made for that
118
	 * specific controller only.
119
	 */
120
	id = 0;
121
	for(i = 0; i < edev->nopt; i++){
122
		if(cistrncmp(edev->opt[i], "id=", 3) == 0)
123
			id = strtol(&edev->opt[i][3], nil, 0);
124
	}
125
 
126
	if(id != 0)
127
		ne2000match(edev, id);
128
	else for(i = 0; ne2000pci[i].name; i++){
129
		if(ne2000match(edev, ne2000pci[i].id) != nil)
130
			break;
131
	}
132
}
133
 
134
static int
135
ne2000reset(Ether* edev)
136
{
137
	ushort buf[16];
138
	ulong port;
139
	Dp8390 *dp8390;
140
	int i;
141
	uchar ea[Eaddrlen];
142
 
143
	if(edev->port == 0)
144
		ne2000pnp(edev);
145
 
146
	/*
147
	 * Set up the software configuration.
148
	 * Use defaults for irq, mem and size
149
	 * if not specified.
150
	 * Must have a port, no more default.
151
	 */
152
	if(edev->port == 0)
153
		return -1;
154
	if(edev->irq == 0)
155
		edev->irq = 2;
156
	if(edev->mem == 0)
157
		edev->mem = 0x4000;
158
	if(edev->size == 0)
159
		edev->size = 16*1024;
160
	port = edev->port;
161
 
162
	if(ioalloc(edev->port, 0x20, 0, "ne2000") < 0)
163
		return -1;
164
 
165
	edev->ctlr = malloc(sizeof(Dp8390));
166
	dp8390 = edev->ctlr;
167
	if(dp8390 == nil)
168
		error(Enomem);
169
	dp8390->width = 2;
170
	dp8390->ram = 0;
171
 
172
	dp8390->port = port;
173
	dp8390->data = port+Data;
174
 
175
	dp8390->tstart = HOWMANY(edev->mem, Dp8390BufSz);
176
	dp8390->pstart = dp8390->tstart + HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
177
	dp8390->pstop = dp8390->tstart + HOWMANY(edev->size, Dp8390BufSz);
178
 
179
	dp8390->dummyrr = 1;
180
	for(i = 0; i < edev->nopt; i++){
181
		if(strcmp(edev->opt[i], "nodummyrr"))
182
			continue;
183
		dp8390->dummyrr = 0;
184
		break;
185
	}
186
 
187
	/*
188
	 * Reset the board. This is done by doing a read
189
	 * followed by a write to the Reset address.
190
	 */
191
	buf[0] = inb(port+Reset);
192
	delay(2);
193
	outb(port+Reset, buf[0]);
194
	delay(2);
195
 
196
	/*
197
	 * Init the (possible) chip, then use the (possible)
198
	 * chip to read the (possible) PROM for ethernet address
199
	 * and a marker byte.
200
	 * Could just look at the DP8390 command register after
201
	 * initialisation has been tried, but that wouldn't be
202
	 * enough, there are other ethernet boards which could
203
	 * match.
204
	 * Parallels has buf[0x0E] == 0x00 whereas real hardware
205
	 * usually has 0x57.
206
	 */
207
	dp8390reset(edev);
208
	memset(buf, 0, sizeof(buf));
209
	dp8390read(dp8390, buf, 0, sizeof(buf));
210
	i = buf[0x0E] & 0xFF;
211
	if((i != 0x00 && i != 0x57) || (buf[0x0F] & 0xFF) != 0x57){
212
		iofree(edev->port);
213
		free(edev->ctlr);
214
		return -1;
215
	}
216
 
217
	/*
218
	 * Stupid machine. Shorts were asked for,
219
	 * shorts were delivered, although the PROM is a byte array.
220
	 * Set the ethernet address.
221
	 */
222
	memset(ea, 0, Eaddrlen);
223
	if(memcmp(ea, edev->ea, Eaddrlen) == 0){
224
		for(i = 0; i < sizeof(edev->ea); i++)
225
			edev->ea[i] = buf[i];
226
	}
227
	dp8390setea(edev);
228
 
229
	return 0;
230
}
231
 
232
void
233
ether2000link(void)
234
{
235
	addethercard("NE2000", ne2000reset);
236
}