xref: /minix3/minix/drivers/net/dp8390/dp8390.c (revision f7df02e7476731c31f12548e38bcadbaf0233f6a)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * dp8390.c
3433d6423SLionel Sambuc  *
4433d6423SLionel Sambuc  * This file contains a ethernet device driver for NS dp8390 based ethernet
5433d6423SLionel Sambuc  * cards.
6433d6423SLionel Sambuc  *
7433d6423SLionel Sambuc  * Created:	before Dec 28, 1992 by Philip Homburg <philip@f-mnx.phicoh.com>
8433d6423SLionel Sambuc  *
9433d6423SLionel Sambuc  * Modified Mar 10 1994 by Philip Homburg
10433d6423SLionel Sambuc  *	Become a generic dp8390 driver.
11433d6423SLionel Sambuc  *
12433d6423SLionel Sambuc  * Modified Dec 20 1996 by G. Falzoni <falzoni@marina.scn.de>
13433d6423SLionel Sambuc  *	Added support for 3c503 boards.
14433d6423SLionel Sambuc  */
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc #include <minix/drivers.h>
17433d6423SLionel Sambuc #include <minix/netdriver.h>
18433d6423SLionel Sambuc 
19433d6423SLionel Sambuc #include <sys/mman.h>
20433d6423SLionel Sambuc #include "assert.h"
21433d6423SLionel Sambuc 
22433d6423SLionel Sambuc #include "local.h"
23433d6423SLionel Sambuc #include "dp8390.h"
24433d6423SLionel Sambuc 
25433d6423SLionel Sambuc static dpeth_t de_state;
26433d6423SLionel Sambuc 
27433d6423SLionel Sambuc u32_t system_hz;
28433d6423SLionel Sambuc 
29433d6423SLionel Sambuc /* Configuration */
30433d6423SLionel Sambuc typedef struct dp_conf
31433d6423SLionel Sambuc {
32433d6423SLionel Sambuc 	port_t dpc_port;
33433d6423SLionel Sambuc 	int dpc_irq;
34433d6423SLionel Sambuc 	phys_bytes dpc_mem;
35433d6423SLionel Sambuc } dp_conf_t;
36433d6423SLionel Sambuc 
37433d6423SLionel Sambuc #define DP_CONF_NR 4
38433d6423SLionel Sambuc static dp_conf_t dp_conf[DP_CONF_NR]=	/* Card addresses */
39433d6423SLionel Sambuc {
40433d6423SLionel Sambuc 	/* I/O port, IRQ,  Buffer address. */
41433d6423SLionel Sambuc 	{  0x280,     3,    0xD0000,       },
42433d6423SLionel Sambuc 	{  0x300,     5,    0xC8000,       },
43433d6423SLionel Sambuc 	{  0x380,    10,    0xD8000,       },
44433d6423SLionel Sambuc 	{  0x000,     0,    0x00000,       },
45433d6423SLionel Sambuc };
46433d6423SLionel Sambuc 
47433d6423SLionel Sambuc /* Card inits configured out? */
48433d6423SLionel Sambuc #if !ENABLE_WDETH
49433d6423SLionel Sambuc #define wdeth_probe(dep)	(0)
50433d6423SLionel Sambuc #endif
51433d6423SLionel Sambuc #if !ENABLE_NE2000
52433d6423SLionel Sambuc #define ne_probe(dep)		(0)
53433d6423SLionel Sambuc #endif
54433d6423SLionel Sambuc #if !ENABLE_3C503
55433d6423SLionel Sambuc #define el2_probe(dep)		(0)
56433d6423SLionel Sambuc #endif
57433d6423SLionel Sambuc 
58433d6423SLionel Sambuc /* Some clones of the dp8390 and the PC emulator 'Bochs' require the CR_STA
59433d6423SLionel Sambuc  * on writes to the CR register. Additional CR_STAs do not appear to hurt
60433d6423SLionel Sambuc  * genuine dp8390s
61433d6423SLionel Sambuc  */
62433d6423SLionel Sambuc #define CR_EXTRA	CR_STA
63433d6423SLionel Sambuc 
64*f7df02e7SDavid van Moolenbroek static int do_init(unsigned int instance, netdriver_addr_t *addr,
65*f7df02e7SDavid van Moolenbroek 	uint32_t *caps, unsigned int *ticks);
66*f7df02e7SDavid van Moolenbroek static void pci_conf(unsigned int instance);
673913e490SDavid van Moolenbroek static int do_send(struct netdriver_data *data, size_t size);
683913e490SDavid van Moolenbroek static ssize_t do_recv(struct netdriver_data *data, size_t max);
69*f7df02e7SDavid van Moolenbroek static void do_set_mode(unsigned int mode, const netdriver_addr_t *mcast_list,
70*f7df02e7SDavid van Moolenbroek 	unsigned int mcast_count);
713913e490SDavid van Moolenbroek static void do_stop(void);
72*f7df02e7SDavid van Moolenbroek static void dp_init(dpeth_t *dep, unsigned int instance);
73*f7df02e7SDavid van Moolenbroek static void dp_confaddr(dpeth_t *dep, unsigned int instance);
74433d6423SLionel Sambuc static void dp_reset(dpeth_t *dep);
753913e490SDavid van Moolenbroek static void do_intr(unsigned int mask);
76*f7df02e7SDavid van Moolenbroek static void do_tick(void);
77433d6423SLionel Sambuc static void dp_getblock(dpeth_t *dep, int page, size_t offset, size_t
78433d6423SLionel Sambuc 	size, void *dst);
79433d6423SLionel Sambuc static void dp_pio8_getblock(dpeth_t *dep, int page, size_t offset,
80433d6423SLionel Sambuc 	size_t size, void *dst);
81433d6423SLionel Sambuc static void dp_pio16_getblock(dpeth_t *dep, int page, size_t offset,
82433d6423SLionel Sambuc 	size_t size, void *dst);
833913e490SDavid van Moolenbroek static void dp_pkt2user_s(dpeth_t *dep, struct netdriver_data *data, int page,
843913e490SDavid van Moolenbroek 	size_t length);
853913e490SDavid van Moolenbroek static void dp_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
863913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count);
873913e490SDavid van Moolenbroek static void dp_pio8_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
883913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count);
893913e490SDavid van Moolenbroek static void dp_pio16_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
903913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count);
913913e490SDavid van Moolenbroek static void dp_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
923913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count);
933913e490SDavid van Moolenbroek static void dp_pio8_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
943913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count);
953913e490SDavid van Moolenbroek static void dp_pio16_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
963913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count);
97*f7df02e7SDavid van Moolenbroek static void conf_hw(dpeth_t *dep, unsigned int instance);
98*f7df02e7SDavid van Moolenbroek static void update_conf(dpeth_t *dep, dp_conf_t *dcp, unsigned int instance);
99433d6423SLionel Sambuc static void map_hw_buffer(dpeth_t *dep);
100433d6423SLionel Sambuc static void insb(port_t port, void *buf, size_t size);
101433d6423SLionel Sambuc static void insw(port_t port, void *buf, size_t size);
102433d6423SLionel Sambuc 
1033913e490SDavid van Moolenbroek static const struct netdriver dp_table = {
104*f7df02e7SDavid van Moolenbroek 	.ndr_name	= "dp",
1053913e490SDavid van Moolenbroek 	.ndr_init	= do_init,
1063913e490SDavid van Moolenbroek 	.ndr_stop	= do_stop,
107*f7df02e7SDavid van Moolenbroek 	.ndr_set_mode	= do_set_mode,
1083913e490SDavid van Moolenbroek 	.ndr_recv	= do_recv,
1093913e490SDavid van Moolenbroek 	.ndr_send	= do_send,
110*f7df02e7SDavid van Moolenbroek 	.ndr_intr	= do_intr,
111*f7df02e7SDavid van Moolenbroek 	.ndr_tick	= do_tick
1123913e490SDavid van Moolenbroek };
113433d6423SLionel Sambuc 
114433d6423SLionel Sambuc /*===========================================================================*
1153913e490SDavid van Moolenbroek  *				main					     *
116433d6423SLionel Sambuc  *===========================================================================*/
main(int argc,char * argv[])117433d6423SLionel Sambuc int main(int argc, char *argv[])
118433d6423SLionel Sambuc {
119433d6423SLionel Sambuc 	env_setargs(argc, argv);
120433d6423SLionel Sambuc 
1213913e490SDavid van Moolenbroek 	netdriver_task(&dp_table);
122433d6423SLionel Sambuc 
1233913e490SDavid van Moolenbroek 	return 0;
124433d6423SLionel Sambuc }
125433d6423SLionel Sambuc 
126433d6423SLionel Sambuc /*===========================================================================*
1273913e490SDavid van Moolenbroek  *				do_init					     *
128433d6423SLionel Sambuc  *===========================================================================*/
do_init(unsigned int instance,netdriver_addr_t * addr,uint32_t * caps,unsigned int * ticks)129*f7df02e7SDavid van Moolenbroek static int do_init(unsigned int instance, netdriver_addr_t *addr,
130*f7df02e7SDavid van Moolenbroek 	uint32_t *caps, unsigned int *ticks)
131433d6423SLionel Sambuc {
132433d6423SLionel Sambuc /* Initialize the dp8390 driver. */
133433d6423SLionel Sambuc 	dpeth_t *dep;
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc 	system_hz = sys_hz();
136433d6423SLionel Sambuc 
137433d6423SLionel Sambuc 	dep = &de_state;
1383913e490SDavid van Moolenbroek 	memset(dep, 0, sizeof(*dep));
139433d6423SLionel Sambuc 
140*f7df02e7SDavid van Moolenbroek 	pci_conf(instance); /* Configure PCI devices. */
141433d6423SLionel Sambuc 
1423913e490SDavid van Moolenbroek 	/* This is the default, try to (re)locate the device. */
143*f7df02e7SDavid van Moolenbroek 	conf_hw(dep, instance);
144433d6423SLionel Sambuc 
145*f7df02e7SDavid van Moolenbroek 	dp_init(dep, instance);
146433d6423SLionel Sambuc 
147*f7df02e7SDavid van Moolenbroek 	memcpy(addr, dep->de_address.na_addr, sizeof(*addr));
148*f7df02e7SDavid van Moolenbroek 	*caps = NDEV_CAP_MCAST | NDEV_CAP_BCAST;
149*f7df02e7SDavid van Moolenbroek 	*ticks = sys_hz(); /* update statistics once a second */
1503913e490SDavid van Moolenbroek 	return OK;
151433d6423SLionel Sambuc }
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc #if 0
154433d6423SLionel Sambuc /*===========================================================================*
155433d6423SLionel Sambuc  *				dp8390_dump				     *
156433d6423SLionel Sambuc  *===========================================================================*/
1573913e490SDavid van Moolenbroek void dp8390_dump(void)
158433d6423SLionel Sambuc {
159433d6423SLionel Sambuc 	dpeth_t *dep;
160433d6423SLionel Sambuc 	int isr;
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc 	dep = &de_state;
163433d6423SLionel Sambuc 
164433d6423SLionel Sambuc 	printf("\n");
165*f7df02e7SDavid van Moolenbroek 	printf("dp8390 statistics of %s:\n", netdriver_name());
166433d6423SLionel Sambuc 
167433d6423SLionel Sambuc 	isr= inb_reg0(dep, DP_ISR);
168433d6423SLionel Sambuc 	printf("dp_isr = 0x%x + 0x%x, de_flags = 0x%x\n", isr,
169433d6423SLionel Sambuc 				inb_reg0(dep, DP_ISR), dep->de_flags);
170433d6423SLionel Sambuc }
171433d6423SLionel Sambuc #endif
172433d6423SLionel Sambuc 
173433d6423SLionel Sambuc /*===========================================================================*
174*f7df02e7SDavid van Moolenbroek  *				pci_env					     *
175*f7df02e7SDavid van Moolenbroek  *===========================================================================*/
pci_env(unsigned int instance)176*f7df02e7SDavid van Moolenbroek static int pci_env(unsigned int instance)
177*f7df02e7SDavid van Moolenbroek {
178*f7df02e7SDavid van Moolenbroek 	char envvar[16], value[EP_BUF_SIZE];
179*f7df02e7SDavid van Moolenbroek 	const char punct[] = ":,;.";
180*f7df02e7SDavid van Moolenbroek 
181*f7df02e7SDavid van Moolenbroek 	strlcpy(envvar, "DPETH0", sizeof(envvar));
182*f7df02e7SDavid van Moolenbroek 	envvar[5] += instance;
183*f7df02e7SDavid van Moolenbroek 
184*f7df02e7SDavid van Moolenbroek 	/* If no setting with this name is present, default to PCI. */
185*f7df02e7SDavid van Moolenbroek 	if (env_get_param(envvar, value, sizeof(value)) != 0)
186*f7df02e7SDavid van Moolenbroek 		return TRUE;
187*f7df02e7SDavid van Moolenbroek 
188*f7df02e7SDavid van Moolenbroek 	/* Legacy support: check for a "pci" prefix. */
189*f7df02e7SDavid van Moolenbroek 	return (strncmp(value, "pci", 3) == 0 &&
190*f7df02e7SDavid van Moolenbroek 	    strchr(punct, value[3]) != NULL);
191*f7df02e7SDavid van Moolenbroek }
192*f7df02e7SDavid van Moolenbroek 
193*f7df02e7SDavid van Moolenbroek /*===========================================================================*
194433d6423SLionel Sambuc  *				pci_conf				     *
195433d6423SLionel Sambuc  *===========================================================================*/
pci_conf(unsigned int instance)196*f7df02e7SDavid van Moolenbroek static void pci_conf(unsigned int instance)
197433d6423SLionel Sambuc {
198433d6423SLionel Sambuc 	struct dpeth *dep;
199*f7df02e7SDavid van Moolenbroek 	unsigned int i, pci_instance;
200433d6423SLionel Sambuc 
201433d6423SLionel Sambuc 	dep= &de_state;
202433d6423SLionel Sambuc 
203*f7df02e7SDavid van Moolenbroek 	if (!(dep->de_pci= pci_env(instance)))
204433d6423SLionel Sambuc 		return;	/* no PCI config */
205433d6423SLionel Sambuc 
206433d6423SLionel Sambuc 	/* Count the number of dp instances before this one that are configured
207433d6423SLionel Sambuc 	 * for PCI, so that we can skip that many when enumerating PCI devices.
208433d6423SLionel Sambuc 	 */
209433d6423SLionel Sambuc 	pci_instance= 0;
210*f7df02e7SDavid van Moolenbroek 	for (i= 0; i < instance; i++) {
211*f7df02e7SDavid van Moolenbroek 		if (pci_env(i))
212433d6423SLionel Sambuc 			pci_instance++;
213433d6423SLionel Sambuc 	}
214433d6423SLionel Sambuc 
215433d6423SLionel Sambuc 	if (!rtl_probe(dep, pci_instance))
2163913e490SDavid van Moolenbroek 		panic("no matching PCI device found");
217433d6423SLionel Sambuc }
218433d6423SLionel Sambuc 
219433d6423SLionel Sambuc /*===========================================================================*
2203913e490SDavid van Moolenbroek  *				do_send					     *
221433d6423SLionel Sambuc  *===========================================================================*/
do_send(struct netdriver_data * data,size_t size)2223913e490SDavid van Moolenbroek static int do_send(struct netdriver_data *data, size_t size)
223433d6423SLionel Sambuc {
224433d6423SLionel Sambuc 	int sendq_head;
225433d6423SLionel Sambuc 	dpeth_t *dep;
226433d6423SLionel Sambuc 
227433d6423SLionel Sambuc 	dep= &de_state;
228433d6423SLionel Sambuc 
229433d6423SLionel Sambuc 	sendq_head= dep->de_sendq_head;
230433d6423SLionel Sambuc 	if (dep->de_sendq[sendq_head].sq_filled)
2313913e490SDavid van Moolenbroek 		return SUSPEND;
232433d6423SLionel Sambuc 
2333913e490SDavid van Moolenbroek 	(dep->de_user2nicf_s)(dep, data,
2343913e490SDavid van Moolenbroek 		dep->de_sendq[sendq_head].sq_sendpage * DP_PAGESIZE, 0, size);
235433d6423SLionel Sambuc 
236433d6423SLionel Sambuc 	dep->de_sendq[sendq_head].sq_filled= TRUE;
237433d6423SLionel Sambuc 	if (dep->de_sendq_tail == sendq_head)
238433d6423SLionel Sambuc 	{
239433d6423SLionel Sambuc 		outb_reg0(dep, DP_TPSR, dep->de_sendq[sendq_head].sq_sendpage);
240433d6423SLionel Sambuc 		outb_reg0(dep, DP_TBCR1, size >> 8);
241433d6423SLionel Sambuc 		outb_reg0(dep, DP_TBCR0, size & 0xff);
242433d6423SLionel Sambuc 		outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);/* there it goes.. */
243433d6423SLionel Sambuc 	}
244433d6423SLionel Sambuc 	else
245433d6423SLionel Sambuc 		dep->de_sendq[sendq_head].sq_size= size;
246433d6423SLionel Sambuc 
247433d6423SLionel Sambuc 	if (++sendq_head == dep->de_sendq_nr)
248433d6423SLionel Sambuc 		sendq_head= 0;
249433d6423SLionel Sambuc 	assert(sendq_head < SENDQ_NR);
250433d6423SLionel Sambuc 	dep->de_sendq_head= sendq_head;
251433d6423SLionel Sambuc 
2523913e490SDavid van Moolenbroek 	return OK;
253433d6423SLionel Sambuc }
254433d6423SLionel Sambuc 
255433d6423SLionel Sambuc /*===========================================================================*
256*f7df02e7SDavid van Moolenbroek  *				do_set_mode				     *
257433d6423SLionel Sambuc  *===========================================================================*/
do_set_mode(unsigned int mode,const netdriver_addr_t * mcast_list __unused,unsigned int mcast_count __unused)258*f7df02e7SDavid van Moolenbroek static void do_set_mode(unsigned int mode,
259*f7df02e7SDavid van Moolenbroek 	const netdriver_addr_t * mcast_list __unused,
260*f7df02e7SDavid van Moolenbroek 	unsigned int mcast_count __unused)
261433d6423SLionel Sambuc {
262433d6423SLionel Sambuc 	dpeth_t *dep;
2633913e490SDavid van Moolenbroek 	int dp_rcr_reg;
264433d6423SLionel Sambuc 
265433d6423SLionel Sambuc 	dep = &de_state;
266433d6423SLionel Sambuc 
2673913e490SDavid van Moolenbroek 	outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
268433d6423SLionel Sambuc 
2693913e490SDavid van Moolenbroek 	dp_rcr_reg = 0;
270*f7df02e7SDavid van Moolenbroek 	if (mode & NDEV_MODE_PROMISC)
2713913e490SDavid van Moolenbroek 		dp_rcr_reg |= RCR_AB | RCR_PRO | RCR_AM;
272*f7df02e7SDavid van Moolenbroek 	if (mode & NDEV_MODE_BCAST)
2733913e490SDavid van Moolenbroek 		dp_rcr_reg |= RCR_AB;
274*f7df02e7SDavid van Moolenbroek 	if (mode & (NDEV_MODE_MCAST_LIST | NDEV_MODE_MCAST_ALL))
2753913e490SDavid van Moolenbroek 		dp_rcr_reg |= RCR_AM;
2763913e490SDavid van Moolenbroek 	outb_reg0(dep, DP_RCR, dp_rcr_reg);
277433d6423SLionel Sambuc }
278433d6423SLionel Sambuc 
279433d6423SLionel Sambuc /*===========================================================================*
280*f7df02e7SDavid van Moolenbroek  *				dp_update_stats				     *
281433d6423SLionel Sambuc  *===========================================================================*/
dp_update_stats(dpeth_t * dep)282*f7df02e7SDavid van Moolenbroek static void dp_update_stats(dpeth_t * dep)
283433d6423SLionel Sambuc {
284433d6423SLionel Sambuc 
285*f7df02e7SDavid van Moolenbroek 	netdriver_stat_ierror(inb_reg0(dep, DP_CNTR0));
286*f7df02e7SDavid van Moolenbroek 	netdriver_stat_ierror(inb_reg0(dep, DP_CNTR1));
287*f7df02e7SDavid van Moolenbroek 	netdriver_stat_ierror(inb_reg0(dep, DP_CNTR2));
288*f7df02e7SDavid van Moolenbroek }
289433d6423SLionel Sambuc 
290*f7df02e7SDavid van Moolenbroek /*===========================================================================*
291*f7df02e7SDavid van Moolenbroek  *				do_tick					     *
292*f7df02e7SDavid van Moolenbroek  *===========================================================================*/
do_tick(void)293*f7df02e7SDavid van Moolenbroek static void do_tick(void)
294*f7df02e7SDavid van Moolenbroek {
295433d6423SLionel Sambuc 
296*f7df02e7SDavid van Moolenbroek 	dp_update_stats(&de_state);
297433d6423SLionel Sambuc }
298433d6423SLionel Sambuc 
299433d6423SLionel Sambuc /*===========================================================================*
3003913e490SDavid van Moolenbroek  *				do_stop					     *
301433d6423SLionel Sambuc  *===========================================================================*/
do_stop(void)3023913e490SDavid van Moolenbroek static void do_stop(void)
303433d6423SLionel Sambuc {
3043913e490SDavid van Moolenbroek 	dpeth_t *dep;
305433d6423SLionel Sambuc 
3063913e490SDavid van Moolenbroek 	dep = &de_state;
307433d6423SLionel Sambuc 
308433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
309433d6423SLionel Sambuc 	(dep->de_stopf)(dep);
310433d6423SLionel Sambuc }
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc /*===========================================================================*
313433d6423SLionel Sambuc  *				dp_init					     *
314433d6423SLionel Sambuc  *===========================================================================*/
dp_init(dpeth_t * dep,unsigned int instance)315*f7df02e7SDavid van Moolenbroek static void dp_init(dpeth_t *dep, unsigned int instance)
316433d6423SLionel Sambuc {
317433d6423SLionel Sambuc 	int i, r;
318433d6423SLionel Sambuc 
319433d6423SLionel Sambuc 	/* General initialization */
320433d6423SLionel Sambuc 	dep->de_flags = DEF_EMPTY;
321433d6423SLionel Sambuc 	(*dep->de_initf)(dep);
322433d6423SLionel Sambuc 
323*f7df02e7SDavid van Moolenbroek 	dp_confaddr(dep, instance);
324433d6423SLionel Sambuc 
325433d6423SLionel Sambuc 	if (debug)
326433d6423SLionel Sambuc 	{
327*f7df02e7SDavid van Moolenbroek 		printf("%s: Ethernet address ", netdriver_name());
328433d6423SLionel Sambuc 		for (i= 0; i < 6; i++)
329*f7df02e7SDavid van Moolenbroek 			printf("%x%c", dep->de_address.na_addr[i],
330433d6423SLionel Sambuc 							i < 5 ? ':' : '\n');
331433d6423SLionel Sambuc 	}
332433d6423SLionel Sambuc 
333433d6423SLionel Sambuc 	/* Map buffer */
334433d6423SLionel Sambuc 	map_hw_buffer(dep);
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc 	/* Initialization of the dp8390 following the mandatory procedure
337433d6423SLionel Sambuc 	 * in reference manual ("DP8390D/NS32490D NIC Network Interface
338433d6423SLionel Sambuc 	 * Controller", National Semiconductor, July 1995, Page 29).
339433d6423SLionel Sambuc 	 */
340433d6423SLionel Sambuc 	/* Step 1: */
341433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
342433d6423SLionel Sambuc 	/* Step 2: */
343433d6423SLionel Sambuc 	if (dep->de_16bit)
344433d6423SLionel Sambuc 		outb_reg0(dep, DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
345433d6423SLionel Sambuc 	else
346433d6423SLionel Sambuc 		outb_reg0(dep, DP_DCR, DCR_BYTEWIDE | DCR_8BYTES | DCR_BMS);
347433d6423SLionel Sambuc 	/* Step 3: */
348433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, 0);
349433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
350433d6423SLionel Sambuc 	/* Step 4: */
3513913e490SDavid van Moolenbroek 	outb_reg0(dep, DP_RCR, 0);
352433d6423SLionel Sambuc 	/* Step 5: */
353433d6423SLionel Sambuc 	outb_reg0(dep, DP_TCR, TCR_INTERNAL);
354433d6423SLionel Sambuc 	/* Step 6: */
355433d6423SLionel Sambuc 	outb_reg0(dep, DP_BNRY, dep->de_startpage);
356433d6423SLionel Sambuc 	outb_reg0(dep, DP_PSTART, dep->de_startpage);
357433d6423SLionel Sambuc 	outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
358433d6423SLionel Sambuc 	/* Step 7: */
359433d6423SLionel Sambuc 	outb_reg0(dep, DP_ISR, 0xFF);
360433d6423SLionel Sambuc 	/* Step 8: */
361433d6423SLionel Sambuc 	outb_reg0(dep, DP_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE |
362433d6423SLionel Sambuc 		IMR_OVWE | IMR_CNTE);
363433d6423SLionel Sambuc 	/* Step 9: */
364433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
365433d6423SLionel Sambuc 
366*f7df02e7SDavid van Moolenbroek 	outb_reg1(dep, DP_PAR0, dep->de_address.na_addr[0]);
367*f7df02e7SDavid van Moolenbroek 	outb_reg1(dep, DP_PAR1, dep->de_address.na_addr[1]);
368*f7df02e7SDavid van Moolenbroek 	outb_reg1(dep, DP_PAR2, dep->de_address.na_addr[2]);
369*f7df02e7SDavid van Moolenbroek 	outb_reg1(dep, DP_PAR3, dep->de_address.na_addr[3]);
370*f7df02e7SDavid van Moolenbroek 	outb_reg1(dep, DP_PAR4, dep->de_address.na_addr[4]);
371*f7df02e7SDavid van Moolenbroek 	outb_reg1(dep, DP_PAR5, dep->de_address.na_addr[5]);
372433d6423SLionel Sambuc 
373433d6423SLionel Sambuc 	outb_reg1(dep, DP_MAR0, 0xff);
374433d6423SLionel Sambuc 	outb_reg1(dep, DP_MAR1, 0xff);
375433d6423SLionel Sambuc 	outb_reg1(dep, DP_MAR2, 0xff);
376433d6423SLionel Sambuc 	outb_reg1(dep, DP_MAR3, 0xff);
377433d6423SLionel Sambuc 	outb_reg1(dep, DP_MAR4, 0xff);
378433d6423SLionel Sambuc 	outb_reg1(dep, DP_MAR5, 0xff);
379433d6423SLionel Sambuc 	outb_reg1(dep, DP_MAR6, 0xff);
380433d6423SLionel Sambuc 	outb_reg1(dep, DP_MAR7, 0xff);
381433d6423SLionel Sambuc 
382433d6423SLionel Sambuc 	outb_reg1(dep, DP_CURR, dep->de_startpage + 1);
383433d6423SLionel Sambuc 	/* Step 10: */
384433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_ABORT | CR_STA);
385433d6423SLionel Sambuc 	/* Step 11: */
386433d6423SLionel Sambuc 	outb_reg0(dep, DP_TCR, TCR_NORMAL);
387433d6423SLionel Sambuc 
388433d6423SLionel Sambuc 	inb_reg0(dep, DP_CNTR0);		/* reset counters by reading */
389433d6423SLionel Sambuc 	inb_reg0(dep, DP_CNTR1);
390433d6423SLionel Sambuc 	inb_reg0(dep, DP_CNTR2);
391433d6423SLionel Sambuc 
392433d6423SLionel Sambuc 	/* Finish the initialization. */
393433d6423SLionel Sambuc 	for (i= 0; i<dep->de_sendq_nr; i++)
394433d6423SLionel Sambuc 		dep->de_sendq[i].sq_filled= 0;
395433d6423SLionel Sambuc 	dep->de_sendq_head= 0;
396433d6423SLionel Sambuc 	dep->de_sendq_tail= 0;
397433d6423SLionel Sambuc 	if (!dep->de_prog_IO)
398433d6423SLionel Sambuc 	{
399433d6423SLionel Sambuc 		dep->de_user2nicf_s= dp_user2nic_s;
400433d6423SLionel Sambuc 		dep->de_nic2userf_s= dp_nic2user_s;
401433d6423SLionel Sambuc 		dep->de_getblockf= dp_getblock;
402433d6423SLionel Sambuc 	}
403433d6423SLionel Sambuc 	else if (dep->de_16bit)
404433d6423SLionel Sambuc 	{
405433d6423SLionel Sambuc 		dep->de_user2nicf_s= dp_pio16_user2nic_s;
406433d6423SLionel Sambuc 		dep->de_nic2userf_s= dp_pio16_nic2user_s;
407433d6423SLionel Sambuc 		dep->de_getblockf= dp_pio16_getblock;
408433d6423SLionel Sambuc 	}
409433d6423SLionel Sambuc 	else
410433d6423SLionel Sambuc 	{
411433d6423SLionel Sambuc 		dep->de_user2nicf_s= dp_pio8_user2nic_s;
412433d6423SLionel Sambuc 		dep->de_nic2userf_s= dp_pio8_nic2user_s;
413433d6423SLionel Sambuc 		dep->de_getblockf= dp_pio8_getblock;
414433d6423SLionel Sambuc 	}
415433d6423SLionel Sambuc 
416433d6423SLionel Sambuc 	/* Set the interrupt handler and policy. Do not automatically
417433d6423SLionel Sambuc 	 * reenable interrupts. Return the IRQ line number on interrupts.
418433d6423SLionel Sambuc  	 */
419433d6423SLionel Sambuc  	dep->de_hook = dep->de_irq;
420433d6423SLionel Sambuc 	r= sys_irqsetpolicy(dep->de_irq, 0, &dep->de_hook);
421433d6423SLionel Sambuc 	if (r != OK)
422433d6423SLionel Sambuc 		panic("sys_irqsetpolicy failed: %d", r);
423433d6423SLionel Sambuc 
424433d6423SLionel Sambuc 	r= sys_irqenable(&dep->de_hook);
425433d6423SLionel Sambuc 	if (r != OK)
4263913e490SDavid van Moolenbroek 		panic("unable to enable interrupts: %d", r);
427433d6423SLionel Sambuc }
428433d6423SLionel Sambuc 
429433d6423SLionel Sambuc /*===========================================================================*
430433d6423SLionel Sambuc  *				dp_confaddr				     *
431433d6423SLionel Sambuc  *===========================================================================*/
dp_confaddr(dpeth_t * dep,unsigned int instance)432*f7df02e7SDavid van Moolenbroek static void dp_confaddr(dpeth_t *dep, unsigned int instance)
433433d6423SLionel Sambuc {
434433d6423SLionel Sambuc 	int i;
435433d6423SLionel Sambuc 	char eakey[16];
436433d6423SLionel Sambuc 	static char eafmt[]= "x:x:x:x:x:x";
437433d6423SLionel Sambuc 	long v;
438433d6423SLionel Sambuc 
439433d6423SLionel Sambuc 	/* User defined ethernet address? */
440433d6423SLionel Sambuc 	strlcpy(eakey, "DPETH0_EA", sizeof(eakey));
441*f7df02e7SDavid van Moolenbroek 	eakey[5] += instance;
442433d6423SLionel Sambuc 
443433d6423SLionel Sambuc 	for (i= 0; i < 6; i++)
444433d6423SLionel Sambuc 	{
445*f7df02e7SDavid van Moolenbroek 		v= dep->de_address.na_addr[i];
446433d6423SLionel Sambuc 		if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
447433d6423SLionel Sambuc 		{
448433d6423SLionel Sambuc 			break;
449433d6423SLionel Sambuc 		}
450*f7df02e7SDavid van Moolenbroek 		dep->de_address.na_addr[i]= v;
451433d6423SLionel Sambuc 	}
452433d6423SLionel Sambuc 
453433d6423SLionel Sambuc 	if (i != 0 && i != 6) env_panic(eakey);	/* It's all or nothing */
454433d6423SLionel Sambuc }
455433d6423SLionel Sambuc 
456433d6423SLionel Sambuc /*===========================================================================*
457433d6423SLionel Sambuc  *				dp_reset				     *
458433d6423SLionel Sambuc  *===========================================================================*/
dp_reset(dpeth_t * dep)4593913e490SDavid van Moolenbroek static void dp_reset(dpeth_t *dep)
460433d6423SLionel Sambuc {
461433d6423SLionel Sambuc 	int i;
462433d6423SLionel Sambuc 
463433d6423SLionel Sambuc 	/* Stop chip */
464433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_STP | CR_DM_ABORT);
465433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, 0);
466433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, 0);
467433d6423SLionel Sambuc 	for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); i++)
468433d6423SLionel Sambuc 		; /* Do nothing */
469433d6423SLionel Sambuc 	outb_reg0(dep, DP_TCR, TCR_1EXTERNAL|TCR_OFST);
470433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_STA|CR_DM_ABORT);
471433d6423SLionel Sambuc 	outb_reg0(dep, DP_TCR, TCR_NORMAL);
472433d6423SLionel Sambuc 
473433d6423SLionel Sambuc 	/* Acknowledge the ISR_RDC (remote dma) interrupt. */
474433d6423SLionel Sambuc 	for (i= 0; i < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); i++)
475433d6423SLionel Sambuc 		; /* Do nothing */
476433d6423SLionel Sambuc 	outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & ~ISR_RDC);
477433d6423SLionel Sambuc 
478433d6423SLionel Sambuc 	/* Reset the transmit ring. If we were transmitting a packet, we
479433d6423SLionel Sambuc 	 * pretend that the packet is processed. Higher layers will
480433d6423SLionel Sambuc 	 * retransmit if the packet wasn't actually sent.
481433d6423SLionel Sambuc 	 */
482433d6423SLionel Sambuc 	dep->de_sendq_head= dep->de_sendq_tail= 0;
483433d6423SLionel Sambuc 	for (i= 0; i<dep->de_sendq_nr; i++)
484433d6423SLionel Sambuc 		dep->de_sendq[i].sq_filled= 0;
4853913e490SDavid van Moolenbroek 	netdriver_send();
486433d6423SLionel Sambuc 	dep->de_flags &= ~DEF_STOPPED;
487433d6423SLionel Sambuc }
488433d6423SLionel Sambuc 
489433d6423SLionel Sambuc /*===========================================================================*
4903913e490SDavid van Moolenbroek  *				do_intr					     *
491433d6423SLionel Sambuc  *===========================================================================*/
do_intr(unsigned int __unused mask)4923913e490SDavid van Moolenbroek static void do_intr(unsigned int __unused mask)
493433d6423SLionel Sambuc {
4943913e490SDavid van Moolenbroek 	dpeth_t *dep;
495433d6423SLionel Sambuc 	int isr, tsr;
4963913e490SDavid van Moolenbroek 	int r, size, sendq_tail;
497433d6423SLionel Sambuc 
4983913e490SDavid van Moolenbroek 	dep = &de_state;
499433d6423SLionel Sambuc 
500433d6423SLionel Sambuc 	for(;;)
501433d6423SLionel Sambuc 	{
502433d6423SLionel Sambuc 		isr = inb_reg0(dep, DP_ISR);
503433d6423SLionel Sambuc 		if (!isr)
504433d6423SLionel Sambuc 			break;
505433d6423SLionel Sambuc 		outb_reg0(dep, DP_ISR, isr);
506433d6423SLionel Sambuc 		if (isr & (ISR_PTX|ISR_TXE))
507433d6423SLionel Sambuc 		{
508433d6423SLionel Sambuc 			if (isr & ISR_TXE)
509433d6423SLionel Sambuc 			{
510433d6423SLionel Sambuc #if DEBUG
511*f7df02e7SDavid van Moolenbroek 				printf("%s: got send error\n",
512*f7df02e7SDavid van Moolenbroek 				    netdriver_name());
513433d6423SLionel Sambuc #endif
514*f7df02e7SDavid van Moolenbroek 				netdriver_stat_oerror(1);
515433d6423SLionel Sambuc 			}
516433d6423SLionel Sambuc 			else
517433d6423SLionel Sambuc 			{
518433d6423SLionel Sambuc 				tsr = inb_reg0(dep, DP_TSR);
519433d6423SLionel Sambuc 
520*f7df02e7SDavid van Moolenbroek 				if (tsr & TSR_PTX) {
521*f7df02e7SDavid van Moolenbroek 					/* Transmission was successful. */
522*f7df02e7SDavid van Moolenbroek 				}
523433d6423SLionel Sambuc #if 0	/* Reserved in later manuals, should be ignored */
524433d6423SLionel Sambuc 				if (!(tsr & TSR_DFR))
525433d6423SLionel Sambuc 				{
526433d6423SLionel Sambuc 					/* In most (all?) implementations of
527433d6423SLionel Sambuc 					 * the dp8390, this bit is set
528433d6423SLionel Sambuc 					 * when the packet is not deferred
529433d6423SLionel Sambuc 					 */
530433d6423SLionel Sambuc 				}
531433d6423SLionel Sambuc #endif
532*f7df02e7SDavid van Moolenbroek 				if (tsr & TSR_COL) netdriver_stat_coll(1);
533433d6423SLionel Sambuc 			}
534433d6423SLionel Sambuc 			sendq_tail= dep->de_sendq_tail;
535433d6423SLionel Sambuc 
536433d6423SLionel Sambuc 			if (!(dep->de_sendq[sendq_tail].sq_filled))
537433d6423SLionel Sambuc 			{
538433d6423SLionel Sambuc 				/* Software bug? */
539433d6423SLionel Sambuc 				assert(!debug);
540433d6423SLionel Sambuc 
541433d6423SLionel Sambuc 				/* Or hardware bug? */
542433d6423SLionel Sambuc 				printf(
543433d6423SLionel Sambuc 				"%s: transmit interrupt, but not sending\n",
544*f7df02e7SDavid van Moolenbroek 					netdriver_name());
545433d6423SLionel Sambuc 				continue;
546433d6423SLionel Sambuc 			}
547433d6423SLionel Sambuc 			dep->de_sendq[sendq_tail].sq_filled= 0;
548433d6423SLionel Sambuc 			if (++sendq_tail == dep->de_sendq_nr)
549433d6423SLionel Sambuc 				sendq_tail= 0;
550433d6423SLionel Sambuc 			dep->de_sendq_tail= sendq_tail;
551433d6423SLionel Sambuc 			if (dep->de_sendq[sendq_tail].sq_filled)
552433d6423SLionel Sambuc 			{
553433d6423SLionel Sambuc 				size= dep->de_sendq[sendq_tail].sq_size;
554433d6423SLionel Sambuc 				outb_reg0(dep, DP_TPSR,
555433d6423SLionel Sambuc 					dep->de_sendq[sendq_tail].sq_sendpage);
556433d6423SLionel Sambuc 				outb_reg0(dep, DP_TBCR1, size >> 8);
557433d6423SLionel Sambuc 				outb_reg0(dep, DP_TBCR0, size & 0xff);
558433d6423SLionel Sambuc 				outb_reg0(dep, DP_CR, CR_TXP | CR_EXTRA);
559433d6423SLionel Sambuc 			}
5603913e490SDavid van Moolenbroek 			netdriver_send();
561433d6423SLionel Sambuc 		}
562433d6423SLionel Sambuc 
563433d6423SLionel Sambuc 		if (isr & ISR_PRX)
5643913e490SDavid van Moolenbroek 			netdriver_recv();
565433d6423SLionel Sambuc 
566*f7df02e7SDavid van Moolenbroek 		if (isr & ISR_RXE)
567*f7df02e7SDavid van Moolenbroek 			netdriver_stat_ierror(1);
568433d6423SLionel Sambuc 		if (isr & ISR_CNT)
569*f7df02e7SDavid van Moolenbroek 			dp_update_stats(dep);
570433d6423SLionel Sambuc 		if (isr & ISR_RDC)
571433d6423SLionel Sambuc 		{
572433d6423SLionel Sambuc 			/* Nothing to do */
573433d6423SLionel Sambuc 		}
574433d6423SLionel Sambuc 		if (isr & ISR_RST)
575433d6423SLionel Sambuc 		{
576433d6423SLionel Sambuc 			/* this means we got an interrupt but the ethernet
577433d6423SLionel Sambuc 			 * chip is shutdown. We set the flag DEF_STOPPED,
578433d6423SLionel Sambuc 			 * and continue processing arrived packets. When the
579433d6423SLionel Sambuc 			 * receive buffer is empty, we reset the dp8390.
580433d6423SLionel Sambuc 			 */
581433d6423SLionel Sambuc #if 0
582433d6423SLionel Sambuc 			 { printW(); printf(
583*f7df02e7SDavid van Moolenbroek 				"%s: NIC stopped\n", netdriver_name()); }
584433d6423SLionel Sambuc #endif
585433d6423SLionel Sambuc 			dep->de_flags |= DEF_STOPPED;
5863913e490SDavid van Moolenbroek 			netdriver_recv(); /* see if we can reset right now */
587433d6423SLionel Sambuc 			break;
588433d6423SLionel Sambuc 		}
589433d6423SLionel Sambuc 	}
5903913e490SDavid van Moolenbroek 
5913913e490SDavid van Moolenbroek 	if ((r = sys_irqenable(&dep->de_hook)) != OK)
5923913e490SDavid van Moolenbroek 		panic("unable enable interrupts: %d", r);
593433d6423SLionel Sambuc }
594433d6423SLionel Sambuc 
595433d6423SLionel Sambuc /*===========================================================================*
5963913e490SDavid van Moolenbroek  *				do_recv					     *
597433d6423SLionel Sambuc  *===========================================================================*/
do_recv(struct netdriver_data * data,size_t max)5983913e490SDavid van Moolenbroek static ssize_t do_recv(struct netdriver_data *data, size_t max)
599433d6423SLionel Sambuc {
6003913e490SDavid van Moolenbroek 	dpeth_t *dep;
601433d6423SLionel Sambuc 	dp_rcvhdr_t header;
602433d6423SLionel Sambuc 	unsigned pageno, curr, next;
6033913e490SDavid van Moolenbroek 	size_t length;
6043913e490SDavid van Moolenbroek 	int packet_processed;
605433d6423SLionel Sambuc 	u16_t eth_type;
606433d6423SLionel Sambuc 
6073913e490SDavid van Moolenbroek 	dep = &de_state;
6083913e490SDavid van Moolenbroek 
609433d6423SLionel Sambuc 	packet_processed = FALSE;
610433d6423SLionel Sambuc 	pageno = inb_reg0(dep, DP_BNRY) + 1;
611433d6423SLionel Sambuc 	if (pageno == dep->de_stoppage) pageno = dep->de_startpage;
612433d6423SLionel Sambuc 
613433d6423SLionel Sambuc 	do
614433d6423SLionel Sambuc 	{
615433d6423SLionel Sambuc 		outb_reg0(dep, DP_CR, CR_PS_P1 | CR_EXTRA);
616433d6423SLionel Sambuc 		curr = inb_reg1(dep, DP_CURR);
617433d6423SLionel Sambuc 		outb_reg0(dep, DP_CR, CR_PS_P0 | CR_EXTRA);
618433d6423SLionel Sambuc 
6193913e490SDavid van Moolenbroek 		if (curr == pageno) {
6203913e490SDavid van Moolenbroek 			if (dep->de_flags & DEF_STOPPED) {
6213913e490SDavid van Moolenbroek 				/* The chip is stopped, and all arrived packets
6223913e490SDavid van Moolenbroek 				 * are delivered.
6233913e490SDavid van Moolenbroek 				 */
6243913e490SDavid van Moolenbroek 				dp_reset(dep);
6253913e490SDavid van Moolenbroek 			}
6263913e490SDavid van Moolenbroek 
6273913e490SDavid van Moolenbroek 			return SUSPEND;
6283913e490SDavid van Moolenbroek 		}
629433d6423SLionel Sambuc 
630433d6423SLionel Sambuc 		(dep->de_getblockf)(dep, pageno, (size_t)0, sizeof(header),
631433d6423SLionel Sambuc 			&header);
632433d6423SLionel Sambuc 		(dep->de_getblockf)(dep, pageno, sizeof(header) +
633*f7df02e7SDavid van Moolenbroek 			2*sizeof(netdriver_addr_t), sizeof(eth_type),
634*f7df02e7SDavid van Moolenbroek 			&eth_type);
635433d6423SLionel Sambuc 
636433d6423SLionel Sambuc 		length = (header.dr_rbcl | (header.dr_rbch << 8)) -
637433d6423SLionel Sambuc 			sizeof(dp_rcvhdr_t);
638433d6423SLionel Sambuc 		next = header.dr_next;
639*f7df02e7SDavid van Moolenbroek 		if (length < NDEV_ETH_PACKET_MIN || length > max)
640433d6423SLionel Sambuc 		{
641433d6423SLionel Sambuc 			printf("%s: packet with strange length arrived: %d\n",
642*f7df02e7SDavid van Moolenbroek 				netdriver_name(), (int) length);
643433d6423SLionel Sambuc 			next= curr;
644433d6423SLionel Sambuc 		}
645433d6423SLionel Sambuc 		else if (next < dep->de_startpage || next >= dep->de_stoppage)
646433d6423SLionel Sambuc 		{
647*f7df02e7SDavid van Moolenbroek 			printf("%s: strange next page\n", netdriver_name());
648433d6423SLionel Sambuc 			next= curr;
649433d6423SLionel Sambuc 		}
650433d6423SLionel Sambuc 		else if (header.dr_status & RSR_FO)
651433d6423SLionel Sambuc 		{
652433d6423SLionel Sambuc 			/* This is very serious, so we issue a warning and
653433d6423SLionel Sambuc 			 * reset the buffers */
654433d6423SLionel Sambuc 			printf("%s: fifo overrun, resetting receive buffer\n",
655*f7df02e7SDavid van Moolenbroek 				netdriver_name());
656*f7df02e7SDavid van Moolenbroek 			netdriver_stat_ierror(1);
657433d6423SLionel Sambuc 			next = curr;
658433d6423SLionel Sambuc 		}
6593913e490SDavid van Moolenbroek 		else if (header.dr_status & RSR_PRX)
660433d6423SLionel Sambuc 		{
6613913e490SDavid van Moolenbroek 			dp_pkt2user_s(dep, data, pageno, length);
662433d6423SLionel Sambuc 
663433d6423SLionel Sambuc 			packet_processed = TRUE;
664433d6423SLionel Sambuc 		}
665433d6423SLionel Sambuc 		if (next == dep->de_startpage)
666433d6423SLionel Sambuc 			outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
667433d6423SLionel Sambuc 		else
668433d6423SLionel Sambuc 			outb_reg0(dep, DP_BNRY, next - 1);
669433d6423SLionel Sambuc 
670433d6423SLionel Sambuc 		pageno = next;
6713913e490SDavid van Moolenbroek 	} while (!packet_processed);
672433d6423SLionel Sambuc 
6733913e490SDavid van Moolenbroek 	return length;
674433d6423SLionel Sambuc }
675433d6423SLionel Sambuc 
676433d6423SLionel Sambuc /*===========================================================================*
677433d6423SLionel Sambuc  *				dp_getblock				     *
678433d6423SLionel Sambuc  *===========================================================================*/
dp_getblock(dpeth_t * dep,int page,size_t offset,size_t size,void * dst)6793913e490SDavid van Moolenbroek static void dp_getblock(dpeth_t *dep, int page, size_t offset, size_t size,
6803913e490SDavid van Moolenbroek 	void *dst)
681433d6423SLionel Sambuc {
682433d6423SLionel Sambuc 	offset = page * DP_PAGESIZE + offset;
683433d6423SLionel Sambuc 
684433d6423SLionel Sambuc 	memcpy(dst, dep->de_locmem + offset, size);
685433d6423SLionel Sambuc }
686433d6423SLionel Sambuc 
687433d6423SLionel Sambuc /*===========================================================================*
688433d6423SLionel Sambuc  *				dp_pio8_getblock			     *
689433d6423SLionel Sambuc  *===========================================================================*/
dp_pio8_getblock(dpeth_t * dep,int page,size_t offset,size_t size,void * dst)6903913e490SDavid van Moolenbroek static void dp_pio8_getblock(dpeth_t *dep, int page, size_t offset,
6913913e490SDavid van Moolenbroek 	size_t size, void *dst)
692433d6423SLionel Sambuc {
693433d6423SLionel Sambuc 	offset = page * DP_PAGESIZE + offset;
694433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, size & 0xFF);
695433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, size >> 8);
696433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, offset & 0xFF);
697433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, offset >> 8);
698433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
699433d6423SLionel Sambuc 
700433d6423SLionel Sambuc 	insb(dep->de_data_port, dst, size);
701433d6423SLionel Sambuc }
702433d6423SLionel Sambuc 
703433d6423SLionel Sambuc /*===========================================================================*
704433d6423SLionel Sambuc  *				dp_pio16_getblock			     *
705433d6423SLionel Sambuc  *===========================================================================*/
dp_pio16_getblock(dpeth_t * dep,int page,size_t offset,size_t size,void * dst)7063913e490SDavid van Moolenbroek static void dp_pio16_getblock(dpeth_t *dep, int page, size_t offset,
7073913e490SDavid van Moolenbroek 	size_t size, void *dst)
708433d6423SLionel Sambuc {
709433d6423SLionel Sambuc 	offset = page * DP_PAGESIZE + offset;
710433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, size & 0xFF);
711433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, size >> 8);
712433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, offset & 0xFF);
713433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, offset >> 8);
714433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
715433d6423SLionel Sambuc 
716433d6423SLionel Sambuc 	assert (!(size & 1));
717433d6423SLionel Sambuc 	insw(dep->de_data_port, dst, size);
718433d6423SLionel Sambuc }
719433d6423SLionel Sambuc 
720433d6423SLionel Sambuc /*===========================================================================*
721433d6423SLionel Sambuc  *				dp_pkt2user_s				     *
722433d6423SLionel Sambuc  *===========================================================================*/
dp_pkt2user_s(dpeth_t * dep,struct netdriver_data * data,int page,size_t length)7233913e490SDavid van Moolenbroek static void dp_pkt2user_s(dpeth_t *dep, struct netdriver_data *data, int page,
7243913e490SDavid van Moolenbroek 	size_t length)
725433d6423SLionel Sambuc {
726*f7df02e7SDavid van Moolenbroek 	unsigned int last, count;
727433d6423SLionel Sambuc 
728433d6423SLionel Sambuc 	last = page + (length - 1) / DP_PAGESIZE;
729433d6423SLionel Sambuc 	if (last >= dep->de_stoppage)
730433d6423SLionel Sambuc 	{
731433d6423SLionel Sambuc 		count = (dep->de_stoppage - page) * DP_PAGESIZE -
732433d6423SLionel Sambuc 			sizeof(dp_rcvhdr_t);
733433d6423SLionel Sambuc 
7343913e490SDavid van Moolenbroek 		(dep->de_nic2userf_s)(dep, data,
7353913e490SDavid van Moolenbroek 		    page * DP_PAGESIZE + sizeof(dp_rcvhdr_t), 0, count);
7363913e490SDavid van Moolenbroek 		(dep->de_nic2userf_s)(dep, data,
7373913e490SDavid van Moolenbroek 		    dep->de_startpage * DP_PAGESIZE, count, length - count);
738433d6423SLionel Sambuc 	}
739433d6423SLionel Sambuc 	else
740433d6423SLionel Sambuc 	{
7413913e490SDavid van Moolenbroek 		(dep->de_nic2userf_s)(dep, data,
7423913e490SDavid van Moolenbroek 		    page * DP_PAGESIZE + sizeof(dp_rcvhdr_t), 0, length);
743433d6423SLionel Sambuc 	}
744433d6423SLionel Sambuc }
745433d6423SLionel Sambuc 
746433d6423SLionel Sambuc /*===========================================================================*
747433d6423SLionel Sambuc  *				dp_user2nic_s				     *
748433d6423SLionel Sambuc  *===========================================================================*/
dp_user2nic_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)7493913e490SDavid van Moolenbroek static void dp_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
7503913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count)
751433d6423SLionel Sambuc {
7523913e490SDavid van Moolenbroek 	netdriver_copyin(data, offset, dep->de_locmem + nic_addr, count);
753433d6423SLionel Sambuc }
754433d6423SLionel Sambuc 
755433d6423SLionel Sambuc /*===========================================================================*
756433d6423SLionel Sambuc  *				dp_pio8_user2nic_s			     *
757433d6423SLionel Sambuc  *===========================================================================*/
dp_pio8_user2nic_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)7583913e490SDavid van Moolenbroek static void dp_pio8_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
7593913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count)
760433d6423SLionel Sambuc {
7613913e490SDavid van Moolenbroek 	int i;
762433d6423SLionel Sambuc 
763433d6423SLionel Sambuc 	outb_reg0(dep, DP_ISR, ISR_RDC);
764433d6423SLionel Sambuc 
765433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, count & 0xFF);
766433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, count >> 8);
767433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
768433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
769433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
770433d6423SLionel Sambuc 
7713913e490SDavid van Moolenbroek 	netdriver_portoutb(data, offset, dep->de_data_port, count);
772433d6423SLionel Sambuc 
773433d6423SLionel Sambuc 	for (i= 0; i<100; i++)
774433d6423SLionel Sambuc 	{
775433d6423SLionel Sambuc 		if (inb_reg0(dep, DP_ISR) & ISR_RDC)
776433d6423SLionel Sambuc 			break;
777433d6423SLionel Sambuc 	}
778433d6423SLionel Sambuc 	if (i == 100)
779433d6423SLionel Sambuc 	{
780433d6423SLionel Sambuc 		panic("dp8390: remote dma failed to complete");
781433d6423SLionel Sambuc 	}
782433d6423SLionel Sambuc }
783433d6423SLionel Sambuc 
784433d6423SLionel Sambuc /*===========================================================================*
785433d6423SLionel Sambuc  *				dp_pio16_user2nic_s			     *
786433d6423SLionel Sambuc  *===========================================================================*/
dp_pio16_user2nic_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)7873913e490SDavid van Moolenbroek static void dp_pio16_user2nic_s(dpeth_t *dep, struct netdriver_data *data,
7883913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count)
789433d6423SLionel Sambuc {
7903913e490SDavid van Moolenbroek 	size_t ecount;
7913913e490SDavid van Moolenbroek 	int i;
792433d6423SLionel Sambuc 
793433d6423SLionel Sambuc 	ecount= (count+1) & ~1;
794433d6423SLionel Sambuc 
795433d6423SLionel Sambuc 	outb_reg0(dep, DP_ISR, ISR_RDC);
796433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
797433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, ecount >> 8);
798433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
799433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
800433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
801433d6423SLionel Sambuc 
8023913e490SDavid van Moolenbroek 	netdriver_portoutw(data, offset, dep->de_data_port, count);
803433d6423SLionel Sambuc 
804433d6423SLionel Sambuc 	for (i= 0; i<100; i++)
805433d6423SLionel Sambuc 	{
806433d6423SLionel Sambuc 		if (inb_reg0(dep, DP_ISR) & ISR_RDC)
807433d6423SLionel Sambuc 			break;
808433d6423SLionel Sambuc 	}
809433d6423SLionel Sambuc 	if (i == 100)
810433d6423SLionel Sambuc 	{
811433d6423SLionel Sambuc 		panic("dp8390: remote dma failed to complete");
812433d6423SLionel Sambuc 	}
813433d6423SLionel Sambuc }
814433d6423SLionel Sambuc 
815433d6423SLionel Sambuc /*===========================================================================*
816433d6423SLionel Sambuc  *				dp_nic2user_s				     *
817433d6423SLionel Sambuc  *===========================================================================*/
dp_nic2user_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)8183913e490SDavid van Moolenbroek static void dp_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
8193913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count)
820433d6423SLionel Sambuc {
8213913e490SDavid van Moolenbroek 	netdriver_copyout(data, offset, dep->de_locmem + nic_addr, count);
822433d6423SLionel Sambuc }
823433d6423SLionel Sambuc 
824433d6423SLionel Sambuc /*===========================================================================*
825433d6423SLionel Sambuc  *				dp_pio8_nic2user_s			     *
826433d6423SLionel Sambuc  *===========================================================================*/
dp_pio8_nic2user_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)8273913e490SDavid van Moolenbroek static void dp_pio8_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
8283913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count)
829433d6423SLionel Sambuc {
830433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, count & 0xFF);
831433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, count >> 8);
832433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
833433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
834433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
835433d6423SLionel Sambuc 
8363913e490SDavid van Moolenbroek 	netdriver_portinb(data, offset, dep->de_data_port, count);
837433d6423SLionel Sambuc }
838433d6423SLionel Sambuc 
839433d6423SLionel Sambuc /*===========================================================================*
840433d6423SLionel Sambuc  *				dp_pio16_nic2user_s			     *
841433d6423SLionel Sambuc  *===========================================================================*/
dp_pio16_nic2user_s(dpeth_t * dep,struct netdriver_data * data,int nic_addr,size_t offset,size_t count)8423913e490SDavid van Moolenbroek static void dp_pio16_nic2user_s(dpeth_t *dep, struct netdriver_data *data,
8433913e490SDavid van Moolenbroek 	int nic_addr, size_t offset, size_t count)
844433d6423SLionel Sambuc {
8453913e490SDavid van Moolenbroek 	size_t ecount;
846433d6423SLionel Sambuc 
847433d6423SLionel Sambuc 	ecount= (count+1) & ~1;
848433d6423SLionel Sambuc 
849433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR0, ecount & 0xFF);
850433d6423SLionel Sambuc 	outb_reg0(dep, DP_RBCR1, ecount >> 8);
851433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR0, nic_addr & 0xFF);
852433d6423SLionel Sambuc 	outb_reg0(dep, DP_RSAR1, nic_addr >> 8);
853433d6423SLionel Sambuc 	outb_reg0(dep, DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
854433d6423SLionel Sambuc 
8553913e490SDavid van Moolenbroek 	netdriver_portinw(data, offset, dep->de_data_port, count);
856433d6423SLionel Sambuc }
857433d6423SLionel Sambuc 
858433d6423SLionel Sambuc /*===========================================================================*
859433d6423SLionel Sambuc  *				conf_hw					     *
860433d6423SLionel Sambuc  *===========================================================================*/
conf_hw(dpeth_t * dep,unsigned int instance)861*f7df02e7SDavid van Moolenbroek static void conf_hw(dpeth_t *dep, unsigned int instance)
862433d6423SLionel Sambuc {
863433d6423SLionel Sambuc 	int confnr;
864433d6423SLionel Sambuc 	dp_conf_t *dcp;
865433d6423SLionel Sambuc 
866433d6423SLionel Sambuc 	/* Pick a default configuration for this instance. */
867*f7df02e7SDavid van Moolenbroek 	confnr= MIN(instance, DP_CONF_NR-1);
868433d6423SLionel Sambuc 
869433d6423SLionel Sambuc 	dcp= &dp_conf[confnr];
870*f7df02e7SDavid van Moolenbroek 	update_conf(dep, dcp, instance);
871433d6423SLionel Sambuc 	if (!wdeth_probe(dep) && !ne_probe(dep) && !el2_probe(dep))
8723913e490SDavid van Moolenbroek 		panic("no ethernet card found at 0x%x\n", dep->de_base_port);
873433d6423SLionel Sambuc 
874433d6423SLionel Sambuc /* XXX */ if (dep->de_linmem == 0) dep->de_linmem= 0xFFFF0000;
875433d6423SLionel Sambuc }
876433d6423SLionel Sambuc 
877433d6423SLionel Sambuc /*===========================================================================*
878433d6423SLionel Sambuc  *				update_conf				     *
879433d6423SLionel Sambuc  *===========================================================================*/
update_conf(dpeth_t * dep,dp_conf_t * dcp,unsigned int instance)880*f7df02e7SDavid van Moolenbroek static void update_conf(dpeth_t *dep, dp_conf_t *dcp, unsigned int instance)
881433d6423SLionel Sambuc {
882433d6423SLionel Sambuc 	long v;
883433d6423SLionel Sambuc 	static char dpc_fmt[] = "x:d:x:x";
884433d6423SLionel Sambuc 	char eckey[16];
885433d6423SLionel Sambuc 
886433d6423SLionel Sambuc 	if (dep->de_pci)
887433d6423SLionel Sambuc 	{
888433d6423SLionel Sambuc 		/* PCI device is present */
889433d6423SLionel Sambuc 		return;		/* Already configured */
890433d6423SLionel Sambuc 	}
891433d6423SLionel Sambuc 
892433d6423SLionel Sambuc 	strlcpy(eckey, "DPETH0", sizeof(eckey));
893*f7df02e7SDavid van Moolenbroek 	eckey[5] += instance;
894433d6423SLionel Sambuc 
895433d6423SLionel Sambuc 	/* Get the default settings and modify them from the environment. */
896433d6423SLionel Sambuc 	v= dcp->dpc_port;
8973913e490SDavid van Moolenbroek 	(void) env_parse(eckey, dpc_fmt, 0, &v, 0x0000L, 0xFFFFL);
898433d6423SLionel Sambuc 	dep->de_base_port= v;
899433d6423SLionel Sambuc 
900433d6423SLionel Sambuc 	v= dcp->dpc_irq | DEI_DEFAULT;
901433d6423SLionel Sambuc 	(void) env_parse(eckey, dpc_fmt, 1, &v, 0L, (long) NR_IRQ_VECTORS - 1);
902433d6423SLionel Sambuc 	dep->de_irq= v;
903433d6423SLionel Sambuc 
904433d6423SLionel Sambuc 	v= dcp->dpc_mem;
905433d6423SLionel Sambuc 	(void) env_parse(eckey, dpc_fmt, 2, &v, 0L, 0xFFFFFL);
906433d6423SLionel Sambuc 	dep->de_linmem= v;
907433d6423SLionel Sambuc 
908433d6423SLionel Sambuc 	v= 0;
909433d6423SLionel Sambuc 	(void) env_parse(eckey, dpc_fmt, 3, &v, 0x2000L, 0x8000L);
910433d6423SLionel Sambuc 	dep->de_ramsize= v;
911433d6423SLionel Sambuc }
912433d6423SLionel Sambuc 
913433d6423SLionel Sambuc /*===========================================================================*
914433d6423SLionel Sambuc  *				map_hw_buffer				     *
915433d6423SLionel Sambuc  *===========================================================================*/
map_hw_buffer(dpeth_t * dep)9163913e490SDavid van Moolenbroek static void map_hw_buffer(dpeth_t *dep)
917433d6423SLionel Sambuc {
918433d6423SLionel Sambuc 
919433d6423SLionel Sambuc 	if (dep->de_prog_IO)
920433d6423SLionel Sambuc 	{
921433d6423SLionel Sambuc #if 0
922433d6423SLionel Sambuc 		printf(
923433d6423SLionel Sambuc 		"map_hw_buffer: programmed I/O, no need to map buffer\n");
924433d6423SLionel Sambuc #endif
925433d6423SLionel Sambuc 		dep->de_locmem = (char *)-dep->de_ramsize; /* trap errors */
926433d6423SLionel Sambuc 		return;
927433d6423SLionel Sambuc 	}
928433d6423SLionel Sambuc 
929433d6423SLionel Sambuc 	dep->de_locmem=
930433d6423SLionel Sambuc 		vm_map_phys(SELF, (void *) dep->de_linmem, dep->de_ramsize);
931433d6423SLionel Sambuc 	if (dep->de_locmem == MAP_FAILED)
932433d6423SLionel Sambuc 		panic("map_hw_buffer: vm_map_phys failed");
933433d6423SLionel Sambuc }
934433d6423SLionel Sambuc 
inb(port_t port)935433d6423SLionel Sambuc u8_t inb(port_t port)
936433d6423SLionel Sambuc {
937433d6423SLionel Sambuc 	int r;
938433d6423SLionel Sambuc 	u32_t value;
939433d6423SLionel Sambuc 
940433d6423SLionel Sambuc 	r= sys_inb(port, &value);
941433d6423SLionel Sambuc 	if (r != OK)
942433d6423SLionel Sambuc 	{
943433d6423SLionel Sambuc 		printf("inb failed for port 0x%x\n", port);
944433d6423SLionel Sambuc 		panic("sys_inb failed: %d", r);
945433d6423SLionel Sambuc 	}
946433d6423SLionel Sambuc 	return value;
947433d6423SLionel Sambuc }
948433d6423SLionel Sambuc 
inw(port_t port)949433d6423SLionel Sambuc u16_t inw(port_t port)
950433d6423SLionel Sambuc {
951433d6423SLionel Sambuc 	int r;
952433d6423SLionel Sambuc 	u32_t value;
953433d6423SLionel Sambuc 
954433d6423SLionel Sambuc 	r= sys_inw(port, &value);
955433d6423SLionel Sambuc 	if (r != OK)
956433d6423SLionel Sambuc 		panic("sys_inw failed: %d", r);
957433d6423SLionel Sambuc 	return (u16_t) value;
958433d6423SLionel Sambuc }
959433d6423SLionel Sambuc 
outb(port_t port,u8_t value)960433d6423SLionel Sambuc void outb(port_t port, u8_t value)
961433d6423SLionel Sambuc {
962433d6423SLionel Sambuc 	int r;
963433d6423SLionel Sambuc 
964433d6423SLionel Sambuc 	r= sys_outb(port, value);
965433d6423SLionel Sambuc 	if (r != OK)
966433d6423SLionel Sambuc 		panic("sys_outb failed: %d", r);
967433d6423SLionel Sambuc }
968433d6423SLionel Sambuc 
outw(port_t port,u16_t value)969433d6423SLionel Sambuc void outw(port_t port, u16_t value)
970433d6423SLionel Sambuc {
971433d6423SLionel Sambuc 	int r;
972433d6423SLionel Sambuc 
973433d6423SLionel Sambuc 	r= sys_outw(port, value);
974433d6423SLionel Sambuc 	if (r != OK)
975433d6423SLionel Sambuc 		panic("sys_outw failed: %d", r);
976433d6423SLionel Sambuc }
977433d6423SLionel Sambuc 
insb(port_t port,void * buf,size_t size)978433d6423SLionel Sambuc static void insb(port_t port, void *buf, size_t size)
979433d6423SLionel Sambuc {
980433d6423SLionel Sambuc 	int r;
981433d6423SLionel Sambuc 
9823913e490SDavid van Moolenbroek 	r= sys_insb(port, SELF, buf, size);
983433d6423SLionel Sambuc 	if (r != OK)
984433d6423SLionel Sambuc 		panic("sys_sdevio failed: %d", r);
985433d6423SLionel Sambuc }
986433d6423SLionel Sambuc 
insw(port_t port,void * buf,size_t size)9873913e490SDavid van Moolenbroek static void insw(port_t port, void *buf, size_t size)
988433d6423SLionel Sambuc {
989433d6423SLionel Sambuc 	int r;
990433d6423SLionel Sambuc 
9913913e490SDavid van Moolenbroek 	r= sys_insw(port, SELF, buf, size);
992433d6423SLionel Sambuc 	if (r != OK)
993433d6423SLionel Sambuc 		panic("sys_sdevio failed: %d", r);
994433d6423SLionel Sambuc }
995433d6423SLionel Sambuc 
996433d6423SLionel Sambuc /*
997433d6423SLionel Sambuc  * $PchId: dp8390.c,v 1.25 2005/02/10 17:32:07 philip Exp $
998433d6423SLionel Sambuc  */
999