"Der Herr Hofr.at" wrote: > is your code with the ne2000 available on the net ?? > I would like to get two boxes connected via a realtime link > on a minimum system. I haven't put it on the web ... but you I give you in attached file the source. This source has been inspired of the linux-kernel source. !! Carefull , I don't support reception of message with size > 1 ring_page !! But it is a real-time driver, which means very short message. Target: - ISA NE2000 Compatible only. - SMP dual-PIII. - RTAI-0.7 + kernel 2.2.12 Todo with this file : - include from rt-module file ( with init_module , cleanup_module ) - initialize the 'dev' struct with the io and the irq of the card (no auto find .....) - initialize the 'ne2000_get' semaphore which is pulled up when a valid packet is arrived. - call 'FindNE2000()' to initialise dev struct - call 'NE2000Start()' to start listening (or reset receive ring if blocked du to large packet) - call 'ne2000_sender' to send packet in 'ne2000_buffer_send' struct - pullup of 'ne2000_get' SEM when a packet is ready in 'ne2000_buffer_get' Good Luck. PS: This source is for RTAI ... but little changes needed for RTL. -- Kumsta Christophe <[EMAIL PROTECTED]> Real-Time System developper RT-Linux/RTAI ( Use the Source Luck !)
#define TX_2X_PAGES 12 #define TX_PAGES TX_2X_PAGES /* Some generic ethernet register configurations. */ #define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */ #define E8390_RX_IRQ_MASK 0x5 #define E8390_RXCONFIG 0x06 //#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */ #define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */ #define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */ #define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */ /* Register accessed at EN_CMD, the 8390 base addr. */ #define E8390_STOP 0x01 /* Stop and reset the chip */ #define E8390_START 0x02 /* Start the chip, clear reset */ #define E8390_TRANS 0x04 /* Transmit a frame */ #define E8390_RREAD 0x08 /* Remote read */ #define E8390_RWRITE 0x10 /* Remote write */ #define E8390_NODMA 0x20 /* Remote DMA */ #define E8390_PAGE0 0x00 /* Select page chip registers */ #define E8390_PAGE1 0x40 /* using the two high-order bits */ #define E8390_PAGE2 0x80 /* Page 3 is invalid. */ #define E8390_CMD 0x00 /* The command register (for all pages) */ /* Page 0 register offsets. */ #define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ #define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ #define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ #define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ #define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ #define EN0_TSR 0x04 /* Transmit status reg RD */ #define EN0_TPSR 0x04 /* Transmit starting page WR */ #define EN0_NCR 0x05 /* Number of collision reg RD */ #define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ #define EN0_FIFO 0x06 /* FIFO RD */ #define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ #define EN0_ISR 0x07 /* Interrupt status reg RD WR */ #define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ #define EN0_RSARLO 0x08 /* Remote start address reg 0 */ #define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ #define EN0_RSARHI 0x09 /* Remote start address reg 1 */ #define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ #define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ #define EN0_RSR 0x0c /* rx status reg RD */ #define EN0_RXCR 0x0c /* RX configuration reg WR */ #define EN0_TXCR 0x0d /* TX configuration reg WR */ #define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ #define EN0_DCFG 0x0e /* Data configuration reg WR */ #define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ #define EN0_IMR 0x0f /* Interrupt mask reg WR */ #define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ /* Bits in EN0_ISR - Interrupt status register */ #define ENISR_RX 0x01 /* Receiver, no error */ #define ENISR_TX 0x02 /* Transmitter, no error */ #define ENISR_RX_ERR 0x04 /* Receiver, with error */ #define ENISR_TX_ERR 0x08 /* Transmitter, with error */ #define ENISR_OVER 0x10 /* Receiver overwrote the ring */ #define ENISR_COUNTERS 0x20 /* Counters need emptying */ #define ENISR_RDC 0x40 /* remote dma complete */ #define ENISR_RESET 0x80 /* Reset completed */ #define ENISR_ALL 0x3f /* Interrupts we will enable */ /* Bits in EN0_DCFG - Data config register */ #define ENDCFG_WTS 0x01 /* word transfer mode selection */ /* Page 1 register offsets. */ #define EN1_PHYS 0x01 /* This board's physical enet addr RD WR */ #define EN1_PHYS_SHIFT(i) i+1 /* Get and set mac address */ #define EN1_CURPAG 0x07 /* Current memory page RD WR */ #define EN1_MULT 0x08 /* Multicast filter mask array (8 bytes) RD WR */ #define EN1_MULT_SHIFT(i) 8+i /* Get and set multicast filter */ #define NE_BASE (dev.io) #define NE_CMD 0x00 #define NE_DATAPORT 0x10 #define NE_RESET 0x1f // read to reset / write to clear #define NE_IO_EXTENT 0x20 #define NE1SM_START_PG 0x20 // first page of TX buffer #define NE1SM_STOP_PG 0x40 // last page+1 of RX ring #define NESM_START_PG 0x40 #define NESM_STOP_PG 0x80 typedef struct { unsigned char dst[6] ; // Hardware addr of dest ethernet card unsigned char src[6] ; // Hardware addr of source ethernet card unsigned char proto[2] ; // neither TCP nor UDP ... just own (0x9000) unsigned char taille ; // size of data unsigned char data[1000] ; } Tne2000_mess ; volatile Tne2000_mess ne2000_buffer_get ; volatile Tne2000_mess ne2000_buffer_send ; typedef struct { int io ; int irq ; int wordsize ; unsigned char tx_start_page ; unsigned char rx_start_page ; unsigned char start_page ; unsigned char stop_page ; unsigned char current_page ; short tx1,tx2 ; unsigned char SA_prom[32] ; unsigned char HWaddr[6] ; char *buffread ; char *buffwrite ; } TNE2000 ; /* The 8390 specific per-packet-header format. */ typedef struct { unsigned char status; /* status */ unsigned char next; /* pointer to next packet. */ unsigned short count; /* header + packet length in bytes */ } THeader ; static TNE2000 NE2000dev ; volatile static int irqtest = 0 ; volatile static int transmit = 0 ; static SEM ne2000_get ; /******************************************************/ /* */ /* Gestion des ERREURS de message */ /* */ /* */ /******************************************************/ #define INT_PACKET_RECEIVED 0x01 #define INT_PACKET_TRANSMITTED 0x02 #define INT_RECEIVE_ERROR 0x04 #define INT_TRANSMIT_ERROR 0x08 #define INT_OVERWRITE_WARNING 0x10 #define INT_COUNTER_OVERFLOW 0x20 #define INT_REMOTE_DMA_COMPLETE 0x40 #define INT_RESET_STATUS 0x80 /* Bits in received packet status byte and EN0_RSR*/ #define ENRSR_RXOK 0x01 /* Received a good packet */ #define ENRSR_CRC 0x02 /* CRC error */ #define ENRSR_FAE 0x04 /* frame alignment error */ #define ENRSR_FO 0x08 /* FIFO overrun */ #define ENRSR_MPA 0x10 /* missed pkt */ #define ENRSR_PHY 0x20 /* physical/multicast address */ #define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ #define ENRSR_DEF 0x80 /* deferring */ /* Transmitted packet status, EN0_TSR. */ #define ENTSR_PTX 0x01 /* Packet transmitted without error */ #define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ #define ENTSR_COL 0x04 /* The transmit collided at least once. */ #define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ #define ENTSR_CRS 0x10 /* The carrier sense was lost. */ #define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ #define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ #define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ /******************************************************/ /* */ /* Interrupt Handling */ /* */ /* */ /******************************************************/ //#define debugirq(x) printk("[NE2000 :0x%3.3x:#%2.2d] <IRQ_HANDLER> -> %s.\n",dev.io,dev.irq,x) #define debugirq(x) static void IrqHandlerNE2000() { unsigned char which , test ; //printk("NE2000 :[CPU#%d] IRQ BEGIN\n",hard_cpu_id()) ; outb_p(0x00,NE_BASE+EN0_IMR) ; // mask all rt_disable_irq(dev.irq) ; which = inb_p(NE_BASE+EN0_ISR) ; irqtest = which ; while(which) { if(which & INT_PACKET_RECEIVED) { unsigned char frame, frame_next ; THeader header ; which ^= INT_PACKET_RECEIVED ; /* Get the rx page (incoming packet pointer). */ outb_p(E8390_NODMA+E8390_PAGE1, NE_BASE + E8390_CMD); frame_next = inb_p(NE_BASE + EN1_CURPAG); outb_p(E8390_NODMA+E8390_PAGE0, NE_BASE + E8390_CMD); frame = dev.current_page ; /* printk("NE2000 : RECEIVING FRAME : %i\n",dev.io,dev.irq,frame) ; */ // get HEADER of 8390 outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, NE_BASE+ NE_CMD); outb_p(sizeof(header) , NE_BASE + EN0_RCNTLO); outb_p(0 , NE_BASE + EN0_RCNTHI); outb_p(0 , NE_BASE + EN0_RSARLO); /* On page boundary */ outb_p(frame , NE_BASE + EN0_RSARHI); outb_p(E8390_RREAD+E8390_START , NE_BASE + NE_CMD); insb(NE_BASE + NE_DATAPORT, &header, sizeof(header)); outb_p(ENISR_RDC, NE_BASE + EN0_ISR); /* Ack intr. */ // get datas outb_p(E8390_NODMA+E8390_PAGE0+E8390_START , NE_BASE + NE_CMD); outb_p((header.count-sizeof(header)) & 0xff, NE_BASE + EN0_RCNTLO); outb_p((header.count-sizeof(header)) >> 8 , NE_BASE + EN0_RCNTHI); outb_p(((frame<<8)+sizeof(header)) & 0xff , NE_BASE + EN0_RSARLO); outb_p(((frame<<8)+sizeof(header)) >> 8 , NE_BASE + EN0_RSARHI); outb_p(E8390_RREAD+E8390_START , NE_BASE + NE_CMD); insb(NE_BASE + NE_DATAPORT, dev.buffread, header.count); outb_p(ENISR_RDC, NE_BASE + EN0_ISR); NE2000dev.current_page = frame_next ; outb_p(frame,NE_BASE+EN0_BOUNDARY) ; outb_p(E8390_RXCONFIG,NE_BASE+EN0_RXCR) ; /* printk("NE2000 : GET TERMINATED.\n",dev.io,dev.irq) ; */ if((ne2000_buffer_get.proto[0]==0x90)&&(ne2000_buffer_get.proto[1]==0x00)) rt_sem_signal(&ne2000_get) ; else printk("NE2000 : ####### BAD PROTOCOL DETECTED !! ###(%2.2x%2.2x)###\n", ne2000_buffer_get.proto[0],ne2000_buffer_get.proto[1]) ; } if(which & INT_RECEIVE_ERROR) { which ^= INT_RECEIVE_ERROR ; test = inb_p(NE_BASE+EN0_RSR) ; if(test & ENRSR_RXOK) printk("NE2000 : RECEIVE STATUS : RECEIVE_OK\n") ; if(test & ENRSR_CRC) printk("NE2000 : RECEIVE STATUS : CRC_ERROR\n") ; if(test & ENRSR_FAE) printk("NE2000 : RECEIVE STATUS : FRAME_ALIGN_ERROR\n") ; if(test & ENRSR_FO) printk("NE2000 : RECEIVE STATUS : FIFO_OVERRUN\n") ; if(test & ENRSR_MPA) printk("NE2000 : RECEIVE STATUS : MISSED_PACKET\n") ; if(test & ENRSR_PHY) printk("NE2000 : RECEIVE STATUS : PHYS/MULTI_ADDRESS\n") ; if(test & ENRSR_DIS) printk("NE2000 : RECEIVE STATUS : RECEIVER_DISABLED\n") ; if(test & ENRSR_DEF) printk("NE2000 : RECEIVE STATUS : DEFERRING\n") ; outb_p(E8390_RXCONFIG,NE_BASE+EN0_RXCR) ; } if(which & INT_PACKET_TRANSMITTED) { which ^= INT_PACKET_TRANSMITTED ; //printk("NE2000 : IRQ_TRANSMIT_OK\n") ; transmit = 0 ; } if(which & INT_TRANSMIT_ERROR) { which ^= INT_TRANSMIT_ERROR ; test = inb_p(NE_BASE+EN0_TSR) ; if(test & ENTSR_PTX) printk("NE2000 : TRANSMIT STATUS : TRANSMIT_OK\n") ; if(test & ENTSR_ND) printk("NE2000 : TRANSMIT STATUS : NOT_DEFERRED\n") ; if(test & ENTSR_COL) printk("NE2000 : TRANSMIT STATUS : COLLISION\n") ; if(test & ENTSR_ABT) printk("NE2000 : TRANSMIT STATUS : COLLISION>16\n") ; if(test & ENTSR_CRS) printk("NE2000 : TRANSMIT STATUS : CARRIER_LOST\n") ; if(test & ENTSR_FU) printk("NE2000 : TRANSMIT STATUS : FIFO_UNDERRUN\n") ; if(test & ENTSR_CDH) printk("NE2000 : TRANSMIT STATUS : HEARTBEAT_LOST\n") ; if(test & ENTSR_OWC) printk("NE2000 : TRANSMIT STATUS : OUT_OF_WINDOW\n") ; outb_p(E8390_TXCONFIG,NE_BASE+EN0_TXCR) ; transmit = 0 ; } if(which & INT_OVERWRITE_WARNING) { which ^= INT_OVERWRITE_WARNING ; debugirq("INT_OVERWRITE_WARNING") ; } if(which & INT_COUNTER_OVERFLOW) { which ^= INT_COUNTER_OVERFLOW ; debugirq("INT_COUNTER_OVERFLOW") ; } if(which & INT_REMOTE_DMA_COMPLETE) { which ^= INT_REMOTE_DMA_COMPLETE ; debugirq("INT_REMOTE_DMA_COMPLETE") ; } if(which & INT_RESET_STATUS) { which ^= INT_RESET_STATUS ; debugirq("INT_RESET_STATUS") ; } } outb_p(0xFF,NE_BASE+EN0_ISR) ; // acknowledge rt_enable_irq(dev.irq) ; outb_p(ENISR_ALL,NE_BASE+EN0_IMR) ; /* printk("<<<<IRQ END>>>>\n") ; */ } /******************************************************/ /* */ /* Send function */ /* */ /* */ /******************************************************/ void ne2000_sender(void) { int mess_count ; if(transmit==0) { transmit = 1 ; mess_count = ne2000_buffer_send.taille + 15 ; outb_p(E8390_PAGE0+E8390_START+E8390_NODMA,NE_BASE+NE_CMD) ; outb_p(ENISR_RDC,NE_BASE+EN0_ISR) ; outb_p(mess_count & 0xFF,NE_BASE+EN0_RCNTLO) ; outb_p(mess_count >> 8 ,NE_BASE+EN0_RCNTHI) ; outb_p(0x00 ,NE_BASE+EN0_RSARLO) ; outb_p(dev.start_page ,NE_BASE+EN0_RSARHI) ; outb_p(E8390_RWRITE+E8390_START,NE_BASE+NE_CMD) ; outsb(NE_BASE+NE_DATAPORT,dev.buffwrite,mess_count) ; outb_p(ENISR_RDC,NE_BASE+EN0_ISR) ; /* paquet sending ... */ outb_p(E8390_NODMA+E8390_PAGE0, NE_BASE+E8390_CMD); outb_p(mess_count & 0xff, NE_BASE + EN0_TCNTLO); outb_p(mess_count >> 8, NE_BASE + EN0_TCNTHI); outb_p(dev.start_page, NE_BASE + EN0_TPSR); outb_p(E8390_NODMA+E8390_TRANS+E8390_START, NE_BASE+E8390_CMD); } } /******************************************************/ /* */ /* Initialisation */ /* */ /* */ /******************************************************/ static void NE2000Init() { int i ; // initialisation de la carte reseau ... outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP,NE_BASE+E8390_CMD) ; outb_p(0x48,NE_BASE+EN0_DCFG) ; // clear remote byte count regiters outb_p(0x00,NE_BASE+EN0_RCNTLO) ; outb_p(0x00,NE_BASE+EN0_RCNTHI) ; // set monitor and loopback mode ... indispensable ! outb_p(E8390_RXOFF,NE_BASE+EN0_RXCR) ; outb_p(E8390_TXOFF,NE_BASE+EN0_TXCR) ; // set transmit page and receive ring outb_p(dev.tx_start_page,NE_BASE+EN0_TPSR) ; dev.tx1 = dev.tx2 = 0 ; outb_p(dev.rx_start_page,NE_BASE+EN0_STARTPG) ; outb_p(dev.stop_page-1,NE_BASE+EN0_BOUNDARY) ; dev.current_page = dev.rx_start_page ; outb_p(dev.stop_page,NE_BASE+EN0_STOPPG) ; // clear pending irq and mask outb_p(0xFF,NE_BASE+EN0_ISR) ; outb_p(0x00,NE_BASE+EN0_IMR) ; // copy of HWaddr outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP,NE_BASE+E8390_CMD) ; for(i=0;i<6;i++) { ne2000_buffer_send.src[i] = dev.HWaddr[i] ; outb_p(dev.HWaddr[i],NE_BASE+EN1_PHYS_SHIFT(i)) ; if(inb_p(NE_BASE+EN1_PHYS_SHIFT(i)) != dev.HWaddr[i]) printk("NE2000 : 0x%3.3x:#%2.2d -> HWaddr read/write mismap %d\n",dev.io,dev.irq,i) ; } ne2000_buffer_send.proto[0] = 0x90 ; ne2000_buffer_send.proto[1] = 0x00 ; printk("NE2000 : HWaddr [") ; for(i=0;i<6;i++) printk("%2.2x",inb_p(NE_BASE+EN1_PHYS_SHIFT(i))) ; printk("]\n") ; outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP,NE_BASE+E8390_CMD) ; outb_p(dev.rx_start_page,NE_BASE+EN1_CURPAG) ; outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP,NE_BASE+E8390_CMD) ; printk("NE2000 : Initialisation done.\n") ; } /******************************************************/ /* */ /* Starting ... */ /* */ /* */ /******************************************************/ static void NE2000Start() { outb_p(E8390_NODMA+E8390_PAGE0+E8390_START,NE_BASE+E8390_CMD) ; outb_p(0xFF,NE_BASE+EN0_ISR) ; outb_p(E8390_TXCONFIG,NE_BASE+EN0_TXCR) ; outb_p(E8390_RXCONFIG,NE_BASE+EN0_RXCR) ; outb_p(ENISR_ALL,NE_BASE+EN0_IMR) ; printk("NE2000 : Startup done.\n") ; } /******************************************************/ /* */ /* network card finding ... */ /* */ /* */ /******************************************************/ static int FindNE2000() { int regd,reg0 ; dev.wordsize = 2 ; // preliminary check ... if(inb_p(dev.io)==0xFF) return -1 ; reg0 = inb_p(dev.io) ; outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP,dev.io+E8390_CMD) ; regd = inb_p(dev.io+0x0d) ; outb_p(0xff,dev.io+0x0d) ; outb_p(E8390_NODMA+E8390_PAGE0,dev.io+E8390_CMD) ; inb_p(dev.io+EN0_COUNTER0) ; // nettoyage du compteur en faisant une lecture ... if(inb_p(dev.io+EN0_COUNTER0)!=0) { outb_p(reg0,dev.io) ; outb_p(regd,dev.io+0x0d) ; return -1 ; } // check the SA PROM ... { int i ; struct {unsigned char value, offset; } program_seq[]= { {E8390_NODMA+E8390_PAGE0+E8390_STOP,E8390_CMD }, {0x48 ,EN0_DCFG }, {0x00 ,EN0_RCNTLO}, {0x00 ,EN0_RCNTHI}, {0x00 ,EN0_IMR }, {0xFF ,EN0_ISR }, {E8390_RXOFF ,EN0_RXCR }, {E8390_TXOFF ,EN0_TXCR }, {32 ,EN0_RCNTLO}, {0x00 ,EN0_RCNTHI}, {0x00 ,EN0_RSARLO}, {0x00 ,EN0_RSARHI}, {E8390_RREAD+E8390_START ,E8390_CMD }, } ; for(i=0;i<sizeof(program_seq)/sizeof(program_seq[0]);i++) outb_p(program_seq[i].value,dev.io+program_seq[i].offset) ; for(i=0;i<32;i+=2) { dev.SA_prom[i] = inb(dev.io+NE_DATAPORT) ; dev.SA_prom[i+1] = inb(dev.io+NE_DATAPORT) ; // lecture en word ... if(dev.SA_prom[i] != dev.SA_prom[i+1]) dev.wordsize = 1 ; } if(dev.wordsize==2) { for(i=0;i<16;i++) dev.SA_prom[i] = dev.SA_prom[i+i] ; // set to word mode ... outb_p(0x49,dev.io+EN0_DCFG) ; dev.start_page = NESM_START_PG ; dev.stop_page = NESM_STOP_PG ; } else { // set to byte mode ... dev.start_page = NE1SM_START_PG ; dev.stop_page = NE1SM_STOP_PG ; } if((dev.SA_prom[14]==0x57)&&(dev.SA_prom[15]==0x57)) printk("NE2000 : 0x%3.3x:#%2.2d -> Signature of NE2000 compatible found.\n",dev.io,dev.irq) ; if((dev.SA_prom[0]==0x00)&&(dev.SA_prom[1]==0x00)&&(dev.SA_prom[2]==0x1d)) printk("NE2000 : 0x%3.3x:#%2.2d -> Signature of CTRON found.\n",dev.io,dev.irq) ; if((dev.SA_prom[14]==0x49)&&(dev.SA_prom[15]==0x00)) printk("NE2000 : 0x%3.3x:#%2.2d -> Signature of COPAN found.\n",dev.io,dev.irq) ; rt_reset_irq_to_sym_mode(dev.irq) ; /* rt_assign_irq_to_cpu (dev.irq,0) ; */ if(rt_request_global_irq(dev.irq,&IrqHandlerNE2000)<0) { printk("NE2000 : 0x%3.3x:#%2.2d -> Attaching Irq Handler Failed !\n",dev.io,dev.irq) ; return -1 ; } rt_enable_irq(dev.irq) ; if(machine==0) for(i=0;i<6;i++) dev.HWaddr[i] = dev.SA_prom[i] ; else { dev.HWaddr[0] = 0x63 ; dev.HWaddr[1] = 0x63 ; dev.HWaddr[2] = 0x27 ; dev.HWaddr[3] = 0x70 ; dev.HWaddr[4] = (unsigned char)(machine>>8) ; dev.HWaddr[5] = (unsigned char)(machine) ; } dev.tx_start_page = dev.start_page ; dev.rx_start_page = dev.start_page+TX_PAGES ; dev.buffread = (unsigned char *)&ne2000_buffer_get ; dev.buffwrite = (unsigned char *)&ne2000_buffer_send ; return 0 ; } }