panic() cleanup.
[minix.git] / drivers / dpeth / 8390.c
blob74f887b3cce4f60497289bbc3460fad6fd425d06
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/gen/ether.h>
19 #include <net/gen/eth_io.h>
20 #include "dp.h"
22 #if (ENABLE_DP8390 == 1)
24 #define PIO16 0 /* NOTE: pio 16 functions missing */
26 #include "8390.h"
28 #if 0
29 #define sys_nic2mem(srcOffs,dstProc,dstOffs,length) \
30 sys_vircopy(SELF,dep->de_memsegm,(vir_bytes)(srcOffs),\
31 (dstProc),D,(vir_bytes)(dstOffs),length)
32 #endif
33 #if 0
34 #define sys_user2nic_s(srcProc,grant,dstOffs,length) \
35 sys_safecopyfrom((srcProc),(grant),0, \
36 (vir_bytes)(dstOffs),length,dep->de_memsegm)
37 #endif
39 static char RdmaErrMsg[] = "remote dma failed to complete";
42 ** Name: void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset);
43 ** Function: Sets the board for reading/writing.
45 static void ns_rw_setup(dpeth_t *dep, int mode, int size, u16_t offset)
48 if (mode == CR_DM_RW) outb_reg0(dep, DP_ISR, ISR_RDC);
49 outb_reg0(dep, DP_RBCR0, size & 0xFF);
50 outb_reg0(dep, DP_RBCR1, (size >> 8) & 0xFF);
51 outb_reg0(dep, DP_RSAR0, offset & 0xFF);
52 outb_reg0(dep, DP_RSAR1, (offset >> 8) & 0xFF);
53 mode |= (CR_PS_P0 | CR_STA);
54 outb_reg0(dep, DP_CR, mode);
55 return;
59 ** Name: void ns_start_xmit(dpeth_t *dep, int size, int pageno);
60 ** Function: Sets the board for for transmitting and fires it.
62 static void ns_start_xmit(dpeth_t * dep, int size, int pageno)
65 outb_reg0(dep, DP_TPSR, pageno);
66 outb_reg0(dep, DP_TBCR1, size >> 8);
67 outb_reg0(dep, DP_TBCR0, size & 0xFF);
68 outb_reg0(dep, DP_CR, CR_NO_DMA | CR_STA | CR_TXP); /* Fires transmission */
69 return;
73 ** Name: void mem_getblock(dpeth_t *dep, u16_t offset,
74 ** int size, void *dst)
75 ** Function: Reads a block of packet from board (shared memory).
77 static void mem_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
79 panic("mem_getblock: not converted to safecopies");
80 #if 0
81 sys_nic2mem(dep->de_linmem + offset, SELF, dst, size);
82 return;
83 #endif
87 ** Name: void mem_nic2user(dpeth_t *dep, int pageno, int pktsize);
88 ** Function: Copies a packet from board to user area (shared memory).
90 static void mem_nic2user(dpeth_t * dep, int pageno, int pktsize)
92 phys_bytes offset;
93 iovec_dat_s_t *iovp = &dep->de_read_iovec;
94 int bytes, ix = 0;
96 panic("mem_nic2user: not converted to safecopies");
97 #if 0
99 /* Computes shared memory address (skipping receive header) */
100 offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
102 do { /* Reads chuncks of packet into user area */
104 bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
105 if (bytes > pktsize) bytes = pktsize;
107 /* Reads from board to user area */
108 if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
110 /* Circular buffer wrap-around */
111 bytes = dep->de_stoppage * DP_PAGESIZE - offset;
112 sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr,
113 iovp->iod_iovec[ix].iov_grant, bytes);
114 pktsize -= bytes;
115 phys_user += bytes;
116 bytes = iovp->iod_iovec[ix].iov_size - bytes;
117 if (bytes > pktsize) bytes = pktsize;
118 offset = dep->de_startpage * DP_PAGESIZE;
120 sys_nic2mem_s(dep->de_linmem + offset, iovp->iod_proc_nr,
121 iovp->iod_iovec[ix].iov_grant, bytes);
122 offset += bytes;
124 if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
125 dp_next_iovec(iovp);
126 ix = 0;
128 /* Till packet done */
129 } while ((pktsize -= bytes) > 0);
130 return;
131 #endif
135 ** Name: void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
136 ** Function: Copies a packet from user area to board (shared memory).
138 static void mem_user2nic(dpeth_t *dep, int pageno, int pktsize)
140 phys_bytes offset, phys_user;
141 iovec_dat_s_t *iovp = &dep->de_write_iovec;
142 int bytes, ix = 0;
144 panic("mem_user2nic: not converted to safecopies");
145 #if 0
147 /* Computes shared memory address */
148 offset = pageno * DP_PAGESIZE;
150 do { /* Reads chuncks of packet from user area */
152 bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
153 if (bytes > pktsize) bytes = pktsize;
155 /* Reads from user area to board (shared memory) */
156 sys_user2nic_s(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_grant,
157 dep->de_linmem + offset, bytes);
158 offset += bytes;
160 if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
161 dp_next_iovec(iovp);
162 ix = 0;
164 /* Till packet done */
165 } while ((pktsize -= bytes) > 0);
166 return;
167 #endif
171 ** Name: void pio_getblock(dpeth_t *dep, u16_t offset,
172 ** int size, void *dst)
173 ** Function: Reads a block of packet from board (Prog. I/O).
175 static void pio_getblock(dpeth_t *dep, u16_t offset, int size, void *dst)
178 /* Sets up board for reading */
179 ns_rw_setup(dep, CR_DM_RR, size, offset);
181 #if PIO16 == 0
182 insb(dep->de_data_port, SELF, dst, size);
183 #else
184 if (dep->de_16bit == TRUE) {
185 insw(dep->de_data_port, dst, size);
186 } else {
187 insb(dep->de_data_port, dst, size);
189 #endif
190 return;
194 ** Name: void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
195 ** Function: Copies a packet from board to user area (Prog. I/O).
197 static void pio_nic2user(dpeth_t *dep, int pageno, int pktsize)
199 iovec_dat_s_t *iovp = &dep->de_read_iovec;
200 unsigned offset, iov_offset; int r, bytes, ix = 0;
202 /* Computes memory address (skipping receive header) */
203 offset = pageno * DP_PAGESIZE + sizeof(dp_rcvhdr_t);
204 /* Sets up board for reading */
205 ns_rw_setup(dep, CR_DM_RR, ((offset + pktsize) > (dep->de_stoppage * DP_PAGESIZE)) ?
206 (dep->de_stoppage * DP_PAGESIZE) - offset : pktsize, offset);
208 iov_offset= 0;
209 do { /* Reads chuncks of packet into user area */
211 bytes = iovp->iod_iovec[ix].iov_size; /* Size of a chunck */
212 if (bytes > pktsize) bytes = pktsize;
214 if ((offset + bytes) > (dep->de_stoppage * DP_PAGESIZE)) {
216 /* Circular buffer wrap-around */
217 bytes = dep->de_stoppage * DP_PAGESIZE - offset;
218 r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
219 iovp->iod_iovec[ix].iov_grant, iov_offset, bytes);
220 if (r != OK) {
221 panic("pio_nic2user: sys_safe_insb failed: %d", r);
223 pktsize -= bytes;
224 iov_offset += bytes;
225 bytes = iovp->iod_iovec[ix].iov_size - bytes;
226 if (bytes > pktsize) bytes = pktsize;
227 offset = dep->de_startpage * DP_PAGESIZE;
228 ns_rw_setup(dep, CR_DM_RR, pktsize, offset);
230 r= sys_safe_insb(dep->de_data_port, iovp->iod_proc_nr,
231 iovp->iod_iovec[ix].iov_grant, iov_offset, bytes);
232 if (r != OK)
233 panic("pio_nic2user: sys_safe_insb failed: %d", r);
234 offset += bytes;
236 if (++ix >= IOVEC_NR) { /* Next buffer of IO vector */
237 dp_next_iovec(iovp);
238 ix = 0;
240 iov_offset= 0;
241 /* Till packet done */
242 } while ((pktsize -= bytes) > 0);
243 return;
247 ** Name: void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
248 ** Function: Copies a packet from user area to board (Prog. I/O).
250 static void pio_user2nic(dpeth_t *dep, int pageno, int pktsize)
252 iovec_dat_s_t *iovp = &dep->de_write_iovec;
253 int r, bytes, ix = 0;
255 /* Sets up board for writing */
256 ns_rw_setup(dep, CR_DM_RW, pktsize, pageno * DP_PAGESIZE);
258 do { /* Reads chuncks of packet from user area */
260 bytes = iovp->iod_iovec[ix].iov_size; /* Size of chunck */
261 if (bytes > pktsize) bytes = pktsize;
262 r= sys_safe_outsb(dep->de_data_port, iovp->iod_proc_nr,
263 iovp->iod_iovec[ix].iov_grant, 0, bytes);
264 if (r != OK)
265 panic("pio_user2nic: sys_safe_outsb failed: %d", r);
267 if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
268 dp_next_iovec(iovp);
269 ix = 0;
271 /* Till packet done */
272 } while ((pktsize -= bytes) > 0);
274 for (ix = 0; ix < 100; ix += 1) {
275 if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
277 if (ix == 100) {
278 panic(RdmaErrMsg);
280 return;
284 ** Name: void ns_stats(dpeth_t * dep)
285 ** Function: Updates counters reading from device
287 static void ns_stats(dpeth_t * dep)
290 dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
291 dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
292 dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
293 return;
297 ** Name: void ns_dodump(dpeth_t * dep)
298 ** Function: Displays statistics (a request from F5 key).
300 static void ns_dodump(dpeth_t * dep)
303 ns_stats(dep); /* Forces reading fo counters from board */
304 return;
308 ** Name: void ns_reinit(dpeth_t *dep)
309 ** Function: Updates receiver configuration.
311 static void ns_reinit(dpeth_t * dep)
313 int dp_reg = 0;
315 if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
316 if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
317 if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
318 outb_reg0(dep, DP_CR, CR_PS_P0);
319 outb_reg0(dep, DP_RCR, dp_reg);
320 return;
324 ** Name: void ns_send(dpeth_t * dep, int from_int, int size)
325 ** Function: Transfers packet to device and starts sending.
327 static void ns_send(dpeth_t * dep, int from_int, int size)
329 int queue;
331 if (queue = dep->de_sendq_head, dep->de_sendq[queue].sq_filled) {
332 if (from_int) panic("should not be sending ");
333 dep->de_send_s = size;
334 return;
336 (dep->de_user2nicf) (dep, dep->de_sendq[queue].sq_sendpage, size);
337 dep->bytes_Tx += (long) size;
338 dep->de_sendq[queue].sq_filled = TRUE;
339 dep->de_flags |= (DEF_XMIT_BUSY | DEF_ACK_SEND);
340 if (dep->de_sendq_tail == queue) { /* there it goes.. */
341 ns_start_xmit(dep, size, dep->de_sendq[queue].sq_sendpage);
342 } else
343 dep->de_sendq[queue].sq_size = size;
345 if (++queue == dep->de_sendq_nr) queue = 0;
346 dep->de_sendq_head = queue;
347 dep->de_flags &= NOT(DEF_SENDING);
349 return;
353 ** Name: void ns_reset(dpeth_t *dep)
354 ** Function: Resets device.
356 static void ns_reset(dpeth_t * dep)
358 int ix;
360 /* Stop chip */
361 outb_reg0(dep, DP_CR, CR_STP | CR_NO_DMA);
362 outb_reg0(dep, DP_RBCR0, 0);
363 outb_reg0(dep, DP_RBCR1, 0);
364 for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RST) == 0); ix += 1)
365 /* Do nothing */ ;
366 outb_reg0(dep, DP_TCR, TCR_1EXTERNAL | TCR_OFST);
367 outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA);
368 outb_reg0(dep, DP_TCR, TCR_NORMAL | TCR_OFST);
370 /* Acknowledge the ISR_RDC (remote dma) interrupt. */
371 for (ix = 0; ix < 0x1000 && ((inb_reg0(dep, DP_ISR) & ISR_RDC) == 0); ix += 1)
372 /* Do nothing */ ;
373 outb_reg0(dep, DP_ISR, inb_reg0(dep, DP_ISR) & NOT(ISR_RDC));
375 /* Reset the transmit ring. If we were transmitting a packet, we
376 * pretend that the packet is processed. Higher layers will
377 * retransmit if the packet wasn't actually sent. */
378 dep->de_sendq_head = dep->de_sendq_tail = 0;
379 for (ix = 0; ix < dep->de_sendq_nr; ix++)
380 dep->de_sendq[ix].sq_filled = FALSE;
381 ns_send(dep, TRUE, dep->de_send_s);
382 return;
386 ** Name: void ns_recv(dpeth_t *dep, int fromint, int size)
387 ** Function: Gets a packet from device
389 static void ns_recv(dpeth_t *dep, int fromint, int size)
391 dp_rcvhdr_t header;
392 dp_rcvhdr_t dummy;
393 unsigned pageno, curr, next;
394 vir_bytes length;
395 int packet_processed = FALSE;
396 #ifdef ETH_IGN_PROTO
397 u16_t eth_type;
398 #endif
400 pageno = inb_reg0(dep, DP_BNRY) + 1;
401 if (pageno == dep->de_stoppage) pageno = dep->de_startpage;
403 do {
404 /* */
405 outb_reg0(dep, DP_CR, CR_PS_P1);
406 curr = inb_reg1(dep, DP_CURR);
407 outb_reg0(dep, DP_CR, CR_PS_P0 | CR_NO_DMA | CR_STA);
409 if (curr == pageno) break;
411 (dep->de_getblockf) (dep, pageno * DP_PAGESIZE, sizeof(header), &header);
412 #ifdef ETH_IGN_PROTO
413 (dep->de_getblockf) (dep, pageno * DP_PAGESIZE + sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), &eth_type);
414 #endif
415 length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t);
416 next = header.dr_next;
418 if (length < ETH_MIN_PACK_SIZE || length > ETH_MAX_PACK_SIZE) {
419 printf("%s: packet with strange length arrived: %d\n", dep->de_name, length);
420 dep->de_stat.ets_recvErr += 1;
421 next = curr;
423 } else if (next < dep->de_startpage || next >= dep->de_stoppage) {
424 printf("%s: strange next page\n", dep->de_name);
425 dep->de_stat.ets_recvErr += 1;
426 next = curr;
428 #ifdef ETH_IGN_PROTO
429 } else if (eth_type == eth_ign_proto) {
430 /* Hack: ignore packets of a given protocol */
431 static int first = TRUE;
432 if (first) {
433 first = FALSE;
434 printf("%s: dropping proto %04x packet\n", dep->de_name, ntohs(eth_ign_proto));
436 next = curr;
437 #endif
438 } else if (header.dr_status & RSR_FO) {
439 /* This is very serious, issue a warning and reset buffers */
440 printf("%s: fifo overrun, resetting receive buffer\n", dep->de_name);
441 dep->de_stat.ets_fifoOver += 1;
442 next = curr;
444 } else if ((header.dr_status & RSR_PRX) && (dep->de_flags & DEF_ENABLED)) {
446 if (!(dep->de_flags & DEF_READING)) break;
448 (dep->de_nic2userf) (dep, pageno, length);
449 dep->de_read_s = length;
450 dep->de_flags |= DEF_ACK_RECV;
451 dep->de_flags &= NOT(DEF_READING);
452 packet_processed = TRUE;
454 dep->bytes_Rx += (long) length;
455 dep->de_stat.ets_packetR += 1;
456 outb_reg0(dep, DP_BNRY, (next == dep->de_startpage ? dep->de_stoppage : next) - 1);
457 pageno = next;
459 } while (!packet_processed);
460 #if 0
461 if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED))
462 /* The chip is stopped, and all arrived packets delivered */
463 (*dep->de_resetf) (dep);
464 dep->de_flags &= NOT(DEF_STOPPED);
465 #endif
466 return;
470 ** Name: void ns_interrupt(dpeth_t * dep)
471 ** Function: Handles interrupt.
473 static void ns_interrupt(dpeth_t * dep)
475 int isr, tsr;
476 int queue;
478 while ((isr = inb_reg0(dep, DP_ISR)) != 0) {
480 outb_reg0(dep, DP_ISR, isr);
481 if (isr & (ISR_PTX | ISR_TXE)) {
483 tsr = inb_reg0(dep, DP_TSR);
484 if (tsr & TSR_PTX) {
485 dep->de_stat.ets_packetT++;
487 if (tsr & TSR_COL) dep->de_stat.ets_collision++;
488 if (tsr & (TSR_ABT | TSR_FU)) {
489 dep->de_stat.ets_fifoUnder++;
491 if ((isr & ISR_TXE) || (tsr & (TSR_CRS | TSR_CDH | TSR_OWC))) {
492 printf("%s: got send Error (0x%02X)\n", dep->de_name, tsr);
493 dep->de_stat.ets_sendErr++;
495 queue = dep->de_sendq_tail;
497 if (!(dep->de_sendq[queue].sq_filled)) { /* Hardware bug? */
498 printf("%s: transmit interrupt, but not sending\n", dep->de_name);
499 continue;
501 dep->de_sendq[queue].sq_filled = FALSE;
502 if (++queue == dep->de_sendq_nr) queue = 0;
503 dep->de_sendq_tail = queue;
504 if (dep->de_sendq[queue].sq_filled) {
505 ns_start_xmit(dep, dep->de_sendq[queue].sq_size,
506 dep->de_sendq[queue].sq_sendpage);
508 if (dep->de_flags & DEF_SENDING) {
509 ns_send(dep, TRUE, dep->de_send_s);
512 if (isr & ISR_PRX) {
513 ns_recv(dep, TRUE, 0);
515 if (isr & ISR_RXE) {
516 printf("%s: got recv Error (0x%04X)\n", dep->de_name, inb_reg0(dep, DP_RSR));
517 dep->de_stat.ets_recvErr++;
519 if (isr & ISR_CNT) {
520 dep->de_stat.ets_CRCerr += inb_reg0(dep, DP_CNTR0);
521 dep->de_stat.ets_recvErr += inb_reg0(dep, DP_CNTR1);
522 dep->de_stat.ets_fifoOver += inb_reg0(dep, DP_CNTR2);
524 if (isr & ISR_OVW) {
525 printf("%s: got overwrite warning\n", dep->de_name);
527 if (isr & ISR_RDC) {
528 /* Nothing to do */
530 if (isr & ISR_RST) {
531 /* This means we got an interrupt but the ethernet
532 * chip is shutdown. We set the flag DEF_STOPPED, and
533 * continue processing arrived packets. When the
534 * receive buffer is empty, we reset the dp8390. */
535 printf("%s: network interface stopped\n", dep->de_name);
536 dep->de_flags |= DEF_STOPPED;
537 break;
540 if ((dep->de_flags & (DEF_READING | DEF_STOPPED)) == (DEF_READING | DEF_STOPPED)) {
542 /* The chip is stopped, and all arrived packets delivered */
543 ns_reset(dep);
544 dep->de_flags &= NOT(DEF_STOPPED);
546 return;
550 ** Name: void ns_init(dpeth_t *dep)
551 ** Function: Initializes the NS 8390
553 void ns_init(dpeth_t * dep)
555 int dp_reg;
556 int ix;
558 /* NS8390 initialization (as recommended in National Semiconductor specs) */
559 outb_reg0(dep, DP_CR, CR_PS_P0 | CR_STP | CR_NO_DMA); /* 0x21 */
560 #if PIO16 == 0
561 outb_reg0(dep, DP_DCR, (DCR_BYTEWIDE | DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
562 #else
563 outb_reg0(dep, DP_DCR, (((dep->de_16bit) ? DCR_WORDWIDE : DCR_BYTEWIDE) |
564 DCR_LTLENDIAN | DCR_8BYTES | DCR_BMS));
565 #endif
566 outb_reg0(dep, DP_RBCR0, 0);
567 outb_reg0(dep, DP_RBCR1, 0);
568 outb_reg0(dep, DP_RCR, RCR_MON); /* Sets Monitor mode */
569 outb_reg0(dep, DP_TCR, TCR_INTERNAL); /* Sets Loopback mode 1 */
570 outb_reg0(dep, DP_PSTART, dep->de_startpage);
571 outb_reg0(dep, DP_PSTOP, dep->de_stoppage);
572 outb_reg0(dep, DP_BNRY, dep->de_stoppage - 1);
573 outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
574 outb_reg0(dep, DP_IMR, 0); /* Clears Interrupt Mask Register */
576 /* Copies station address in page 1 registers */
577 outb_reg0(dep, DP_CR, CR_PS_P1 | CR_NO_DMA); /* Selects Page 1 */
578 for (ix = 0; ix < SA_ADDR_LEN; ix += 1) /* Initializes address */
579 outb_reg1(dep, DP_PAR0 + ix, dep->de_address.ea_addr[ix]);
580 for (ix = DP_MAR0; ix <= DP_MAR7; ix += 1) /* Initializes address */
581 outb_reg1(dep, ix, 0xFF);
583 outb_reg1(dep, DP_CURR, dep->de_startpage);
584 outb_reg1(dep, DP_CR, CR_PS_P0 | CR_NO_DMA); /* Selects Page 0 */
586 inb_reg0(dep, DP_CNTR0); /* Resets counters by reading them */
587 inb_reg0(dep, DP_CNTR1);
588 inb_reg0(dep, DP_CNTR2);
590 dp_reg = IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE;
591 outb_reg0(dep, DP_ISR, 0xFF); /* Clears Interrupt Status Register */
592 outb_reg0(dep, DP_IMR, dp_reg); /* Sets Interrupt Mask register */
594 dp_reg = 0;
595 if (dep->de_flags & DEF_PROMISC) dp_reg |= RCR_AB | RCR_PRO | RCR_AM;
596 if (dep->de_flags & DEF_BROAD) dp_reg |= RCR_AB;
597 if (dep->de_flags & DEF_MULTI) dp_reg |= RCR_AM;
598 outb_reg0(dep, DP_RCR, dp_reg); /* Sets receive as requested */
599 outb_reg0(dep, DP_TCR, TCR_NORMAL); /* Sets transmitter */
601 outb_reg0(dep, DP_CR, CR_STA | CR_NO_DMA); /* Starts board */
603 /* Initializes the send queue. */
604 for (ix = 0; ix < dep->de_sendq_nr; ix += 1)
605 dep->de_sendq[ix].sq_filled = 0;
606 dep->de_sendq_head = dep->de_sendq_tail = 0;
608 /* Device specific functions */
609 if (!dep->de_prog_IO) {
610 dep->de_user2nicf = mem_user2nic;
611 dep->de_nic2userf = mem_nic2user;
612 dep->de_getblockf = mem_getblock;
613 } else {
614 #if PIO16 == 0
615 dep->de_user2nicf = pio_user2nic;
616 dep->de_nic2userf = pio_nic2user;
617 dep->de_getblockf = pio_getblock;
618 #else
619 #error Missing I/O functions for pio 16 bits
620 #endif
622 dep->de_recvf = ns_recv;
623 dep->de_sendf = ns_send;
624 dep->de_flagsf = ns_reinit;
625 dep->de_resetf = ns_reset;
626 dep->de_getstatsf = ns_stats;
627 dep->de_dumpstatsf = ns_dodump;
628 dep->de_interruptf = ns_interrupt;
630 return; /* Done */
633 #if PIO16 == 1
636 ** Name: void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
637 ** Function: Copies a packet from user area to board (Prog. I/O, 16bits).
639 static void dp_pio16_user2nic(dpeth_t *dep, int pageno, int pktsize)
641 u8_t two_bytes[2];
642 phys_bytes phys_user, phys_2bytes = vir2phys(two_bytes);
643 vir_bytes ecount = (pktsize + 1) & NOT(0x0001);
644 int bytes, ix = 0, odd_byte = 0;
645 iovec_dat_t *iovp = &dep->de_write_iovec;
647 outb_reg0(dep, DP_ISR, ISR_RDC);
648 dp_read_setup(dep, ecount, pageno * DP_PAGESIZE);
650 do {
651 bytes = iovp->iod_iovec[ix].iov_size;
652 if (bytes > pktsize) bytes = pktsize;
654 phys_user = numap(iovp->iod_proc_nr, iovp->iod_iovec[ix].iov_addr, bytes);
655 if (!phys_user) panic(UmapErrMsg);
657 if (odd_byte) {
658 phys_copy(phys_user, phys_2bytes + 1, (phys_bytes) 1);
659 out_word(dep->de_data_port, *(u16_t *)two_bytes);
660 pktsize--;
661 bytes--;
662 phys_user++;
663 odd_byte = 0;
664 if (!bytes) continue;
666 ecount = bytes & NOT(0x0001);
667 if (ecount != 0) {
668 phys_outsw(dep->de_data_port, phys_user, ecount);
669 pktsize -= ecount;
670 bytes -= ecount;
671 phys_user += ecount;
673 if (bytes) {
674 phys_copy(phys_user, phys_2bytes, (phys_bytes) 1);
675 pktsize--;
676 bytes--;
677 phys_user++;
678 odd_byte = 1;
680 if (++ix >= IOVEC_NR) { /* Next buffer of I/O vector */
681 dp_next_iovec(iovp);
682 ix = 0;
685 } while (bytes > 0);
687 if (odd_byte) out_word(dep->de_data_port, *(u16_t *) two_bytes);
688 for (ix = 0; ix < 100; ix++) {
689 if (inb_reg0(dep, DP_ISR) & ISR_RDC) break;
691 if (ix == 100) {
692 panic(RdmaErrMsg);
694 return;
698 ** Name: void dp_pio16_nic2user(dpeth_t *dep, int pageno, int pktsize)
699 ** Function: Copies a packet from board to user area (Prog. I/O, 16bits).
701 static void dp_pio16_nic2user(dpeth_t * dep, int nic_addr, int count)
703 phys_bytes phys_user;
704 vir_bytes ecount;
705 int bytes, i;
706 u8_t two_bytes[2];
707 phys_bytes phys_2bytes;
708 int odd_byte;
710 ecount = (count + 1) & ~1;
711 phys_2bytes = vir2phys(two_bytes);
712 odd_byte = 0;
714 dp_read_setup(dep, ecount, nic_addr);
716 i = 0;
717 while (count > 0) {
718 if (i >= IOVEC_NR) {
719 dp_next_iovec(iovp);
720 i = 0;
721 continue;
723 bytes = iovp->iod_iovec[i].iov_size;
724 if (bytes > count) bytes = count;
726 phys_user = numap(iovp->iod_proc_nr,
727 iovp->iod_iovec[i].iov_addr, bytes);
728 if (!phys_user) panic(UmapErrMsg);
729 if (odd_byte) {
730 phys_copy(phys_2bytes + 1, phys_user, (phys_bytes) 1);
731 count--;
732 bytes--;
733 phys_user++;
734 odd_byte = 0;
735 if (!bytes) continue;
737 ecount = bytes & ~1;
738 if (ecount != 0) {
739 phys_insw(dep->de_data_port, phys_user, ecount);
740 count -= ecount;
741 bytes -= ecount;
742 phys_user += ecount;
744 if (bytes) {
745 *(u16_t *) two_bytes = in_word(dep->de_data_port);
746 phys_copy(phys_2bytes, phys_user, (phys_bytes) 1);
747 count--;
748 bytes--;
749 phys_user++;
750 odd_byte = 1;
753 return;
756 #endif /* PIO16 == 1 */
758 #endif /* ENABLE_DP8390 */
760 /** end 8390.c **/