~kris/9p

9hist

ref: 2daec0b5fc69bba8f7fb6f4736debfe5bc837a28 9hist/pc/etherec2t.c -rw-r--r-- 3.0 KiB
2daec0b5 — David du Colombier Plan 9 from Bell Labs 2000-06-06 26 years ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
 * Linksys Combo PCMCIA EthernetCard (EC2T)
 * and EtherFast 10/100 PC Card (PCMPC100).
 * Supposedly NE2000 clones, see the comments in ether2000.c
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"
#include "../port/netif.h"

#include "etherif.h"
#include "ether8390.h"

enum {
	Data		= 0x10,		/* offset from I/O base of data port */
	Reset		= 0x1F,		/* offset from I/O base of reset port */
};

static char* ec2tpcmcia[] = {
	"EC2T",
	"PCMPC100",
	nil,
};

static int
reset(Ether* ether)
{
	ushort buf[16];
	ulong port;
	Dp8390 *ctlr;
	int i, slot;
	uchar ea[Eaddrlen], sum, x;
	char *type;

	/*
	 * Set up the software configuration.
	 * Use defaults for port, irq, mem and size
	 * if not specified.
	 * The manual says 16KB memory, the box
	 * says 32KB. The manual seems to be correct.
	 */
	if(ether->port == 0)
		ether->port = 0x300;
	if(ether->irq == 0)
		ether->irq = 9;
	if(ether->mem == 0)
		ether->mem = 0x4000;
	if(ether->size == 0)
		ether->size = 16*1024;
	port = ether->port;

	if(ioalloc(ether->port, 0x20, 0, "ec2t") < 0)
		return -1;
	slot = -1;
	type = nil;
	for(i = 0; ec2tpcmcia[i] != nil; i++){
		type = ec2tpcmcia[i];
		if((slot = pcmspecial(type, ether)) >= 0)
			break;
	}
	if(slot < 0){
		iofree(port);
		return -1;
	}

	ether->ctlr = malloc(sizeof(Dp8390));
	ctlr = ether->ctlr;
	ctlr->width = 2;
	ctlr->ram = 0;

	ctlr->port = port;
	ctlr->data = port+Data;

	ctlr->tstart = HOWMANY(ether->mem, Dp8390BufSz);
	ctlr->pstart = ctlr->tstart + HOWMANY(sizeof(Etherpkt), Dp8390BufSz);
	ctlr->pstop = ctlr->tstart + HOWMANY(ether->size, Dp8390BufSz);

	ctlr->dummyrr = 0;

	/*
	 * Reset the board. This is done by doing a read
	 * followed by a write to the Reset address.
	 */
	buf[0] = inb(port+Reset);
	delay(2);
	outb(port+Reset, buf[0]);
	delay(2);

	/*
	 * Init the (possible) chip, then use the (possible)
	 * chip to read the (possible) PROM for ethernet address
	 * and a marker byte.
	 * Could just look at the DP8390 command register after
	 * initialisation has been tried, but that wouldn't be
	 * enough, there are other ethernet boards which could
	 * match.
	 */
	dp8390reset(ether);
	sum = 0;
	if(strcmp(type, "PCMPC100")){
		memset(buf, 0, sizeof(buf));
		dp8390read(ctlr, buf, 0, sizeof(buf));
		if((buf[0x0E] & 0xFF) == 0x57 && (buf[0x0F] & 0xFF) == 0x57)
			sum = 0xFF;
	}
	else{
		/*
		 * The PCMPC100 has the ethernet address in I/O space.
		 * There's a checksum over 8 bytes which sums to 0xFF.
		 */
		for(i = 0; i < 8; i++){
			x = inb(port+0x14+i);
			sum += x;
			buf[i] = (x<<8)|x;
		}
	}
	if(sum != 0xFF){
		pcmspecialclose(slot);
		iofree(ether->port);
		free(ether->ctlr);
		return -1;
	}

	/*
	 * Stupid machine. Shorts were asked for,
	 * shorts were delivered, although the PROM is a byte array.
	 * Set the ethernet address.
	 */
	memset(ea, 0, Eaddrlen);
	if(memcmp(ea, ether->ea, Eaddrlen) == 0){
		for(i = 0; i < sizeof(ether->ea); i++)
			ether->ea[i] = buf[i];
	}
	dp8390setea(ether);

	return 0;
}

void
etherec2tlink(void)
{
	addethercard("EC2T", reset);
}