/*- * Copyright (c) 2002-2018 The UbixOS Project. * All rights reserved. * * This was developed by Christopher W. Olsen for the UbixOS Project. * * Redistribution and use in source and binary forms, with or without modification, are permitted * provided that the following conditions are met: * * 1) Redistributions of source code must retain the above copyright notice, this list of * conditions, the following disclaimer and the list of authors. * 2) Redistributions in binary form must reproduce the above copyright notice, this list of * conditions, the following disclaimer and the list of authors in the documentation and/or * other materials provided with the distribution. * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to * endorse or promote products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include <isa/ne2k.h> #include <isa/8259.h> #include <sys/device.old.h> #include <sys/io.h> #include <sys/idt.h> #include <lib/kmalloc.h> #include <lib/kprintf.h> #include <string.h> #include <ubixos/kpanic.h> #include <ubixos/vitals.h> #include <ubixos/spinlock.h> #include <assert.h> static struct spinLock ne2k_spinLock = SPIN_LOCK_INITIALIZER; static int dp_pkt2user(struct device *dev, int page, int length); static void getblock(struct device *dev, int page, size_t offset, size_t size, void *dst); static int dp_recv(struct device *); static struct nicBuffer *ne2kBuffer = 0x0; static struct device *mDev = 0x0; asm( ".globl ne2kISR \n" "ne2kISR: \n" " pusha \n" /* Save all registers */ " call ne2kHandler \n" " popa \n" " iret \n" /* Exit interrupt */ ); /************************************************************************ Function: int ne2kInit(uInt32 ioAddr) Description: This Function Will Initialize The Programmable Timer Notes: ************************************************************************/ int ne2k_init() { mDev = (struct device *) kmalloc(sizeof(struct device)); mDev->ioAddr = 0x280; mDev->irq = 10; setVector(&ne2kISR, mVec + 10, dPresent + dInt + dDpl0); irqEnable(10); // 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); outportByte(mDev->ioAddr + NE_CMD, 0x21); // stop mode outportByte(mDev->ioAddr + NE_DCR, 0x29); // 0x29 data config reg outportByte(mDev->ioAddr + NE_RBCR0, 0x00); // LOW byte count (remote) outportByte(mDev->ioAddr + NE_RBCR1, 0x00); // HIGH byte count (remote) outportByte(mDev->ioAddr + NE_RCR, 0x3C); // receive config reg outportByte(mDev->ioAddr + NE_TCR, 0x02); // LOOP mode (temp) outportByte(mDev->ioAddr + NE_PSTART, startPage); // 0x26 PAGE start outportByte(mDev->ioAddr + NE_BNRY, startPage); // 0x26 BOUNDARY outportByte(mDev->ioAddr + NE_PSTOP, stopPage); // 0x40 PAGE stop outportByte(mDev->ioAddr + NE_ISR, 0xFF); // interrupt status reg outportByte(mDev->ioAddr + NE_IMR, 0x0B); outportByte(mDev->ioAddr + NE_CMD, 0x61); // PAGE 1 regs outportByte(mDev->ioAddr + DP_MAR0, 0xFF); outportByte(mDev->ioAddr + DP_MAR1, 0xFF); outportByte(mDev->ioAddr + DP_MAR2, 0xFF); outportByte(mDev->ioAddr + DP_MAR3, 0xFF); outportByte(mDev->ioAddr + DP_MAR4, 0xFF); outportByte(mDev->ioAddr + DP_MAR5, 0xFF); outportByte(mDev->ioAddr + DP_MAR6, 0xFF); outportByte(mDev->ioAddr + DP_MAR7, 0xFF); outportByte(mDev->ioAddr + DP_CURR, startPage + 1); outportByte(mDev->ioAddr + NE_CMD, 0x20); inportByte(mDev->ioAddr + DP_CNTR0); /* reset counters by reading */ inportByte(mDev->ioAddr + DP_CNTR1); inportByte(mDev->ioAddr + DP_CNTR2); outportByte(mDev->ioAddr + NE_TCR, 0x00); outportByte(mDev->ioAddr + NE_CMD, 0x0); outportByte(mDev->ioAddr + NE_DCR, 0x29); kprintf("Initialized"); /* Return so we know everything went well */ return (0x0); } int PCtoNIC(struct device *dev, void *packet, int length) { int i = 0x0; uInt16 *packet16 = (uInt16 *) packet; uInt8 *packet8 = (uInt8 *) packet; uInt8 word16 = 0x1; if ((inportByte(dev->ioAddr) & 0x04) == 0x04) { kpanic("Device Not Ready\n"); } assert(length); if ((word16 == 1) && (length & 0x01)) { length++; } outportByte(dev->ioAddr + EN0_RCNTLO, (length & 0xFF)); outportByte(dev->ioAddr + EN0_RCNTHI, (length >> 8)); outportByte(dev->ioAddr + EN0_RSARLO, 0x0); outportByte(dev->ioAddr + EN0_RSARHI, 0x41); outportByte(dev->ioAddr, E8390_RWRITE + E8390_START); if (word16 != 0x0) { for (i = 0; i < length / 2; i++) { outportWord(dev->ioAddr + NE_DATAPORT, packet16[i]); } } else { for (i = 0; i < length; i++) { outportByte(dev->ioAddr + NE_DATAPORT, packet8[i]); } } for (i = 0; i <= 100; i++) { if ((inportByte(dev->ioAddr + EN0_ISR) & 0x40) == 0x40) { break; } } outportByte(dev->ioAddr + EN0_ISR, 0x40); outportByte(dev->ioAddr + EN0_TPSR, 0x41); //ei_local->txStartPage); outportByte(dev->ioAddr + 0x05, (length & 0xFF)); outportByte(dev->ioAddr + 0x06, (length >> 8)); outportByteP(dev->ioAddr, 0x26); //kprintf("SENT\n"); return (length); } int NICtoPC(struct device *dev, void *packet, int length, int nic_addr) { int i = 0x0; uInt16 *packet16 = (uInt16 *) packet; assert(length); if (length & 0x01) length++; outportByte(dev->ioAddr + EN0_RCNTLO, (length & 0xFF)); outportByte(dev->ioAddr + EN0_RCNTHI, (length >> 8)); outportByte(dev->ioAddr + EN0_RSARLO, nic_addr & 0xFF); outportByte(dev->ioAddr + EN0_RSARHI, nic_addr >> 8); outportByte(dev->ioAddr, 0x0A); for (i = 0; i < length / 2; i++) { packet16[i] = inportWord(dev->ioAddr + NE_DATAPORT); } outportByte(dev->ioAddr + EN0_ISR, 0x40); return (length); } void ne2kHandler() { uInt16 isr = 0x0; uInt16 status = 0x0; irqDisable(10); outportByte(mPic, eoi); outportByte(sPic, eoi); asm("sti"); isr = inportByte(mDev->ioAddr + NE_ISR); if ((isr & 0x02) == 0x02) { outportByte(mDev->ioAddr + NE_ISR, 0x0A); status = inportByte(0x280 + NE_TPSR); } if ((isr & 0x01) == 0x01) { if (dp_recv(mDev)) { kprintf("Error Getting Packet\n"); } outportByte(mDev->ioAddr + NE_ISR, 0x05); } outportByte(mDev->ioAddr + NE_IMR, 0x0); outportByte(mDev->ioAddr + NE_IMR, 0x0B); asm("cli"); irqEnable(10); return; } static int dp_recv(struct device *dev) { dp_rcvhdr_t header; unsigned int pageno = 0x0, curr = 0x0, next = 0x0; int packet_processed = 0x0, r = 0x0; uInt16 eth_type = 0x0; uInt32 length = 0x0; pageno = inportByte(dev->ioAddr + NE_BNRY) + 1; if (pageno == stopPage) pageno = startPage; do { outportByte(dev->ioAddr + NE_CMD, 0x40); curr = inportByte(dev->ioAddr + NE_CURRENT); outportByte(dev->ioAddr, 0x0); if (curr == pageno) break; getblock(dev, pageno, (size_t) 0, sizeof(header), &header); getblock(dev, pageno, sizeof(header) + 2 * sizeof(ether_addr_t), sizeof(eth_type), ð_type); length = (header.dr_rbcl | (header.dr_rbch << 8)) - sizeof(dp_rcvhdr_t); next = header.dr_next; //kprintf("length: [0x%X:0x%X:0x%X]\n",header.dr_next,header.dr_status,length); if (length < 60 || length > 1514) { kprintf("dp8390: packet with strange length arrived: %d\n", length); next = curr; } else if (next < startPage || next >= stopPage) { kprintf("dp8390: strange next page\n"); next = curr; } else if (header.dr_status & RSR_FO) { kpanic("dp8390: fifo overrun, resetting receive buffer\n"); next = curr; } else if (header.dr_status & RSR_PRX) { r = dp_pkt2user(dev, pageno, length); if (r != OK) { kprintf("FRUIT"); return (0x0); } packet_processed = 0x1; } if (next == startPage) outportByte(dev->ioAddr + NE_BNRY, stopPage - 1); else outportByte(dev->ioAddr + NE_BNRY, next - 1); pageno = next; } while (packet_processed == 0x0); return (0x0); } static void getblock(struct device *dev, int page, size_t offset, size_t size, void *dst) { uInt16 *ha = 0x0; int i = 0x0; ha = (uInt16 *) dst; offset = page * DP_PAGESIZE + offset; outportByte(dev->ioAddr + NE_RBCR0, size & 0xFF); outportByte(dev->ioAddr + NE_RBCR1, size >> 8); outportByte(dev->ioAddr + EN0_RSARLO, offset & 0xFF); outportByte(dev->ioAddr + EN0_RSARHI, offset >> 8); outportByte(dev->ioAddr + NE_CMD, E8390_RREAD | E8390_START); size /= 2; for (i = 0; i < size; i++) ha[i] = inportWord(dev->ioAddr + NE_DATAPORT); outportByte(dev->ioAddr + EN0_ISR, 0x40); } static int dp_pkt2user(struct device *dev, int page, int length) { int last = 0x0; struct nicBuffer *tmpBuf = 0x0; last = page + (length - 1) / DP_PAGESIZE; if (last >= stopPage) { kprintf("FOOK STOP PAGE!!!"); } else { tmpBuf = ne2kAllocBuffer(length); NICtoPC(dev, tmpBuf->buffer, length, page * DP_PAGESIZE + sizeof(dp_rcvhdr_t)); } return (OK); } struct nicBuffer *ne2kAllocBuffer(int length) { struct nicBuffer *tmpBuf = 0x0; spinLock(&ne2k_spinLock); if (ne2kBuffer == 0x0) { ne2kBuffer = (struct nicBuffer *) kmalloc(sizeof(struct nicBuffer)); ne2kBuffer->next = 0x0; ne2kBuffer->length = length; ne2kBuffer->buffer = (char *) kmalloc(length); spinUnlock(&ne2k_spinLock); return (ne2kBuffer); } else { for (tmpBuf = ne2kBuffer; tmpBuf->next != 0x0; tmpBuf = tmpBuf->next) ; tmpBuf->next = (struct nicBuffer *) kmalloc(sizeof(struct nicBuffer)); tmpBuf = tmpBuf->next; tmpBuf->next = 0x0; tmpBuf->length = length; tmpBuf->buffer = (char *) kmalloc(length); spinUnlock(&ne2k_spinLock); return (tmpBuf); } spinUnlock(&ne2k_spinLock); return (0x0); } struct nicBuffer *ne2kGetBuffer() { struct nicBuffer *tmpBuf = 0x0; if (ne2k_spinLock == 0x1) return (0x0); tmpBuf = ne2kBuffer; if (ne2kBuffer != 0x0) ne2kBuffer = ne2kBuffer->next; return (tmpBuf); } void ne2kFreeBuffer(struct nicBuffer *buf) { kfree(buf->buffer); kfree(buf); return; } /*** $Log: ne2k.c,v $ Revision 1.1.1.1 2006/06/01 12:46:12 reddawg ubix2 Revision 1.2 2005/10/12 00:13:37 reddawg Removed Revision 1.1.1.1 2005/09/26 17:24:02 reddawg no message Revision 1.24 2004/09/28 21:47:56 reddawg Fixed deadlock now safe to use in bochs Revision 1.23 2004/09/16 22:35:28 reddawg Demo Release Revision 1.22 2004/09/15 21:25:33 reddawg Fixens Revision 1.21 2004/09/11 19:15:37 reddawg here you go irq 10 io 240 for your ne2k nic Revision 1.20 2004/09/07 22:26:04 reddawg synced in Revision 1.19 2004/09/07 21:54:38 reddawg ok reverted back to old scheduling for now.... Revision 1.18 2004/09/06 15:13:25 reddawg Last commit before FreeBSD 6.0 Revision 1.17 2004/08/01 20:40:45 reddawg Net related fixes Revision 1.16 2004/07/28 22:23:02 reddawg make sure it still works before I goto bed Revision 1.15 2004/07/17 17:04:47 reddawg ne2k: added assert hopefully it will help me solve this dma size 0 random error Revision 1.14 2004/07/14 12:03:50 reddawg ne2k: ne2kInit to ne2k_init Changed Startup Routines Revision 1.13 2004/06/04 10:19:42 reddawg notes: we compile again, thank g-d anyways i was about to cry Revision 1.12 2004/05/21 12:48:22 reddawg Cleaned up Revision 1.11 2004/05/19 04:07:42 reddawg kmalloc(size,pid) no more it is no kmalloc(size); the way it should of been Revision 1.10 2004/05/10 02:23:24 reddawg Minor Changes To Source Code To Prepare It For Open Source Release END ***/