dp8390.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Lukas Mejdrech
00003  * Copyright (c) 2011 Martin Decky
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * - Redistributions of source code must retain the above copyright
00011  *   notice, this list of conditions and the following disclaimer.
00012  * - Redistributions in binary form must reproduce the above copyright
00013  *   notice, this list of conditions and the following disclaimer in the
00014  *   documentation and/or other materials provided with the distribution.
00015  * - The name of the author may not be used to endorse or promote products
00016  *   derived from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00019  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00020  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00021  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00023  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00024  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00025  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00027  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * This code is based upon the NE2000 driver for MINIX,
00032  * distributed according to a BSD-style license.
00033  *
00034  * Copyright (c) 1987, 1997, 2006 Vrije Universiteit
00035  * Copyright (c) 1992, 1994 Philip Homburg
00036  * Copyright (c) 1996 G. Falzoni
00037  *
00038  */
00039 
00052 #include <assert.h>
00053 #include <byteorder.h>
00054 #include <errno.h>
00055 #include <stdio.h>
00056 #include <libarch/ddi.h>
00057 #include <net/packet.h>
00058 #include <packet_client.h>
00059 #include "dp8390.h"
00060 
00062 #define DP_PAGE  256
00063 
00065 #define SQ_PAGES  6
00066 
00067 /* NE2000 implementation. */
00068 
00070 #define NE2K_DATA  0x0010
00071 
00073 #define NE2K_RESET  0x001f
00074 
00076 #define NE2K_START  0x4000
00077 
00079 #define NE2K_SIZE  0x4000
00080 
00082 #define NE2K_RETRY  0x1000
00083 
00085 #define NE2K_ERL  10
00086 
00088 #define ETH_MIN_PACK_SIZE  60
00089 
00091 #define ETH_MAX_PACK_SIZE_TAGGED  1518
00092 
00096 typedef struct {
00098         uint8_t status;
00099         
00101         uint8_t next;
00102         
00104         uint8_t rbcl;
00105         
00107         uint8_t rbch;
00108 } recv_header_t;
00109 
00117 static void pio_read_buf_16(void *port, void *buf, size_t size)
00118 {
00119         size_t i;
00120         
00121         for (i = 0; (i << 1) < size; i++)
00122                 *((uint16_t *) buf + i) = pio_read_16((ioport16_t *) (port));
00123 }
00124 
00132 static void pio_write_buf_16(void *port, void *buf, size_t size)
00133 {
00134         size_t i;
00135         
00136         for (i = 0; (i << 1) < size; i++)
00137                 pio_write_16((ioport16_t *) port, *((uint16_t *) buf + i));
00138 }
00139 
00140 static void ne2k_download(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
00141 {
00142         size_t esize = size & ~1;
00143         
00144         pio_write_8(ne2k->port + DP_RBCR0, esize & 0xff);
00145         pio_write_8(ne2k->port + DP_RBCR1, (esize >> 8) & 0xff);
00146         pio_write_8(ne2k->port + DP_RSAR0, addr & 0xff);
00147         pio_write_8(ne2k->port + DP_RSAR1, (addr >> 8) & 0xff);
00148         pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
00149         
00150         if (esize != 0) {
00151                 pio_read_buf_16(ne2k->data_port, buf, esize);
00152                 size -= esize;
00153                 buf += esize;
00154         }
00155         
00156         if (size) {
00157                 assert(size == 1);
00158                 
00159                 uint16_t word = pio_read_16(ne2k->data_port);
00160                 memcpy(buf, &word, 1);
00161         }
00162 }
00163 
00164 static void ne2k_upload(ne2k_t *ne2k, void *buf, size_t addr, size_t size)
00165 {
00166         size_t esize = size & ~1;
00167         
00168         pio_write_8(ne2k->port + DP_RBCR0, esize & 0xff);
00169         pio_write_8(ne2k->port + DP_RBCR1, (esize >> 8) & 0xff);
00170         pio_write_8(ne2k->port + DP_RSAR0, addr & 0xff);
00171         pio_write_8(ne2k->port + DP_RSAR1, (addr >> 8) & 0xff);
00172         pio_write_8(ne2k->port + DP_CR, CR_DM_RW | CR_PS_P0 | CR_STA);
00173         
00174         if (esize != 0) {
00175                 pio_write_buf_16(ne2k->data_port, buf, esize);
00176                 size -= esize;
00177                 buf += esize;
00178         }
00179         
00180         if (size) {
00181                 assert(size == 1);
00182                 
00183                 uint16_t word = 0;
00184                 
00185                 memcpy(&word, buf, 1);
00186                 pio_write_16(ne2k->data_port, word);
00187         }
00188 }
00189 
00190 static void ne2k_init(ne2k_t *ne2k)
00191 {
00192         unsigned int i;
00193         
00194         /* Reset the ethernet card */
00195         uint8_t val = pio_read_8(ne2k->port + NE2K_RESET);
00196         usleep(2000);
00197         pio_write_8(ne2k->port + NE2K_RESET, val);
00198         usleep(2000);
00199         
00200         /* Reset the DP8390 */
00201         pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
00202         for (i = 0; i < NE2K_RETRY; i++) {
00203                 if (pio_read_8(ne2k->port + DP_ISR) != 0)
00204                         break;
00205         }
00206 }
00207 
00218 int ne2k_probe(ne2k_t *ne2k, void *port, int irq)
00219 {
00220         unsigned int i;
00221         
00222         /* General initialization */
00223         ne2k->port = port;
00224         ne2k->data_port = ne2k->port + NE2K_DATA;
00225         ne2k->irq = irq;
00226         ne2k->probed = false;
00227         ne2k->up = false;
00228         
00229         ne2k_init(ne2k);
00230         
00231         /* Check if the DP8390 is really there */
00232         uint8_t val = pio_read_8(ne2k->port + DP_CR);
00233         if ((val & (CR_STP | CR_DM_ABORT)) != (CR_STP | CR_DM_ABORT))
00234                 return EXDEV;
00235         
00236         /* Disable the receiver and init TCR and DCR */
00237         pio_write_8(ne2k->port + DP_RCR, RCR_MON);
00238         pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
00239         pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
00240         
00241         /* Setup a transfer to get the MAC address */
00242         pio_write_8(ne2k->port + DP_RBCR0, ETH_ADDR << 1);
00243         pio_write_8(ne2k->port + DP_RBCR1, 0);
00244         pio_write_8(ne2k->port + DP_RSAR0, 0);
00245         pio_write_8(ne2k->port + DP_RSAR1, 0);
00246         pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
00247         
00248         for (i = 0; i < ETH_ADDR; i++)
00249                 ne2k->mac[i] = pio_read_16(ne2k->data_port);
00250         
00251         ne2k->probed = true;
00252         return EOK;
00253 }
00254 
00263 int ne2k_up(ne2k_t *ne2k)
00264 {
00265         if (!ne2k->probed)
00266                 return EXDEV;
00267         
00268         ne2k_init(ne2k);
00269         
00270         /*
00271          * Setup send queue. Use the first
00272          * SQ_PAGES of NE2000 memory for the send
00273          * buffer.
00274          */
00275         ne2k->sq.dirty = false;
00276         ne2k->sq.page = NE2K_START / DP_PAGE;
00277         fibril_mutex_initialize(&ne2k->sq_mutex);
00278         fibril_condvar_initialize(&ne2k->sq_cv);
00279         
00280         /*
00281          * Setup receive ring buffer. Use all the rest
00282          * of the NE2000 memory (except the first SQ_PAGES
00283          * reserved for the send buffer) for the receive
00284          * ring buffer.
00285          */
00286         ne2k->start_page = ne2k->sq.page + SQ_PAGES;
00287         ne2k->stop_page = ne2k->sq.page + NE2K_SIZE / DP_PAGE;
00288         
00289         /*
00290          * Initialization of the DP8390 following the mandatory procedure
00291          * in reference manual ("DP8390D/NS32490D NIC Network Interface
00292          * Controller", National Semiconductor, July 1995, Page 29).
00293          */
00294         
00295         /* Step 1: */
00296         pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STP | CR_DM_ABORT);
00297         
00298         /* Step 2: */
00299         pio_write_8(ne2k->port + DP_DCR, DCR_WORDWIDE | DCR_8BYTES | DCR_BMS);
00300         
00301         /* Step 3: */
00302         pio_write_8(ne2k->port + DP_RBCR0, 0);
00303         pio_write_8(ne2k->port + DP_RBCR1, 0);
00304         
00305         /* Step 4: */
00306         pio_write_8(ne2k->port + DP_RCR, RCR_AB);
00307         
00308         /* Step 5: */
00309         pio_write_8(ne2k->port + DP_TCR, TCR_INTERNAL);
00310         
00311         /* Step 6: */
00312         pio_write_8(ne2k->port + DP_BNRY, ne2k->start_page);
00313         pio_write_8(ne2k->port + DP_PSTART, ne2k->start_page);
00314         pio_write_8(ne2k->port + DP_PSTOP, ne2k->stop_page);
00315         
00316         /* Step 7: */
00317         pio_write_8(ne2k->port + DP_ISR, 0xff);
00318         
00319         /* Step 8: */
00320         pio_write_8(ne2k->port + DP_IMR,
00321             IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
00322         
00323         /* Step 9: */
00324         pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_DM_ABORT | CR_STP);
00325         
00326         pio_write_8(ne2k->port + DP_PAR0, ne2k->mac[0]);
00327         pio_write_8(ne2k->port + DP_PAR1, ne2k->mac[1]);
00328         pio_write_8(ne2k->port + DP_PAR2, ne2k->mac[2]);
00329         pio_write_8(ne2k->port + DP_PAR3, ne2k->mac[3]);
00330         pio_write_8(ne2k->port + DP_PAR4, ne2k->mac[4]);
00331         pio_write_8(ne2k->port + DP_PAR5, ne2k->mac[5]);
00332         
00333         pio_write_8(ne2k->port + DP_MAR0, 0xff);
00334         pio_write_8(ne2k->port + DP_MAR1, 0xff);
00335         pio_write_8(ne2k->port + DP_MAR2, 0xff);
00336         pio_write_8(ne2k->port + DP_MAR3, 0xff);
00337         pio_write_8(ne2k->port + DP_MAR4, 0xff);
00338         pio_write_8(ne2k->port + DP_MAR5, 0xff);
00339         pio_write_8(ne2k->port + DP_MAR6, 0xff);
00340         pio_write_8(ne2k->port + DP_MAR7, 0xff);
00341         
00342         pio_write_8(ne2k->port + DP_CURR, ne2k->start_page + 1);
00343         
00344         /* Step 10: */
00345         pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_DM_ABORT | CR_STA);
00346         
00347         /* Step 11: */
00348         pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
00349         
00350         /* Reset counters by reading */
00351         pio_read_8(ne2k->port + DP_CNTR0);
00352         pio_read_8(ne2k->port + DP_CNTR1);
00353         pio_read_8(ne2k->port + DP_CNTR2);
00354         
00355         /* Finish the initialization */
00356         ne2k->up = true;
00357         return EOK;
00358 }
00359 
00365 void ne2k_down(ne2k_t *ne2k)
00366 {
00367         if ((ne2k->probed) && (ne2k->up)) {
00368                 pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
00369                 ne2k_init(ne2k);
00370                 ne2k->up = false;
00371         }
00372 }
00373 
00380 void ne2k_send(ne2k_t *ne2k, packet_t *packet)
00381 {
00382         assert(ne2k->probed);
00383         assert(ne2k->up);
00384         
00385         fibril_mutex_lock(&ne2k->sq_mutex);
00386         
00387         while (ne2k->sq.dirty)
00388                 fibril_condvar_wait(&ne2k->sq_cv, &ne2k->sq_mutex);
00389         
00390         void *buf = packet_get_data(packet);
00391         size_t size = packet_get_data_length(packet);
00392         
00393         if ((size < ETH_MIN_PACK_SIZE) || (size > ETH_MAX_PACK_SIZE_TAGGED)) {
00394                 fibril_mutex_unlock(&ne2k->sq_mutex);
00395                 fprintf(stderr, "%s: Frame dropped (invalid size %zu bytes)\n",
00396                     NAME, size);
00397                 return;
00398         }
00399         
00400         /* Upload the frame to the ethernet card */
00401         ne2k_upload(ne2k, buf, ne2k->sq.page * DP_PAGE, size);
00402         ne2k->sq.dirty = true;
00403         ne2k->sq.size = size;
00404         
00405         /* Initialize the transfer */
00406         pio_write_8(ne2k->port + DP_TPSR, ne2k->sq.page);
00407         pio_write_8(ne2k->port + DP_TBCR0, size & 0xff);
00408         pio_write_8(ne2k->port + DP_TBCR1, (size >> 8) & 0xff);
00409         pio_write_8(ne2k->port + DP_CR, CR_TXP | CR_STA);
00410         
00411         fibril_mutex_unlock(&ne2k->sq_mutex);
00412 }
00413 
00414 static void ne2k_reset(ne2k_t *ne2k)
00415 {
00416         unsigned int i;
00417         
00418         /* Stop the chip */
00419         pio_write_8(ne2k->port + DP_CR, CR_STP | CR_DM_ABORT);
00420         pio_write_8(ne2k->port + DP_RBCR0, 0);
00421         pio_write_8(ne2k->port + DP_RBCR1, 0);
00422         
00423         for (i = 0; i < NE2K_RETRY; i++) {
00424                 if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RST) != 0)
00425                         break;
00426         }
00427         
00428         pio_write_8(ne2k->port + DP_TCR, TCR_1EXTERNAL | TCR_OFST);
00429         pio_write_8(ne2k->port + DP_CR, CR_STA | CR_DM_ABORT);
00430         pio_write_8(ne2k->port + DP_TCR, TCR_NORMAL);
00431         
00432         /* Acknowledge the ISR_RDC (remote DMA) interrupt */
00433         for (i = 0; i < NE2K_RETRY; i++) {
00434                 if ((pio_read_8(ne2k->port + DP_ISR) & ISR_RDC) != 0)
00435                         break;
00436         }
00437         
00438         uint8_t val = pio_read_8(ne2k->port + DP_ISR);
00439         pio_write_8(ne2k->port + DP_ISR, val & ~ISR_RDC);
00440         
00441         /*
00442          * Reset the transmit ring. If we were transmitting a frame,
00443          * we pretend that the packet is processed. Higher layers will
00444          * retransmit if the packet wasn't actually sent.
00445          */
00446         fibril_mutex_lock(&ne2k->sq_mutex);
00447         ne2k->sq.dirty = false;
00448         fibril_mutex_unlock(&ne2k->sq_mutex);
00449 }
00450 
00451 static frame_t *ne2k_receive_frame(ne2k_t *ne2k, uint8_t page, size_t length)
00452 {
00453         frame_t *frame = (frame_t *) malloc(sizeof(frame_t));
00454         if (frame == NULL)
00455                 return NULL;
00456         
00457         link_initialize(&frame->link);
00458         
00459         frame->packet = netif_packet_get_1(length);
00460         if (frame->packet == NULL) {
00461                 free(frame);
00462                 return NULL;
00463         }
00464         
00465         void *buf = packet_suffix(frame->packet, length);
00466         bzero(buf, length);
00467         uint8_t last = page + length / DP_PAGE;
00468         
00469         if (last >= ne2k->stop_page) {
00470                 size_t left = (ne2k->stop_page - page) * DP_PAGE
00471                     - sizeof(recv_header_t);
00472                 
00473                 ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
00474                     left);
00475                 ne2k_download(ne2k, buf + left, ne2k->start_page * DP_PAGE,
00476                     length - left);
00477         } else
00478                 ne2k_download(ne2k, buf, page * DP_PAGE + sizeof(recv_header_t),
00479                     length);
00480         
00481         ne2k->stats.receive_packets++;
00482         return frame;
00483 }
00484 
00485 static link_t *ne2k_receive(ne2k_t *ne2k)
00486 {
00487         /*
00488          * Allocate memory for the list of received frames.
00489          * If the allocation fails here we still receive the
00490          * frames from the network, but they will be lost.
00491          */
00492         link_t *frames = (link_t *) malloc(sizeof(link_t));
00493         if (frames != NULL)
00494                 list_initialize(frames);
00495         
00496         while (true) {
00497                 uint8_t boundary = pio_read_8(ne2k->port + DP_BNRY) + 1;
00498                 
00499                 if (boundary == ne2k->stop_page)
00500                         boundary = ne2k->start_page;
00501                 
00502                 pio_write_8(ne2k->port + DP_CR, CR_PS_P1 | CR_STA);
00503                 uint8_t current = pio_read_8(ne2k->port + DP_CURR);
00504                 pio_write_8(ne2k->port + DP_CR, CR_PS_P0 | CR_STA);
00505                 
00506                 if (current == boundary)
00507                         /* No more frames to process */
00508                         break;
00509                 
00510                 recv_header_t header;
00511                 size_t size = sizeof(header);
00512                 size_t offset = boundary * DP_PAGE;
00513                 
00514                 /* Get the frame header */
00515                 pio_write_8(ne2k->port + DP_RBCR0, size & 0xff);
00516                 pio_write_8(ne2k->port + DP_RBCR1, (size >> 8) & 0xff);
00517                 pio_write_8(ne2k->port + DP_RSAR0, offset & 0xff);
00518                 pio_write_8(ne2k->port + DP_RSAR1, (offset >> 8) & 0xff);
00519                 pio_write_8(ne2k->port + DP_CR, CR_DM_RR | CR_PS_P0 | CR_STA);
00520                 
00521                 pio_read_buf_16(ne2k->data_port, (void *) &header, size);
00522                 
00523                 size_t length =
00524                     (((size_t) header.rbcl) | (((size_t) header.rbch) << 8)) - size;
00525                 uint8_t next = header.next;
00526                 
00527                 if ((length < ETH_MIN_PACK_SIZE)
00528                     || (length > ETH_MAX_PACK_SIZE_TAGGED)) {
00529                         fprintf(stderr, "%s: Rant frame (%zu bytes)\n", NAME, length);
00530                         next = current;
00531                 } else if ((header.next < ne2k->start_page)
00532                     || (header.next > ne2k->stop_page)) {
00533                         fprintf(stderr, "%s: Malformed next frame %u\n", NAME,
00534                             header.next);
00535                         next = current;
00536                 } else if (header.status & RSR_FO) {
00537                         /*
00538                          * This is very serious, so we issue a warning and
00539                          * reset the buffers.
00540                          */
00541                         fprintf(stderr, "%s: FIFO overrun\n", NAME);
00542                         ne2k->overruns++;
00543                         next = current;
00544                 } else if ((header.status & RSR_PRX) && (ne2k->up)) {
00545                         if (frames != NULL) {
00546                                 frame_t *frame = ne2k_receive_frame(ne2k, boundary, length);
00547                                 if (frame != NULL)
00548                                         list_append(&frame->link, frames);
00549                         }
00550                 }
00551                 
00552                 /*
00553                  * Update the boundary pointer
00554                  * to the value of the page
00555                  * prior to the next packet to
00556                  * be processed.
00557                  */
00558                 if (next == ne2k->start_page)
00559                         next = ne2k->stop_page - 1;
00560                 else
00561                         next--;
00562                 
00563                 pio_write_8(ne2k->port + DP_BNRY, next);
00564         }
00565         
00566         return frames;
00567 }
00568 
00569 link_t *ne2k_interrupt(ne2k_t *ne2k, uint8_t isr, uint8_t tsr)
00570 {
00571         /* List of received frames */
00572         link_t *frames = NULL;
00573         
00574         if (isr & (ISR_PTX | ISR_TXE)) {
00575                 if (isr & ISR_TXE)
00576                         ne2k->stats.send_errors++;
00577                 else {
00578                         if (tsr & TSR_PTX)
00579                                 ne2k->stats.send_packets++;
00580                         
00581                         if (tsr & TSR_COL)
00582                                 ne2k->stats.collisions++;
00583                         
00584                         if (tsr & TSR_ABT)
00585                                 ne2k->stats.send_aborted_errors++;
00586                         
00587                         if (tsr & TSR_CRS)
00588                                 ne2k->stats.send_carrier_errors++;
00589                         
00590                         if (tsr & TSR_FU) {
00591                                 ne2k->underruns++;
00592                                 if (ne2k->underruns < NE2K_ERL)
00593                                         fprintf(stderr, "%s: FIFO underrun\n", NAME);
00594                         }
00595                         
00596                         if (tsr & TSR_CDH) {
00597                                 ne2k->stats.send_heartbeat_errors++;
00598                                 if (ne2k->stats.send_heartbeat_errors < NE2K_ERL)
00599                                         fprintf(stderr, "%s: CD heartbeat failure\n", NAME);
00600                         }
00601                         
00602                         if (tsr & TSR_OWC)
00603                                 ne2k->stats.send_window_errors++;
00604                 }
00605                 
00606                 fibril_mutex_lock(&ne2k->sq_mutex);
00607                 
00608                 if (ne2k->sq.dirty) {
00609                         /* Prepare the buffer for next packet */
00610                         ne2k->sq.dirty = false;
00611                         ne2k->sq.size = 0;
00612                         
00613                         /* Signal a next frame to be sent */
00614                         fibril_condvar_broadcast(&ne2k->sq_cv);
00615                 } else {
00616                         ne2k->misses++;
00617                         if (ne2k->misses < NE2K_ERL)
00618                                 fprintf(stderr, "%s: Spurious PTX interrupt\n", NAME);
00619                 }
00620                 
00621                 fibril_mutex_unlock(&ne2k->sq_mutex);
00622         }
00623         
00624         if (isr & ISR_RXE)
00625                 ne2k->stats.receive_errors++;
00626         
00627         if (isr & ISR_CNT) {
00628                 ne2k->stats.receive_crc_errors +=
00629                     pio_read_8(ne2k->port + DP_CNTR0);
00630                 ne2k->stats.receive_frame_errors +=
00631                     pio_read_8(ne2k->port + DP_CNTR1);
00632                 ne2k->stats.receive_missed_errors +=
00633                     pio_read_8(ne2k->port + DP_CNTR2);
00634         }
00635         
00636         if (isr & ISR_PRX)
00637                 frames = ne2k_receive(ne2k);
00638         
00639         if (isr & ISR_RST) {
00640                 /*
00641                  * The chip is stopped, and all arrived
00642                  * frames are delivered.
00643                  */
00644                 ne2k_reset(ne2k);
00645         }
00646         
00647         /* Unmask interrupts to be processed in the next round */
00648         pio_write_8(ne2k->port + DP_IMR,
00649             IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE | IMR_CNTE);
00650         
00651         return frames;
00652 }
00653 

Generated on Thu Jun 2 07:45:50 2011 for HelenOS/USB by  doxygen 1.4.7