openblt

a hobby OS from the late 90s
git clone http://frotz.net/git/openblt.git
Log | Files | Refs | LICENSE

ne2000.c (29981B)


      1 /* $Id: //depot/blt/srv/network/device/ne/ne2000.c#1 $
      2 **
      3 ** Copyright 1998 Brian J. Swetland
      4 ** All rights reserved.
      5 **
      6 ** Redistribution and use in source and binary forms, with or without
      7 ** modification, are permitted provided that the following conditions
      8 ** are met:
      9 ** 1. Redistributions of source code must retain the above copyright
     10 **    notice, this list of conditions, and the following disclaimer.
     11 ** 2. Redistributions in binary form must reproduce the above copyright
     12 **    notice, this list of conditions, and the following disclaimer in the
     13 **    documentation and/or other materials provided with the distribution.
     14 ** 3. The name of the author may not be used to endorse or promote products
     15 **    derived from this software without specific prior written permission.
     16 **
     17 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18 ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19 ** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20 ** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21 ** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22 ** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26 ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 */
     28 /* This file contains a network driver core for the NE2000 card.
     29 // Use at your own risk!    (C) Copyright 1997,
     30 // Douglas Armstrong	site@xnet.com	drarmstr@uiuc.edu	10/11/97
     31 // ... 
     32 // derived from National Semiconductor datasheets and application notes
     33 // as well as the Linux driver by Donald Becker */
     34 
     35 /* History Log:
     36 10-25-97	Setup under CVS					drarmstr
     37 10-27-97	Added alloc_buffer() and free_buffer()		drarmstr
     38 12-08-97	Finished scatter gather				drarmstr
     39 03-03-98	Minor bug / Output cleanup			drarmstr
     40 03-04-98	snic->tx_buf[]  packet_buf -> packet_buf*	drarmstr
     41 03-04-98	added passback pointer to notify and snic	drarmstr
     42 */
     43 
     44 #ifndef NULL
     45 #define NULL	0
     46 #endif	/* NULL */
     47 #include <i386/io.h>
     48 #include "defs.h"
     49 #include "ne2000.h"
     50 #include "err.h"
     51 //extern void kprintf(char *, ...);	/* Make sure your OS has these...*/
     52 #define kprintf(f, a...)
     53 //#define kprintf printf
     54 extern void idle();
     55 extern unsigned long ticks;	
     56 			/* replace with a better timeout method, like wait() */
     57 
     58 #ifdef XXX
     59 static char *BLARGH = 0xB8000 + 160*23 + 152;
     60 #define t(a) { BLARGH[0] = #a[0]; }
     61 #define T(a) { BLARGH[2] = #a[0]; }
     62 #else
     63 #define t(a) {}
     64 #define T(a) {}
     65 #endif
     66 
     67 /* we may have to change inb and outb to inb_p and outb_p.
     68 // Note, none of this code is gauranteed to be reentrant.
     69 
     70 // Note, don't create two nics to the same card and then try to use both 
     71 // of them.  The results will be unpredictable.
     72 
     73 // This violates IO resource manegment if your OS handles that, but it 
     74 // works for now.  Make sure that the driver has privlige access to the 
     75 // mapped I/O space and the IRQ.*/
     76 static unsigned int default_ports[] = { 0x300, 0x280, 0x320, 0x340, 0x360, 0 };
     77 
     78 /* internal procedure, don't call this directly.*/
     79 int nic_probe(int addr) {
     80 	uint regd;
     81 	uint state=inb(addr);		/* save command state */
     82 
     83 	if(inb(addr==0xff)) return ERRNOTFOUND;
     84 
     85 	outb(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr);
     86 	regd=inb(addr + 0x0d);
     87 	outb(0xff, addr + 0x0d);
     88 	outb(NIC_DMA_DISABLE | NIC_PAGE0, addr);
     89 	inb(addr + FAE_TALLY);	/* reading CNTR0 resets it.*/
     90 	if(inb(addr + FAE_TALLY)) {	/* counter didn't clear so probe fails*/
     91 		outb(state,addr);	/* restore command state*/
     92 		outb(regd,addr + 0x0d);
     93 		return ERRNOTFOUND; }
     94 
     95 	return addr;	/* network card detected at io addr;*/
     96 }
     97 
     98 /* Detects for presence of NE2000 card.  Will check given io addr that 
     99 // is passed to it as well as the default_ports array.  Returns ERRNOTFOUND 
    100 // if no card is found, i/o address otherwise.  This does conduct an ISA
    101 // probe, so it's not always a good idea to run it.  If you already have 
    102 // the information, then you can just use that with nic_init().*/
    103 int nic_detect(int given) {
    104 	int found; int f;
    105 	kprintf("NE2000: detecting card...");
    106 	if(given) if((found=nic_probe(given))!=ERRNOTFOUND) {
    107 		kprintf("found at given:0x%x\n",given);
    108 		return found; }
    109 
    110 	/* probe for PCI clones here....  or not...*/
    111 
    112 	for(f=0;default_ports[f]!='\0';f++) {
    113 		// perform resource manegment here
    114 		if((found=nic_probe(default_ports[f]))!=ERRNOTFOUND) {
    115 			kprintf("found at default:0x%x\n",default_ports[f]);
    116 			return found; }
    117 	}
    118 	kprintf("none found.\n");
    119 	return ERRNOTFOUND;
    120 }
    121 
    122 /* This initializes the NE2000 card.  If it turns out the card is not
    123 // really a NE2000 after all then it will return ERRNOTFOUND, else NOERR
    124 // It also dumps the prom into buffer prom for the upper layers..
    125 // Pass it a nic with a null iobase and it will initialize the structure for
    126 // you, otherwise it will just reinitialize it. */
    127 int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual) {
    128 	uint f;
    129 	kprintf("NE2000: reseting NIC card...");
    130 	if(!nic->iobase) {
    131 		nic->iobase=addr;
    132 		nic_stat_clear(&nic->stat);
    133 		nic->pstart=0; nic->pstop=0; nic->wordlength=0; 
    134 		nic->current_page=0;
    135 		nic->notify=NULL;
    136 		for(f=0;f<MAX_TX;f++) {
    137 			nic->tx_packet[f]= NULL;
    138 /*			nic->tx_packet[f].count=0;
    139 			nic->tx_packet[f].buf=NULL;
    140 			nic->tx_packet[f].page=0; */
    141 		}
    142 		nic->last_tx=NULL;
    143 		nic->busy=0;
    144 		nic->sending=0;
    145 	} else {
    146 		if(!nic->iobase || nic->iobase!=addr) return ERR;
    147 	}
    148 	
    149 
    150 	outb(inb(addr + NE_RESET), addr + NE_RESET);	/* reset the NE2000*/
    151 	while(!(inb_p(addr+INTERRUPTSTATUS) & ISR_RST)) {
    152 		/* TODO insert timeout code here.*/
    153 	}
    154 	kprintf("done.\n");
    155 	outb_p(0xff,addr + INTERRUPTSTATUS);	/* clear all pending ints*/
    156 
    157 	// Initialize registers
    158 	outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr);	/* enter page 0*/
    159 	outb_p(DCR_DEFAULT, addr + DATACONFIGURATION);
    160 	outb_p(0x00, addr + REMOTEBYTECOUNT0);
    161 	outb_p(0x00, addr + REMOTEBYTECOUNT1);
    162 	outb_p(0x00, addr + INTERRUPTMASK);	/* mask off all irq's*/
    163 	outb_p(0xff, addr + INTERRUPTSTATUS);	/* clear pending ints*/
    164 	outb_p(RCR_MON, RECEIVECONFIGURATION);	/* enter monitor mode*/
    165 	outb_p(TCR_INTERNAL_LOOPBACK, TRANSMITCONFIGURATION); /* internal loopback*/
    166 	
    167 	nic->wordlength=nic_dump_prom(nic,prom);
    168 	if(prom[14]!=0x57 || prom[15]!=0x57) {
    169 		kprintf("NE2000: PROM signature does not match NE2000 0x57.\n");
    170 		return ERRNOTFOUND;
    171 	}
    172 	kprintf("NE2000: PROM signature matches NE2000 0x57.\n");
    173 
    174 	/* if the wordlength for the NE2000 card is 2 bytes, then
    175 	// we have to setup the DP8390 chipset to be the same or 
    176 	// else all hell will break loose.*/
    177 	if(nic->wordlength==2) {
    178 		outb_p(DCR_DEFAULT_WORD, addr + DATACONFIGURATION);
    179 	}
    180 	nic->pstart=(nic->wordlength==2) ? PSTARTW : PSTART;
    181 	nic->pstop=(nic->wordlength==2) ? PSTOPW : PSTOP;
    182 
    183 	outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr);
    184 	outb_p(nic->pstart, addr + TRANSMITPAGE);	/* setup local buffer*/
    185 	outb_p(nic->pstart + TXPAGES, addr + PAGESTART);
    186 	outb_p(nic->pstop - 1, addr + BOUNDARY);
    187 	outb_p(nic->pstop, addr + PAGESTOP);
    188 	outb_p(0x00, addr + INTERRUPTMASK);	/* mask off all irq's*/
    189 	outb_p(0xff, addr + INTERRUPTSTATUS);	/* clear pending ints*/
    190 	nic->current_page=nic->pstart + TXPAGES;
    191 	
    192 	/* put physical address in the registers */
    193 	outb_p(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr);  /* switch to page 1 */
    194 	if(manual) for(f=0;f<6;f++) outb_p(manual[f], addr + PHYSICAL + f);
    195 	else for(f=0;f<LEN_ADDR;f++) outb_p(prom[f], addr + PHYSICAL + f);
    196 	kprintf("NE2000: Physical Address- ");
    197 	kprintf("%X:%X:%X:%X:%X:%X\n",
    198 		inb(addr+PAR0),inb(addr+PAR1),inb(addr+PAR2),
    199 		inb(addr+PAR3),inb(addr+PAR4),inb(addr+PAR5));
    200 
    201 	/* setup multicast filter to accept all packets*/
    202 	for(f=0;f<8;f++) outb_p(0xFF, addr + MULTICAST + f);
    203 
    204 	outb_p(nic->pstart+TXPAGES, addr + CURRENT);
    205 	outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* switch to page 0 */
    206 
    207 	return NOERR;
    208 }
    209 
    210 /* This registers the function that will be called when a new packet 
    211 // comes in. */
    212 void nic_register_notify(snic *nic,
    213 			void (*newnotify)(void*,packet_data*), void *passback){
    214 	nic->kore= passback;
    215 	nic->notify= newnotify;
    216 }
    217 
    218 /* start the NIC so it can actually recieve or transmit packets */
    219 void nic_start(snic *nic, int promiscuous) {
    220 	int iobase;
    221 	kprintf("NE2000: Starting NIC.\n");
    222 	if(!nic || !nic->iobase) {
    223 		kprintf("NE2000: can't start a non-initialized card.\n");
    224 		return; }
    225 	iobase=nic->iobase;
    226 	outb(0xff, iobase + INTERRUPTSTATUS);
    227 	outb(IMR_DEFAULT, iobase + INTERRUPTMASK);
    228 	outb(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
    229 	outb(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION);
    230 	if(promiscuous)
    231 		outb(RCR_PRO | RCR_AM, iobase + RECEIVECONFIGURATION);
    232 	else
    233 		outb(RCR_DEFAULT, iobase + RECEIVECONFIGURATION);
    234 
    235 	/* The following is debugging code! */
    236 #ifdef SHIT
    237 	kprintf("NE2000: Trying to fire off an IRQ.\n");
    238 	outb_p(0x50,iobase+INTERRUPTMASK);
    239 	outb_p(0x00,iobase+REMOTEBYTECOUNT0);
    240 	outb_p(0x00,iobase+REMOTEBYTECOUNT1); 
    241 	outb_p(NIC_REM_READ | NIC_START,iobase);   /* this should fire off */
    242 	outb_p(IMR_DEFAULT,iobase+INTERRUPTMASK);  /* an interrupt... */
    243 	outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
    244 	outb_p(0xff,iobase+INTERRUPTSTATUS); 
    245 #endif
    246             /* End debugging code */
    247 }
    248 
    249 /* stops the NIC */
    250 void nic_stop(snic *nic) {
    251 	unsigned char tmp_buffer[16];	
    252 	if(!nic || !nic->iobase) return;    /* make sure card was initialized */
    253 	nic_init(nic,nic->iobase,tmp_buffer,NULL);
    254 }
    255 
    256 void nic_isr(snic *nic) {
    257 	uint isr;	/* Illinois Sreet Residence Hall */
    258 	uint overload;
    259 	if(!nic || !nic->iobase) return;    /* make sure card was initialized */
    260 	outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase);
    261 	overload=MAX_LOAD+1;
    262 	while((isr=inb_p(nic->iobase+INTERRUPTSTATUS))) {
    263 		if((--overload)<=0) break;
    264 		if(isr & ISR_OVW)			nic_overrun(nic);
    265 		else if(isr & (ISR_PRX | ISR_RXE))	nic_rx(nic);
    266 		if(isr & ISR_PTX)			nic_tx(nic);
    267 		else if(isr & ISR_TXE)			nic_tx_err(nic);
    268 		if(isr & ISR_CNT)			nic_counters(nic);
    269 		if(isr & ISR_RDC) outb_p(ISR_RDC, nic->iobase+ INTERRUPTSTATUS);
    270 		outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase);
    271 	}
    272 	if(isr) {
    273 		outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase);
    274 		if(!overload) {
    275 			kprintf("NE2000: Too many requests in ISR.  ISR:%X  MaxLoad:%X\n",
    276 				isr, MAX_LOAD);
    277 			outb_p(ISR_ALL, nic->iobase + INTERRUPTSTATUS); // clear
    278 		} else {
    279 			kprintf("NE2000: Unhandeled interrupt, ISR:%X\n",isr);
    280 			outb_p(0xff, nic->iobase + INTERRUPTSTATUS);
    281 								// Ack it anyway
    282 		}
    283 	}
    284 }
    285 
    286 /* You should call this before you just read the stats directlly from the
    287 // snic struct.  This procedure updates the counters */
    288 nic_stat nic_get_stats(snic *nic) { 
    289 	nic->stat.errors.frame_alignment+=inb_p(nic->iobase + FAE_TALLY);
    290 	nic->stat.errors.crc+=inb_p(nic->iobase + CRC_TALLY);
    291 	nic->stat.errors.missed_packets+=inb_p(nic->iobase + MISS_PKT_TALLY);
    292 	return nic->stat;
    293 }
    294 
    295 void nic_stat_clear(nic_stat *that) {
    296 	that->rx_packets=0;
    297 	that->tx_buffered=0;		that->tx_packets=0;
    298 	that->errors.frame_alignment=0;	that->errors.crc=0;
    299 	that->errors.missed_packets=0;	that->errors.rx=0;
    300 	that->errors.rx_size=0;		that->errors.rx_dropped=0;
    301 	that->errors.rx_fifo=0;		that->errors.rx_overruns=0;
    302 	that->errors.tx_collisions=0;
    303 }
    304 
    305 /* Since this could be called by more than one other device, it should
    306 // be properly protected for reentrancy.  We should put in a proper
    307 // semaphore or something, look into this.
    308 // NOTE: It is your responsibility to clean up the packet_buffer when you 
    309 // are done calling this. */
    310 /* TODO- Have it check how lonk a transmission is taking and attempt to 
    311     restart the card if it's too long. */
    312 int nic_send_packet(snic *nic, packet_buffer *buffer) {
    313 	uint timeout;	uint f;	int iobase;
    314 /*	kprintf("nic_send_packet()\n"); */
    315 	if(!buffer) return ERRARG;
    316 	if(!buffer->count || !buffer->buf) return ERRARG;
    317 	if(!nic || !nic->iobase) return ERR;
    318 	iobase=nic->iobase;
    319 
    320 	t(A);
    321         
    322 	buffer->len=0;
    323 	for(f=0;f<buffer->count;f++) buffer->len+=buffer->buf[f].len;
    324 	if(buffer->len>MAX_LENGTH) return ERRTOOBIG;
    325 
    326         t(B);
    327         
    328 	/* the following wait for anyother tasks that are calling 
    329 	// nic_send_packet() right now.  Note that this doesn't use
    330 	// an atomic semaphore, so something MAY leak through. */
    331 /*	timeout=ticks+10;	wait 10 ticks */
    332 	timeout=ticks+100;
    333 	while(nic->busy && ticks<=timeout) idle();
    334 	/* Replace this with a proper timeout thing that doesn't use the
    335 	// ticks method which will be diffrent on each OS. */
    336 	t(C);
    337         if(nic->busy) {
    338 		kprintf("NE2000: ERROR: Card stalled, timeout.\n");
    339 		return ERRTIMEOUT;
    340 	}
    341 	nic->busy=1;	/* mark as busy, replace with semaphore */
    342 
    343         t(D);
    344         
    345 	outb_p(0x00, iobase + INTERRUPTMASK);	/* mask ints for now */
    346         t(E);
    347         
    348 	timeout=ticks+TIMEOUT_TX;
    349 	while(idle(), ticks<=timeout) for(f=0;f<MAX_TX;f++) {
    350 		if(!nic->tx_packet[f]) {
    351                     t(F);
    352                     
    353 /*			nic->tx_packet[f]=*buffer;*/
    354 			nic->tx_packet[f]=buffer;
    355 			nic->tx_packet[f]->page=nic->pstart + (f * MAX_PAGESPERPACKET);
    356 								/*output page */
    357 
    358 /*			kprintf("NE2000: sending packet with count:%x on page:%X with buffer:%x\n",
    359 				buffer->count,buffer->page,buffer->buf); */
    360                         t(>);
    361                         
    362                         nic_block_output(nic,nic->tx_packet[f]);
    363 
    364                         t(<);
    365                         
    366 			if(!nic->sending) {
    367 				nic->send=f;	nic->sending=1;
    368 				/* now let's actually trigger the transmitter */
    369                                 t(I);
    370                                 
    371                                 if(nic_send(nic,f)<0) {
    372 					nic->sending=0;
    373 					break; }
    374                                 
    375 				/* note, the nic_tx() interrupt will mark this
    376 				// tx_packet buffer as free again once it
    377 				// confirms that the packet was sent. */
    378 			}
    379                         t(J);
    380                                 
    381 			nic->stat.tx_buffered++;
    382 			outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */
    383 			nic->busy=0;	/* V() */
    384                         t(K);
    385                         
    386 			return NOERR;
    387 		}
    388 	}
    389 
    390         t(L);
    391         
    392 	outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK);	/* unmask */
    393 	nic->busy=0;	/* V() */
    394 	kprintf("NE2000: ERROR: Transmitter stalled, card timeout.\n");
    395 	if(f==MAX_TX) {
    396 		kprintf("NE2000: ERROR: There are no transmit buffers available.  TX stalled.\n");
    397 		return ERRTIMEOUT;
    398 	}
    399 	return ERR;
    400 }
    401 
    402 /* dumps the prom into a 16 byte buffer and returns the wordlength of
    403 // the card.
    404 // You should be able to make this procedure a wrapper of nic_block_input(). */
    405 int nic_dump_prom(snic *nic, unsigned char *prom) {
    406 	uint f;
    407 	int iobase=nic->iobase;
    408 	char wordlength=2;		/* default wordlength of 2 */
    409 	unsigned char dump[32];
    410 	outb_p(32, iobase + REMOTEBYTECOUNT0);	  /* read 32 bytes from DMA->IO */
    411 	outb_p(0x00, iobase + REMOTEBYTECOUNT1);  /*  this is for the PROM dump */
    412 	outb_p(0x00, iobase + REMOTESTARTADDRESS0); /* configure DMA for 0x0000 */
    413 	outb_p(0x00, iobase + REMOTESTARTADDRESS1);
    414 	outb_p(NIC_REM_READ | NIC_START, iobase);
    415 	for(f=0;f<32;f+=2) {
    416 		dump[f]=inb_p(iobase + NE_DATA);
    417 		dump[f+1]=inb_p(iobase + NE_DATA);
    418 		if(dump[f]!=dump[f+1]) wordlength=1;
    419 	}
    420 	/* if wordlength is 2 bytes, then collapse prom to 16 bytes */
    421 	for(f=0;f<LEN_PROM;f++) prom[f]=dump[f+((wordlength==2)?f:0)];
    422 /*	kprintf("NE2000: prom dump - ");
    423 	for(f=0;f<LEN_PROM;f++) kprintf("%X",prom[f]);
    424 	kprintf("\n");	*/
    425 
    426 	return wordlength;
    427 }
    428 
    429 void nic_overrun(snic *nic) {
    430 	uint tx_status;	int iobase=nic->iobase;
    431 	long starttime;	uint resend=0;
    432 	kprintf("NE2000: Receive packet ring overrun!\n");
    433 	if(!nic || !nic->iobase) return;
    434 	tx_status=inb_p(iobase) & NIC_TRANSMIT;
    435 	outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, iobase);
    436 	nic->stat.errors.rx_overruns++;
    437 
    438 	starttime=ticks;
    439 kprintf("BEFORE\n");
    440 	while(ticks-starttime<=10/*ticks to wait*/) idle();
    441 	/* Arrgh!  TODO: Replace this whole crappy code with a decent
    442 	// wait method.  We need to wait at least 1.6ms as per National
    443 	// Semiconductor datasheets, but we should probablly wait a 
    444 	// little more to be safe. */
    445 kprintf("AFTER\n");
    446 
    447 	outb_p(0x00, iobase + REMOTEBYTECOUNT0);
    448 	outb_p(0x00, iobase + REMOTEBYTECOUNT1);
    449 	if(tx_status) {
    450 		uint tx_completed=inb_p(iobase + INTERRUPTSTATUS) & 
    451 			(ISR_PTX | ISR_TXE);
    452 		if(!tx_completed) resend=1;
    453 	}
    454 
    455 	outb_p(TCR_INTERNAL_LOOPBACK, iobase + TRANSMITCONFIGURATION);
    456 	outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
    457 	nic_rx(nic);	/* cleanup RX ring */
    458 	outb_p(ISR_OVW, iobase + INTERRUPTSTATUS);	/* ACK INT */
    459 
    460 	outb_p(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION);
    461 	if(resend)
    462 		outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START | NIC_TRANSMIT,
    463 			iobase);
    464 }
    465 
    466 /* This is the procedure that markst the transmit buffer as available again */
    467 void nic_tx(snic *nic) {
    468 	uint f;			int iobase=nic->iobase;
    469 	uint status;
    470 /*	kprintf("nic_tx()\n"); */
    471 	if(!nic || !nic->iobase) return;
    472 	status=inb(iobase + TRANSMITSTATUS);
    473 
    474 	if(!nic->tx_packet[nic->send]) {
    475 		kprintf("NE2000: ERROR: Invalid transmison packet buffer.\n");
    476 		return;
    477 	}
    478 	if(!nic->sending) kprintf("NE2000: ERROR: Invalid nic->sending value.\n");
    479 
    480 	free_buffer(nic->tx_packet[nic->send]);
    481 	nic->tx_packet[nic->send]= NULL;
    482 /*	nic->tx_packet[nic->send].count=0;	 mark buffer as available */
    483 /*	nic->tx_packet[nic->send].len=0;
    484 	nic->tx_packet[nic->send].page=0; */
    485 
    486 	for(f=0;f<MAX_TX;f++) {
    487 		if(nic->tx_packet[f]) {
    488 			kprintf("NE2000: DEBUG: transmitting secondary buffer:%X\n",f);
    489 			nic->stat.tx_buffered++;
    490 			nic->send=f;	nic->sending=1;
    491 			nic_send(nic,f);	/* send a back-to-back buffer */
    492 			break;
    493 		}
    494 	}
    495 	if(f==MAX_TX) nic->sending=0;
    496 
    497 	if(status & TSR_COL) nic->stat.errors.tx_collisions++;
    498 	if(status & TSR_PTX) nic->stat.tx_packets++;
    499 	else {
    500 		if(status & TSR_ABT) {
    501 			nic->stat.errors.tx_aborts++;
    502 			nic->stat.errors.tx_collisions+=16; }
    503 		if(status & TSR_CRS) nic->stat.errors.tx_carrier++;
    504 		if(status & TSR_FU) nic->stat.errors.tx_fifo++;
    505 		if(status & TSR_CDH) nic->stat.errors.tx_heartbeat++;
    506 		if(status & TSR_OWC) nic->stat.errors.tx_window++;
    507 	}
    508 
    509 	outb_p(ISR_PTX, iobase + INTERRUPTSTATUS);	/* ack int */
    510 }
    511 
    512 void nic_tx_err(snic *nic) {
    513 	unsigned char tsr;	int iobase=nic->iobase;
    514 	if(!nic || !nic->iobase) return;
    515 	tsr=inb_p(nic->iobase);
    516 	kprintf("NE2000: ERROR: TX error: ");
    517 	if(tsr & TSR_ABT) kprintf("Too many collisions.\n");
    518 	if(tsr & TSR_ND) kprintf("Not deffered.\n");
    519 	if(tsr & TSR_CRS) kprintf("Carrier lost.\n");
    520 	if(tsr & TSR_FU) kprintf("FIFO underrun.\n");
    521 	if(tsr & TSR_CDH) kprintf("Heart attack!\n");
    522 
    523 	outb_p(ISR_TXE, iobase + INTERRUPTSTATUS);
    524 	if(tsr & (TSR_ABT | TSR_FU)) {
    525 		kprintf("NE2000: DEBUG: Attempting to retransmit packet.\n");
    526 		nic_tx(nic);
    527 	}
    528 }
    529 
    530 void nic_rx(snic *nic) {
    531 	uint packets=0;	uint frame;	uint rx_page;	uint rx_offset;
    532 	uint len;	uint next_pkt;	uint numpages;
    533 	int iobase=nic->iobase;
    534 	buffer_header header;
    535 	if(!nic || !nic->iobase) return;
    536 	while(packets<MAX_RX) {
    537 		outb_p(NIC_DMA_DISABLE | NIC_PAGE1, iobase); /*curr is on page 1 */
    538 		rx_page=inb_p(iobase + CURRENT);	/* get current page */
    539 		outb_p(NIC_DMA_DISABLE | NIC_PAGE0, iobase);
    540 		frame=inb(iobase + BOUNDARY)+1;
    541 			/* we add one becuase boundary is a page behind
    542 			// as pre NS notes to help in overflow problems */
    543 		if(frame>=nic->pstop) frame=nic->pstart+TXPAGES;
    544 							/* circual buffer */
    545 
    546 		if(frame != nic->current_page) {
    547 			kprintf("NE2000: ERROR: mismatched read page pointers!\n");
    548 			kprintf("NE2000: NIC-Boundary:%x  dev-current_page:%x\n",
    549 				frame, nic->current_page); }
    550 
    551 /*		kprintf("Boundary-%x  Current-%x\n",frame-1,rx_page); */
    552 		if(frame==rx_page) break;	/* all frames read */
    553 
    554 		rx_offset=frame << 8;  /* current ptr in bytes(not pages) */
    555 
    556 		nic_get_header(nic,frame,&header);
    557 		len=header.count - sizeof(buffer_header);
    558 							/* length of packet */
    559 		next_pkt=frame + 1 + ((len+4)>>8); /* next packet frame */
    560 
    561 		numpages=nic->pstop-(nic->pstart+TXPAGES);
    562 		if(	   (header.next!=next_pkt)
    563 			&& (header.next!=next_pkt + 1)
    564 			&& (header.next!=next_pkt - numpages)
    565 			&& (header.next != next_pkt +1 - numpages)){
    566 				kprintf("NE2000: ERROR: Index mismatch.   header.next:%X  next_pkt:%X frame:%X\n",
    567 					header.next,next_pkt,frame);
    568 				nic->current_page=frame;
    569 				outb(nic->current_page-1, iobase + BOUNDARY);
    570 				nic->stat.errors.rx++;
    571 				continue;
    572 		}
    573 
    574 		if(len<60 || len>1518) {
    575 			kprintf("NE2000: invalid packet size:%d\n",len);
    576 			nic->stat.errors.rx_size++;
    577 		} else if((header.status & 0x0f) == RSR_PRX) {
    578 			/* We have a good packet, so let's recieve it! */
    579 
    580 			packet_data *newpacket=alloc_buffer_data(len);
    581 			if(!newpacket) {
    582 				kprintf("NE2000: ERROR: out of memory!\n");
    583 				nic->stat.errors.rx_dropped++;
    584                                 nic_block_input(nic,NULL,len,rx_offset+
    585                                                 sizeof(buffer_header));
    586 			} else {
    587                             nic_block_input(nic,newpacket->ptr,newpacket->len,
    588                                             rx_offset+sizeof(buffer_header));
    589 								/* read it */
    590                             
    591                             if(nic->notify) nic->notify(nic->kore,newpacket);
    592                             else free_buffer_data(newpacket);
    593                                 /* NOTE: you are responsible for deleting this buffer. */
    594 
    595                             nic->stat.rx_packets++;
    596                         }
    597 		} else {
    598 			kprintf("NE2000: ERROR: bad packet.  header-> status:%X next:%X len:%x.\n",
    599 				header.status,header.next,header.count);
    600 			if(header.status & RSR_FO) nic->stat.errors.rx_fifo++;
    601 		}
    602 /*		kprintf("frame:%x  header.next:%x  next_pkt:%x\n",
    603 			frame,header.next,next_pkt); */
    604 		next_pkt=header.next;
    605 
    606 		if(next_pkt >= nic->pstop) {
    607 			kprintf("NE2000: ERROR: next frame beyond local buffer!  next:%x.\n",
    608 				next_pkt);
    609 			next_pkt=nic->pstart+TXPAGES;
    610 		}
    611 
    612 		nic->current_page=next_pkt;
    613 		outb_p(next_pkt-1, iobase + BOUNDARY);
    614 	}
    615 	outb_p(ISR_PRX | ISR_RXE, iobase + INTERRUPTSTATUS);	/* ack int */
    616 }
    617 
    618 void nic_counters(snic *nic) {
    619 	nic->stat.errors.frame_alignment+=inb_p(nic->iobase+FAE_TALLY);
    620 	nic->stat.errors.crc+=inb_p(nic->iobase+CRC_TALLY);
    621 	nic->stat.errors.missed_packets+=inb_p(nic->iobase+MISS_PKT_TALLY);
    622 	/* reading the counters on the DC8390 clears them. */
    623 	outb_p(ISR_CNT, nic->iobase + INTERRUPTSTATUS); /* ackkowledge int */
    624 }
    625 
    626 /* You should be able to make this procedure a wrapper of nic_block_input */
    627 void nic_get_header(snic *nic, uint page, buffer_header *header) {
    628 	int iobase=nic->iobase;	uint f;
    629 	outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
    630 	outb_p(sizeof(buffer_header), iobase + REMOTEBYTECOUNT0);
    631 	outb_p(0, iobase + REMOTEBYTECOUNT1);		/* read the header */
    632 	outb_p(0, iobase + REMOTESTARTADDRESS0); 	/* page boundary */
    633 	outb_p(page, iobase + REMOTESTARTADDRESS1); 	/* from this page */
    634 	outb_p(NIC_REM_READ | NIC_START, iobase);	/* start reading */
    635 
    636 	if(nic->wordlength==2) for(f=0;f<(sizeof(buffer_header)>>1);f++)
    637 		((unsigned short *)header)[f]=inw(iobase+NE_DATA);
    638 	else for(f=0;f<sizeof(buffer_header);f++)
    639 		((unsigned char *)header)[f]=inb(iobase+NE_DATA);
    640 					/* Do these need to be *_p variants??? */
    641 	outb_p(ISR_RDC, iobase + INTERRUPTSTATUS);	/* finish DMA cycle */
    642 }
    643 
    644 int nic_send(snic *nic, uint buf) {
    645 	uint len= (nic->tx_packet[buf]->len<MIN_LENGTH) ?
    646 		MIN_LENGTH : nic->tx_packet[buf]->len;
    647 /*	kprintf("nic_send()\n"); */
    648 	if(!nic->tx_packet[buf]) return ERR; /* this is bad */
    649 	outb_p(NIC_DMA_DISABLE |  NIC_PAGE0, nic->iobase);
    650         if(inb_p(nic->iobase + STATUS) & NIC_TRANSMIT) {
    651 		kprintf("NE2000: ERROR: Transmitor busy.\n");
    652 		free_buffer(nic->tx_packet[buf]);
    653 		nic->tx_packet[buf]= NULL;
    654 /*                nic->tx_packet[buf].count=0;  mark as free again */
    655                 return ERRTIMEOUT; }
    656         outb_p(len & 0xff,nic->iobase+TRANSMITBYTECOUNT0);
    657         outb_p(len >> 8,nic->iobase+TRANSMITBYTECOUNT1);
    658         outb_p(nic->tx_packet[buf]->page,nic->iobase+TRANSMITPAGE);
    659         outb_p(NIC_DMA_DISABLE | NIC_TRANSMIT | NIC_START,nic->iobase);
    660 	return NOERR;
    661 }
    662 
    663 void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset) {
    664 	int iobase=nic->iobase;	uint f;
    665 	uint xfers=len;
    666 	uint timeout=TIMEOUT_DMAMATCH;	uint addr;
    667 /*	kprintf("NE2000: RX: Length:%x  Offset:%x  ",len,offset); */
    668 	outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
    669 	outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0);
    670 	outb_p(len >> 8, iobase + REMOTEBYTECOUNT1);
    671 	outb_p(offset & 0xff, iobase + REMOTESTARTADDRESS0);
    672 	outb_p(offset >> 8, iobase + REMOTESTARTADDRESS1);
    673 	outb_p(NIC_REM_READ | NIC_START, iobase);
    674 
    675             /* allow for no buffer */
    676         if(buf){
    677             if(nic->wordlength==2) {
    678 		for(f=0;f<(len>>1);f++)
    679                     ((unsigned short *)buf)[f]=inw(iobase+NE_DATA);
    680 		if(len&0x01) {
    681                     ((unsigned char *)buf)[len-1]=inb(iobase+NE_DATA);
    682                     xfers++;
    683 		}
    684             } else {
    685                 for(f=0;f<len;f++)
    686                     ((unsigned char *)buf)[f]=inb(iobase+NE_DATA);
    687             }
    688         } else {
    689             if(nic->wordlength==2) {
    690 		for(f=0;f<(len>>1);f++)
    691                     inw(iobase+NE_DATA);
    692 		if(len&0x01) {
    693                     inb(iobase+NE_DATA);
    694                     xfers++;
    695 		}
    696             } else {
    697                 for(f=0;f<len;f++)
    698                     inb(iobase+NE_DATA);
    699             }
    700         }
    701 					/* Do these need to be *_p variants??? */
    702 
    703 /*	for(f=0;f<15;f++) kprintf("%X",buf[f]); kprintf("\n"); */
    704 	/* TODO: make this timeout a constant */
    705 	for(f=0;f<timeout;f++) {
    706 		uint high=inb_p(iobase + REMOTESTARTADDRESS1);
    707 		uint low=inb_p(iobase + REMOTESTARTADDRESS0);
    708 		addr=(high<<8)+low;
    709 		if(((offset+xfers)&0xff)==low)	break;
    710 	}
    711             /*
    712 	if(f>=timeout)
    713 		kprintf("NE2000: Remote DMA address invalid.  expected:%x - actual:%x\n",
    714 			offset+xfers, addr); HUH WHAT? BJS*/
    715 	
    716 	outb_p(ISR_RDC, iobase + INTERRUPTSTATUS);	/* finish DMA cycle */
    717 }
    718 
    719 /* Now supports scatter gather */
    720 void nic_block_output(snic *nic, packet_buffer *pkt) {
    721 	int iobase=nic->iobase;
    722 	int timeout=TIMEOUT_DMAMATCH;	int f;	uint addr;	int tmplen;
    723 	int bufidx, buflen; /* current packet_data in packet_buffer */
    724 	void *bufptr;
    725 	char skip=0; /* Ask me about this if you have questions */
    726 	uint deleteme=0;	/* delete when done debugging */
    727 	outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase);
    728 
    729 	T(A);
    730         
    731 	for(f=0;f<pkt->count;f++) deleteme+=pkt->buf[f].len;
    732         T(B);
    733         
    734 	if(pkt->len != deleteme) return;
    735 
    736 	if(pkt->len > MAX_LENGTH) return;
    737 		/* we should not have gotten this far...  Paranoia check */
    738 
    739 	/* this next part is to supposedly fix a "read-before-write" bug... */
    740 	outb_p(0x42, iobase + REMOTEBYTECOUNT0);
    741 	outb_p(0x00, iobase + REMOTEBYTECOUNT1);
    742 	outb_p(0x42, iobase + REMOTESTARTADDRESS0);
    743 	outb_p(0x00, iobase + REMOTESTARTADDRESS1);
    744 	outb_p(NIC_REM_READ | NIC_START, iobase);
    745 	SLOW_DOWN_IO;	SLOW_DOWN_IO;	SLOW_DOWN_IO;
    746 
    747 	outb_p(ISR_RDC, iobase + INTERRUPTSTATUS);	/* ack remote DMA int */
    748         T(C);
    749         
    750 	tmplen=(pkt->len < MIN_LENGTH) ? MIN_LENGTH : pkt->len;
    751 	outb_p(tmplen & 0xff, iobase + REMOTEBYTECOUNT0);
    752 	outb_p(tmplen >> 8, iobase + REMOTEBYTECOUNT1);
    753 	outb_p(0x00, iobase + REMOTESTARTADDRESS0);
    754 	outb_p(pkt->page, iobase + REMOTESTARTADDRESS1);
    755 	outb_p(NIC_REM_WRITE | NIC_START, iobase);
    756 
    757         T(D);
    758         
    759 	/* go through each buffer and transfer it's contents */
    760 	for(bufidx=pkt->count-1; bufidx >= 0; bufidx--) {
    761 	  char odd;
    762 	  buflen=pkt->buf[bufidx].len; /* only do derefrence once */
    763 	  bufptr=pkt->buf[bufidx].ptr; /* for performance :) */
    764 
    765 	  if(nic->wordlength==2) {
    766 
    767 	    odd=(buflen & 0x01);
    768 	    buflen>>=1;		/* half the transfers */
    769 
    770 	    if(skip) ((uint)bufptr)--;   /* korewa baka desu */
    771 
    772 	    for(f=skip;f<buflen;f++) { /* do we skip? */
    773 	      outw(((unsigned short *)bufptr)[f],iobase+NE_DATA);
    774 	      tmplen -= 2;
    775 	    }
    776 
    777 	    /* output 16-bits of the last odd byte */
    778 	    skip=0;		/* assume we don't skip */
    779 
    780 	    if(odd) {
    781 	      short tmp=((unsigned char *)bufptr)[buflen<<1];
    782 				/* get the byte from the next segment */
    783 	      if((bufidx-1)>=0) {
    784 		tmp |= ((unsigned char *) pkt->buf[bufidx-1].ptr)[0]  << 8;
    785 	      }
    786 	      outw(tmp,iobase + NE_DATA);
    787 	      tmplen -= 2;
    788 	      skip=1;
    789 	    }
    790 	  } else 
    791 	    for(f=0;f<buflen;f++) {
    792 	      outb(((unsigned char *)bufptr)[f],iobase+NE_DATA);
    793 	      tmplen--;
    794 	    }
    795 	}
    796         T(E);
    797         
    798 	/* If it's too short, pad with 0s */
    799 	if(tmplen > 0) {
    800             T(F);
    801 /*	kprintf("Padding runt\n"); */
    802 		if(nic->wordlength==2) {
    803                     for(f=0;f<tmplen/2;f++){
    804 		      outw(0x00,iobase + NE_DATA);
    805 		      tmplen -= 2;
    806 		    }
    807 		}
    808 	}
    809 	if (tmplen > 0) {
    810 	  for(f=0;f<tmplen;f++) {
    811 	    outb(0x00,iobase + NE_DATA);
    812 	    tmplen--;
    813 	  }
    814 	}
    815 
    816 
    817         T(G);
    818 #ifdef SHIT       
    819 	if(nic->wordlength==2) {
    820 		for(w=0;w<(len>>1);w++)
    821 			outw(((unsigned short *)buf)[w],iobase+NE_DATA);
    822 		if(len & 0x01) {
    823 			short tmp=buf[len-1]; //so we can output a whole 16-bits
    824 			// if buf were on the end of something, we would die.
    825 			outw(tmp,iobase+NE_DATA);
    826 		}
    827 	} else for(f=0;f<len;f++)
    828 		outb(((unsigned char *)buf)[f],iobase+NE_DATA);
    829 
    830 #endif
    831 	for(f=0;f<timeout;f++) {
    832 		uint high=inb_p(iobase + REMOTESTARTADDRESS1);
    833 		uint low=inb_p(iobase + REMOTESTARTADDRESS0);
    834 		addr=(high<<8)+low;
    835 		if(( (((pkt->page<<8)+(nic->wordlength==2 && (pkt->len&0x01))?
    836 /*				pkt->len+1:pkt->len+2))&0xff)==low)*/
    837 				pkt->len+0:pkt->len+1))&0xff)==low)
    838 			break;
    839 		if( (pkt->len < MIN_LENGTH) && ( (((pkt->page<<8)+MIN_LENGTH)
    840 				& 0xff) == low) )
    841 			break;
    842 	}
    843         T(H);
    844 #ifdef SHIT        
    845 	if(f>=timeout)
    846 		kprintf("NE2000: Remote DMA address invalid.  expected:%x - actual:%x\n",
    847 			( (pkt->len >= MIN_LENGTH) ?
    848 				((pkt->page<<8)+
    849 					(nic->wordlength==2&&(pkt->len&0x01))?
    850 					pkt->len+0:pkt->len+1)
    851 /*					pkt->len+1:pkt->len+2)*/
    852 				: ((pkt->page<<8)+MIN_LENGTH) ),
    853 			addr);
    854 #endif
    855 /* TODO Check ISR_RDC */
    856 
    857         T(I);
    858         
    859 	outb_p(ISR_RDC, iobase + INTERRUPTSTATUS);	/* finish DMA cycle */
    860 }