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 

Generated on Fri Dec 15 11:18:55 2006 for UbixOS V2 by  doxygen 1.4.7