dec21140A ethernet driver for virtualpc, contributed by nicolas tittley.
[minix.git] / drivers / dpeth / 8390.c
blob8f6ecb5e791273a5b7c4fbe69cf79d9b13230b49
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.
13 ** $Id$
16 #include "drivers.h"
17 #include <minix/com.h>
18 #include <net/hton.h>
19 #include <net/gen/ether.h>
20 #include <net/gen/eth_io.h>
21 #include "dp.h"
23 #if (ENABLE_DP8390 == 1)
25 #define PIO16 0 /* NOTE: pio 16 functions missing */
27 #include "8390.h"
29 #if 0
30 #define sys_nic2mem(srcOffs,dstProc,dstOffs,length) \
31 sys_vircopy(SELF,dep->de_memsegm,(vir_bytes)(srcOffs),\
32 (dstProc),D,(vir_bytes)(dstOffs),length)
33 #endif
34 #if 0
35 #define sys_user2nic_s(srcProc,grant,dstOffs,length) \
36 sys_safecopyfrom((srcProc),(grant),0, \
37 (vir_bytes)(dstOffs),length,dep->de_memsegm)
38 #endif
40 static char RdmaErrMsg[] = "remote dma failed to complete";
43 ** Name: void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset);
44 ** Function: Sets the board for reading/writing.
46 static void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset)
49 if (mode == CR_DM_RW) outb_reg0(dep, DP_ISR, ISR_RDC);
50 outb_reg0(dep, DP_RBCR0, size & 0xFF);
51 outb_reg0(dep, DP_RBCR1, (size >> 8) & 0xFF);
52 outb_reg0(dep, DP_RSAR0, offset & 0xFF);
53 outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF);
54 mode |= (CR_PS_P0 | CR_STA);
55 outb_reg0(dep, DP_CR, mode);
56 return;
60 ** Name: void ns_start_xmit(dpeth_t *dep, int size, int pageno);
61 ** Function: Sets the board for for transmitting and fires it.
63 static void ns_start_xmit(dpeth_t * dep, int size, int pageno)
66 outb_reg0(dep, DP_TPSR, pageno);
67 outb_reg0(dep, DP_TBCR1, size >> 8);
68 outb_reg0(dep, DP_TBCR0, size & 0xFF);
69 outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP); /* Fires transmission */
70 return;
74 ** Name: void mem_getblock(dpeth_t *dep, u16_t offset,
75 ** int size, void *dst)
76 ** Function: Reads a block of packet from board (shared memory).
78 static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
80 panic(__FILE__, "mem_getblock: not converted to safecopies", NO_NUM);
81 #if 0
82 sys_nic2mem(dep->de_linmem + offset, SELF, dst, size);
83 return;
84 #endif
88 ** Name: void mem_nic2user(dpeth_t *dep, int pageno, int pktsize);
89 ** Function: Copies a packet from board to user area (shared memory).
91 static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
93 phys_bytes offset;
94 iovec_dat_s_t *iovp = &dep->de_read_iovec;
95 int bytes, ix = 0;
97 panic(__FILE__, "mem_nic2user: not converted to safecopies", NO_NUM);
98 #if 0
100 /* Computes shared memory address (skipping receive header) */
101 offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
103 do { /* Reads chuncks of packet into user area */
105 bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
106 if (bytes > pktsize) bytes = pktsize;
108 /* Reads from board to user area */
109 if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
111 /* Circular buffer wrap-around */
112 bytes = dep->de_stoppage * DP_PAGESIZE - offset;
113 sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr,
114 iovp->iod_iovec[ix].iov_grant, bytes);
115 pktsize -= bytes;
116 phys_user += bytes;
117 bytes = iovp->iod_iovec[ix].iov_size - bytes;
118 if (bytes > pktsize) bytes = pktsize;
119 offset = dep->de_startpage * DP_PAGESIZE;
121 sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr,
122 iovp->iod_iovec[ix].iov_grant, bytes);
123 offset += bytes;
125 if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
126 dp_next_iovec(iovp);
127 ix = 0;
129 /* Till packet done */
130 } while ((pktsize -= bytes) > 0);
131 return;
132 #endif
136 ** Name: void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
137 ** Function: Copies a packet from user area to board (shared memory).
139 static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
141 phys_bytes offset, phys_user;
142 iovec_dat_s_t *iovp = &dep->de_write_iovec;
143 int bytes, ix = 0;
145 panic(__FILE__, "mem_user2nic: not converted to safecopies", NO_NUM);
146 #if 0
148 /* Computes shared memory address */
149 offset = pageno * DP_PAGESIZE;
151 do { /* Reads chuncks of packet from user area */
153 bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
154 if (bytes > pktsize) bytes = pktsize;
156 /* Reads from user area to board (shared memory) */
157 sys_user2nic_s(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
158 dep->de_linmem + offset, bytes);
159 offset += bytes;
161 if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
162 dp_next_iovec(iovp);
163 ix = 0;
165 /* Till packet done */
166 } while ((pktsize -= bytes) > 0);
167 return;
168 #endif
172 ** Name: void pio_getblock(dpeth_t *dep, u16_t offset,
173 ** int size, void *dst)
174 ** Function: Reads a block of packet from board (Prog. I/O).
176 static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
179 /* Sets up board for reading */
180 ns_rw_setup(dep, CR_DM_RR, size, offset);
182 #if PIO16 == 0
183 insb(dep->de_data_port, SELF, dst, size);
184 #else
185 if (dep->de_16bit == TRUE) {
186 insw(dep->de_data_port, dst, size);
187 } else {
188 insb(dep->de_data_port, dst, size);
190 #endif
191 return;
195 ** Name: void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
196 ** Function: Copies a packet from board to user area (Prog. I/O).
198 static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
200 iovec_dat_s_t *iovp = &dep->de_read_iovec;
201 unsigned offset, iov_offset; int r, bytes, ix = 0;
203 /* Computes memory address (skipping receive header) */
204 offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
205 /* Sets up board for reading */
206 ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ?
207 (dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset);
209 iov_offset= 0;
210 do { /* Reads chuncks of packet into user area */
212 bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
213 if (bytes > pktsize) bytes = pktsize;
215 if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
217 /* Circular buffer wrap-around */
218 bytes = dep->de_stoppage * DP_PAGESIZE - offset;
219 r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
220 iovp->iod_iovec[ix].iov_grant, iov_offset, bytes);
221 if (r != OK)
223 panic(__FILE__, "pio_nic2user: sys_safe_insb failed",
226 pktsize -= bytes;
227 iov_offset += bytes;
228 bytes = iovp->iod_iovec[ix].iov_size - bytes;
229 if (bytes > pktsize) bytes = pktsize;
230 offset = dep->de_startpage * DP_PAGESIZE;
231 ns_rw_setup(dep, CR_DM_RR, pktsize, offset);
233 r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
234 iovp->iod_iovec[ix].iov_grant, iov_offset, bytes);
235 if (r != OK)
236 panic(__FILE__, "pio_nic2user: sys_safe_insb failed", r);
237 offset += bytes;
239 if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
240 dp_next_iovec(iovp);
241 ix = 0;
243 iov_offset= 0;
244 /* Till packet done */
245 } while ((pktsize -= bytes) > 0);
246 return;
250 ** Name: void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
251 ** Function: Copies a packet from user area to board (Prog. I/O).
253 static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
255 iovec_dat_s_t *iovp = &dep->de_write_iovec;
256 int r, bytes, ix = 0;
258 /* Sets up board for writing */
259 ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE);
261 do { /* Reads chuncks of packet from user area */
263 bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
264 if (bytes > pktsize) bytes = pktsize;
265 r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr,
266 iovp->iod_iovec[ix].iov_grant, 0, bytes);
267 if (r != OK)
268 panic(__FILE__, "pio_user2nic: sys_safe_outsb failed", r);
270 if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
271 dp_next_iovec(iovp);
272 ix = 0;
274 /* Till packet done */
275 } while ((pktsize -= bytes) > 0);
277 for (ix = 0; ix < 100; ix += 1) {
278 if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
280 if (ix == 100) {
281 panic(dep->de_name, RdmaErrMsg, NO_NUM);
283 return;
287 ** Name: void ns_stats(dpeth_t * dep)
288 ** Function: Updates counters reading from device
290 static void ns_stats(dpeth_t * dep)
293 dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
294 dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
295 dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
296 return;
300 ** Name: void ns_dodump(dpeth_t * dep)
301 ** Function: Displays statistics (a request from F5 key).
303 static void ns_dodump(dpeth_t * dep)
306 ns_stats(dep); /* Forces reading fo counters from board */
307 return;
311 ** Name: void ns_reinit(dpeth_t *dep)
312 ** Function: Updates receiver configuration.
314 static void ns_reinit(dpeth_t * dep)
316 int dp_reg = 0;
318 if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
319 if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
320 if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
321 outb_reg0(dep, DP_CR, CR_PS_P0);
322 outb_reg0(dep, DP_RCR, dp_reg);
323 return;
327 ** Name: void ns_send(dpeth_t * dep, int from_int, int size)
328 ** Function: Transfers packet to device and starts sending.
330 static void ns_send(dpeth_t * dep, int from_int, int size)
332 int queue;
334 if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) {
335 if (from_int) panic(dep->de_name, "should not be sending ", NO_NUM);
336 dep->de_send_s = size;
337 return;
339 (dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size);
340 dep->bytes_Tx += (long) size;
341 dep->de_sendq[queue].sq_filled = TRUE;
342 dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
343 if (dep->de_sendq_tail == queue) { /* there it goes.. */
344 ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage);
345 } else
346 dep->de_sendq[queue].sq_size = size;
348 if (++queue == dep->de_sendq_nr) queue = 0;
349 dep->de_sendq_head = queue;
350 dep->de_flags &= NOT(DEF_SENDING);
352 return;
356 ** Name: void ns_reset(dpeth_t *dep)
357 ** Function: Resets device.
359 static void ns_reset(dpeth_t * dep)
361 int ix;
363 /* Stop chip */
364 outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA);
365 outb_reg0(dep, DP_RBCR0, 0);
366 outb_reg0(dep, DP_RBCR1, 0);
367 for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1)
368 /* Do nothing */ ;
369 outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
370 outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);
371 outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST);
373 /* Acknowledge the ISR_RDC (remote dma) interrupt. */
374 for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1)
375 /* Do nothing */ ;
376 outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC));
378 /* Reset the transmit ring. If we were transmitting a packet, we
379 * pretend that the packet is processed. Higher layers will
380 * retransmit if the packet wasn't actually sent. */
381 dep->de_sendq_head = dep->de_sendq_tail = 0;
382 for (ix = 0; ix < dep->de_sendq_nr; ix++)
383 dep->de_sendq[ix].sq_filled = FALSE;
384 ns_send(dep, TRUE, dep->de_send_s);
385 return;
389 ** Name: void ns_recv(dpeth_t *dep, int fromint, int size)
390 ** Function: Gets a packet from device
392 static void ns_recv(dpeth_t *dep, int fromint, int size)
394 dp_rcvhdr_t header;
395 dp_rcvhdr_t dummy;
396 unsigned pageno, curr, next;
397 vir_bytes length;
398 int packet_processed = FALSE;
399 #ifdef ETH_IGN_PROTO
400 u16_t eth_type;
401 #endif
403 pageno = inb_reg0(dep, DP_BNRY) + 1;
404 if (pageno == dep->de_stoppage) pageno = dep->de_startpage;
406 do {
407 /* */
408 outb_reg0(dep, DP_CR, CR_PS_P1);
409 curr = inb_reg1(dep, DP_CURR);
410 outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA);
412 if (curr == pageno) break;
414 (dep->de_getblockf) (dep, pageno * DP_PAGESIZE, sizeof(header), &header);
415 #ifdef ETH_IGN_PROTO
416 (dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), &eth_type);
417 #endif
418 length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t);
419 next = header.dr_next;
421 if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) {
422 printf("%s: packet with strange length arrived: %d\n", dep->de_name, length);
423 dep->de_stat.ets_recvErr += 1;
424 next = curr;
426 } else if (next < dep->de_startpage || next >= dep->de_stoppage) {
427 printf("%s: strange next page\n", dep->de_name);
428 dep->de_stat.ets_recvErr += 1;
429 next = curr;
431 #ifdef ETH_IGN_PROTO
432 } else if (eth_type == eth_ign_proto) {
433 /* Hack: ignore packets of a given protocol */
434 static int first = TRUE;
435 if (first) {
436 first = FALSE;
437 printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto));
439 next = curr;
440 #endif
441 } else if (header.dr_status & RSR_FO) {
442 /* This is very serious, issue a warning and reset buffers */
443 printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name);
444 dep->de_stat.ets_fifoOver += 1;
445 next = curr;
447 } else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) {
449 if (!(dep->de_flags & DEF_READING)) break;
451 (dep->de_nic2userf) (dep, pageno, length);
452 dep->de_read_s = length;
453 dep->de_flags |= DEF_ACK_RECV;
454 dep->de_flags &= NOT(DEF_READING);
455 packet_processed = TRUE;
457 dep->bytes_Rx += (long) length;
458 dep->de_stat.ets_packetR += 1;
459 outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1);
460 pageno = next;
462 } while (!packet_processed);
463 #if 0
464 if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
465 /* The chip is stopped, and all arrived packets delivered */
466 (*dep->de_resetf) (dep);
467 dep->de_flags &= NOT(DEF_STOPPED);
468 #endif
469 return;
473 ** Name: void ns_interrupt(dpeth_t * dep)
474 ** Function: Handles interrupt.
476 static void ns_interrupt(dpeth_t * dep)
478 int isr, tsr;
479 int queue;
481 while ((isr = inb_reg0(dep, DP_ISR)) != 0) {
483 outb_reg0(dep, DP_ISR, isr);
484 if (isr & (ISR_PTX | ISR_TXE)) {
486 tsr = inb_reg0(dep, DP_TSR);
487 if (tsr & TSR_PTX) {
488 dep->de_stat.ets_packetT++;
490 if (tsr & TSR_COL) dep->de_stat.ets_collision++;
491 if (tsr & (TSR_ABT | TSR_FU)) {
492 dep->de_stat.ets_fifoUnder++;
494 if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) {
495 printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr);
496 dep->de_stat.ets_sendErr++;
498 queue = dep->de_sendq_tail;
500 if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */
501 printf("%s: transmit interrupt, but not sending\n", dep->de_name);
502 continue;
504 dep->de_sendq[queue].sq_filled = FALSE;
505 if (++queue == dep->de_sendq_nr) queue = 0;
506 dep->de_sendq_tail = queue;
507 if (dep->de_sendq[queue].sq_filled) {
508 ns_start_xmit(dep, dep->de_sendq[queue].sq_size,
509 dep->de_sendq[queue].sq_sendpage);
511 if (dep->de_flags & DEF_SENDING) {
512 ns_send(dep, TRUE, dep->de_send_s);
515 if (isr & ISR_PRX) {
516 ns_recv(dep, TRUE, 0);
518 if (isr & ISR_RXE) {
519 printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR));
520 dep->de_stat.ets_recvErr++;
522 if (isr & ISR_CNT) {
523 dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
524 dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
525 dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
527 if (isr & ISR_OVW) {
528 printf("%s: got overwrite warning\n", dep->de_name);
530 if (isr & ISR_RDC) {
531 /* Nothing to do */
533 if (isr & ISR_RST) {
534 /* This means we got an interrupt but the ethernet
535 * chip is shutdown. We set the flag DEF_STOPPED, and
536 * continue processing arrived packets. When the
537 * receive buffer is empty, we reset the dp8390. */
538 printf("%s: network interface stopped\n", dep->de_name);
539 dep->de_flags |= DEF_STOPPED;
540 break;
543 if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) {
545 /* The chip is stopped, and all arrived packets delivered */
546 ns_reset(dep);
547 dep->de_flags &= NOT(DEF_STOPPED);
549 return;
553 ** Name: void ns_init(dpeth_t *dep)
554 ** Function: Initializes the NS 8390
556 void ns_init(dpeth_t * dep)
558 int dp_reg;
559 int ix;
561 /* NS8390 initialization (as recommended in National Semiconductor specs) */
562 outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */
563 #if PIO16 == 0
564 outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
565 #else
566 outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) |
567 DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
568 #endif
569 outb_reg0(dep, DP_RBCR0, 0);
570 outb_reg0(dep, DP_RBCR1, 0);
571 outb_reg0(dep, DP_RCR, RCR_MON); /* Sets Monitor mode */
572 outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Sets Loopback mode 1 */
573 outb_reg0(dep, DP_PSTART, dep->de_startpage);
574 outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
575 outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
576 outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
577 outb_reg0(dep, DP_IMR, 0); /* Clears Interrupt Mask Register */
579 /* Copies station address in page 1 registers */
580 outb_reg0(dep, DP_CR, CR_PS_P1 | CR_NO_DMA); /* Selects Page 1 */
581 for (ix = 0; ix < SA_ADDR_LEN; ix += 1) /* Initializes address */
582 outb_reg1(dep, DP_PAR0 + ix, dep->de_address.ea_addr[ix]);
583 for (ix = DP_MAR0; ix <= DP_MAR7; ix += 1) /* Initializes address */
584 outb_reg1(dep, ix, 0xFF);
586 outb_reg1(dep, DP_CURR, dep->de_startpage);
587 outb_reg1(dep, DP_CR, CR_PS_P0 | CR_NO_DMA); /* Selects Page 0 */
589 inb_reg0(dep, DP_CNTR0); /* Resets counters by reading them */
590 inb_reg0(dep, DP_CNTR1);
591 inb_reg0(dep, DP_CNTR2);
593 dp_reg = IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE;
594 outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
595 outb_reg0(dep, DP_IMR, dp_reg); /* Sets Interrupt Mask register */
597 dp_reg = 0;
598 if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
599 if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
600 if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
601 outb_reg0(dep, DP_RCR, dp_reg); /* Sets receive as requested */
602 outb_reg0(dep, DP_TCR, TCR_NORMAL); /* Sets transmitter */
604 outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); /* Starts board */
606 /* Initializes the send queue. */
607 for (ix = 0; ix < dep->de_sendq_nr; ix += 1)
608 dep->de_sendq[ix].sq_filled = 0;
609 dep->de_sendq_head = dep->de_sendq_tail = 0;
611 /* Device specific functions */
612 if (!dep->de_prog_IO) {
613 dep->de_user2nicf = mem_user2nic;
614 dep->de_nic2userf = mem_nic2user;
615 dep->de_getblockf = mem_getblock;
616 } else {
617 #if PIO16 == 0
618 dep->de_user2nicf = pio_user2nic;
619 dep->de_nic2userf = pio_nic2user;
620 dep->de_getblockf = pio_getblock;
621 #else
622 #error Missing I/O functions for pio 16 bits
623 #endif
625 dep->de_recvf = ns_recv;
626 dep->de_sendf = ns_send;
627 dep->de_flagsf = ns_reinit;
628 dep->de_resetf = ns_reset;
629 dep->de_getstatsf = ns_stats;
630 dep->de_dumpstatsf = ns_dodump;
631 dep->de_interruptf = ns_interrupt;
633 return; /* Done */
636 #if PIO16 == 1
639 ** Name: void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
640 ** Function: Copies a packet from user area to board (Prog. I/O, 16bits).
642 static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
644 u8_t two_bytes[2];
645 phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes);
646 vir_bytes ecount = (pktsize + 1) & NOT(0x0001);
647 int bytes, ix = 0, odd_byte = 0;
648 iovec_dat_t *iovp = &dep->de_write_iovec;
650 outb_reg0(dep, DP_ISR, ISR_RDC);
651 dp_read_setup(dep, ecount, pageno * DP_PAGESIZE);
653 do {
654 bytes = iovp->iod_iovec[ix].iov_size;
655 if (bytes > pktsize) bytes = pktsize;
657 phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes);
658 if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
660 if (odd_byte) {
661 phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1);
662 out_word(dep->de_data_port, *(u16_t *)two_bytes);
663 pktsize--;
664 bytes--;
665 phys_user++;
666 odd_byte = 0;
667 if (!bytes) continue;
669 ecount = bytes & NOT(0x0001);
670 if (ecount != 0) {
671 phys_outsw(dep->de_data_port, phys_user, ecount);
672 pktsize -= ecount;
673 bytes -= ecount;
674 phys_user += ecount;
676 if (bytes) {
677 phys_copy(phys_user, phys_2bytes, (phys_bytes) 1);
678 pktsize--;
679 bytes--;
680 phys_user++;
681 odd_byte = 1;
683 if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
684 dp_next_iovec(iovp);
685 ix = 0;
688 } while (bytes > 0);
690 if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes);
691 for (ix = 0; ix < 100; ix++) {
692 if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
694 if (ix == 100) {
695 panic(dep->de_name, RdmaErrMsg, NO_NUM);
697 return;
701 ** Name: void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize)
702 ** Function: Copies a packet from board to user area (Prog. I/O, 16bits).
704 static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count)
706 phys_bytes phys_user;
707 vir_bytes ecount;
708 int bytes, i;
709 u8_t two_bytes[2];
710 phys_bytes phys_2bytes;
711 int odd_byte;
713 ecount = (count + 1) & ~1;
714 phys_2bytes = vir2phys(two_bytes);
715 odd_byte = 0;
717 dp_read_setup(dep, ecount, nic_addr);
719 i = 0;
720 while (count > 0) {
721 if (i >= IOVEC_NR) {
722 dp_next_iovec(iovp);
723 i = 0;
724 continue;
726 bytes = iovp->iod_iovec[i].iov_size;
727 if (bytes > count) bytes = count;
729 phys_user = numap(iovp->iod_proc_nr,
730 iovp->iod_iovec[i].iov_addr, bytes);
731 if (!phys_user) panic(dep->de_name, UmapErrMsg, NO_NUM);
732 if (odd_byte) {
733 phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1);
734 count--;
735 bytes--;
736 phys_user++;
737 odd_byte = 0;
738 if (!bytes) continue;
740 ecount = bytes & ~1;
741 if (ecount != 0) {
742 phys_insw(dep->de_data_port, phys_user, ecount);
743 count -= ecount;
744 bytes -= ecount;
745 phys_user += ecount;
747 if (bytes) {
748 *(u16_t *) two_bytes = in_word(dep->de_data_port);
749 phys_copy(phys_2bytes, phys_user, (phys_bytes) 1);
750 count--;
751 bytes--;
752 phys_user++;
753 odd_byte = 1;
756 return;
759 #endif /* PIO16 == 1 */
761 #endif /* ENABLE_DP8390 */
763 /** end 8390.c **/