File: tiara.c

package info (click to toggle)
grub 0.97-84
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 7,240 kB
  • sloc: ansic: 40,100; sh: 5,393; asm: 2,227; makefile: 479; perl: 338
file content (255 lines) | stat: -rw-r--r-- 7,541 bytes parent folder | download | duplicates (13)
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/**************************************************************************
Etherboot -  BOOTP/TFTP Bootstrap Program

TIARA (Fujitsu Etherstar) NIC driver for Etherboot
Copyright (c) Ken Yap 1998

Information gleaned from:

TIARA.ASM Packet driver by Brian Fisher, Queens U, Kingston, Ontario
Fujitsu MB86960 spec sheet (different chip but same family)
***************************************************************************/

/*
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2, or (at
 * your option) any later version.
 */

/* to get some global routines like printf */
#include "etherboot.h"
/* to get the interface to the body of the program */
#include "nic.h"
#include "cards.h"

/*
	EtherStar I/O Register offsets
*/

/* Offsets of registers */
#define	DLCR_XMIT_STAT	0x00
#define	DLCR_XMIT_MASK	0x01
#define	DLCR_RECV_STAT	0x02
#define	DLCR_RECV_MASK	0x03
#define	DLCR_XMIT_MODE	0x04
#define	DLCR_RECV_MODE	0x05
#define	DLCR_ENABLE	0x06
#define	DLCR_TDR_LOW	0x07
#define	DLCR_NODE_ID	0x08
#define	DLCR_TDR_HIGH	0x0F
#define	BMPR_MEM_PORT	0x10
#define	BMPR_PKT_LEN	0x12
#define	BMPR_DMA_ENABLE	0x14
#define	PROM_ID		0x18

#define	TMST		0x80
#define	TMT_OK		0x80
#define	TMT_16COLL	0x02
#define	BUF_EMPTY	0x40

#define	CARD_DISABLE	0x80	/* written to DLCR_ENABLE to disable card */
#define	CARD_ENABLE	0	/* written to DLCR_ENABLE to enable card */

#define	CLEAR_STATUS	0x0F	/* used to clear status info */
/*
	00001111B
	!!!!!!!!--------
	!!!!!!!+--------CLEAR BUS WRITE ERROR
	!!!!!!+---------CLEAR 16 COLLISION
	!!!!!+----------CLEAR COLLISION
	!!!!+-----------CLEAR UNDERFLOW
	!!!+------------NC
	!!+-------------NC
	!+--------------NC
	+---------------NC
*/

#define	NO_TX_IRQS	0	/* written to clear transmit IRQs */

#define	CLR_RCV_STATUS	0xCF	/* clears receive status */

#define	EN_RCV_IRQS	0x80	/* enable receive interrupts */
/*
	10000000B
	!!!!!!!!--------
	!!!!!!!+--------ENABLE OVERFLOW
	!!!!!!+---------ENABLE CRC
	!!!!!+----------ENABLE ALIGN
	!!!!+-----------ENABLE SHORT PKT
	!!!+------------DISABLE REMOTE RESET
	!!+-------------RESERVED
	!+--------------RESERVED
	+---------------ENABLE PKT READY
*/

#define	XMIT_MODE	0x02
/*
	00000010B
	!!!!!!!!---------ENABLE CARRIER DETECT
	!!!!!!!+---------DISABLE LOOPBACK
*/

#define	RECV_MODE	0x02
/*
	00000010B
	!!!!!!!!---------ACCEPT ALL PACKETS
	!!!!!!!+---------ACCEPT PHYSICAL, MULTICAST, AND
	!!!!!!+----------BROADCAST PACKETS
	!!!!!+-----------DISABLE REMOTE RESET
	!!!!+------------DISABLE SHORT PACKETS
	!!!+-------------USE 6 BYTE ADDRESS
	!!+--------------NC
	!+---------------NC
	+----------------DISABLE CRC TEST MODE
*/

/* NIC specific static variables go here */

static unsigned short	ioaddr;

