# ne2k.c

Go to the documentation of this file.

    00001 /*****************************************************************************************
    00002  Copyright (c) 2002-2004 The UbixOS Project
    00003  All rights reserved.
    00004
    00005  Redistribution and use in source and binary forms, with or without modification, are
    00006  permitted provided that the following conditions are met:
    00007
    00008  Redistributions of source code must retain the above copyright notice, this list of
    00009  conditions, the following disclaimer and the list of authors.  Redistributions in binary
    00010  form must reproduce the above copyright notice, this list of conditions, the following
    00011  disclaimer and the list of authors in the documentation and/or other materials provided
    00012  with the distribution. Neither the name of the UbixOS Project nor the names of its
    00013  contributors may be used to endorse or promote products derived from this software
    00014  without specific prior written permission.
    00015
    00016  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
    00017  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    00018  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
    00019  THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    00020  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
    00021  OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    00022  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
    00023  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    00024  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    00025
    00026  $Id: ne2k_8c-source.html 88 2016-01-12 00:11:29Z reddawg $
    00027
    00028 *****************************************************************************************/
    00029
    00030 #include <isa/ne2k.h>
    00031 #include <isa/8259.h>
    00032 #include <sys/device.old.h>
    00033 #include <sys/io.h>
    00034 #include <sys/idt.h>
    00035 #include <lib/kmalloc.h>
    00036 #include <lib/kprintf.h>
    00037 #include <string.h>
    00038 #include <ubixos/kpanic.h>
    00039 #include <ubixos/vitals.h>
    00040 #include <ubixos/spinlock.h>
    00041 #include <assert.h>
    00042
    00043
    00044 static spinLock_t ne2k_spinLock = SPIN_LOCK_INITIALIZER;
    00045
    00046 static int dp_pkt2user(struct device *dev,int page,int length);
    00047 static void getblock(struct device *dev,int page,size_t offset,size_t size,void *dst);
    00048 static int dp_recv(struct device *);
    00049
    00050 static struct nicBuffer *ne2kBuffer = 0x0;
    00051 static struct device    *mDev        = 0x0;
    00052
    00053 asm(
    00054   ".globl ne2kISR         \n"
    00055   "ne2kISR:               \n"
    00056   "  pusha                \n" /* Save all registers           */
    00057   "  call ne2kHandler     \n"
    00058   "  popa                 \n"
    00059   "  iret                 \n" /* Exit interrupt               */
    00060   );
    00061
    00062 /************************************************************************
    00063
    00064 Function: int ne2kInit(uInt32 ioAddr)
    00065 Description: This Function Will Initialize The Programmable Timer
    00066
    00067 Notes:
    00068
    00069 ************************************************************************/
    00070 int ne2k_init() {
    00071   mDev = (struct device *)kmalloc(sizeof(struct device));
    00072   mDev->ioAddr = 0x280;
    00073   mDev->irq    = 10;
    00074   setVector(&ne2kISR, mVec+10, dPresent + dInt + dDpl0);
    00075   irqEnable(10);
    00076 //  kprintf("ne0 - irq: %i, ioAddr: 0x%X MAC: %X:%X:%X:%X:%X:%X\n",dev->irq,dev->ioAddr,dev->net->mac[0] & 0xFF,dev->net->mac[1] & 0xFF,dev->net->mac[2] & 0xFF,dev->net->mac[3] & 0xFF,dev->net->mac[4] & 0xFF,dev->net->mac[5] & 0xFF);
    00077
    00078   outportByte(mDev->ioAddr + NE_CMD, 0x21);        // stop mode
    00079   outportByte(mDev->ioAddr + NE_DCR,0x29);         // 0x29 data config reg
    00080   outportByte(mDev->ioAddr + NE_RBCR0,0x00);       // LOW byte count (remote)
    00081   outportByte(mDev->ioAddr + NE_RBCR1,0x00);       // HIGH byte count (remote)
    00082   outportByte(mDev->ioAddr + NE_RCR,0x3C);         // receive config reg
    00083   outportByte(mDev->ioAddr + NE_TCR,0x02);         // LOOP mode (temp)
    00084   outportByte(mDev->ioAddr + NE_PSTART,startPage); // 0x26 PAGE start
    00085   outportByte(mDev->ioAddr + NE_BNRY,startPage);   // 0x26 BOUNDARY
    00086   outportByte(mDev->ioAddr + NE_PSTOP,stopPage);   // 0x40 PAGE stop
    00087   outportByte(mDev->ioAddr + NE_ISR,0xFF);         // interrupt status reg
    00088   outportByte(mDev->ioAddr + NE_IMR,0x0B);
    00089   outportByte(mDev->ioAddr + NE_CMD,0x61);         // PAGE 1 regs
    00090
    00091   outportByte(mDev->ioAddr + DP_MAR0, 0xFF);
    00092   outportByte(mDev->ioAddr + DP_MAR1, 0xFF);
    00093   outportByte(mDev->ioAddr + DP_MAR2, 0xFF);
    00094   outportByte(mDev->ioAddr + DP_MAR3, 0xFF);
    00095   outportByte(mDev->ioAddr + DP_MAR4, 0xFF);
    00096   outportByte(mDev->ioAddr + DP_MAR5, 0xFF);
    00097   outportByte(mDev->ioAddr + DP_MAR6, 0xFF);
    00098   outportByte(mDev->ioAddr + DP_MAR7, 0xFF);
    00099   outportByte(mDev->ioAddr + DP_CURR, startPage + 1);
    00100   outportByte(mDev->ioAddr + NE_CMD,  0x20);
    00101   inportByte(mDev->ioAddr + DP_CNTR0);                /* reset counters by reading */
    00102   inportByte(mDev->ioAddr + DP_CNTR1);
    00103   inportByte(mDev->ioAddr + DP_CNTR2);
    00104
    00105   outportByte(mDev->ioAddr + NE_TCR,  0x00);
    00106
    00107   outportByte(mDev->ioAddr + NE_CMD, 0x0);
    00108   outportByte(mDev->ioAddr + NE_DCR, 0x29);
    00109
    00110   kprintf("Initialized");
    00111   /* Return so we know everything went well */
    00112   return(0x0);
    00113   }
    00114
    00115 int PCtoNIC(struct device *dev,void *packet,int length) {
    00116   int     i        = 0x0;
    00117   uInt16 *packet16 = (uInt16 *)packet;
    00118   uInt8  *packet8  = (uInt8  *)packet;
    00119   uInt8   word16   = 0x1;
    00120
    00121   if ((inportByte(dev->ioAddr) & 0x04) == 0x04) {
    00122     kpanic("Device Not Ready\n");
    00123     }
    00124
    00125   assert(length);
    00126   if ((word16 == 1) && (length & 0x01)) {
    00127     length++;
    00128     }
    00129
    00130   outportByte(dev->ioAddr+EN0_RCNTLO,(length & 0xFF));
    00131   outportByte(dev->ioAddr+EN0_RCNTHI,(length >> 8));
    00132
    00133   outportByte(dev->ioAddr+EN0_RSARLO,0x0);
    00134   outportByte(dev->ioAddr+EN0_RSARHI,0x41);
    00135
    00136   outportByte(dev->ioAddr,E8390_RWRITE+E8390_START);
    00137
    00138   if (word16 != 0x0) {
    00139     for(i=0;i<length/2;i++){
    00140       outportWord(dev->ioAddr + NE_DATAPORT,packet16[i]);
    00141       }
    00142     }
    00143   else {
    00144     for(i=0;i<length;i++){
    00145       outportByte(dev->ioAddr + NE_DATAPORT,packet8[i]);
    00146       }
    00147     }
    00148
    00149   for (i = 0;i<=100;i++) {
    00150     if ((inportByte(dev->ioAddr+EN0_ISR) & 0x40) == 0x40) {
    00151       break;
    00152       }
    00153     }
    00154
    00155   outportByte(dev->ioAddr+EN0_ISR,0x40);
    00156   outportByte(dev->ioAddr+EN0_TPSR,0x41);//ei_local->txStartPage);
    00157   outportByte(dev->ioAddr+0x05,(length & 0xFF));
    00158   outportByte(dev->ioAddr+0x06,(length >> 8));
    00159   outportByteP(dev->ioAddr,0x26);
    00160   //kprintf("SENT\n");
    00161   return(length);
    00162   }
    00163
    00164 int NICtoPC(struct device *dev,void *packet,int length,int nic_addr) {
    00165   int i = 0x0;
    00166   uInt16 *packet16 = (uInt16 *)packet;
    00167
    00168   assert(length);
    00169
    00170   if (length & 0x01)
    00171     length++;
    00172
    00173
    00174
    00175   outportByte(dev->ioAddr+EN0_RCNTLO,(length & 0xFF));
    00176   outportByte(dev->ioAddr+EN0_RCNTHI,(length >> 8));
    00177
    00178   outportByte(dev->ioAddr+EN0_RSARLO,nic_addr & 0xFF);
    00179   outportByte(dev->ioAddr+EN0_RSARHI,nic_addr >> 8);
    00180
    00181   outportByte(dev->ioAddr,0x0A);
    00182
    00183   for(i=0;i<length/2;i++){
    00184     packet16[i] = inportWord(dev->ioAddr + NE_DATAPORT);
    00185     }
    00186
    00187   outportByte(dev->ioAddr+EN0_ISR,0x40);
    00188   return(length);
    00189   }
    00190
    00191 void ne2kHandler() {
    00192   uInt16 isr    = 0x0;
    00193   uInt16 status = 0x0;
    00194
    00195   irqDisable(10);
    00196   outportByte(mPic, eoi);
    00197   outportByte(sPic, eoi);
    00198
    00199   asm("sti");
    00200
    00201   isr = inportByte(mDev->ioAddr + NE_ISR);
    00202
    00203   if ((isr & 0x02) == 0x02) {
    00204     outportByte(mDev->ioAddr + NE_ISR, 0x0A);
    00205     status = inportByte(0x280 + NE_TPSR);
    00206     }
    00207   if ((isr & 0x01) == 0x01) {
    00208     if (dp_recv(mDev)) {
    00209       kprintf("Error Getting Packet\n");
    00210       }
    00211     outportByte(mDev->ioAddr + NE_ISR, 0x05);
    00212     }
    00213
    00214   outportByte(mDev->ioAddr + NE_IMR,0x0);
    00215   outportByte(mDev->ioAddr + NE_IMR,0x0B);
    00216
    00217   asm("cli");
    00218   irqEnable(10);
    00219
    00220   return;
    00221   }
    00222
    00223 static int dp_recv(struct device *dev) {
    00224   dp_rcvhdr_t header;
    00225   unsigned int pageno = 0x0, curr = 0x0, next = 0x0;
    00226   int packet_processed = 0x0, r = 0x0;
    00227   uInt16 eth_type = 0x0;
    00228
    00229   uInt32 length = 0x0;
    00230
    00231   pageno = inportByte(dev->ioAddr + NE_BNRY) + 1;
    00232   if (pageno == stopPage) pageno = startPage;
    00233
    00234   do {
    00235     outportByte(dev->ioAddr + NE_CMD, 0x40);
    00236     curr = inportByte(dev->ioAddr + NE_CURRENT);
    00237     outportByte(dev->ioAddr, 0x0);
    00238     if (curr == pageno) break;
    00239     getblock(dev, pageno, (size_t)0, sizeof(header), &header);
    00240     getblock(dev, pageno, sizeof(header) + 2*sizeof(ether_addr_t), sizeof(eth_type), &eth_type);
    00241
    00242     length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t);
    00243     next = header.dr_next;
    00244
    00245     //kprintf("length: [0x%X:0x%X:0x%X]\n",header.dr_next,header.dr_status,length);
    00246
    00247     if (length < 60 || length > 1514) {
    00248       kprintf("dp8390: packet with strange length arrived: %d\n",length);
    00249       next= curr;
    00250       }
    00251     else if (next < startPage || next >= stopPage) {
    00252       kprintf("dp8390: strange next page\n");
    00253       next= curr;
    00254       }
    00255     else if (header.dr_status & RSR_FO) {
    00256       kpanic("dp8390: fifo overrun, resetting receive buffer\n");
    00257       next = curr;
    00258       }
    00259     else if (header.dr_status & RSR_PRX) {
    00260       r = dp_pkt2user(dev, pageno, length);
    00261       if (r != OK) {
    00262         kprintf("FRUIT");
    00263         return(0x0);
    00264         }
    00265
    00266       packet_processed = 0x1;
    00267       }
    00268     if (next == startPage)
    00269       outportByte(dev->ioAddr + NE_BNRY, stopPage - 1);
    00270     else
    00271       outportByte(dev->ioAddr + NE_BNRY, next - 1);
    00272
    00273     pageno = next;
    00274
    00275     } while (packet_processed == 0x0);
    00276   return(0x0);
    00277   }
    00278
    00279 static void getblock(struct device *dev,int page,size_t offset,size_t size,void *dst) {
    00280         uInt16 *ha = 0x0;
    00281         int i      = 0x0;
    00282
    00283         ha = (uInt16 *) dst;
    00284         offset = page * DP_PAGESIZE + offset;
    00285         outportByte(dev->ioAddr + NE_RBCR0, size & 0xFF);
    00286         outportByte(dev->ioAddr + NE_RBCR1, size >> 8);
    00287         outportByte(dev->ioAddr + EN0_RSARLO, offset & 0xFF);
    00288         outportByte(dev->ioAddr + EN0_RSARHI, offset >> 8);
    00289         outportByte(dev->ioAddr + NE_CMD, E8390_RREAD | E8390_START);
    00290
    00291         size /= 2;
    00292         for (i= 0; i<size; i++)
    00293                 ha[i]= inportWord(dev->ioAddr + NE_DATAPORT);
    00294   outportByte(dev->ioAddr+EN0_ISR,0x40);
    00295   }
    00296
    00297 static int dp_pkt2user(struct device *dev,int page,int length) {
    00298   int last = 0x0;
    00299   struct nicBuffer *tmpBuf = 0x0;
    00300
    00301   last = page + (length - 1) / DP_PAGESIZE;
    00302
    00303   if (last >= stopPage) {
    00304     kprintf("FOOK STOP PAGE!!!");
    00305     }
    00306   else {
    00307     tmpBuf = ne2kAllocBuffer(length);
    00308     NICtoPC(dev,tmpBuf->buffer,length,page * DP_PAGESIZE + sizeof(dp_rcvhdr_t));
    00309     }
    00310   return(OK);
    00311   }
    00312
    00313 struct nicBuffer *ne2kAllocBuffer(int length) {
    00314   struct nicBuffer *tmpBuf = 0x0;
    00315
    00316   spinLock(&ne2k_spinLock);
    00317
    00318   if (ne2kBuffer == 0x0) {
    00319     ne2kBuffer = (struct nicBuffer *)kmalloc(sizeof(struct nicBuffer));
    00320     ne2kBuffer->next   = 0x0;
    00321     ne2kBuffer->length = length;
    00322     ne2kBuffer->buffer = (char *)kmalloc(length);
    00323     spinUnlock(&ne2k_spinLock);
    00324     return(ne2kBuffer);
    00325     }
    00326   else {
    00327     for (tmpBuf = ne2kBuffer;tmpBuf->next != 0x0;tmpBuf = tmpBuf->next);
    00328
    00329     tmpBuf->next   = (struct nicBuffer *)kmalloc(sizeof(struct nicBuffer));
    00330     tmpBuf         = tmpBuf->next;
    00331     tmpBuf->next   = 0x0;
    00332     tmpBuf->length = length;
    00333     tmpBuf->buffer = (char *)kmalloc(length);
    00334     spinUnlock(&ne2k_spinLock);
    00335     return(tmpBuf);
    00336     }
    00337   spinUnlock(&ne2k_spinLock);
    00338   return(0x0);
    00339   }
    00340
    00341 struct nicBuffer *ne2kGetBuffer() {
    00342   struct nicBuffer *tmpBuf = 0x0;
    00343
    00344   if (ne2k_spinLock == 0x1)
    00345     return(0x0);
    00346
    00347   tmpBuf     = ne2kBuffer;
    00348   if (ne2kBuffer != 0x0)
    00349     ne2kBuffer = ne2kBuffer->next;
    00350   return(tmpBuf);
    00351   }
    00352
    00353 void ne2kFreeBuffer(struct nicBuffer *buf) {
    00354   kfree(buf->buffer);
    00355   kfree(buf);
    00356   return;
    00357   }
    00358
    00359 /***
    00360
    00361  $Log: ne2k_8c-source.html,v $
    00361  Revision 1.7  2006/12/15 17:47:06  reddawg
    00361  Updates
    00361
    00362  Revision 1.1.1.1  2006/06/01 12:46:12  reddawg
    00363  ubix2
    00364
    00365  Revision 1.2  2005/10/12 00:13:37  reddawg
    00366  Removed
    00367
    00368  Revision 1.1.1.1  2005/09/26 17:24:02  reddawg
    00369  no message
    00370
    00371  Revision 1.24  2004/09/28 21:47:56  reddawg
    00372  Fixed deadlock now safe to use in bochs
    00373
    00374  Revision 1.23  2004/09/16 22:35:28  reddawg
    00375  Demo Release
    00376
    00377  Revision 1.22  2004/09/15 21:25:33  reddawg
    00378  Fixens
    00379
    00380  Revision 1.21  2004/09/11 19:15:37  reddawg
    00381  here you go irq 10 io 240 for your ne2k nic
    00382
    00383  Revision 1.20  2004/09/07 22:26:04  reddawg
    00384  synced in
    00385
    00386  Revision 1.19  2004/09/07 21:54:38  reddawg
    00387  ok reverted back to old scheduling for now....
    00388
    00389  Revision 1.18  2004/09/06 15:13:25  reddawg
    00390  Last commit before FreeBSD 6.0
    00391
    00392  Revision 1.17  2004/08/01 20:40:45  reddawg
    00393  Net related fixes
    00394
    00395  Revision 1.16  2004/07/28 22:23:02  reddawg
    00396  make sure it still works before I goto bed
    00397
    00398  Revision 1.15  2004/07/17 17:04:47  reddawg
    00399  ne2k: added assert hopefully it will help me solve this dma size 0 random error
    00400
    00401  Revision 1.14  2004/07/14 12:03:50  reddawg
    00402  ne2k: ne2kInit to ne2k_init
    00403  Changed Startup Routines
    00404
    00405  Revision 1.13  2004/06/04 10:19:42  reddawg
    00406  notes: we compile again, thank g-d anyways i was about to cry
    00407
    00408  Revision 1.12  2004/05/21 12:48:22  reddawg
    00409  Cleaned up
    00410
    00411  Revision 1.11  2004/05/19 04:07:42  reddawg
    00412  kmalloc(size,pid) no more it is no kmalloc(size); the way it should of been
    00413
    00414  Revision 1.10  2004/05/10 02:23:24  reddawg
    00415  Minor Changes To Source Code To Prepare It For Open Source Release
    00416
    00417  END
    00418  ***/
    00419