xref: /minix/minix/drivers/net/dpeth/8390.c (revision 7f5f010b)
1 #include <assert.h>
2 /*
3 **  File:	8390.c		May  02, 2000
4 **
5 **  Author:	Giovanni Falzoni <gfalzoni@inwind.it>
6 **
7 **  This file contains an ethernet device driver for NICs
8 **  equipped with the National Semiconductor NS 8390 chip.
9 **  It has to be associated with the board specific driver.
10 **  Rewritten from Minix 2.0.0 ethernet driver dp8390.c
11 **  to extract the NS 8390 common functions.
12 */
13 
14 #include <minix/drivers.h>
15 #include <minix/com.h>
16 #include <net/gen/ether.h>
17 #include <net/gen/eth_io.h>
18 #include "dp.h"
19 
20 #if (ENABLE_DP8390 == 1)
21 
22 #define PIO16	0	/* NOTE: pio 16 functions missing */
23 
24 #include "8390.h"
25 
26 #if 0
27 #define	sys_nic2mem(srcOffs,dstProc,dstOffs,length) \
28 	sys_vircopy(SELF,dep->de_memsegm,(vir_bytes)(srcOffs),\
29 		    (dstProc),D,(vir_bytes)(dstOffs),length)
30 #endif
31 #if 0
32 #define	sys_user2nic_s(srcProc,grant,dstOffs,length) \
33 	sys_safecopyfrom((srcProc),(grant),0, \
34 		    (vir_bytes)(dstOffs),length,dep->de_memsegm)
35 #endif
36 
37 static char RdmaErrMsg[] = "remote dma failed to complete";
38 
39 /*
40 **  Name:	void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset);
41 **  Function:	Sets the board for reading/writing.
42 */
43 static void ns_rw_setup(const dpeth_t *dep, int mode, int size, u16_t offset)
44 {
45 
46   if (mode == CR_DM_RW) outb_reg0(dep, DP_ISR, ISR_RDC);
47   outb_reg0(dep, DP_RBCR0, size & 0xFF);
48   outb_reg0(dep, DP_RBCR1, (size >> 8) & 0xFF);
49   outb_reg0(dep, DP_RSAR0, offset & 0xFF);
50   outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF);
51   mode |= (CR_PS_P0 | CR_STA);
52   outb_reg0(dep, DP_CR, mode);
53   return;
54 }
55 
56 /*
57 **  Name:	void ns_start_xmit(dpeth_t *dep, int size, int pageno);
58 **  Function:	Sets the board for for transmitting and fires it.
59 */
60 static void ns_start_xmit(const dpeth_t * dep, int size, int pageno)
61 {
62 
63   outb_reg0(dep, DP_TPSR, pageno);
64   outb_reg0(dep, DP_TBCR1, size >> 8);
65   outb_reg0(dep, DP_TBCR0, size & 0xFF);
66   outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP);	/* Fires transmission */
67   return;
68 }
69 
70 /*
71 **  Name:	void mem_getblock(dpeth_t *dep, u16_t offset,
72 **  				int size, void *dst)
73 **  Function:	Reads a block of packet from board (shared memory).
74 */
75 static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
76 {
77   panic("mem_getblock: not converted to safecopies");
78 #if 0
79   sys_nic2mem(dep->de_linmem + offset, SELF, dst, size);
80   return;
81 #endif
82 }
83 
84 /*
85 **  Name:	void mem_nic2user(dpeth_t *dep, int pageno, int pktsize);
86 **  Function:	Copies a packet from board to user area (shared memory).
87 */
88 static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
89 {
90   panic("mem_nic2user: not converted to safecopies");
91 #if 0
92   phys_bytes offset;
93   iovec_dat_s_t *iovp = &dep->de_read_iovec;
94   int bytes, ix = 0;
95 
96 
97   /* Computes shared memory address (skipping receive header) */
98   offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
99 
100   do {				/* Reads chuncks of packet into user area */
101 
102 	bytes = iovp->iod_iovec[ix].iov_size;	/* Size of a chunck */
103 	if (bytes > pktsize) bytes = pktsize;
104 
105 	/* Reads from board to user area */
106 	if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
107 
108 		/* Circular buffer wrap-around */
109 		bytes = dep->de_stoppage * DP_PAGESIZE - offset;
110 		sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr,
111 			    iovp->iod_iovec[ix].iov_grant, bytes);
112 		pktsize -= bytes;
113 		phys_user += bytes;
114 		bytes = iovp->iod_iovec[ix].iov_size - bytes;
115 		if (bytes > pktsize) bytes = pktsize;
116 		offset = dep->de_startpage * DP_PAGESIZE;
117 	}
118 	sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr,
119 		    iovp->iod_iovec[ix].iov_grant, bytes);
120 	offset += bytes;
121 
122 	if (++ix >= IOVEC_NR) {	/* Next buffer of IO vector */
123 		dp_next_iovec(iovp);
124 		ix = 0;
125 	}
126 	/* Till packet done */
127   } while ((pktsize -= bytes) > 0);
128   return;
129 #endif
130 }
131 
132 /*
133 **  Name:	void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
134 **  Function:	Copies a packet from user area to board (shared memory).
135 */
136 static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
137 {
138 #if 1
139   panic("mem_user2nic: not converted to safecopies");
140 #else
141   phys_bytes offset, phys_user;
142   iovec_dat_s_t *iovp = &dep->de_write_iovec;
143   int bytes, ix = 0;
144 
145   /* Computes shared memory address */
146   offset = pageno * DP_PAGESIZE;
147 
148   do {				/* Reads chuncks of packet from user area */
149 
150 	bytes = iovp->iod_iovec[ix].iov_size;	/* Size of chunck */
151 	if (bytes > pktsize) bytes = pktsize;
152 
153 	/* Reads from user area to board (shared memory) */
154 	sys_user2nic_s(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
155 		     dep->de_linmem + offset, bytes);
156 	offset += bytes;
157 
158 	if (++ix >= IOVEC_NR) {	/* Next buffer of IO vector */
159 		dp_next_iovec(iovp);
160 		ix = 0;
161 	}
162 	/* Till packet done */
163   } while ((pktsize -= bytes) > 0);
164   return;
165 #endif
166 }
167 
168 /*
169 **  Name:	void pio_getblock(dpeth_t *dep, u16_t offset,
170 **  				int size, void *dst)
171 **  Function:	Reads a block of packet from board (Prog. I/O).
172 */
173 static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
174 {
175 
176   /* Sets up board for reading */
177   ns_rw_setup(dep, CR_DM_RR, size, offset);
178 
179 #if PIO16 == 0
180   insb(dep->de_data_port, SELF, dst, size);
181 #else
182   if (dep->de_16bit == TRUE) {
183 	insw(dep->de_data_port, dst, size);
184   } else {
185 	insb(dep->de_data_port, dst, size);
186   }
187 #endif
188   return;
189 }
190 
191 /*
192 **  Name:	void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
193 **  Function:	Copies a packet from board to user area (Prog. I/O).
194 */
195 static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
196 {
197   iovec_dat_s_t *iovp = &dep->de_read_iovec;
198   unsigned offset, iov_offset; int r, bytes, ix = 0;
199 
200   /* Computes memory address (skipping receive header) */
201   offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
202   /* Sets up board for reading */
203   ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ?
204 	(dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset);
205 
206   iov_offset= 0;
207   do {				/* Reads chuncks of packet into user area */
208 
209 	bytes = iovp->iod_iovec[ix].iov_size;	/* Size of a chunck */
210 	if (bytes > pktsize) bytes = pktsize;
211 
212 	if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
213 
214 		/* Circular buffer wrap-around */
215 		bytes = dep->de_stoppage * DP_PAGESIZE - offset;
216 		r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
217 			iovp->iod_iovec[ix].iov_grant, iov_offset, bytes);
218 		if (r != OK) {
219 			panic("pio_nic2user: sys_safe_insb failed: %d", 				r);
220 		}
221 		pktsize -= bytes;
222 		iov_offset += bytes;
223 		bytes = iovp->iod_iovec[ix].iov_size - bytes;
224 		if (bytes > pktsize) bytes = pktsize;
225 		offset = dep->de_startpage * DP_PAGESIZE;
226   		ns_rw_setup(dep, CR_DM_RR, pktsize, offset);
227 	}
228 	r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
229 		iovp->iod_iovec[ix].iov_grant, iov_offset, bytes);
230 	if (r != OK)
231 		panic("pio_nic2user: sys_safe_insb failed: %d", r);
232 	offset += bytes;
233 
234 	if (++ix >= IOVEC_NR) {	/* Next buffer of IO vector */
235 		dp_next_iovec(iovp);
236 		ix = 0;
237 	}
238 	iov_offset= 0;
239 	/* Till packet done */
240   } while ((pktsize -= bytes) > 0);
241   return;
242 }
243 
244 /*
245 **  Name:	void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
246 **  Function:	Copies a packet from user area to board (Prog. I/O).
247 */
248 static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
249 {
250   iovec_dat_s_t *iovp = &dep->de_write_iovec;
251   int r, bytes, ix = 0;
252 
253   /* Sets up board for writing */
254   ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE);
255 
256   do {				/* Reads chuncks of packet from user area */
257 
258 	bytes = iovp->iod_iovec[ix].iov_size;	/* Size of chunck */
259 	if (bytes > pktsize) bytes = pktsize;
260 	r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr,
261 	      iovp->iod_iovec[ix].iov_grant, 0, bytes);
262 	if (r != OK)
263 		panic("pio_user2nic: sys_safe_outsb failed: %d", r);
264 
265 	if (++ix >= IOVEC_NR) {	/* Next buffer of I/O vector */
266 		dp_next_iovec(iovp);
267 		ix = 0;
268 	}
269 	/* Till packet done */
270   } while ((pktsize -= bytes) > 0);
271 
272   for (ix = 0; ix < 100; ix += 1) {
273 	if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
274   }
275   if (ix == 100) {
276 	panic("%s", RdmaErrMsg);
277   }
278   return;
279 }
280 
281 /*
282 **  Name:	void ns_stats(dpeth_t * dep)
283 **  Function:	Updates counters reading from device
284 */
285 static void ns_stats(dpeth_t * dep)
286 {
287 
288   dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
289   dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
290   dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
291   return;
292 }
293 
294 /*
295 **  Name:	void ns_dodump(dpeth_t * dep)
296 **  Function:	Displays statistics (a request from F5 key).
297 */
298 static void ns_dodump(dpeth_t * dep)
299 {
300 
301   ns_stats(dep);		/* Forces reading fo counters from board */
302   return;
303 }
304 
305 /*
306 **  Name:	void ns_reinit(dpeth_t *dep)
307 **  Function:	Updates receiver configuration.
308 */
309 static void ns_reinit(dpeth_t * dep)
310 {
311   int dp_reg = 0;
312 
313   if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
314   if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
315   if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
316   outb_reg0(dep, DP_CR, CR_PS_P0);
317   outb_reg0(dep, DP_RCR, dp_reg);
318   return;
319 }
320 
321 /*
322 **  Name:	void ns_send(dpeth_t * dep, int from_int, int size)
323 **  Function:	Transfers packet to device and starts sending.
324 */
325 static void ns_send(dpeth_t * dep, int from_int, int size)
326 {
327   int queue;
328 
329   if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) {
330 	if (from_int) panic("should not be sending ");
331 	dep->de_send_s = size;
332 	return;
333   }
334   (dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size);
335   dep->bytes_Tx += (long) size;
336   dep->de_sendq[queue].sq_filled = TRUE;
337   dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
338   if (dep->de_sendq_tail == queue) {	/* there it goes.. */
339 	ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage);
340   } else
341 	dep->de_sendq[queue].sq_size = size;
342 
343   if (++queue == dep->de_sendq_nr) queue = 0;
344   dep->de_sendq_head = queue;
345   dep->de_flags &= NOT(DEF_SENDING);
346 
347   return;
348 }
349 
350 /*
351 **  Name:	void ns_reset(dpeth_t *dep)
352 **  Function:	Resets device.
353 */
354 static void ns_reset(dpeth_t * dep)
355 {
356   int ix;
357 
358   /* Stop chip */
359   outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA);
360   outb_reg0(dep, DP_RBCR0, 0);
361   outb_reg0(dep, DP_RBCR1, 0);
362   for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1)
363 	 /* Do nothing */ ;
364   outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
365   outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);
366   outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST);
367 
368   /* Acknowledge the ISR_RDC (remote dma) interrupt. */
369   for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1)
370 	 /* Do nothing */ ;
371   outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC));
372 
373   /* Reset the transmit ring. If we were transmitting a packet, we
374    * pretend that the packet is processed. Higher layers will
375    * retransmit if the packet wasn't actually sent. */
376   dep->de_sendq_head = dep->de_sendq_tail = 0;
377   for (ix = 0; ix < dep->de_sendq_nr; ix++)
378 	dep->de_sendq[ix].sq_filled = FALSE;
379   ns_send(dep, TRUE, dep->de_send_s);
380   return;
381 }
382 
383 /*
384 **  Name:	void ns_recv(dpeth_t *dep, int fromint, int size)
385 **  Function:	Gets a packet from device
386 */
387 static void ns_recv(dpeth_t *dep, int fromint, int size)
388 {
389   dp_rcvhdr_t header;
390   unsigned pageno, curr, next;
391   vir_bytes length;
392   int packet_processed = FALSE;
393 #ifdef ETH_IGN_PROTO
394   u16_t eth_type;
395 #endif
396 
397   pageno = inb_reg0(dep, DP_BNRY) + 1;
398   if (pageno == dep->de_stoppage) pageno = dep->de_startpage;
399 
400   do {
401 	/* */
402 	outb_reg0(dep, DP_CR, CR_PS_P1);
403 	curr = inb_reg1(dep, DP_CURR);
404 	outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA);
405 
406 	if (curr == pageno) break;
407 
408 	(dep->de_getblockf) (dep, pageno * DP_PAGESIZE, sizeof(header), &header);
409 #ifdef ETH_IGN_PROTO
410 	(dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), &eth_type);
411 #endif
412 	length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t);
413 	next = header.dr_next;
414 
415 	if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) {
416 		printf("%s: packet with strange length arrived: %ld\n",
417 			dep->de_name, length);
418 		dep->de_stat.ets_recvErr += 1;
419 		next = curr;
420 
421 	} else if (next < dep->de_startpage || next >= dep->de_stoppage) {
422 		printf("%s: strange next page\n", dep->de_name);
423 		dep->de_stat.ets_recvErr += 1;
424 		next = curr;
425 
426 #ifdef ETH_IGN_PROTO
427 	} else if (eth_type == eth_ign_proto) {
428 		/* Hack: ignore packets of a given protocol */
429 		static int first = TRUE;
430 		if (first) {
431 			first = FALSE;
432 			printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto));
433 		}
434 		next = curr;
435 #endif
436 	} else if (header.dr_status & RSR_FO) {
437 		/* This is very serious, issue a warning and reset buffers */
438 		printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name);
439 		dep->de_stat.ets_fifoOver += 1;
440 		next = curr;
441 
442 	} else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) {
443 
444 		if (!(dep->de_flags & DEF_READING)) break;
445 
446 		(dep->de_nic2userf) (dep, pageno, length);
447 		dep->de_read_s = length;
448 		dep->de_flags |= DEF_ACK_RECV;
449 		dep->de_flags &= NOT(DEF_READING);
450 		packet_processed = TRUE;
451 	}
452 	dep->bytes_Rx += (long) length;
453 	dep->de_stat.ets_packetR += 1;
454 	outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1);
455 	pageno = next;
456 
457   } while (!packet_processed);
458 #if 0
459   if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
460 	/* The chip is stopped, and all arrived packets delivered */
461 	(*dep->de_resetf) (dep);
462   dep->de_flags &= NOT(DEF_STOPPED);
463 #endif
464   return;
465 }
466 
467 /*
468 **  Name:	void ns_interrupt(dpeth_t * dep)
469 **  Function:	Handles interrupt.
470 */
471 static void ns_interrupt(dpeth_t * dep)
472 {
473   int isr, tsr;
474   int queue;
475 
476   while ((isr = inb_reg0(dep, DP_ISR)) != 0) {
477 
478 	outb_reg0(dep, DP_ISR, isr);
479 	if (isr & (ISR_PTX | ISR_TXE)) {
480 
481 		tsr = inb_reg0(dep, DP_TSR);
482 		if (tsr & TSR_PTX) {
483 			dep->de_stat.ets_packetT++;
484 		}
485 		if (tsr & TSR_COL) dep->de_stat.ets_collision++;
486 		if (tsr & (TSR_ABT | TSR_FU)) {
487 			dep->de_stat.ets_fifoUnder++;
488 		}
489 		if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) {
490 			printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr);
491 			dep->de_stat.ets_sendErr++;
492 		}
493 		queue = dep->de_sendq_tail;
494 
495 		if (!(dep->de_sendq[queue].sq_filled)) {	/* Hardware bug? */
496 			printf("%s: transmit interrupt, but not sending\n", dep->de_name);
497 			continue;
498 		}
499 		dep->de_sendq[queue].sq_filled = FALSE;
500 		if (++queue == dep->de_sendq_nr) queue = 0;
501 		dep->de_sendq_tail = queue;
502 		if (dep->de_sendq[queue].sq_filled) {
503 			ns_start_xmit(dep, dep->de_sendq[queue].sq_size,
504 				dep->de_sendq[queue].sq_sendpage);
505 		}
506 		if (dep->de_flags & DEF_SENDING) {
507 			ns_send(dep, TRUE, dep->de_send_s);
508 		}
509 	}
510 	if (isr & ISR_PRX) {
511 		ns_recv(dep, TRUE, 0);
512 	}
513 	if (isr & ISR_RXE) {
514 		printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR));
515 		dep->de_stat.ets_recvErr++;
516 	}
517 	if (isr & ISR_CNT) {
518 		dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
519 		dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
520 		dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
521 	}
522 	if (isr & ISR_OVW) {
523 		printf("%s: got overwrite warning\n", dep->de_name);
524 	}
525 	if (isr & ISR_RDC) {
526 		/* Nothing to do */
527 	}
528 	if (isr & ISR_RST) {
529 		/* This means we got an interrupt but the ethernet
530 		 * chip is shutdown. We set the flag DEF_STOPPED, and
531 		 * continue processing arrived packets. When the
532 		 * receive buffer is empty, we reset the dp8390. */
533 		printf("%s: network interface stopped\n", dep->de_name);
534 		dep->de_flags |= DEF_STOPPED;
535 		break;
536 	}
537   }
538   if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) {
539 
540 	/* The chip is stopped, and all arrived packets delivered */
541 	ns_reset(dep);
542 	dep->de_flags &= NOT(DEF_STOPPED);
543   }
544   return;
545 }
546 
547 /*
548 **  Name:	void ns_init(dpeth_t *dep)
549 **  Function:	Initializes the NS 8390
550 */
551 void ns_init(dpeth_t * dep)
552 {
553   int dp_reg;
554   int ix;
555 
556   /* NS8390 initialization (as recommended in National Semiconductor specs) */
557   outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA);	/* 0x21 */
558 #if PIO16 == 0
559   outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
560 #else
561   outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) |
562 			DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
563 #endif
564   outb_reg0(dep, DP_RBCR0, 0);
565   outb_reg0(dep, DP_RBCR1, 0);
566   outb_reg0(dep, DP_RCR, RCR_MON);	/* Sets Monitor mode */
567   outb_reg0(dep, DP_TCR, TCR_INTERNAL);	/* Sets Loopback mode 1 */
568   outb_reg0(dep, DP_PSTART, dep->de_startpage);
569   outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
570   outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
571   outb_reg0(dep, DP_ISR, 0xFF);	/* Clears Interrupt Status Register */
572   outb_reg0(dep, DP_IMR, 0);	/* Clears Interrupt Mask Register */
573 
574   /* Copies station address in page 1 registers */
575   outb_reg0(dep, DP_CR, CR_PS_P1 | CR_NO_DMA);	/* Selects Page 1 */
576   for (ix = 0; ix < SA_ADDR_LEN; ix += 1)	/* Initializes address */
577 	outb_reg1(dep, DP_PAR0 + ix, dep->de_address.ea_addr[ix]);
578   for (ix = DP_MAR0; ix <= DP_MAR7; ix += 1)	/* Initializes address */
579 	outb_reg1(dep, ix, 0xFF);
580 
581   outb_reg1(dep, DP_CURR, dep->de_startpage);
582   outb_reg1(dep, DP_CR, CR_PS_P0 | CR_NO_DMA);	/* Selects Page 0 */
583 
584   inb_reg0(dep, DP_CNTR0);	/* Resets counters by reading them */
585   inb_reg0(dep, DP_CNTR1);
586   inb_reg0(dep, DP_CNTR2);
587 
588   dp_reg = IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE;
589   outb_reg0(dep, DP_ISR, 0xFF);	/* Clears Interrupt Status Register */
590   outb_reg0(dep, DP_IMR, dp_reg);	/* Sets Interrupt Mask register */
591 
592   dp_reg = 0;
593   if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
594   if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
595   if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
596   outb_reg0(dep, DP_RCR, dp_reg);	/* Sets receive as requested */
597   outb_reg0(dep, DP_TCR, TCR_NORMAL);	/* Sets transmitter */
598 
599   outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);	/* Starts board */
600 
601   /* Initializes the send queue. */
602   for (ix = 0; ix < dep->de_sendq_nr; ix += 1)
603 	dep->de_sendq[ix].sq_filled = 0;
604   dep->de_sendq_head = dep->de_sendq_tail = 0;
605 
606   /* Device specific functions */
607   if (!dep->de_prog_IO) {
608 	dep->de_user2nicf = mem_user2nic;
609 	dep->de_nic2userf = mem_nic2user;
610 	dep->de_getblockf = mem_getblock;
611   } else {
612 #if PIO16 == 0
613 	dep->de_user2nicf = pio_user2nic;
614 	dep->de_nic2userf = pio_nic2user;
615 	dep->de_getblockf = pio_getblock;
616 #else
617 #error	Missing I/O functions for pio 16 bits
618 #endif
619   }
620   dep->de_recvf = ns_recv;
621   dep->de_sendf = ns_send;
622   dep->de_flagsf = ns_reinit;
623   dep->de_resetf = ns_reset;
624   dep->de_getstatsf = ns_stats;
625   dep->de_dumpstatsf = ns_dodump;
626   dep->de_interruptf = ns_interrupt;
627 
628   return;			/* Done */
629 }
630 
631 #if PIO16 == 1
632 
633 /*
634 **  Name:	void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
635 **  Function:	Copies a packet from user area to board (Prog. I/O, 16bits).
636 */
637 static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
638 {
639   u8_t two_bytes[2];
640   phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes);
641   vir_bytes ecount = (pktsize + 1) & NOT(0x0001);
642   int bytes, ix = 0, odd_byte = 0;
643   iovec_dat_t *iovp = &dep->de_write_iovec;
644 
645   outb_reg0(dep, DP_ISR, ISR_RDC);
646   dp_read_setup(dep, ecount, pageno * DP_PAGESIZE);
647 
648   do {
649 	bytes = iovp->iod_iovec[ix].iov_size;
650 	if (bytes > pktsize) bytes = pktsize;
651 
652 	phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes);
653 	if (!phys_user) panic(UmapErrMsg);
654 
655 	if (odd_byte) {
656 		phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1);
657 		out_word(dep->de_data_port, *(u16_t *)two_bytes);
658 		pktsize--;
659 		bytes--;
660 		phys_user++;
661 		odd_byte = 0;
662 		if (!bytes) continue;
663 	}
664 	ecount = bytes & NOT(0x0001);
665 	if (ecount != 0) {
666 		phys_outsw(dep->de_data_port, phys_user, ecount);
667 		pktsize -= ecount;
668 		bytes -= ecount;
669 		phys_user += ecount;
670 	}
671 	if (bytes) {
672 		phys_copy(phys_user, phys_2bytes, (phys_bytes) 1);
673 		pktsize--;
674 		bytes--;
675 		phys_user++;
676 		odd_byte = 1;
677 	}
678 	if (++ix >= IOVEC_NR) {	/* Next buffer of I/O vector */
679 		dp_next_iovec(iovp);
680 		ix = 0;
681 	}
682 
683   }  while (bytes > 0);
684 
685   if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes);
686   for (ix = 0; ix < 100; ix++) {
687 	if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
688   }
689   if (ix == 100) {
690 	panic(RdmaErrMsg);
691   }
692   return;
693 }
694 
695 /*
696 **  Name:	void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize)
697 **  Function:	Copies a packet from board to user area (Prog. I/O, 16bits).
698 */
699 static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count)
700 {
701   phys_bytes phys_user;
702   vir_bytes ecount;
703   int bytes, i;
704   u8_t two_bytes[2];
705   phys_bytes phys_2bytes;
706   int odd_byte;
707 
708   ecount = (count + 1) & ~1;
709   phys_2bytes = vir2phys(two_bytes);
710   odd_byte = 0;
711 
712   dp_read_setup(dep, ecount, nic_addr);
713 
714   i = 0;
715   while (count > 0) {
716 	if (i >= IOVEC_NR) {
717 		dp_next_iovec(iovp);
718 		i = 0;
719 		continue;
720 	}
721 	bytes = iovp->iod_iovec[i].iov_size;
722 	if (bytes > count) bytes = count;
723 
724 	phys_user = numap(iovp->iod_proc_nr,
725 			  iovp->iod_iovec[i].iov_addr, bytes);
726 	if (!phys_user) panic(UmapErrMsg);
727 	if (odd_byte) {
728 		phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1);
729 		count--;
730 		bytes--;
731 		phys_user++;
732 		odd_byte = 0;
733 		if (!bytes) continue;
734 	}
735 	ecount = bytes & ~1;
736 	if (ecount != 0) {
737 		phys_insw(dep->de_data_port, phys_user, ecount);
738 		count -= ecount;
739 		bytes -= ecount;
740 		phys_user += ecount;
741 	}
742 	if (bytes) {
743 		*(u16_t *) two_bytes = in_word(dep->de_data_port);
744 		phys_copy(phys_2bytes, phys_user, (phys_bytes) 1);
745 		count--;
746 		bytes--;
747 		phys_user++;
748 		odd_byte = 1;
749 	}
750   }
751   return;
752 }
753 
754 #endif				/* PIO16 == 1 */
755 
756 #endif				/* ENABLE_DP8390 */
757 
758 /** end 8390.c **/
759