/**************************************************************************
RESET - Reset adapter
***************************************************************************/
static void tiara_reset(struct nic *nic)
{
	int		i;

	outb(CARD_DISABLE, ioaddr + DLCR_ENABLE);
	outb(CLEAR_STATUS, ioaddr + DLCR_XMIT_STAT);
	outb(NO_TX_IRQS, ioaddr + DLCR_XMIT_MASK);
	outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
	outb(XMIT_MODE, ioaddr + DLCR_XMIT_MODE);
	outb(RECV_MODE, ioaddr + DLCR_RECV_MODE);
	/* Vacuum recv buffer */
	while ((inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY) == 0)
		inb(ioaddr + BMPR_MEM_PORT);
	/* Set node address */
	for (i = 0; i < ETH_ALEN; ++i)
		outb(nic->node_addr[i], ioaddr + DLCR_NODE_ID + i);
	outb(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
	outb(CARD_ENABLE, ioaddr + DLCR_ENABLE);
}

/**************************************************************************
POLL - Wait for a frame
***************************************************************************/
static int tiara_poll(struct nic *nic)
{
	unsigned int		len;

	if (inb(ioaddr + DLCR_RECV_MODE) & BUF_EMPTY)
		return (0);
	/* Ack packet */
	outw(CLR_RCV_STATUS, ioaddr + DLCR_RECV_STAT);
	len = inw(ioaddr + BMPR_MEM_PORT);		/* throw away status */
	len = inw(ioaddr + BMPR_MEM_PORT);
	/* Drop overlength packets */
	if (len > ETH_FRAME_LEN)
		return (0);		/* should we drain the buffer? */
	insw(ioaddr + BMPR_MEM_PORT, nic->packet, len / 2);
	/* If it's our own, drop it */
	if (memcmp(nic->packet + ETH_ALEN, nic->node_addr, ETH_ALEN) == 0)
		return (0);
	nic->packetlen = len;
	return (1);
}

/**************************************************************************
TRANSMIT - Transmit a frame
***************************************************************************/
static void tiara_transmit(
struct nic *nic,
const char *d,			/* Destination */
unsigned int t,			/* Type */
unsigned int s,			/* size */
const char *p)			/* Packet */
{
	unsigned int	len;
	unsigned long	time;

	len = s + ETH_HLEN;
	if (len < ETH_ZLEN)
		len = ETH_ZLEN;
	t = htons(t);
	outsw(ioaddr + BMPR_MEM_PORT, d, ETH_ALEN / 2);
	outsw(ioaddr + BMPR_MEM_PORT, nic->node_addr, ETH_ALEN / 2);
	outw(t, ioaddr + BMPR_MEM_PORT);
	outsw(ioaddr + BMPR_MEM_PORT, p, s / 2);
	if (s & 1)					/* last byte */
		outb(p[s-1], ioaddr + BMPR_MEM_PORT);
	while (s++ < ETH_ZLEN - ETH_HLEN)	/* pad */
		outb(0, ioaddr + BMPR_MEM_PORT);
	outw(len | (TMST << 8), ioaddr + BMPR_PKT_LEN);
	/* wait for transmit complete */
	time = currticks() + TICKS_PER_SEC;		/* wait one second */
	while (currticks() < time && (inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0)
		;
	if ((inb(ioaddr) & (TMT_OK|TMT_16COLL)) == 0)
		printf("Tiara timed out on transmit\n");
	/* Do we need to ack the transmit? */
}

/**************************************************************************
DISABLE - Turn off ethernet interface
***************************************************************************/
static void tiara_disable(struct nic *nic)
{
	/* Apparently only a power down can do this properly */
	outb(CARD_DISABLE, ioaddr + DLCR_ENABLE);
}

static int tiara_probe1(struct nic *nic)
{
	/* Hope all the Tiara cards have this vendor prefix */
	static char	vendor_prefix[] = { 0x08, 0x00, 0x1A };
	static char	all_ones[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
	int		i;

	for (i = 0; i < ETH_ALEN; ++i)
		nic->node_addr[i] = inb(ioaddr + PROM_ID + i);
	if (memcmp(nic->node_addr, vendor_prefix, sizeof(vendor_prefix)) != 0)
		return (0);
	if (memcmp(nic->node_addr, all_ones, sizeof(all_ones)) == 0)
		return (0);
	printf("\nTiara ioaddr %#hX, addr %!\n", ioaddr, nic->node_addr);
	return (1);
}

/**************************************************************************
PROBE - Look for an adapter, this routine's visible to the outside
***************************************************************************/
struct nic *tiara_probe(struct nic *nic, unsigned short *probe_addrs)
{
	/* missing entries are addresses usually already used */
	static unsigned short	io_addrs[] = {
		0x100, 0x120, 0x140, 0x160,
		0x180, 0x1A0, 0x1C0, 0x1E0,
		0x200, 0x220, 0x240, /*Par*/
		0x280, 0x2A0, 0x2C0, /*Ser*/
		0x300, 0x320, 0x340, /*Par*/
		0x380, /*Vid,Par*/ 0x3C0, /*Ser*/
		0x0
	};
	unsigned short		*p;

	/* if probe_addrs is 0, then routine can use a hardwired default */
	if (probe_addrs == 0)
		probe_addrs = io_addrs;
	for (p = probe_addrs; (ioaddr = *p) != 0; ++p)
		if (tiara_probe1(nic))
			break;
	/* if board found */
	if (ioaddr != 0)
	{
		tiara_reset(nic);
		/* point to NIC specific routines */
		nic->reset = tiara_reset;
		nic->poll = tiara_poll;
		nic->transmit = tiara_transmit;
		nic->disable = tiara_disable;
		return nic;
	}
	else
		return (0);
}