ne2000.c (22729B)
1 /* $Id: //depot/blt/netboot/ne2000.c#3 $ 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 the shared code base for the 1997 SigOps NE2000 29 // network driver. 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 /* Change Log: 36 10-25-97 Setup under CVS drarmstr 37 10-27-97 Added alloc_buffer() and free_buffer() drarmstr 38 */ 39 40 #ifndef NULL 41 #define NULL 0 42 #endif /* NULL */ 43 #include "io.h" 44 #include "ne2000.h" 45 #include "ne2k.h" 46 #include "err.h" 47 48 extern void idle(); 49 extern long ticks; /* replace with a better timeout method, like wait() */ 50 51 /* we may have to change inb and outb to inb_p and outb_p. 52 // Note, none of this code is gauranteed to be reentrant. 53 54 // Note, don't create to nics to the same card and then try to use both 55 // of them. The results will be unpredictable. 56 57 // This violates IO resource manegment if your OS handles that, but it 58 // works for now. Make sure that the driver has privlige access to the 59 // mapped I/O space and the IRQ.*/ 60 static unsigned int default_ports[] = { 0x300, 0x280, 0x320, 0x340, 0x360, 0 }; 61 62 /* internal procedure, don't call this directly.*/ 63 int nic_probe(int addr) { 64 uint regd; 65 uint state=inb(addr); /* save command state */ 66 67 if(inb(addr==0xff)) return ERRNOTFOUND; 68 69 outb(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); 70 regd=inb(addr + 0x0d); 71 outb(0xff, addr + 0x0d); 72 outb(NIC_DMA_DISABLE | NIC_PAGE0, addr); 73 inb(addr + FAE_TALLY); /* reading CNTR0 resets it.*/ 74 if(inb(addr + FAE_TALLY)) { /* counter didn't clear so probe fails*/ 75 outb(state,addr); /* restore command state*/ 76 outb(regd,addr + 0x0d); 77 return ERRNOTFOUND; } 78 79 return addr; /* network card detected at io addr;*/ 80 } 81 82 /* Detects for presence of NE2000 card. Will check given io addr that 83 // is passed to it as well as the default_ports array. Returns ERRNOTFOUND 84 // if no card is found, i/o address otherwise. This does conduct an ISA 85 // probe, so it's not always a good idea to run it. If you already have 86 // the information, then you can just use that with nic_init().*/ 87 int nic_detect(int given) { 88 int found; 89 if((found=nic_probe(given))!=ERRNOTFOUND) { return found; } 90 return ERRNOTFOUND; 91 } 92 93 /* This initializes the NE2000 card. If it turns out the card is not 94 // really a NE2000 after all then it will return ERRNOTFOUND, else NOERR 95 // It also dumps the prom into buffer prom for the upper layers.. 96 // Pass it a nic with a null iobase and it will initialize the structure for 97 // you, otherwise it will just reinitialize it. */ 98 int nic_init(snic* nic, int addr, unsigned char *prom, unsigned char *manual) { 99 uint f; 100 if(!nic->iobase) { 101 nic->iobase=addr; 102 nic_stat_clear(&nic->stat); 103 nic->pstart=0; nic->pstop=0; nic->wordlength=0; 104 nic->current_page=0; 105 nic->notify=NULL; 106 for(f=0;f<MAX_TX;f++) nic->tx_packet[f].len=0; 107 nic->last_tx=NULL; 108 nic->busy=0; 109 } else { 110 if(!nic->iobase || nic->iobase!=addr) return ERR; 111 } 112 113 outb(inb(addr + NE_RESET), addr + NE_RESET); /* reset the NE2000*/ 114 while(!(inb_p(addr+INTERRUPTSTATUS) & ISR_RST)) { 115 /* TODO insert timeout code here.*/ 116 } 117 118 outb_p(0xff,addr + INTERRUPTSTATUS); /* clear all pending ints*/ 119 120 // Initialize registers 121 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* enter page 0*/ 122 outb_p(DCR_DEFAULT, addr + DATACONFIGURATION); 123 outb_p(0x00, addr + REMOTEBYTECOUNT0); 124 outb_p(0x00, addr + REMOTEBYTECOUNT1); 125 outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/ 126 outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/ 127 outb_p(RCR_MON, RECEIVECONFIGURATION); /* enter monitor mode*/ 128 outb_p(TCR_INTERNAL_LOOPBACK, TRANSMITCONFIGURATION); /* internal loopback*/ 129 130 nic->wordlength=nic_dump_prom(nic,prom); 131 if(prom[14]!=0x57 || prom[15]!=0x57) { 132 return ERRNOTFOUND; 133 } 134 135 /* if the wordlength for the NE2000 card is 2 bytes, then 136 // we have to setup the DP8390 chipset to be the same or 137 // else all hell will break loose.*/ 138 if(nic->wordlength==2) { 139 outb_p(DCR_DEFAULT_WORD, addr + DATACONFIGURATION); 140 } 141 nic->pstart=(nic->wordlength==2) ? PSTARTW : PSTART; 142 nic->pstop=(nic->wordlength==2) ? PSTOPW : PSTOP; 143 144 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); 145 outb_p(nic->pstart, addr + TRANSMITPAGE); /* setup local buffer*/ 146 outb_p(nic->pstart + TXPAGES, addr + PAGESTART); 147 outb_p(nic->pstop - 1, addr + BOUNDARY); 148 outb_p(nic->pstop, addr + PAGESTOP); 149 outb_p(0x00, addr + INTERRUPTMASK); /* mask off all irq's*/ 150 outb_p(0xff, addr + INTERRUPTSTATUS); /* clear pending ints*/ 151 nic->current_page=nic->pstart + TXPAGES; 152 153 /* put physical address in the registers */ 154 outb_p(NIC_DMA_DISABLE | NIC_PAGE1 | NIC_STOP, addr); /* switch to page 1 */ 155 if(manual) for(f=0;f<6;f++) outb_p(manual[f], addr + PHYSICAL + f); 156 else for(f=0;f<LEN_ADDR;f++) outb_p(prom[f], addr + PHYSICAL + f); 157 158 /* setup multicast filter to accept all packets*/ 159 for(f=0;f<8;f++) outb_p(0xFF, addr + MULTICAST + f); 160 161 outb_p(nic->pstart+TXPAGES, addr + CURRENT); 162 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, addr); /* switch to page 0 */ 163 164 return NOERR; 165 } 166 167 /* This registers the function that will be called when a new packet 168 // comes in. */ 169 void nic_register_notify(snic *nic, void (*newnotify)(packet_buffer *newpacket)){ 170 nic->notify=newnotify; 171 } 172 173 /* start the NIC so it can actually recieve or transmit packets */ 174 void nic_start(snic *nic, int promiscuous) { 175 int iobase; 176 if(!nic || !nic->iobase) { 177 return; } 178 iobase=nic->iobase; 179 outb(0xff, iobase + INTERRUPTSTATUS); 180 outb(IMR_DEFAULT, iobase + INTERRUPTMASK); 181 outb(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); 182 outb(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION); 183 if(promiscuous) 184 outb(RCR_PRO | RCR_AM, iobase + RECEIVECONFIGURATION); 185 else 186 outb(RCR_DEFAULT, iobase + RECEIVECONFIGURATION); 187 } 188 189 /* stops the NIC */ 190 void nic_stop(snic *nic) { 191 unsigned char tmp_buffer[16]; 192 if(!nic || !nic->iobase) return; /* make sure card was initialized */ 193 nic_init(nic,nic->iobase,tmp_buffer,NULL); 194 } 195 196 void nic_isr(snic *nic) { 197 uint isr; /* Illinois Sreet Residence Hall */ 198 uint overload; 199 if(!nic || !nic->iobase) return; /* make sure card was initialized */ 200 outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase); 201 overload=MAX_LOAD+1; 202 while((isr=inb_p(nic->iobase+INTERRUPTSTATUS))) { 203 if((--overload)<=0) break; 204 if(isr & ISR_OVW) nic_overrun(nic); 205 else if(isr & (ISR_PRX | ISR_RXE)) nic_rx(nic); 206 if(isr & ISR_PTX) nic_tx(nic); 207 else if(isr & ISR_TXE) nic_tx_err(nic); 208 // if(isr & ISR_CNT) nic_counters(nic); 209 if(isr & ISR_RDC) outb_p(ISR_RDC, nic->iobase+ INTERRUPTSTATUS); 210 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); 211 } 212 if(isr) { 213 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, nic->iobase); 214 if(!overload) { 215 216 outb_p(ISR_ALL, nic->iobase + INTERRUPTSTATUS); // clear 217 } else { 218 outb_p(0xff, nic->iobase + INTERRUPTSTATUS); 219 // Ack it anyway 220 } 221 } 222 } 223 224 /* You should call this before you just read the stats directlly from the 225 // snic struct. This procedure updates the counters */ 226 nic_stat nic_get_stats(snic *nic) { 227 nic->stat.errors.frame_alignment+=inb_p(nic->iobase + FAE_TALLY); 228 nic->stat.errors.crc+=inb_p(nic->iobase + CRC_TALLY); 229 nic->stat.errors.missed_packets+=inb_p(nic->iobase + MISS_PKT_TALLY); 230 return nic->stat; 231 } 232 233 void nic_stat_clear(nic_stat *that) { 234 that->rx_packets=0; 235 that->tx_buffered=0; that->tx_packets=0; 236 that->errors.frame_alignment=0; that->errors.crc=0; 237 that->errors.missed_packets=0; that->errors.rx=0; 238 that->errors.rx_size=0; that->errors.rx_dropped=0; 239 that->errors.rx_fifo=0; that->errors.rx_overruns=0; 240 that->errors.tx_collisions=0; 241 } 242 243 /* Since this could be called by more than one other device, it should 244 // be properly protected for reentrancy. We should put in a proper 245 // semaphore or something, look into this. 246 // NOTE: It is your responsibility to clean up the packet_buffer when you 247 // are done calling this. Also note that the buffer.ptr may change if 248 // you gave us a packet that was too small and we had to pad the data. 249 // UPDATE: we now never change buffer.ptr, but create a whole new 250 // packet_buffer instead. We take care of deleting this, so you don't 251 // have to worry about it. 252 // This is done so we can avoid using dynamic memory allocation ourselves. */ 253 int nic_send_packet(snic *nic, packet_buffer* buffer) { 254 uint timeout; uint f; int iobase=nic->iobase; 255 packet_buffer *pad=NULL; 256 if(!buffer->len || !buffer->ptr) return ERR; 257 if(!nic || !nic->iobase) return ERR; 258 if(buffer->len>MAX_LENGTH) return ERRFORMAT; 259 /* the following wait for anyother tasks that are calling 260 // nic_send_packet() right now. Note that this doesn't use 261 // an atomic semaphore, so something MAY leak through. */ 262 timeout=ticks+10; // wait 10 ticks 263 while(nic->busy && ticks<=timeout) idle(); 264 /* Replace this with a proper timeout thing that doesn't use the 265 // ticks method which will be diffrent on each OS. */ 266 if(nic->busy) { 267 return ERRTIMEOUT; 268 } 269 nic->busy=1; /* mark as busy, replace with semaphore */ 270 271 /* XXX should not have to copy the data --- modify nic_block_output to 272 optionally add padding 0's */ 273 if(buffer->len<MIN_LENGTH) { 274 /* unsigned char *newbuffer=(unsigned char*)kalloc(MIN_LENGTH); 275 if(!newbuffer) return ERRNOMEM; */ 276 pad=alloc_buffer(MIN_LENGTH); 277 if(!pad) { 278 nic->busy=0; /* V() */ 279 return ERRNOMEM; } 280 for(f=0;f<buffer->len;f++) pad->ptr[f]=buffer->ptr[f]; 281 for(;f<MIN_LENGTH;f++) pad->ptr[f]='\0'; 282 /* pad the data to the minimum size. */ 283 buffer=pad; 284 } 285 286 outb_p(0x00, iobase + INTERRUPTMASK); /* mask ints for now */ 287 for(f=0;f<MAX_TX;f++) { 288 if(nic->tx_packet[f].len==0) { 289 nic->tx_packet[f]=*buffer; 290 nic->tx_packet[f].page=nic->pstart + (f * MAX_PAGESPERPACKET); 291 /*output page */ 292 293 nic_block_output(nic,nic->tx_packet[f].ptr, 294 nic->tx_packet[f].len, 295 nic->tx_packet[f].page ); 296 297 nic->send=f; 298 /* now let's actually trigger the transmitter to send */ 299 if(nic_send(nic,f)<0) break; 300 /* note, the nic_tx() interrupt will mark this 301 // tx_packet buffer as free again once it 302 // confirms that the packet was sent. */ 303 304 nic->stat.tx_buffered++; 305 outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */ 306 nic->busy=0; /* V() */ 307 if(pad) free_buffer(pad); 308 return NOERR; 309 } 310 } 311 312 outb_p(IMR_DEFAULT, iobase + INTERRUPTMASK); /* unmask */ 313 nic->busy=0; /* V() */ 314 if(pad) free_buffer(pad); 315 return ERR; 316 /* since we passed with nic->busy not busy then we should 317 // always have at least one buffer free. */ 318 } 319 320 /* dumps the prom into a 16 byte buffer and returns the wordlength of 321 // the card. 322 // You should be able to make this procedure a wrapper of nic_block_input(). */ 323 int nic_dump_prom(snic *nic, unsigned char *prom) { 324 uint f; 325 int iobase=nic->iobase; 326 char wordlength=2; /* default wordlength of 2 */ 327 unsigned char dump[32]; 328 outb_p(32, iobase + REMOTEBYTECOUNT0); /* read 32 bytes from DMA->IO */ 329 outb_p(0x00, iobase + REMOTEBYTECOUNT1); /* this is for the PROM dump */ 330 outb_p(0x00, iobase + REMOTESTARTADDRESS0); /* configure DMA for 0x0000 */ 331 outb_p(0x00, iobase + REMOTESTARTADDRESS1); 332 outb_p(NIC_REM_READ | NIC_START, iobase); 333 for(f=0;f<32;f+=2) { 334 dump[f]=inb_p(iobase + NE_DATA); 335 dump[f+1]=inb_p(iobase + NE_DATA); 336 if(dump[f]!=dump[f+1]) wordlength=1; 337 } 338 /* if wordlength is 2 bytes, then collapse prom to 16 bytes */ 339 for(f=0;f<LEN_PROM;f++) prom[f]=dump[f+((wordlength==2)?f:0)]; 340 341 return wordlength; 342 } 343 344 void nic_overrun(snic *nic) { 345 uint tx_status; int iobase=nic->iobase; 346 long starttime; uint resend=0; 347 if(!nic || !nic->iobase) return; 348 tx_status=inb_p(iobase) & NIC_TRANSMIT; 349 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_STOP, iobase); 350 nic->stat.errors.rx_overruns++; 351 352 starttime=ticks; 353 /*kprintf("BEFORE\n");*/ 354 while(ticks-starttime<=10/*ticks to wait*/) idle(); 355 /* Arrgh! TODO: Replace this whole crappy code with a decent 356 // wait method. We need to wait at least 1.6ms as per National 357 // Semiconductor datasheets, but we should probablly wait a 358 // little more to be safe. 359 //kprintf("AFTER\n"); */ 360 361 outb_p(0x00, iobase + REMOTEBYTECOUNT0); 362 outb_p(0x00, iobase + REMOTEBYTECOUNT1); 363 if(tx_status) { 364 uint tx_completed=inb_p(iobase + INTERRUPTSTATUS) & 365 (ISR_PTX | ISR_TXE); 366 if(!tx_completed) resend=1; 367 } 368 369 outb_p(TCR_INTERNAL_LOOPBACK, iobase + TRANSMITCONFIGURATION); 370 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); 371 nic_rx(nic); /* cleanup RX ring */ 372 outb_p(ISR_OVW, iobase + INTERRUPTSTATUS); /* ACK INT */ 373 374 outb_p(TCR_DEFAULT, iobase + TRANSMITCONFIGURATION); 375 if(resend) 376 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START | NIC_TRANSMIT, 377 iobase); 378 } 379 380 /* This is the procedure that markst the transmit buffer as available again */ 381 void nic_tx(snic *nic) { 382 uint f; int iobase=nic->iobase; 383 uint status; 384 if(!nic || !nic->iobase) return; 385 status=inb(iobase + TRANSMITSTATUS); 386 387 if(!nic->tx_packet[nic->send].len) { 388 return; 389 } 390 nic->tx_packet[nic->send].len=0; /* mark buffer as available */ 391 392 for(f=0;f<MAX_TX;f++) { 393 if(nic->tx_packet[f].len) { 394 nic->stat.tx_buffered++; 395 nic_send(nic,f); /* send a back-to-back buffer */ 396 break; 397 } 398 } 399 400 if(status & TSR_COL) nic->stat.errors.tx_collisions++; 401 if(status & TSR_PTX) nic->stat.tx_packets++; 402 else { 403 if(status & TSR_ABT) { 404 nic->stat.errors.tx_aborts++; 405 nic->stat.errors.tx_collisions+=16; } 406 if(status & TSR_CRS) nic->stat.errors.tx_carrier++; 407 if(status & TSR_FU) nic->stat.errors.tx_fifo++; 408 if(status & TSR_CDH) nic->stat.errors.tx_heartbeat++; 409 if(status & TSR_OWC) nic->stat.errors.tx_window++; 410 } 411 412 outb_p(ISR_PTX, iobase + INTERRUPTSTATUS); /* ack int */ 413 } 414 415 void nic_tx_err(snic *nic) { 416 unsigned char tsr; int iobase=nic->iobase; 417 if(!nic || !nic->iobase) return; 418 tsr=inb_p(nic->iobase); 419 /* kprintf("NE2000: ERROR: TX error: "); 420 if(tsr & TSR_ABT) kprintf("Too many collisions.\n"); 421 if(tsr & TSR_ND) kprintf("Not deffered.\n"); 422 if(tsr & TSR_CRS) kprintf("Carrier lost.\n"); 423 if(tsr & TSR_FU) kprintf("FIFO underrun.\n"); 424 if(tsr & TSR_CDH) kprintf("Heart attack!\n"); 425 */ 426 outb_p(ISR_TXE, iobase + INTERRUPTSTATUS); 427 if(tsr & (TSR_ABT | TSR_FU)) { 428 nic_tx(nic); 429 } 430 } 431 432 void nic_rx(snic *nic) { 433 uint packets=0; uint frame; uint rx_page; uint rx_offset; 434 uint len; uint next_pkt; uint numpages; 435 int iobase=nic->iobase; 436 buffer_header header; 437 if(!nic || !nic->iobase) return; 438 while(packets<MAX_RX) { 439 outb_p(NIC_DMA_DISABLE | NIC_PAGE1, iobase); /*curr is on page 1 */ 440 rx_page=inb_p(iobase + CURRENT); /* get current page */ 441 outb_p(NIC_DMA_DISABLE | NIC_PAGE0, iobase); 442 frame=inb(iobase + BOUNDARY)+1; 443 /* we add one becuase boundary is a page behind 444 // as pre NS notes to help in overflow problems */ 445 if(frame>=nic->pstop) frame=nic->pstart+TXPAGES; 446 /* circual buffer */ 447 448 if(frame==rx_page) break; /* all frames read */ 449 450 rx_offset=frame << 8; /* current ptr in bytes(not pages) */ 451 452 nic_get_header(nic,frame,&header); 453 len=header.count - sizeof(buffer_header); 454 /* length of packet */ 455 next_pkt=frame + 1 + ((len+4)>>8); /* next packet frame */ 456 457 numpages=nic->pstop-(nic->pstart+TXPAGES); 458 if( (header.next!=next_pkt) 459 && (header.next!=next_pkt + 1) 460 && (header.next!=next_pkt - numpages) 461 && (header.next != next_pkt +1 - numpages)){ 462 /* kprintf("NE2000: ERROR: Index mismatch. header.next:%X next_pkt:%X frame:%X\n", 463 header.next,next_pkt,frame);*/ 464 nic->current_page=frame; 465 outb(nic->current_page-1, iobase + BOUNDARY); 466 nic->stat.errors.rx++; 467 continue; 468 } 469 470 if(len<60 || len>1518) { 471 /* kprintf("NE2000: invalid packet size:%d\n",len);*/ 472 nic->stat.errors.rx_size++; 473 } else if((header.status & 0x0f) == RSR_PRX) { 474 /* We have a good packet, so let's recieve it! */ 475 476 packet_buffer *newpacket=alloc_buffer(len); 477 if(!newpacket) { 478 /* kprintf("NE2000: ERROR: out of memory!\n");*/ 479 nic->stat.errors.rx_dropped++; 480 break; 481 } 482 483 nic_block_input(nic,newpacket->ptr,newpacket->len, 484 rx_offset+sizeof(buffer_header)); 485 /* read it */ 486 487 if(nic->notify) nic->notify(newpacket); 488 /* NOTE: you are responsible for deleting this buffer. */ 489 490 nic->stat.rx_packets++; 491 492 } else { 493 /* kprintf("NE2000: ERROR: bad packet. header-> status:%X next:%X len:%x.\n", 494 header.status,header.next,header.count); */ 495 if(header.status & RSR_FO) nic->stat.errors.rx_fifo++; 496 } 497 /* kprintf("frame:%x header.next:%x next_pkt:%x\n", 498 // frame,header.next,next_pkt); */ 499 next_pkt=header.next; 500 501 if(next_pkt >= nic->pstop) { 502 /* kprintf("NE2000: ERROR: next frame beyond local buffer! next:%x.\n", 503 next_pkt);*/ 504 next_pkt=nic->pstart+TXPAGES; 505 } 506 507 nic->current_page=next_pkt; 508 outb_p(next_pkt-1, iobase + BOUNDARY); 509 } 510 outb_p(ISR_PRX | ISR_RXE, iobase + INTERRUPTSTATUS); /* ack int */ 511 } 512 513 /* You should be able to make this procedure a wrapper of nic_block_input */ 514 void nic_get_header(snic *nic, uint page, buffer_header *header) { 515 int iobase=nic->iobase; uint f; 516 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); 517 outb_p(sizeof(buffer_header), iobase + REMOTEBYTECOUNT0); 518 outb_p(0, iobase + REMOTEBYTECOUNT1); /* read the header */ 519 outb_p(0, iobase + REMOTESTARTADDRESS0); /* page boundary */ 520 outb_p(page, iobase + REMOTESTARTADDRESS1); /* from this page */ 521 outb_p(NIC_REM_READ | NIC_START, iobase); /* start reading */ 522 523 if(nic->wordlength==2) for(f=0;f<(sizeof(buffer_header)>>1);f++) 524 ((unsigned short *)header)[f]=inw(iobase+NE_DATA); 525 else for(f=0;f<sizeof(buffer_header);f++) 526 ((unsigned char *)header)[f]=inb(iobase+NE_DATA); 527 /* Do these need to be *_p variants??? */ 528 outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ 529 } 530 531 int nic_send(snic *nic, uint buf) { 532 outb_p(NIC_DMA_DISABLE | NIC_PAGE0, nic->iobase); 533 if(inb_p(nic->iobase + STATUS) & NIC_TRANSMIT) { 534 /* kprintf("NE2000: ERROR: Transmitor busy.\n");*/ 535 nic->tx_packet[buf].len=0; /* mark as free again */ 536 return ERRTIMEOUT; } 537 outb_p(nic->tx_packet[buf].len & 0xff,nic->iobase+TRANSMITBYTECOUNT0); 538 outb_p(nic->tx_packet[buf].len >> 8,nic->iobase+TRANSMITBYTECOUNT1); 539 outb_p(nic->tx_packet[buf].page,nic->iobase+TRANSMITPAGE); 540 outb_p(NIC_DMA_DISABLE | NIC_TRANSMIT | NIC_START,nic->iobase); 541 return NOERR; 542 } 543 544 void nic_block_input(snic *nic, unsigned char *buf, uint len, uint offset) { 545 int iobase=nic->iobase; uint f; 546 uint xfers=len; 547 uint timeout=TIMEOUT_DMAMATCH; uint addr; 548 /* kprintf("NE2000: RX: Length:%x Offset:%x ",len,offset);*/ 549 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); 550 outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0); 551 outb_p(len >> 8, iobase + REMOTEBYTECOUNT1); 552 outb_p(offset & 0xff, iobase + REMOTESTARTADDRESS0); 553 outb_p(offset >> 8, iobase + REMOTESTARTADDRESS1); 554 outb_p(NIC_REM_READ | NIC_START, iobase); 555 556 if(nic->wordlength==2) { 557 for(f=0;f<(len>>1);f++) 558 ((unsigned short *)buf)[f]=inw(iobase+NE_DATA); 559 if(len&0x01) { 560 ((unsigned char *)buf)[len-1]=inb(iobase+NE_DATA); 561 xfers++; 562 } 563 } else for(f=0;f<len;f++) 564 ((unsigned char *)buf)[f]=inb(iobase+NE_DATA); 565 /* Do these need to be *_p variants??? */ 566 567 /* for(f=0;f<15;f++) kprintf("%X",buf[f]); kprintf("\n");*/ 568 /* TODO: make this timeout a constant */ 569 for(f=0;f<timeout;f++) { 570 uint high=inb_p(iobase + REMOTESTARTADDRESS1); 571 uint low=inb_p(iobase + REMOTESTARTADDRESS0); 572 addr=(high<<8)+low; 573 if(((offset+xfers)&0xff)==low) break; 574 } 575 /* if(f>=timeout) 576 kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n", 577 offset+xfers, addr);*/ 578 579 outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ 580 } 581 582 void nic_block_output(snic *nic, unsigned char *buf, uint len, uint page) { 583 int iobase=nic->iobase; 584 int timeout=TIMEOUT_DMAMATCH; int f; uint addr; int w; 585 outb_p(NIC_DMA_DISABLE | NIC_PAGE0 | NIC_START, iobase); 586 587 /* this next part is to supposedly fix a "read-before-write" bug... */ 588 outb_p(0x42, iobase + REMOTEBYTECOUNT0); 589 outb_p(0x00, iobase + REMOTEBYTECOUNT1); 590 outb_p(0x42, iobase + REMOTESTARTADDRESS0); 591 outb_p(0x00, iobase + REMOTESTARTADDRESS1); 592 outb_p(NIC_REM_READ | NIC_START, iobase); 593 SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO; 594 595 outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* ack remote DMA int */ 596 597 outb_p(len & 0xff, iobase + REMOTEBYTECOUNT0); 598 outb_p(len >> 8, iobase + REMOTEBYTECOUNT1); 599 outb_p(0x00, iobase + REMOTESTARTADDRESS0); 600 outb_p(page, iobase + REMOTESTARTADDRESS1); 601 outb_p(NIC_REM_WRITE | NIC_START, iobase); 602 603 if(nic->wordlength==2) { 604 for(w=0;w<(len>>1);w++) 605 outw(((unsigned short *)buf)[w],iobase+NE_DATA); 606 if(len & 0x01) { 607 short tmp=buf[len-1]; //so we can output a whole 16-bits 608 // if buf were on the end of something, we would die. 609 outw(tmp,iobase+NE_DATA); 610 } 611 } else for(f=0;f<len;f++) 612 outb(((unsigned char *)buf)[f],iobase+NE_DATA); 613 614 for(f=0;f<timeout;f++) { 615 uint high=inb_p(iobase + REMOTESTARTADDRESS1); 616 uint low=inb_p(iobase + REMOTESTARTADDRESS0); 617 addr=(high<<8)+low; 618 if(( (((page<<8)+(nic->wordlength==2 && (len&0x01))?len:len+1)) 619 &0xff)==low) 620 break; 621 } 622 /* if(f>=timeout) 623 kprintf("NE2000: Remote DMA address invalid. expected:%x - actual:%x\n", 624 page<<8, addr);*/ 625 626 outb_p(ISR_RDC, iobase + INTERRUPTSTATUS); /* finish DMA cycle */ 627 }