2016-08-14 22:45:58 -04:00
/* Copyright holders: Peter Grehan, SA1988, Tenshi
2016-08-14 22:07:17 -04:00
see COPYING for more details
*/
2017-05-05 01:49:42 +02:00
/*
$ Id : ne2k . cc , v 1.56 .2 .1 2004 / 02 / 02 22 : 37 : 22 cbothamy Exp $
*/
/*
Copyright ( C ) 2002 MandrakeSoft S . A .
MandrakeSoft S . A .
43 , rue d ' Aboukir
75002 Paris - France
http : //www.linux-mandrake.com/
http : //www.mandrakesoft.com/
*/
/* Peter Grehan (grehan@iprg.nokia.com) coded all of this
NE2000 / ether stuff . */
2017-01-17 00:01:59 +01:00
# include <stdarg.h>
2016-06-26 00:34:39 +02:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include "slirp/slirp.h"
# include "slirp/queue.h"
# include <pcap.h>
# include "ibm.h"
# include "device.h"
2017-05-05 01:49:42 +02:00
# include "disc_random.h"
2016-06-26 00:34:39 +02:00
2016-08-13 17:29:14 +02:00
# include "config.h"
2016-06-26 00:34:39 +02:00
# include "nethandler.h"
# include "io.h"
# include "mem.h"
# include "nethandler.h"
# include "rom.h"
# include "ne2000.h"
# include "pci.h"
# include "pic.h"
# include "timer.h"
2017-05-05 01:49:42 +02:00
/* THIS IS THE DEFAULT MAC ADDRESS .... so it wont place nice with multiple VMs. YET. */
2016-06-26 00:34:39 +02:00
uint8_t maclocal [ 6 ] = { 0xac , 0xde , 0x48 , 0x88 , 0xbb , 0xaa } ;
2017-05-05 01:49:42 +02:00
uint8_t maclocal_pci [ 6 ] = { 0xac , 0xde , 0x48 , 0x88 , 0xbb , 0xaa } ;
2016-06-26 00:34:39 +02:00
2017-05-05 01:49:42 +02:00
# define NETBLOCKING 0 /* we won't block our pcap */
2016-06-26 00:34:39 +02:00
pcap_t * net_pcap ;
queueADT slirpq ;
int net_slirp_inited = 0 ;
2017-05-05 01:49:42 +02:00
int net_is_pcap = 0 ; /* and pretend pcap is dead. */
2016-06-26 00:34:39 +02:00
int fizz = 0 ;
void slirp_tic ( ) ;
# define BX_RESET_HARDWARE 0
# define BX_RESET_SOFTWARE 1
2017-05-05 01:49:42 +02:00
/* Never completely fill the ne2k ring so that we never
hit the unclear completely full buffer condition . */
2016-06-26 00:34:39 +02:00
# define BX_NE2K_NEVER_FULL_RING (1)
# define BX_NE2K_MEMSIZ (32*1024)
# define BX_NE2K_MEMSTART (16*1024)
# define BX_NE2K_MEMEND (BX_NE2K_MEMSTART + BX_NE2K_MEMSIZ)
uint8_t rtl8029as_eeprom [ 128 ] ;
typedef struct ne2000_t
{
2017-05-05 01:49:42 +02:00
/* ne2k register state */
/* Page 0 */
2017-02-07 02:19:48 +01:00
2017-05-05 01:49:42 +02:00
/* Command Register - 00h read/write */
2017-02-07 02:19:48 +01:00
struct CR_t
{
2017-05-05 01:49:42 +02:00
int stop ; /* STP - Software Reset command */
int start ; /* START - start the NIC */
int tx_packet ; /* TXP - initiate packet transmission */
uint8_t rdma_cmd ; /* RD0,RD1,RD2 - Remote DMA command */
uint8_t pgsel ; /* PS0,PS1 - Page select */
2017-02-07 02:19:48 +01:00
} CR ;
2017-05-05 01:49:42 +02:00
/* Interrupt Status Register - 07h read/write */
2017-02-07 02:19:48 +01:00
struct ISR_t
{
2017-05-05 01:49:42 +02:00
int pkt_rx ; /* PRX - packet received with no errors */
int pkt_tx ; /* PTX - packet transmitted with no errors */
int rx_err ; /* RXE - packet received with 1 or more errors */
int tx_err ; /* TXE - packet tx'd " " " " " */
int overwrite ; /* OVW - rx buffer resources exhausted */
int cnt_oflow ; /* CNT - network tally counter MSB's set */
int rdma_done ; /* RDC - remote DMA complete */
int reset ; /* RST - reset status */
2017-02-07 02:19:48 +01:00
} ISR ;
2017-05-05 01:49:42 +02:00
/* Interrupt Mask Register - 0fh write */
2017-02-07 02:19:48 +01:00
struct IMR_t
{
2017-05-05 01:49:42 +02:00
int rx_inte ; /* PRXE - packet rx interrupt enable */
int tx_inte ; /* PTXE - packet tx interrput enable */
int rxerr_inte ; /* RXEE - rx error interrupt enable */
int txerr_inte ; /* TXEE - tx error interrupt enable */
int overw_inte ; /* OVWE - overwrite warn int enable */
int cofl_inte ; /* CNTE - counter o'flow int enable */
int rdma_inte ; /* RDCE - remote DMA complete int enable */
int reserved ; /* D7 - reserved */
2017-02-07 02:19:48 +01:00
} IMR ;
2017-05-05 01:49:42 +02:00
/* Data Configuration Register - 0eh write */
2017-02-07 02:19:48 +01:00
struct DCR_t
{
2017-05-05 01:49:42 +02:00
int wdsize ; /* WTS - 8/16-bit select */
int endian ; /* BOS - byte-order select */
int longaddr ; /* LAS - long-address select */
int loop ; /* LS - loopback select */
int auto_rx ; /* AR - auto-remove rx packets with remote DMA */
uint8_t fifo_size ; /* FT0,FT1 - fifo threshold */
2017-02-07 02:19:48 +01:00
} DCR ;
2017-05-05 01:49:42 +02:00
/* Transmit Configuration Register - 0dh write */
2017-02-07 02:19:48 +01:00
struct TCR_t
{
2017-05-05 01:49:42 +02:00
int crc_disable ; /* CRC - inhibit tx CRC */
uint8_t loop_cntl ; /* LB0,LB1 - loopback control */
int ext_stoptx ; /* ATD - allow tx disable by external mcast */
int coll_prio ; /* OFST - backoff algorithm select */
uint8_t reserved ; /* D5,D6,D7 - reserved */
2017-02-07 02:19:48 +01:00
} TCR ;
2017-05-05 01:49:42 +02:00
/* Transmit Status Register - 04h read */
2017-02-07 02:19:48 +01:00
struct TSR_t
{
2017-05-05 01:49:42 +02:00
int tx_ok ; /* PTX - tx complete without error */
int reserved ; /* D1 - reserved */
int collided ; /* COL - tx collided >= 1 times */
int aborted ; /* ABT - aborted due to excessive collisions */
int no_carrier ; /* CRS - carrier-sense lost */
int fifo_ur ; /* FU - FIFO underrun */
int cd_hbeat ; /* CDH - no tx cd-heartbeat from transceiver */
int ow_coll ; /* OWC - out-of-window collision */
2017-02-07 02:19:48 +01:00
} TSR ;
2017-05-05 01:49:42 +02:00
/* Receive Configuration Register - 0ch write */
2017-02-07 02:19:48 +01:00
struct RCR_t
{
2017-05-05 01:49:42 +02:00
int errors_ok ; /* SEP - accept pkts with rx errors */
int runts_ok ; /* AR - accept < 64-byte runts */
int broadcast ; /* AB - accept eth broadcast address */
int multicast ; /* AM - check mcast hash array */
int promisc ; /* PRO - accept all packets */
int monitor ; /* MON - check pkts, but don't rx */
uint8_t reserved ; /* D6,D7 - reserved */
2017-02-07 02:19:48 +01:00
} RCR ;
2017-05-05 01:49:42 +02:00
/* Receive Status Register - 0ch read */
2017-02-07 02:19:48 +01:00
struct RSR_t
{
2017-05-05 01:49:42 +02:00
int rx_ok ; /* PRX - rx complete without error */
int bad_crc ; /* CRC - Bad CRC detected */
int bad_falign ; /* FAE - frame alignment error */
int fifo_or ; /* FO - FIFO overrun */
int rx_missed ; /* MPA - missed packet error */
int rx_mbit ; /* PHY - unicast or mcast/bcast address match */
int rx_disabled ; /* DIS - set when in monitor mode */
int deferred ; /* DFR - collision active */
2017-02-07 02:19:48 +01:00
} RSR ;
2017-05-05 01:49:42 +02:00
uint16_t local_dma ; /* 01,02h read ; current local DMA addr */
uint8_t page_start ; /* 01h write ; page start register */
uint8_t page_stop ; /* 02h write ; page stop register */
uint8_t bound_ptr ; /* 03h read/write ; boundary pointer */
uint8_t tx_page_start ; /* 04h write ; transmit page start register */
uint8_t num_coll ; /* 05h read ; number-of-collisions register */
uint16_t tx_bytes ; /* 05,06h write ; transmit byte-count register */
uint8_t fifo ; /* 06h read ; FIFO */
uint16_t remote_dma ; /* 08,09h read ; current remote DMA addr */
uint16_t remote_start ; /* 08,09h write ; remote start address register */
uint16_t remote_bytes ; /* 0a,0bh write ; remote byte-count register */
uint8_t tallycnt_0 ; /* 0dh read ; tally counter 0 (frame align errors) */
uint8_t tallycnt_1 ; /* 0eh read ; tally counter 1 (CRC errors) */
uint8_t tallycnt_2 ; /* 0fh read ; tally counter 2 (missed pkt errors) */
/* Page 1 */
/* Command Register 00h (repeated) */
uint8_t physaddr [ 6 ] ; /* 01-06h read/write ; MAC address */
uint8_t curr_page ; /* 07h read/write ; current page register */
uint8_t mchash [ 8 ] ; /* 08-0fh read/write ; multicast hash array */
/* Page 2 - diagnostic use only */
/* Command Register 00h (repeated) */
/* Page Start Register 01h read (repeated)
Page Stop Register 02 h read ( repeated )
Current Local DMA Address 01 , 02 h write ( repeated )
Transmit Page start address 04 h read ( repeated )
Receive Configuration Register 0 ch read ( repeated )
Transmit Configuration Register 0 dh read ( repeated )
Data Configuration Register 0 eh read ( repeated )
Interrupt Mask Register 0f h read ( repeated )
*/
uint8_t rempkt_ptr ; /* 03h read/write ; remote next-packet pointer */
uint8_t localpkt_ptr ; /* 05h read/write ; local next-packet pointer */
uint16_t address_cnt ; /* 06,07h read/write ; address counter */
/* Page 3 - should never be modified. */
/* Novell ASIC state */
uint8_t macaddr [ 32 ] ; /* ASIC ROM'd MAC address, even bytes */
uint8_t mem [ BX_NE2K_MEMSIZ ] ; /* on-chip packet memory */
/* ne2k internal state */
2017-02-07 02:19:48 +01:00
uint32_t base_address ;
int base_irq ;
int tx_timer_index ;
int tx_timer_active ;
rom_t bios_rom ;
2016-06-26 00:34:39 +02:00
} ne2000_t ;
int disable_netbios = 0 ;
2016-08-13 03:32:38 +02:00
void ne2000_tx_event ( void * p , uint32_t val ) ;
uint32_t ne2000_chipmem_read ( ne2000_t * ne2000 , uint32_t address , unsigned int io_len ) ;
void ne2000_page0_write ( ne2000_t * ne2000 , uint32_t offset , uint32_t value , unsigned io_len ) ;
2016-06-26 00:34:39 +02:00
void ne2000_rx_frame ( void * p , const void * buf , int io_len ) ;
2016-08-15 02:26:54 +02:00
int ne2000_do_log = 0 ;
void ne2000_log ( const char * format , . . . )
{
2017-01-16 01:49:19 +01:00
# ifdef ENABLE_NE2000_LOG
2017-02-07 02:19:48 +01:00
if ( ne2000_do_log )
{
va_list ap ;
va_start ( ap , format ) ;
vprintf ( format , ap ) ;
va_end ( ap ) ;
fflush ( stdout ) ;
}
2017-01-16 01:49:19 +01:00
# endif
2016-08-15 02:26:54 +02:00
}
2017-05-05 01:49:42 +02:00
static uint8_t * ne2000_mac ( )
{
if ( network_card_current = = 2 )
{
return maclocal_pci ;
}
else
{
return maclocal ;
}
}
void ne2000_generate_maclocal ( int mac )
{
2017-05-05 04:32:05 +02:00
maclocal [ 0 ] = 0x00 ; /* 00:00:D8 (NE2000 ISA vendor prefix). */
2017-05-05 01:49:42 +02:00
maclocal [ 1 ] = 0x00 ;
2017-05-05 04:32:05 +02:00
maclocal [ 2 ] = 0xD8 ;
2017-05-05 01:49:42 +02:00
if ( mac & 0xff000000 )
{
/* Generating new MAC. */
maclocal [ 3 ] = disc_random_generate ( ) ;
maclocal [ 4 ] = disc_random_generate ( ) ;
maclocal [ 5 ] = disc_random_generate ( ) ;
}
else
{
maclocal [ 3 ] = ( mac > > 16 ) & 0xff ;
maclocal [ 4 ] = ( mac > > 8 ) & 0xff ;
maclocal [ 5 ] = mac & 0xff ;
}
}
void ne2000_generate_maclocal_pci ( int mac )
{
maclocal_pci [ 0 ] = 0x00 ; /* 00:20:18 (RTL 8029AS PCI vendor prefix). */
maclocal_pci [ 1 ] = 0x20 ;
maclocal_pci [ 2 ] = 0x18 ;
if ( mac & 0xff000000 )
{
/* Generating new MAC. */
maclocal_pci [ 3 ] = disc_random_generate ( ) ;
maclocal_pci [ 4 ] = disc_random_generate ( ) ;
maclocal_pci [ 5 ] = disc_random_generate ( ) ;
}
else
{
maclocal_pci [ 3 ] = ( mac > > 16 ) & 0xff ;
maclocal_pci [ 4 ] = ( mac > > 8 ) & 0xff ;
maclocal_pci [ 5 ] = mac & 0xff ;
}
}
int net2000_get_maclocal ( )
{
int temp ;
temp = ( ( ( int ) maclocal [ 3 ] ) < < 16 ) ;
temp | = ( ( ( int ) maclocal [ 4 ] ) < < 8 ) ;
temp | = ( ( int ) maclocal [ 5 ] ) ;
return temp ;
}
int net2000_get_maclocal_pci ( )
{
int temp ;
temp = ( ( ( int ) maclocal_pci [ 3 ] ) < < 16 ) ;
temp | = ( ( ( int ) maclocal_pci [ 4 ] ) < < 8 ) ;
temp | = ( ( int ) maclocal_pci [ 5 ] ) ;
return temp ;
}
2016-06-26 00:34:39 +02:00
static void ne2000_setirq ( ne2000_t * ne2000 , int irq )
{
2017-02-07 02:19:48 +01:00
ne2000 - > base_irq = irq ;
2016-06-26 00:34:39 +02:00
}
2017-02-07 02:19:48 +01:00
2017-05-05 01:49:42 +02:00
/* reset - restore state to power-up, cancelling all i/o */
2016-08-13 03:32:38 +02:00
static void ne2000_reset ( void * p , int reset )
2016-06-26 00:34:39 +02:00
{
2017-02-07 02:19:48 +01:00
ne2000_t * ne2000 = ( ne2000_t * ) p ;
int i ;
ne2000_log ( " ne2000 reset \n " ) ;
2017-05-05 01:49:42 +02:00
/* Initialise the mac address area by doubling the physical address */
2017-02-07 02:19:48 +01:00
ne2000 - > macaddr [ 0 ] = ne2000 - > physaddr [ 0 ] ;
ne2000 - > macaddr [ 1 ] = ne2000 - > physaddr [ 0 ] ;
ne2000 - > macaddr [ 2 ] = ne2000 - > physaddr [ 1 ] ;
ne2000 - > macaddr [ 3 ] = ne2000 - > physaddr [ 1 ] ;
ne2000 - > macaddr [ 4 ] = ne2000 - > physaddr [ 2 ] ;
ne2000 - > macaddr [ 5 ] = ne2000 - > physaddr [ 2 ] ;
ne2000 - > macaddr [ 6 ] = ne2000 - > physaddr [ 3 ] ;
ne2000 - > macaddr [ 7 ] = ne2000 - > physaddr [ 3 ] ;
ne2000 - > macaddr [ 8 ] = ne2000 - > physaddr [ 4 ] ;
ne2000 - > macaddr [ 9 ] = ne2000 - > physaddr [ 4 ] ;
ne2000 - > macaddr [ 10 ] = ne2000 - > physaddr [ 5 ] ;
ne2000 - > macaddr [ 11 ] = ne2000 - > physaddr [ 5 ] ;
2017-05-05 01:49:42 +02:00
/* ne2k signature */
2017-02-07 02:19:48 +01:00
for ( i = 12 ; i < 32 ; i + + )
{
ne2000 - > macaddr [ i ] = 0x57 ;
}
2017-05-05 01:49:42 +02:00
/* Zero out registers and memory */
2017-02-07 02:19:48 +01:00
memset ( & ne2000 - > CR , 0 , sizeof ( ne2000 - > CR ) ) ;
memset ( & ne2000 - > ISR , 0 , sizeof ( ne2000 - > ISR ) ) ;
memset ( & ne2000 - > IMR , 0 , sizeof ( ne2000 - > IMR ) ) ;
memset ( & ne2000 - > DCR , 0 , sizeof ( ne2000 - > DCR ) ) ;
memset ( & ne2000 - > TCR , 0 , sizeof ( ne2000 - > TCR ) ) ;
memset ( & ne2000 - > TSR , 0 , sizeof ( ne2000 - > TSR ) ) ;
memset ( & ne2000 - > RSR , 0 , sizeof ( ne2000 - > RSR ) ) ;
ne2000 - > tx_timer_active = 0 ;
ne2000 - > local_dma = 0 ;
ne2000 - > page_start = 0 ;
ne2000 - > page_stop = 0 ;
ne2000 - > bound_ptr = 0 ;
ne2000 - > tx_page_start = 0 ;
ne2000 - > num_coll = 0 ;
ne2000 - > tx_bytes = 0 ;
ne2000 - > fifo = 0 ;
ne2000 - > remote_dma = 0 ;
ne2000 - > remote_start = 0 ;
ne2000 - > remote_bytes = 0 ;
ne2000 - > tallycnt_0 = 0 ;
ne2000 - > tallycnt_1 = 0 ;
ne2000 - > tallycnt_2 = 0 ;
ne2000 - > curr_page = 0 ;
ne2000 - > rempkt_ptr = 0 ;
ne2000 - > localpkt_ptr = 0 ;
ne2000 - > address_cnt = 0 ;
memset ( & ne2000 - > mem , 0 , sizeof ( ne2000 - > mem ) ) ;
2017-05-05 01:49:42 +02:00
/* Set power-up conditions */
2017-02-07 02:19:48 +01:00
ne2000 - > CR . stop = 1 ;
ne2000 - > CR . rdma_cmd = 4 ;
ne2000 - > ISR . reset = 1 ;
ne2000 - > DCR . longaddr = 1 ;
picint ( 1 < < ne2000 - > base_irq ) ;
picintc ( 1 < < ne2000 - > base_irq ) ;
2016-06-26 00:34:39 +02:00
}
# include "bswap.h"
2017-05-05 01:49:42 +02:00
/* read_cr/write_cr - utility routines for handling reads/writes to
the Command Register */
2016-08-13 03:32:38 +02:00
uint32_t ne2000_read_cr ( ne2000_t * ne2000 )
{
uint32_t val ;
2017-02-07 02:19:48 +01:00
val = ( ( ( ne2000 - > CR . pgsel & 0x03 ) < < 6 ) |
( ( ne2000 - > CR . rdma_cmd & 0x07 ) < < 3 ) |
( ne2000 - > CR . tx_packet < < 2 ) |
( ne2000 - > CR . start < < 1 ) |
( ne2000 - > CR . stop ) ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " %s: read CR returns 0x%02x \n " , ( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , val ) ;
2016-08-13 03:32:38 +02:00
return val ;
}
void ne2000_write_cr ( ne2000_t * ne2000 , uint32_t value )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " %s: wrote 0x%02x to CR \n " , ( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , value ) ;
2016-08-13 03:32:38 +02:00
2017-05-05 01:49:42 +02:00
/* Validate remote-DMA */
2017-02-07 02:19:48 +01:00
if ( ( value & 0x38 ) = = 0x00 )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " CR write - invalid rDMA value 0 \n " ) ;
2016-08-13 03:32:38 +02:00
value | = 0x20 ; /* dma_cmd == 4 is a safe default */
}
2017-05-05 01:49:42 +02:00
/* Check for s/w reset */
2017-02-07 02:19:48 +01:00
if ( value & 0x01 )
{
2016-08-13 03:32:38 +02:00
ne2000 - > ISR . reset = 1 ;
ne2000 - > CR . stop = 1 ;
} else {
ne2000 - > CR . stop = 0 ;
}
ne2000 - > CR . rdma_cmd = ( value & 0x38 ) > > 3 ;
2017-05-05 01:49:42 +02:00
/* If start command issued, the RST bit in the ISR */
/* must be cleared */
2017-02-07 02:19:48 +01:00
if ( ( value & 0x02 ) & & ! ne2000 - > CR . start )
{
2016-08-13 03:32:38 +02:00
ne2000 - > ISR . reset = 0 ;
}
ne2000 - > CR . start = ( ( value & 0x02 ) = = 0x02 ) ;
ne2000 - > CR . pgsel = ( value & 0xc0 ) > > 6 ;
2017-05-05 01:49:42 +02:00
/* Check for send-packet command */
2017-02-07 02:19:48 +01:00
if ( ne2000 - > CR . rdma_cmd = = 3 )
{
2017-05-05 01:49:42 +02:00
/* Set up DMA read from receive ring */
2016-08-13 03:32:38 +02:00
ne2000 - > remote_start = ne2000 - > remote_dma = ne2000 - > bound_ptr * 256 ;
ne2000 - > remote_bytes = ( uint16_t ) ne2000_chipmem_read ( ne2000 , ne2000 - > bound_ptr * 256 + 2 , 2 ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " Sending buffer #x%x length %d \n " , ne2000 - > remote_start , ne2000 - > remote_bytes ) ;
2016-08-13 03:32:38 +02:00
}
2017-05-05 01:49:42 +02:00
/* Check for start-tx */
2017-02-07 02:19:48 +01:00
if ( ( value & 0x04 ) & & ne2000 - > TCR . loop_cntl )
{
if ( ne2000 - > TCR . loop_cntl ! = 1 )
{
ne2000_log ( " Loop mode %d not supported \n " , ne2000 - > TCR . loop_cntl ) ;
2016-08-13 03:32:38 +02:00
}
2017-02-07 02:19:48 +01:00
else
{
ne2000_rx_frame ( ne2000 , & ne2000 - > mem [ ne2000 - > tx_page_start * 256 - BX_NE2K_MEMSTART ] , ne2000 - > tx_bytes ) ;
}
}
else if ( value & 0x04 )
{
if ( ne2000 - > CR . stop | | ( ! ne2000 - > CR . start & & ( network_card_current = = 1 ) ) )
{
if ( ne2000 - > tx_bytes = = 0 ) /* njh@bandsman.co.uk */
{
return ; /* Solaris9 probe */
}
ne2000_log ( " CR write - tx start, dev in reset \n " ) ;
2016-08-13 03:32:38 +02:00
}
if ( ne2000 - > tx_bytes = = 0 )
2017-02-07 02:19:48 +01:00
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " CR write - tx start, tx bytes == 0 \n " ) ;
2017-02-07 02:19:48 +01:00
}
2016-08-13 03:32:38 +02:00
2017-05-05 01:49:42 +02:00
/* Send the packet to the system driver */
2016-08-13 03:32:38 +02:00
ne2000 - > CR . tx_packet = 1 ;
2017-02-07 02:19:48 +01:00
if ( ! net_is_pcap )
2016-08-13 03:32:38 +02:00
{
slirp_input ( & ne2000 - > mem [ ne2000 - > tx_page_start * 256 - BX_NE2K_MEMSTART ] , ne2000 - > tx_bytes ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 slirp sending packet \n " ) ;
2016-08-13 03:32:38 +02:00
}
2017-02-07 02:19:48 +01:00
else if ( net_is_pcap & & ( net_pcap ! = NULL ) )
2016-08-13 03:32:38 +02:00
{
2017-02-07 02:19:48 +01:00
pcap_sendpacket ( net_pcap , & ne2000 - > mem [ ne2000 - > tx_page_start * 256 - BX_NE2K_MEMSTART ] , ne2000 - > tx_bytes ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 pcap sending packet \n " ) ;
2016-08-13 03:32:38 +02:00
}
2017-05-05 01:49:42 +02:00
/* some more debug */
2016-08-13 03:32:38 +02:00
if ( ne2000 - > tx_timer_active )
2017-02-07 02:19:48 +01:00
{
ne2000_log ( " CR write, tx timer still active \n " ) ;
}
2016-08-13 03:32:38 +02:00
ne2000_tx_event ( ne2000 , value ) ;
2017-02-07 02:19:48 +01:00
}
2016-08-13 03:32:38 +02:00
2017-05-05 01:49:42 +02:00
/* Linux probes for an interrupt by setting up a remote-DMA read
of 0 bytes with remote - DMA completion interrupts enabled .
Detect this here */
2016-08-13 03:32:38 +02:00
if ( ne2000 - > CR . rdma_cmd = = 0x01 & &
ne2000 - > CR . start & &
2017-02-07 02:19:48 +01:00
ne2000 - > remote_bytes = = 0 )
{
2016-08-13 03:32:38 +02:00
ne2000 - > ISR . rdma_done = 1 ;
2017-02-07 02:19:48 +01:00
if ( ne2000 - > IMR . rdma_inte )
{
picint ( 1 < < ne2000 - > base_irq ) ;
2017-02-14 07:06:24 +01:00
if ( network_card_current = = 1 )
{
picintc ( 1 < < ne2000 - > base_irq ) ;
}
2016-08-13 03:32:38 +02:00
}
}
}
2017-05-05 01:49:42 +02:00
/* chipmem_read/chipmem_write - access the 64K private RAM.
The ne2000 memory is accessed through the data port of
the asic ( offset 0 ) after setting up a remote - DMA transfer .
Both byte and word accesses are allowed .
The first 16 bytes contains the MAC address at even locations ,
and there is 16 K of buffer memory starting at 16 K
*/
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
uint32_t ne2000_chipmem_read ( ne2000_t * ne2000 , uint32_t address , unsigned int io_len )
{
2017-02-07 02:19:48 +01:00
uint32_t retval = 0 ;
if ( ( io_len = = 2 ) & & ( address & 0x1 ) )
{
ne2000_log ( " unaligned chipmem word read \n " ) ;
}
2017-05-05 01:49:42 +02:00
/* ROM'd MAC address */
2017-02-07 02:19:48 +01:00
if ( ( address > = 0 ) & & ( address < = 31 ) )
{
retval = ne2000 - > macaddr [ address % 32 ] ;
if ( ( io_len = = 2 ) | | ( io_len = = 4 ) )
{
retval | = ( ne2000 - > macaddr [ ( address + 1 ) % 32 ] < < 8 ) ;
}
if ( io_len = = 4 )
{
retval | = ( ne2000 - > macaddr [ ( address + 2 ) % 32 ] < < 16 ) ;
retval | = ( ne2000 - > macaddr [ ( address + 3 ) % 32 ] < < 24 ) ;
}
return ( retval ) ;
}
if ( ( address > = BX_NE2K_MEMSTART ) & & ( address < BX_NE2K_MEMEND ) )
{
retval = ne2000 - > mem [ address - BX_NE2K_MEMSTART ] ;
if ( ( io_len = = 2 ) | | ( io_len = = 4 ) )
{
retval | = ( ne2000 - > mem [ address - BX_NE2K_MEMSTART + 1 ] < < 8 ) ;
}
if ( io_len = = 4 )
{
retval | = ( ne2000 - > mem [ address - BX_NE2K_MEMSTART + 2 ] < < 16 ) ;
retval | = ( ne2000 - > mem [ address - BX_NE2K_MEMSTART + 3 ] < < 24 ) ;
}
return ( retval ) ;
}
ne2000_log ( " out-of-bounds chipmem read, %04X \n " , address ) ;
2017-02-14 07:06:24 +01:00
if ( network_card_current = = 1 )
{
switch ( io_len )
{
case 1 :
return 0xff ;
case 2 :
return 0xffff ;
}
}
else
{
2017-05-05 01:49:42 +02:00
return 0xff ;
2017-02-14 07:06:24 +01:00
}
2017-05-05 01:49:42 +02:00
return 0xffff ;
2016-08-13 03:32:38 +02:00
}
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
void ne2000_chipmem_write ( ne2000_t * ne2000 , uint32_t address , uint32_t value , unsigned io_len )
2016-06-26 00:34:39 +02:00
{
2017-02-07 02:19:48 +01:00
if ( ( io_len = = 2 ) & & ( address & 0x1 ) )
{
ne2000_log ( " unaligned chipmem word write \n " ) ;
}
if ( ( address > = BX_NE2K_MEMSTART ) & & ( address < BX_NE2K_MEMEND ) )
{
ne2000 - > mem [ address - BX_NE2K_MEMSTART ] = value & 0xff ;
if ( ( io_len = = 2 ) | | ( io_len = = 4 ) )
{
ne2000 - > mem [ address - BX_NE2K_MEMSTART + 1 ] = value > > 8 ;
}
if ( io_len = = 4 )
{
ne2000 - > mem [ address - BX_NE2K_MEMSTART + 2 ] = value > > 16 ;
ne2000 - > mem [ address - BX_NE2K_MEMSTART + 3 ] = value > > 24 ;
}
}
else
{
ne2000_log ( " out-of-bounds chipmem write, %04X \n " , address ) ;
}
2016-06-26 00:34:39 +02:00
}
2017-05-05 01:49:42 +02:00
/* asic_read/asic_write - This is the high 16 bytes of i/o space
( the lower 16 bytes is for the DS8390 ) . Only two locations
are used : offset 0 , which is used for data transfer , and
offset 0xf , which is used to reset the device .
The data transfer port is used to as ' external ' DMA to the
DS8390 . The chip has to have the DMA registers set up , and
after that , insw / outsw instructions can be used to move
the appropriate number of bytes to / from the device .
*/
2016-08-13 03:32:38 +02:00
uint32_t ne2000_asic_read ( ne2000_t * ne2000 , uint32_t offset , unsigned int io_len )
2016-06-26 00:34:39 +02:00
{
2017-02-07 02:19:48 +01:00
uint32_t retval = 0 ;
switch ( offset )
{
2017-05-05 01:49:42 +02:00
case 0x0 : /* Data register */
/* A read remote-DMA command must have been issued,
and the source - address and length registers must
have been initialised . */
2017-02-07 02:19:48 +01:00
if ( io_len > ne2000 - > remote_bytes )
{
ne2000_log ( " dma read underrun iolen=%d remote_bytes=%d \n " , io_len , ne2000 - > remote_bytes ) ;
}
ne2000_log ( " %s read DMA: addr=%4x remote_bytes=%d \n " , ( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , ne2000 - > remote_dma , ne2000 - > remote_bytes ) ;
retval = ne2000_chipmem_read ( ne2000 , ne2000 - > remote_dma , io_len ) ;
2017-05-05 01:49:42 +02:00
/* The 8390 bumps the address and decreases the byte count
by the selected word size after every access , not by
the amount of data requested by the host ( io_len ) . */
2017-02-07 02:19:48 +01:00
if ( io_len = = 4 )
{
ne2000 - > remote_dma + = io_len ;
}
else
{
ne2000 - > remote_dma + = ( ne2000 - > DCR . wdsize + 1 ) ;
}
if ( ne2000 - > remote_dma = = ne2000 - > page_stop < < 8 )
{
ne2000 - > remote_dma = ne2000 - > page_start < < 8 ;
}
2017-05-05 01:49:42 +02:00
/* keep s.remote_bytes from underflowing */
2017-02-07 02:19:48 +01:00
if ( ne2000 - > remote_bytes > ne2000 - > DCR . wdsize )
{
if ( io_len = = 4 )
{
ne2000 - > remote_bytes - = io_len ;
}
else
{
ne2000 - > remote_bytes - = ( ne2000 - > DCR . wdsize + 1 ) ;
}
}
else
{
ne2000 - > remote_bytes = 0 ;
}
2017-05-05 01:49:42 +02:00
/* If all bytes have been written, signal remote-DMA complete */
2017-02-07 02:19:48 +01:00
if ( ne2000 - > remote_bytes = = 0 )
{
ne2000 - > ISR . rdma_done = 1 ;
if ( ne2000 - > IMR . rdma_inte )
{
picint ( 1 < < ne2000 - > base_irq ) ;
}
}
break ;
2017-05-05 01:49:42 +02:00
case 0xf : /* Reset register */
2017-02-07 02:19:48 +01:00
ne2000_reset ( ne2000 , BX_RESET_SOFTWARE ) ;
break ;
default :
ne2000_log ( " asic read invalid address %04x \n " , ( unsigned ) offset ) ;
break ;
}
return ( retval ) ;
2016-06-26 00:34:39 +02:00
}
2016-08-13 03:32:38 +02:00
void ne2000_asic_write ( ne2000_t * ne2000 , uint32_t offset , uint32_t value , unsigned io_len )
2016-06-26 00:34:39 +02:00
{
2017-02-07 02:19:48 +01:00
ne2000_log ( " %s: asic write addr=0x%02x, value=0x%04x \n " , ( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , ( unsigned ) offset , ( unsigned ) value ) ;
switch ( offset )
{
2017-05-05 01:49:42 +02:00
case 0x0 : /* Data register - see asic_read for a description */
2017-02-07 02:19:48 +01:00
if ( ( io_len > 1 ) & & ( ne2000 - > DCR . wdsize = = 0 ) )
{
ne2000_log ( " dma write length %d on byte mode operation \n " , io_len ) ;
break ;
}
if ( ne2000 - > remote_bytes = = 0 )
{
ne2000_log ( " dma write, byte count 0 \n " ) ;
}
ne2000_chipmem_write ( ne2000 , ne2000 - > remote_dma , value , io_len ) ;
if ( io_len = = 4 )
{
ne2000 - > remote_dma + = io_len ;
}
else
{
ne2000 - > remote_dma + = ( ne2000 - > DCR . wdsize + 1 ) ;
}
if ( ne2000 - > remote_dma = = ne2000 - > page_stop < < 8 )
{
ne2000 - > remote_dma = ne2000 - > page_start < < 8 ;
}
if ( io_len = = 4 )
{
ne2000 - > remote_bytes - = io_len ;
}
else
{
ne2000 - > remote_bytes - = ( ne2000 - > DCR . wdsize + 1 ) ;
}
if ( ne2000 - > remote_bytes > BX_NE2K_MEMSIZ )
{
ne2000 - > remote_bytes = 0 ;
}
2017-05-05 01:49:42 +02:00
/* If all bytes have been written, signal remote-DMA complete */
2017-02-07 02:19:48 +01:00
if ( ne2000 - > remote_bytes = = 0 )
{
ne2000 - > ISR . rdma_done = 1 ;
if ( ne2000 - > IMR . rdma_inte )
{
picint ( 1 < < ne2000 - > base_irq ) ;
}
}
break ;
2017-05-05 01:49:42 +02:00
case 0xf : /* Reset register */
/* end of reset pulse */
2017-02-07 02:19:48 +01:00
break ;
2017-05-05 01:49:42 +02:00
default : /* this is invalid, but happens under win95 device detection */
2017-02-07 02:19:48 +01:00
ne2000_log ( " asic write invalid address %04x, ignoring \n " , ( unsigned ) offset ) ;
break ;
}
2016-06-26 00:34:39 +02:00
}
2017-05-05 01:49:42 +02:00
/* page0_read/page0_write - These routines handle reads/writes to
the ' zeroth ' page of the DS8390 register file */
2016-08-13 03:32:38 +02:00
uint32_t ne2000_page0_read ( ne2000_t * ne2000 , uint32_t offset , unsigned int io_len )
2016-06-26 00:34:39 +02:00
{
2017-02-07 02:19:48 +01:00
uint8_t value = 0 ;
if ( io_len > 1 )
{
ne2000_log ( " bad length! page 0 read from register 0x%02x, len=%u \n " , offset , io_len ) ; /* encountered with win98 hardware probe */
return value ;
}
switch ( offset )
{
2017-05-05 01:49:42 +02:00
case 0x1 : /* CLDA0 */
2017-02-07 02:19:48 +01:00
value = ( ne2000 - > local_dma & 0xff ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0x2 : /* CLDA1 */
2017-02-07 02:19:48 +01:00
value = ( ne2000 - > local_dma > > 8 ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0x3 : /* BNRY */
2017-02-07 02:19:48 +01:00
value = ne2000 - > bound_ptr ;
break ;
2017-05-05 01:49:42 +02:00
case 0x4 : /* TSR */
2017-02-07 02:19:48 +01:00
value = ( ( ne2000 - > TSR . ow_coll < < 7 ) |
( ne2000 - > TSR . cd_hbeat < < 6 ) |
( ne2000 - > TSR . fifo_ur < < 5 ) |
( ne2000 - > TSR . no_carrier < < 4 ) |
( ne2000 - > TSR . aborted < < 3 ) |
( ne2000 - > TSR . collided < < 2 ) |
( ne2000 - > TSR . tx_ok ) ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0x5 : /* NCR */
2017-02-07 02:19:48 +01:00
value = ne2000 - > num_coll ;
break ;
2017-05-05 01:49:42 +02:00
case 0x6 : /* FIFO */
/* reading FIFO is only valid in loopback mode */
2017-02-07 02:19:48 +01:00
ne2000_log ( " reading FIFO not supported yet \n " ) ;
value = ne2000 - > fifo ;
break ;
2017-05-05 01:49:42 +02:00
case 0x7 : /* ISR */
2017-02-07 02:19:48 +01:00
value = ( ( ne2000 - > ISR . reset < < 7 ) |
( ne2000 - > ISR . rdma_done < < 6 ) |
( ne2000 - > ISR . cnt_oflow < < 5 ) |
( ne2000 - > ISR . overwrite < < 4 ) |
( ne2000 - > ISR . tx_err < < 3 ) |
( ne2000 - > ISR . rx_err < < 2 ) |
( ne2000 - > ISR . pkt_tx < < 1 ) |
( ne2000 - > ISR . pkt_rx ) ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0x8 : /* CRDA0 */
2017-02-07 02:19:48 +01:00
value = ( ne2000 - > remote_dma & 0xff ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0x9 : /* CRDA1 */
2017-02-07 02:19:48 +01:00
value = ( ne2000 - > remote_dma > > 8 ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0xa : /* reserved / RTL8029ID0 */
2017-02-07 02:19:48 +01:00
if ( network_card_current = = 2 )
{
value = 0x50 ;
}
else
{
ne2000_log ( " reserved read - page 0, 0xa \n " ) ;
value = 0xff ;
}
break ;
2017-05-05 01:49:42 +02:00
case 0xb : /* reserved / RTL8029ID1 */
2017-02-07 02:19:48 +01:00
if ( network_card_current = = 2 )
{
value = 0x43 ;
}
else
{
ne2000_log ( " reserved read - page 0, 0xb \n " ) ;
value = 0xff ;
}
break ;
2017-05-05 01:49:42 +02:00
case 0xc : /* RSR */
2017-02-07 02:19:48 +01:00
value = ( ( ne2000 - > RSR . deferred < < 7 ) |
( ne2000 - > RSR . rx_disabled < < 6 ) |
( ne2000 - > RSR . rx_mbit < < 5 ) |
( ne2000 - > RSR . rx_missed < < 4 ) |
( ne2000 - > RSR . fifo_or < < 3 ) |
( ne2000 - > RSR . bad_falign < < 2 ) |
( ne2000 - > RSR . bad_crc < < 1 ) |
( ne2000 - > RSR . rx_ok ) ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0xd : /* CNTR0 */
2017-02-07 02:19:48 +01:00
value = ne2000 - > tallycnt_0 ;
break ;
2017-05-05 01:49:42 +02:00
case 0xe : /* CNTR1 */
2017-02-07 02:19:48 +01:00
value = ne2000 - > tallycnt_1 ;
break ;
2017-05-05 01:49:42 +02:00
case 0xf : /* CNTR2 */
2017-02-07 02:19:48 +01:00
value = ne2000 - > tallycnt_2 ;
break ;
default :
ne2000_log ( " page 0 register 0x%02x out of range \n " , offset ) ;
break ;
}
ne2000_log ( " page 0 read from register 0x%02x, value=0x%02x \n " , offset , value ) ;
return value ;
2016-06-26 00:34:39 +02:00
}
2016-08-13 03:32:38 +02:00
void ne2000_page0_write ( ne2000_t * ne2000 , uint32_t offset , uint32_t value , unsigned io_len )
2016-06-26 00:34:39 +02:00
{
2017-02-07 02:19:48 +01:00
uint8_t value2 ;
2017-05-05 01:49:42 +02:00
/* It appears to be a common practice to use outw on page0 regs... */
2017-02-07 02:19:48 +01:00
2017-05-05 01:49:42 +02:00
/* break up outw into two outb's */
2017-02-07 02:19:48 +01:00
if ( io_len = = 2 )
{
ne2000_page0_write ( ne2000 , offset , ( value & 0xff ) , 1 ) ;
if ( offset < 0x0f )
{
ne2000_page0_write ( ne2000 , offset + 1 , ( ( value > > 8 ) & 0xff ) , 1 ) ;
}
return ;
}
ne2000_log ( " page 0 write to register 0x%02x, value=0x%02x \n " , offset , value ) ;
switch ( offset )
{
2017-05-05 01:49:42 +02:00
case 0x1 : /* PSTART */
2017-02-07 02:19:48 +01:00
ne2000 - > page_start = value ;
break ;
2017-05-05 01:49:42 +02:00
case 0x2 : /* PSTOP */
2017-02-07 02:19:48 +01:00
ne2000 - > page_stop = value ;
break ;
2017-05-05 01:49:42 +02:00
case 0x3 : /* BNRY */
2017-02-07 02:19:48 +01:00
ne2000 - > bound_ptr = value ;
break ;
2017-05-05 01:49:42 +02:00
case 0x4 : /* TPSR */
2017-02-07 02:19:48 +01:00
ne2000 - > tx_page_start = value ;
break ;
2017-05-05 01:49:42 +02:00
case 0x5 : /* TBCR0 */
/* Clear out low byte and re-insert */
2017-02-07 02:19:48 +01:00
ne2000 - > tx_bytes & = 0xff00 ;
ne2000 - > tx_bytes | = ( value & 0xff ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0x6 : /* TBCR1 */
/* Clear out high byte and re-insert */
2017-02-07 02:19:48 +01:00
ne2000 - > tx_bytes & = 0x00ff ;
ne2000 - > tx_bytes | = ( ( value & 0xff ) < < 8 ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0x7 : /* ISR */
value & = 0x7f ; /* clear RST bit - status-only bit */
/* All other values are cleared iff the ISR bit is 1 */
2017-02-07 02:19:48 +01:00
ne2000 - > ISR . pkt_rx & = ~ ( ( int ) ( ( value & 0x01 ) = = 0x01 ) ) ;
ne2000 - > ISR . pkt_tx & = ~ ( ( int ) ( ( value & 0x02 ) = = 0x02 ) ) ;
ne2000 - > ISR . rx_err & = ~ ( ( int ) ( ( value & 0x04 ) = = 0x04 ) ) ;
ne2000 - > ISR . tx_err & = ~ ( ( int ) ( ( value & 0x08 ) = = 0x08 ) ) ;
ne2000 - > ISR . overwrite & = ~ ( ( int ) ( ( value & 0x10 ) = = 0x10 ) ) ;
ne2000 - > ISR . cnt_oflow & = ~ ( ( int ) ( ( value & 0x20 ) = = 0x20 ) ) ;
ne2000 - > ISR . rdma_done & = ~ ( ( int ) ( ( value & 0x40 ) = = 0x40 ) ) ;
value = ( ( ne2000 - > ISR . rdma_done < < 6 ) |
( ne2000 - > ISR . cnt_oflow < < 5 ) |
( ne2000 - > ISR . overwrite < < 4 ) |
( ne2000 - > ISR . tx_err < < 3 ) |
( ne2000 - > ISR . rx_err < < 2 ) |
( ne2000 - > ISR . pkt_tx < < 1 ) |
( ne2000 - > ISR . pkt_rx ) ) ;
value & = ( ( ne2000 - > IMR . rdma_inte < < 6 ) |
( ne2000 - > IMR . cofl_inte < < 5 ) |
( ne2000 - > IMR . overw_inte < < 4 ) |
( ne2000 - > IMR . txerr_inte < < 3 ) |
( ne2000 - > IMR . rxerr_inte < < 2 ) |
( ne2000 - > IMR . tx_inte < < 1 ) |
( ne2000 - > IMR . rx_inte ) ) ;
if ( value = = 0 )
{
picintc ( 1 < < ne2000 - > base_irq ) ;
}
break ;
2017-05-05 01:49:42 +02:00
case 0x8 : /* RSAR0 */
/* Clear out low byte and re-insert */
2017-02-07 02:19:48 +01:00
ne2000 - > remote_start & = 0xff00 ;
ne2000 - > remote_start | = ( value & 0xff ) ;
ne2000 - > remote_dma = ne2000 - > remote_start ;
break ;
2017-05-05 01:49:42 +02:00
case 0x9 : /* RSAR1 */
/* Clear out high byte and re-insert */
2017-02-07 02:19:48 +01:00
ne2000 - > remote_start & = 0x00ff ;
ne2000 - > remote_start | = ( ( value & 0xff ) < < 8 ) ;
ne2000 - > remote_dma = ne2000 - > remote_start ;
break ;
2017-05-05 01:49:42 +02:00
case 0xa : /* RBCR0 */
/* Clear out low byte and re-insert */
2017-02-07 02:19:48 +01:00
ne2000 - > remote_bytes & = 0xff00 ;
ne2000 - > remote_bytes | = ( value & 0xff ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0xb : /* RBCR1 */
/* Clear out high byte and re-insert */
2017-02-07 02:19:48 +01:00
ne2000 - > remote_bytes & = 0x00ff ;
ne2000 - > remote_bytes | = ( ( value & 0xff ) < < 8 ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0xc : /* RCR */
/* Check if the reserved bits are set */
2017-02-07 02:19:48 +01:00
if ( value & 0xc0 )
{
ne2000_log ( " RCR write, reserved bits set \n " ) ;
}
2017-05-05 01:49:42 +02:00
/* Set all other bit-fields */
2017-02-07 02:19:48 +01:00
ne2000 - > RCR . errors_ok = ( ( value & 0x01 ) = = 0x01 ) ;
ne2000 - > RCR . runts_ok = ( ( value & 0x02 ) = = 0x02 ) ;
ne2000 - > RCR . broadcast = ( ( value & 0x04 ) = = 0x04 ) ;
ne2000 - > RCR . multicast = ( ( value & 0x08 ) = = 0x08 ) ;
ne2000 - > RCR . promisc = ( ( value & 0x10 ) = = 0x10 ) ;
ne2000 - > RCR . monitor = ( ( value & 0x20 ) = = 0x20 ) ;
2017-05-05 01:49:42 +02:00
/* Monitor bit is a little suspicious... */
2017-02-07 02:19:48 +01:00
if ( value & 0x20 )
{
ne2000_log ( " RCR write, monitor bit set! \n " ) ;
}
break ;
2017-05-05 01:49:42 +02:00
case 0xd : /* TCR */
/* Check reserved bits */
2017-02-07 02:19:48 +01:00
if ( value & 0xe0 )
{
ne2000_log ( " TCR write, reserved bits set \n " ) ;
}
2017-05-05 01:49:42 +02:00
/* Test loop mode (not supported) */
2017-02-07 02:19:48 +01:00
if ( value & 0x06 )
{
ne2000 - > TCR . loop_cntl = ( value & 0x6 ) > > 1 ;
ne2000_log ( " TCR write, loop mode %d not supported \n " , ne2000 - > TCR . loop_cntl ) ;
}
else
{
ne2000 - > TCR . loop_cntl = 0 ;
}
2017-05-05 01:49:42 +02:00
/* Inhibit-CRC not supported. */
2017-02-07 02:19:48 +01:00
if ( value & 0x01 )
{
ne2000_log ( " TCR write, inhibit-CRC not supported \n " ) ;
}
2017-05-05 01:49:42 +02:00
/* Auto-transmit disable very suspicious */
2017-02-07 02:19:48 +01:00
if ( value & 0x08 )
{
ne2000_log ( " TCR write, auto transmit disable not supported \n " ) ;
}
2017-05-05 01:49:42 +02:00
/* Allow collision-offset to be set, although not used */
2017-02-07 02:19:48 +01:00
ne2000 - > TCR . coll_prio = ( ( value & 0x08 ) = = 0x08 ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0xe : /* DCR */
/* the loopback mode is not suppported yet */
2017-02-07 02:19:48 +01:00
if ( ! ( value & 0x08 ) )
{
ne2000_log ( " DCR write, loopback mode selected \n " ) ;
}
2017-05-05 01:49:42 +02:00
/* It is questionable to set longaddr and auto_rx, since they
aren ' t supported on the ne2000 . Print a warning and continue */
2017-02-07 02:19:48 +01:00
if ( value & 0x04 )
{
ne2000_log ( " DCR write - LAS set ??? \n " ) ;
}
if ( value & 0x10 )
{
ne2000_log ( " DCR write - AR set ??? \n " ) ;
}
2017-05-05 01:49:42 +02:00
/* Set other values. */
2017-02-07 02:19:48 +01:00
ne2000 - > DCR . wdsize = ( ( value & 0x01 ) = = 0x01 ) ;
ne2000 - > DCR . endian = ( ( value & 0x02 ) = = 0x02 ) ;
2017-05-05 01:49:42 +02:00
ne2000 - > DCR . longaddr = ( ( value & 0x04 ) = = 0x04 ) ; /* illegal ? */
2017-02-07 02:19:48 +01:00
ne2000 - > DCR . loop = ( ( value & 0x08 ) = = 0x08 ) ;
2017-05-05 01:49:42 +02:00
ne2000 - > DCR . auto_rx = ( ( value & 0x10 ) = = 0x10 ) ; /* also illegal ? */
2017-02-07 02:19:48 +01:00
ne2000 - > DCR . fifo_size = ( value & 0x50 ) > > 5 ;
break ;
2017-05-05 01:49:42 +02:00
case 0xf : /* IMR */
/* Check for reserved bit */
2017-02-07 02:19:48 +01:00
if ( value & 0x80 )
{
ne2000_log ( " IMR write, reserved bit set \n " ) ;
}
2017-05-05 01:49:42 +02:00
/* Set other values */
2017-02-07 02:19:48 +01:00
ne2000 - > IMR . rx_inte = ( ( value & 0x01 ) = = 0x01 ) ;
ne2000 - > IMR . tx_inte = ( ( value & 0x02 ) = = 0x02 ) ;
ne2000 - > IMR . rxerr_inte = ( ( value & 0x04 ) = = 0x04 ) ;
ne2000 - > IMR . txerr_inte = ( ( value & 0x08 ) = = 0x08 ) ;
ne2000 - > IMR . overw_inte = ( ( value & 0x10 ) = = 0x10 ) ;
ne2000 - > IMR . cofl_inte = ( ( value & 0x20 ) = = 0x20 ) ;
ne2000 - > IMR . rdma_inte = ( ( value & 0x40 ) = = 0x40 ) ;
value2 = ( ( ne2000 - > ISR . rdma_done < < 6 ) |
( ne2000 - > ISR . cnt_oflow < < 5 ) |
( ne2000 - > ISR . overwrite < < 4 ) |
( ne2000 - > ISR . tx_err < < 3 ) |
( ne2000 - > ISR . rx_err < < 2 ) |
( ne2000 - > ISR . pkt_tx < < 1 ) |
( ne2000 - > ISR . pkt_rx ) ) ;
if ( ( ( value & value2 ) & 0x7f ) = = 0 )
{
picintc ( 1 < < ne2000 - > base_irq ) ;
}
else
{
picint ( 1 < < ne2000 - > base_irq ) ;
}
break ;
default :
ne2000_log ( " page 0 write, bad register 0x%02x \n " , offset ) ;
break ;
}
2016-08-13 03:32:38 +02:00
}
2016-06-26 00:34:39 +02:00
2017-05-05 01:49:42 +02:00
/* page1_read/page1_write - These routines handle reads/writes to
the first page of the DS8390 register file */
2016-08-13 03:32:38 +02:00
uint32_t ne2000_page1_read ( ne2000_t * ne2000 , uint32_t offset , unsigned int io_len )
{
2017-02-07 02:19:48 +01:00
ne2000_log ( " page 1 read from register 0x%02x, len=%u \n " , offset , io_len ) ;
switch ( offset )
{
2017-05-05 01:49:42 +02:00
case 0x1 : /* PAR0-5 */
2017-02-07 02:19:48 +01:00
case 0x2 :
case 0x3 :
case 0x4 :
case 0x5 :
case 0x6 :
return ( ne2000 - > physaddr [ offset - 1 ] ) ;
2017-05-05 01:49:42 +02:00
case 0x7 : /* CURR */
2017-02-07 02:19:48 +01:00
ne2000_log ( " returning current page: 0x%02x \n " , ( ne2000 - > curr_page ) ) ;
return ( ne2000 - > curr_page ) ;
2017-05-05 01:49:42 +02:00
case 0x8 : /* MAR0-7 */
2017-02-07 02:19:48 +01:00
case 0x9 :
case 0xa :
case 0xb :
case 0xc :
case 0xd :
case 0xe :
case 0xf :
return ( ne2000 - > mchash [ offset - 8 ] ) ;
default :
ne2000_log ( " page 1 read register 0x%02x out of range \n " , offset ) ;
return 0 ;
}
2016-08-13 03:32:38 +02:00
}
void ne2000_page1_write ( ne2000_t * ne2000 , uint32_t offset , uint32_t value , unsigned io_len )
{
2017-02-07 02:19:48 +01:00
ne2000_log ( " page 1 write to register 0x%02x, len=%u, value=0x%04x \n " , offset , io_len , value ) ;
switch ( offset )
{
2017-05-05 01:49:42 +02:00
case 0x1 : /* PAR0-5 */
2017-02-07 02:19:48 +01:00
case 0x2 :
case 0x3 :
case 0x4 :
case 0x5 :
case 0x6 :
ne2000 - > physaddr [ offset - 1 ] = value ;
if ( offset = = 6 )
{
ne2000_log ( " Physical address set to %02x:%02x:%02x:%02x:%02x:%02x \n " , ne2000 - > physaddr [ 0 ] , ne2000 - > physaddr [ 1 ] , ne2000 - > physaddr [ 2 ] , ne2000 - > physaddr [ 3 ] , ne2000 - > physaddr [ 4 ] , ne2000 - > physaddr [ 5 ] ) ;
}
break ;
2017-05-05 01:49:42 +02:00
case 0x7 : /* CURR */
2017-02-07 02:19:48 +01:00
ne2000 - > curr_page = value ;
break ;
2017-05-05 01:49:42 +02:00
case 0x8 : /* MAR0-7 */
2017-02-07 02:19:48 +01:00
case 0x9 :
case 0xa :
case 0xb :
case 0xc :
case 0xd :
case 0xe :
case 0xf :
ne2000 - > mchash [ offset - 8 ] = value ;
break ;
default :
ne2000_log ( " page 1 write register 0x%02x out of range \n " , offset ) ;
break ;
}
2016-08-13 03:32:38 +02:00
}
2016-06-26 00:34:39 +02:00
2017-05-05 01:49:42 +02:00
/* page2_read/page2_write - These routines handle reads/writes to
the second page of the DS8390 register file */
2016-08-13 03:32:38 +02:00
uint32_t ne2000_page2_read ( ne2000_t * ne2000 , uint32_t offset , unsigned int io_len )
{
2017-02-07 02:19:48 +01:00
ne2000_log ( " page 2 read from register 0x%02x, len=%u \n " , offset , io_len ) ;
2016-08-13 03:32:38 +02:00
2017-02-07 02:19:48 +01:00
switch ( offset )
{
2017-05-05 01:49:42 +02:00
case 0x1 : /* PSTART */
2017-02-07 02:19:48 +01:00
return ( ne2000 - > page_start ) ;
2017-05-05 01:49:42 +02:00
case 0x2 : /* PSTOP */
2017-02-07 02:19:48 +01:00
return ( ne2000 - > page_stop ) ;
2017-05-05 01:49:42 +02:00
case 0x3 : /* Remote Next-packet pointer */
2017-02-07 02:19:48 +01:00
return ( ne2000 - > rempkt_ptr ) ;
2017-05-05 01:49:42 +02:00
case 0x4 : /* TPSR */
2017-02-07 02:19:48 +01:00
return ( ne2000 - > tx_page_start ) ;
2017-05-05 01:49:42 +02:00
case 0x5 : /* Local Next-packet pointer */
2017-02-07 02:19:48 +01:00
return ( ne2000 - > localpkt_ptr ) ;
2017-05-05 01:49:42 +02:00
case 0x6 : /* Address counter (upper) */
2017-02-07 02:19:48 +01:00
return ( ne2000 - > address_cnt > > 8 ) ;
2017-05-05 01:49:42 +02:00
case 0x7 : /* Address counter (lower) */
2017-02-07 02:19:48 +01:00
return ( ne2000 - > address_cnt & 0xff ) ;
2017-05-05 01:49:42 +02:00
case 0x8 : /* Reserved */
2017-02-07 02:19:48 +01:00
case 0x9 :
case 0xa :
case 0xb :
ne2000_log ( " reserved read - page 2, register 0x%02x \n " , offset ) ;
return ( 0xff ) ;
2017-05-05 01:49:42 +02:00
case 0xc : /* RCR */
2017-02-07 02:19:48 +01:00
return ( ( ne2000 - > RCR . monitor < < 5 ) |
( ne2000 - > RCR . promisc < < 4 ) |
( ne2000 - > RCR . multicast < < 3 ) |
( ne2000 - > RCR . broadcast < < 2 ) |
( ne2000 - > RCR . runts_ok < < 1 ) |
( ne2000 - > RCR . errors_ok ) ) ;
2017-05-05 01:49:42 +02:00
case 0xd : /* TCR */
2017-02-07 02:19:48 +01:00
return ( ( ne2000 - > TCR . coll_prio < < 4 ) |
( ne2000 - > TCR . ext_stoptx < < 3 ) |
( ( ne2000 - > TCR . loop_cntl & 0x3 ) < < 1 ) |
( ne2000 - > TCR . crc_disable ) ) ;
2017-05-05 01:49:42 +02:00
case 0xe : /* DCR */
2017-02-07 02:19:48 +01:00
return ( ( ( ne2000 - > DCR . fifo_size & 0x3 ) < < 5 ) |
( ne2000 - > DCR . auto_rx < < 4 ) |
( ne2000 - > DCR . loop < < 3 ) |
( ne2000 - > DCR . longaddr < < 2 ) |
( ne2000 - > DCR . endian < < 1 ) |
( ne2000 - > DCR . wdsize ) ) ;
2017-05-05 01:49:42 +02:00
case 0xf : /* IMR */
2017-02-07 02:19:48 +01:00
return ( ( ne2000 - > IMR . rdma_inte < < 6 ) |
( ne2000 - > IMR . cofl_inte < < 5 ) |
( ne2000 - > IMR . overw_inte < < 4 ) |
( ne2000 - > IMR . txerr_inte < < 3 ) |
( ne2000 - > IMR . rxerr_inte < < 2 ) |
( ne2000 - > IMR . tx_inte < < 1 ) |
( ne2000 - > IMR . rx_inte ) ) ;
default :
ne2000_log ( " page 2 register 0x%02x out of range \n " , offset ) ;
break ;
}
return ( 0 ) ;
2016-08-13 03:32:38 +02:00
}
void ne2000_page2_write ( ne2000_t * ne2000 , uint32_t offset , uint32_t value , unsigned io_len )
{
2017-05-05 01:49:42 +02:00
/* Maybe all writes here should be BX_PANIC()'d, since they
affect internal operation , but let them through for now
and print a warning . */
2017-02-07 02:19:48 +01:00
ne2000_log ( " page 2 write to register 0x%02x, len=%u, value=0x%04x \n " , offset , io_len , value ) ;
switch ( offset )
{
2017-05-05 01:49:42 +02:00
case 0x1 : /* CLDA0 */
/* Clear out low byte and re-insert */
2017-02-07 02:19:48 +01:00
ne2000 - > local_dma & = 0xff00 ;
ne2000 - > local_dma | = ( value & 0xff ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0x2 : /* CLDA1 */
/* Clear out high byte and re-insert */
2017-02-07 02:19:48 +01:00
ne2000 - > local_dma & = 0x00ff ;
ne2000 - > local_dma | = ( ( value & 0xff ) < < 8 ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0x3 : /* Remote Next-pkt pointer */
2017-02-07 02:19:48 +01:00
ne2000 - > rempkt_ptr = value ;
break ;
case 0x4 :
ne2000_log ( " page 2 write to reserved register 0x04 \n " ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0x5 : /* Local Next-packet pointer */
2017-02-07 02:19:48 +01:00
ne2000 - > localpkt_ptr = value ;
break ;
2017-05-05 01:49:42 +02:00
case 0x6 : /* Address counter (upper) */
/* Clear out high byte and re-insert */
2017-02-07 02:19:48 +01:00
ne2000 - > address_cnt & = 0x00ff ;
ne2000 - > address_cnt | = ( ( value & 0xff ) < < 8 ) ;
break ;
2017-05-05 01:49:42 +02:00
case 0x7 : /* Address counter (lower) */
/* Clear out low byte and re-insert */
2017-02-07 02:19:48 +01:00
ne2000 - > address_cnt & = 0xff00 ;
ne2000 - > address_cnt | = ( value & 0xff ) ;
break ;
case 0x8 :
case 0x9 :
case 0xa :
case 0xb :
case 0xc :
case 0xd :
case 0xe :
case 0xf :
ne2000_log ( " page 2 write to reserved register 0x%02x \n " , offset ) ;
break ;
default :
ne2000_log ( " page 2 write, illegal register 0x%02x \n " , offset ) ;
break ;
}
2016-08-13 03:32:38 +02:00
}
2017-05-05 01:49:42 +02:00
/* page3_read/page3_write - writes to this page are illegal */
2016-08-13 03:32:38 +02:00
uint32_t ne2000_page3_read ( ne2000_t * ne2000 , uint32_t offset , unsigned int io_len )
{
2017-02-07 02:19:48 +01:00
if ( network_card_current = = 2 )
{
switch ( offset )
{
2017-05-05 01:49:42 +02:00
case 0x3 : /* CONFIG0 */
2017-02-07 02:19:48 +01:00
return ( 0 ) ;
2017-05-05 01:49:42 +02:00
case 0x5 : /* CONFIG2 */
2017-02-07 02:19:48 +01:00
return ( 0x40 ) ;
2017-05-05 01:49:42 +02:00
case 0x6 : /* CONFIG3 */
2017-02-07 02:19:48 +01:00
return ( 0x40 ) ;
default :
ne2000_log ( " page 3 read register 0x%02x attempted \n " , offset ) ;
return ( 0 ) ;
}
}
else
{
ne2000_log ( " page 3 read register 0x%02x attempted \n " , offset ) ;
return ( 0 ) ;
}
2016-08-13 03:32:38 +02:00
}
void ne2000_page3_write ( ne2000_t * ne2000 , uint32_t offset , uint32_t value , unsigned io_len )
{
2017-02-07 02:19:48 +01:00
ne2000_log ( " page 3 write register 0x%02x attempted \n " , offset ) ;
return ;
2016-08-13 03:32:38 +02:00
}
void ne2000_tx_event ( void * p , uint32_t val )
{
2017-02-07 02:19:48 +01:00
ne2000_t * ne2000 = ( ne2000_t * ) p ;
ne2000_log ( " tx_timer \n " ) ;
ne2000 - > CR . tx_packet = 0 ;
ne2000 - > TSR . tx_ok = 1 ;
ne2000 - > ISR . pkt_tx = 1 ;
2017-05-05 01:49:42 +02:00
/* Generate an interrupt if not masked */
2017-02-07 02:19:48 +01:00
if ( ne2000 - > IMR . tx_inte )
{
picint ( 1 < < ne2000 - > base_irq ) ;
}
ne2000 - > tx_timer_active = 0 ;
2016-08-13 03:32:38 +02:00
}
2017-05-05 01:49:42 +02:00
/* read_handler/read - i/o 'catcher' function called from BOCHS
mainline when the CPU attempts a read in the i / o space registered
by this ne2000 instance */
2016-08-13 03:32:38 +02:00
uint32_t ne2000_read ( ne2000_t * ne2000 , uint32_t address , unsigned io_len )
{
2017-02-07 02:19:48 +01:00
uint32_t retval = 0 ;
int offset = address - ne2000 - > base_address ;
2017-05-05 01:49:42 +02:00
ne2000_log ( " %s: read addr %x, len %d \n " , ( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , address , io_len ) ;
2017-02-07 02:19:48 +01:00
if ( offset > = 0x10 )
{
retval = ne2000_asic_read ( ne2000 , offset - 0x10 , io_len ) ;
}
else if ( offset = = 0x00 )
{
retval = ne2000_read_cr ( ne2000 ) ;
}
else
{
switch ( ne2000 - > CR . pgsel )
{
case 0x00 :
retval = ne2000_page0_read ( ne2000 , offset , io_len ) ;
break ;
case 0x01 :
retval = ne2000_page1_read ( ne2000 , offset , io_len ) ;
break ;
case 0x02 :
retval = ne2000_page2_read ( ne2000 , offset , io_len ) ;
break ;
case 0x03 :
retval = ne2000_page3_read ( ne2000 , offset , io_len ) ;
break ;
default :
ne2000_log ( " unknown value of pgsel in read - %d \n " , ne2000 - > CR . pgsel ) ;
break ;
}
}
return ( retval ) ;
2016-08-13 03:32:38 +02:00
}
void ne2000_write ( ne2000_t * ne2000 , uint32_t address , uint32_t value , unsigned io_len )
{
2017-02-07 02:19:48 +01:00
int offset = address - ne2000 - > base_address ;
2017-05-05 01:49:42 +02:00
ne2000_log ( " %s: write addr %x, value %x len %d \n " , ( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , address , value , io_len ) ;
/* The high 16 bytes of i/o space are for the ne2000 asic -
the low 16 bytes are for the DS8390 , with the current
page being selected by the PS0 , PS1 registers in the
command register */
2017-02-07 02:19:48 +01:00
if ( offset > = 0x10 )
{
ne2000_asic_write ( ne2000 , offset - 0x10 , value , io_len ) ;
}
else if ( offset = = 0x00 )
{
ne2000_write_cr ( ne2000 , value ) ;
}
else
{
switch ( ne2000 - > CR . pgsel )
{
case 0x00 :
ne2000_page0_write ( ne2000 , offset , value , io_len ) ;
break ;
case 0x01 :
ne2000_page1_write ( ne2000 , offset , value , io_len ) ;
break ;
case 0x02 :
ne2000_page2_write ( ne2000 , offset , value , io_len ) ;
break ;
case 0x03 :
ne2000_page3_write ( ne2000 , offset , value , io_len ) ;
break ;
default :
ne2000_log ( " unknown value of pgsel in write - %d \n " , ne2000 - > CR . pgsel ) ;
break ;
}
}
2016-06-26 00:34:39 +02:00
}
/*
* mcast_index ( ) - return the 6 - bit index into the multicast
* table . Stolen unashamedly from FreeBSD ' s if_ed . c
*/
static int mcast_index ( const void * dst )
{
# define POLYNOMIAL 0x04c11db6
2017-02-07 02:19:48 +01:00
unsigned long crc = 0xffffffffL ;
int carry , i , j ;
unsigned char b ;
unsigned char * ep = ( unsigned char * ) dst ;
for ( i = 6 ; - - i > = 0 ; )
{
b = * ep + + ;
for ( j = 8 ; - - j > = 0 ; )
{
carry = ( ( crc & 0x80000000L ) ? 1 : 0 ) ^ ( b & 0x01 ) ;
crc < < = 1 ;
b > > = 1 ;
if ( carry )
{
crc = ( ( crc ^ POLYNOMIAL ) | carry ) ;
}
}
}
return ( crc > > 26 ) ;
2016-06-26 00:34:39 +02:00
# undef POLYNOMIAL
}
/*
* rx_frame ( ) - called by the platform - specific code when an
* ethernet frame has been received . The destination address
* is tested to see if it should be accepted , and if the
* rx ring has enough room , it is copied into it and
* the receive process is updated
*/
void ne2000_rx_frame ( void * p , const void * buf , int io_len )
{
2017-02-07 02:19:48 +01:00
ne2000_t * ne2000 = ( ne2000_t * ) p ;
int pages ;
int avail ;
int idx ;
int nextpage ;
uint8_t pkthdr [ 4 ] ;
uint8_t * pktbuf = ( uint8_t * ) buf ;
uint8_t * startptr ;
static uint8_t bcast_addr [ 6 ] = { 0xff , 0xff , 0xff , 0xff , 0xff , 0xff } ;
uint32_t mac_cmp32 [ 2 ] ;
uint16_t mac_cmp16 [ 2 ] ;
if ( io_len ! = 60 )
{
ne2000_log ( " rx_frame with length %d \n " , io_len ) ;
}
if ( ( ne2000 - > CR . stop ! = 0 ) | |
( ne2000 - > page_start = = 0 ) )
{
return ;
}
2017-05-05 01:49:42 +02:00
/* Add the pkt header + CRC to the length, and work
out how many 256 - byte pages the frame would occupy */
2017-02-07 02:19:48 +01:00
pages = ( io_len + 4 + 4 + 255 ) / 256 ;
if ( ne2000 - > curr_page < ne2000 - > bound_ptr )
{
avail = ne2000 - > bound_ptr - ne2000 - > curr_page ;
}
else
{
avail = ( ne2000 - > page_stop - ne2000 - > page_start ) - ( ne2000 - > curr_page - ne2000 - > bound_ptr ) ;
}
2017-05-05 01:49:42 +02:00
/* Avoid getting into a buffer overflow condition by not attempting
to do partial receives . The emulation to handle this condition
seems particularly painful . */
2017-02-07 02:19:48 +01:00
if ( ( avail < pages )
2016-06-26 00:34:39 +02:00
# if BX_NE2K_NEVER_FULL_RING
2017-02-07 02:19:48 +01:00
| | ( avail = = pages )
2016-06-26 00:34:39 +02:00
# endif
2017-02-07 02:19:48 +01:00
)
{
ne2000_log ( " no space \n " ) ;
return ;
}
2016-06-26 00:34:39 +02:00
2017-02-07 02:19:48 +01:00
if ( ( io_len < 40 /*60*/ ) & & ! ne2000 - > RCR . runts_ok )
{
ne2000_log ( " rejected small packet, length %d \n " , io_len ) ;
return ;
}
2017-05-05 01:49:42 +02:00
/* some computers don't care... */
2017-02-07 02:19:48 +01:00
if ( io_len < 60 )
{
io_len = 60 ;
}
2017-05-05 01:49:42 +02:00
/* Do address filtering if not in promiscuous mode */
2017-02-07 02:19:48 +01:00
if ( ! ne2000 - > RCR . promisc )
{
/* Received. */
mac_cmp32 [ 0 ] = * ( uint32_t * ) ( buf ) ;
2017-05-05 01:49:42 +02:00
mac_cmp16 [ 0 ] = * ( uint16_t * ) ( ( ( uint8_t * ) buf ) + 4 ) ;
2017-02-07 02:19:48 +01:00
/* Local. */
mac_cmp32 [ 1 ] = * ( uint32_t * ) ( bcast_addr ) ;
mac_cmp16 [ 1 ] = * ( uint16_t * ) ( bcast_addr + 4 ) ;
if ( ( mac_cmp32 [ 0 ] = = mac_cmp32 [ 1 ] ) & & ( mac_cmp16 [ 0 ] = = mac_cmp16 [ 1 ] ) )
{
if ( ! ne2000 - > RCR . broadcast )
{
return ;
}
}
else if ( pktbuf [ 0 ] & 0x01 )
{
if ( ! ne2000 - > RCR . multicast )
{
return ;
}
idx = mcast_index ( buf ) ;
if ( ! ( ne2000 - > mchash [ idx > > 3 ] & ( 1 < < ( idx & 0x7 ) ) ) )
{
return ;
}
}
else if ( 0 ! = memcmp ( buf , ne2000 - > physaddr , 6 ) )
{
return ;
}
}
else
{
ne2000_log ( " rx_frame promiscuous receive \n " ) ;
}
ne2000_log ( " rx_frame %d to %x:%x:%x:%x:%x:%x from %x:%x:%x:%x:%x:%x \n " , io_len , pktbuf [ 0 ] , pktbuf [ 1 ] , pktbuf [ 2 ] , pktbuf [ 3 ] , pktbuf [ 4 ] , pktbuf [ 5 ] , pktbuf [ 6 ] , pktbuf [ 7 ] , pktbuf [ 8 ] , pktbuf [ 9 ] , pktbuf [ 10 ] , pktbuf [ 11 ] ) ;
nextpage = ne2000 - > curr_page + pages ;
if ( nextpage > = ne2000 - > page_stop )
{
nextpage - = ne2000 - > page_stop - ne2000 - > page_start ;
}
2017-05-05 01:49:42 +02:00
/* Setup packet header */
pkthdr [ 0 ] = 0 ; /* rx status - old behavior
pkthdr [ 0 ] = 1 ; /* Probably better to set it all the time
rather than set it to 0 , which is clearly wrong . */
2017-02-07 02:19:48 +01:00
if ( pktbuf [ 0 ] & 0x01 )
{
2017-05-05 01:49:42 +02:00
pkthdr [ 0 ] | = 0x20 ; /* rx status += multicast packet */
2017-02-07 02:19:48 +01:00
}
2017-05-05 01:49:42 +02:00
pkthdr [ 1 ] = nextpage ; /* ptr to next packet */
pkthdr [ 2 ] = ( io_len + 4 ) & 0xff ; /* length-low */
pkthdr [ 3 ] = ( io_len + 4 ) > > 8 ; /* length-hi */
2017-02-07 02:19:48 +01:00
2017-05-05 01:49:42 +02:00
/* copy into buffer, update curpage, and signal interrupt if config'd */
2017-02-07 02:19:48 +01:00
startptr = & ne2000 - > mem [ ne2000 - > curr_page * 256 - BX_NE2K_MEMSTART ] ;
if ( ( nextpage > ne2000 - > curr_page ) | | ( ( ne2000 - > curr_page + pages ) = = ne2000 - > page_stop ) )
{
* ( uint32_t * ) startptr = * ( uint32_t * ) pkthdr ;
memcpy ( startptr + 4 , buf , io_len ) ;
ne2000 - > curr_page = nextpage ;
}
else
{
int endbytes = ( ne2000 - > page_stop - ne2000 - > curr_page ) * 256 ;
* ( uint32_t * ) startptr = * ( uint32_t * ) pkthdr ;
memcpy ( startptr + 4 , buf , endbytes - 4 ) ;
startptr = & ne2000 - > mem [ ne2000 - > page_start * 256 - BX_NE2K_MEMSTART ] ;
memcpy ( startptr , ( void * ) ( pktbuf + endbytes - 4 ) , io_len - endbytes + 8 ) ;
ne2000 - > curr_page = nextpage ;
}
ne2000 - > RSR . rx_ok = 1 ;
if ( pktbuf [ 0 ] & 0x80 )
{
ne2000 - > RSR . rx_mbit = 1 ;
}
ne2000 - > ISR . pkt_rx = 1 ;
if ( ne2000 - > IMR . rx_inte )
{
picint ( 1 < < ne2000 - > base_irq ) ;
}
2016-06-26 00:34:39 +02:00
}
2016-08-13 17:29:14 +02:00
uint8_t ne2000_readb ( uint16_t addr , void * p )
2016-06-26 00:34:39 +02:00
{
2016-08-13 03:32:38 +02:00
ne2000_t * ne2000 = ( ne2000_t * ) p ;
return ne2000_read ( ne2000 , addr , 1 ) ;
}
2016-06-26 00:34:39 +02:00
2016-08-13 17:29:14 +02:00
uint16_t ne2000_readw ( uint16_t addr , void * p )
2016-08-13 03:32:38 +02:00
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
if ( ne2000 - > DCR . wdsize & 1 )
2017-02-07 02:19:48 +01:00
{
2016-08-13 03:32:38 +02:00
return ne2000_read ( ne2000 , addr , 2 ) ;
2017-02-07 02:19:48 +01:00
}
2016-08-13 03:32:38 +02:00
else
2017-02-07 02:19:48 +01:00
{
return ne2000_read ( ne2000 , addr , 1 ) ;
}
2016-06-26 00:34:39 +02:00
}
2016-08-13 17:29:14 +02:00
uint32_t ne2000_readl ( uint16_t addr , void * p )
2016-06-26 00:34:39 +02:00
{
2016-08-13 03:32:38 +02:00
ne2000_t * ne2000 = ( ne2000_t * ) p ;
return ne2000_read ( ne2000 , addr , 4 ) ;
2016-06-26 00:34:39 +02:00
}
2016-08-13 17:29:14 +02:00
void ne2000_writeb ( uint16_t addr , uint8_t val , void * p )
2016-08-13 03:32:38 +02:00
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
ne2000_write ( ne2000 , addr , val , 1 ) ;
}
2016-08-13 17:29:14 +02:00
void ne2000_writew ( uint16_t addr , uint16_t val , void * p )
2016-08-13 03:32:38 +02:00
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
if ( ne2000 - > DCR . wdsize & 1 )
2017-02-07 02:19:48 +01:00
{
2016-08-13 03:32:38 +02:00
ne2000_write ( ne2000 , addr , val , 2 ) ;
2017-02-07 02:19:48 +01:00
}
2016-08-13 03:32:38 +02:00
else
2017-02-07 02:19:48 +01:00
{
2016-08-13 03:32:38 +02:00
ne2000_write ( ne2000 , addr , val , 1 ) ;
2017-02-07 02:19:48 +01:00
}
2016-08-13 03:32:38 +02:00
}
2016-08-13 17:29:14 +02:00
void ne2000_writel ( uint16_t addr , uint32_t val , void * p )
2016-08-13 03:32:38 +02:00
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
ne2000_write ( ne2000 , addr , val , 4 ) ;
}
void ne2000_poller ( void * p )
2016-06-26 00:34:39 +02:00
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
struct queuepacket * qp ;
const unsigned char * data ;
struct pcap_pkthdr h ;
2017-01-05 01:35:16 +01:00
uint32_t mac_cmp32 [ 2 ] ;
uint16_t mac_cmp16 [ 2 ] ;
2016-06-26 00:34:39 +02:00
2017-02-07 02:19:48 +01:00
if ( ! net_is_pcap )
{
while ( QueuePeek ( slirpq ) > 0 )
{
qp = QueueDelete ( slirpq ) ;
if ( ( ne2000 - > DCR . loop = = 0 ) | | ( ne2000 - > TCR . loop_cntl ! = 0 ) )
{
free ( qp ) ;
return ;
}
ne2000_rx_frame ( ne2000 , & qp - > data , qp - > len ) ;
ne2000_log ( " ne2000 inQ:%d got a %dbyte packet @%d \n " , QueuePeek ( slirpq ) , qp - > len , qp ) ;
free ( qp ) ;
}
2016-06-26 00:34:39 +02:00
fizz + + ;
2017-02-07 02:19:48 +01:00
if ( fizz > 1200 )
{
fizz = 0 ; slirp_tic ( ) ;
}
2017-05-05 01:49:42 +02:00
} /* end slirp */
2017-02-07 02:19:48 +01:00
else if ( net_is_pcap & & ( net_pcap ! = NULL ) )
{
2017-01-05 02:39:35 +01:00
if ( ( ne2000 - > DCR . loop = = 0 ) | | ( ne2000 - > TCR . loop_cntl ! = 0 ) )
{
return ;
}
2017-02-07 02:19:48 +01:00
data = pcap_next ( net_pcap , & h ) ;
if ( data = = 0x0 )
2017-01-05 02:43:54 +01:00
{
return ;
}
2017-01-05 01:35:16 +01:00
/* Received. */
mac_cmp32 [ 0 ] = * ( uint32_t * ) ( data + 6 ) ;
mac_cmp16 [ 0 ] = * ( uint16_t * ) ( data + 10 ) ;
/* Local. */
2017-05-05 01:49:42 +02:00
mac_cmp32 [ 1 ] = * ( uint32_t * ) ( ne2000_mac ( ) ) ;
mac_cmp16 [ 1 ] = * ( uint16_t * ) ( ne2000_mac ( ) + 4 ) ;
2017-01-05 02:39:35 +01:00
if ( ( mac_cmp32 [ 0 ] ! = mac_cmp32 [ 1 ] ) | | ( mac_cmp16 [ 0 ] ! = mac_cmp16 [ 1 ] ) )
{
ne2000_rx_frame ( ne2000 , data , h . caplen ) ;
}
2017-02-07 02:19:48 +01:00
}
2016-06-26 00:34:39 +02:00
}
2016-08-13 03:32:38 +02:00
typedef union
{
uint32_t addr ;
uint8_t addr_regs [ 4 ] ;
} bar_t ;
2016-06-26 00:34:39 +02:00
uint8_t ne2000_pci_regs [ 256 ] ;
2016-08-13 03:32:38 +02:00
bar_t ne2000_pci_bar [ 2 ] ;
2016-08-13 17:29:14 +02:00
uint32_t bios_addr = 0xD0000 ;
uint32_t old_base_addr = 0 ;
2016-08-13 03:32:38 +02:00
uint32_t bios_size = 0 ;
uint32_t bios_mask = 0 ;
2016-06-26 00:34:39 +02:00
void ne2000_io_set ( uint16_t addr , ne2000_t * ne2000 )
2016-08-13 03:32:38 +02:00
{
2017-02-07 02:19:48 +01:00
old_base_addr = addr ;
2017-02-14 07:06:24 +01:00
if ( network_card_current = = 1 )
{
io_sethandler ( addr , 0x0010 , ne2000_readb , NULL , NULL , ne2000_writeb , NULL , NULL , ne2000 ) ;
io_sethandler ( addr + 0x10 , 0x0010 , ne2000_readb , ne2000_readw , NULL , ne2000_writeb , ne2000_writew , NULL , ne2000 ) ;
io_sethandler ( addr + 0x1f , 0x0001 , ne2000_readb , NULL , NULL , ne2000_writeb , NULL , NULL , ne2000 ) ;
}
else
{
io_sethandler ( addr , 0x0010 , ne2000_readb , ne2000_readw , ne2000_readl , ne2000_writeb , ne2000_writew , ne2000_writel , ne2000 ) ;
io_sethandler ( addr + 0x10 , 0x0010 , ne2000_readb , ne2000_readw , ne2000_readl , ne2000_writeb , ne2000_writew , ne2000_writel , ne2000 ) ;
io_sethandler ( addr + 0x1f , 0x0001 , ne2000_readb , ne2000_readw , ne2000_readl , ne2000_writeb , ne2000_writew , ne2000_writel , ne2000 ) ;
}
2016-06-26 00:34:39 +02:00
}
2016-08-15 01:34:46 +02:00
void ne2000_io_remove ( int16_t addr , ne2000_t * ne2000 )
2016-06-26 00:34:39 +02:00
{
2017-02-14 07:06:24 +01:00
if ( network_card_current = = 1 )
{
io_removehandler ( addr , 0x0010 , ne2000_readb , NULL , NULL , ne2000_writeb , NULL , NULL , ne2000 ) ;
io_removehandler ( addr + 0x10 , 0x0010 , ne2000_readb , ne2000_readw , NULL , ne2000_writeb , ne2000_writew , NULL , ne2000 ) ;
io_removehandler ( addr + 0x1f , 0x0001 , ne2000_readb , NULL , NULL , ne2000_writeb , NULL , NULL , ne2000 ) ;
}
else
{
io_removehandler ( addr , 0x0010 , ne2000_readb , ne2000_readw , ne2000_readl , ne2000_writeb , ne2000_writew , ne2000_writel , ne2000 ) ;
io_removehandler ( addr + 0x10 , 0x0010 , ne2000_readb , ne2000_readw , ne2000_readl , ne2000_writeb , ne2000_writew , ne2000_writel , ne2000 ) ;
io_removehandler ( addr + 0x1f , 0x0001 , ne2000_readb , ne2000_readw , ne2000_readl , ne2000_writeb , ne2000_writew , ne2000_writel , ne2000 ) ;
}
2016-06-26 00:34:39 +02:00
}
uint8_t ne2000_pci_read ( int func , int addr , void * p )
{
2017-02-07 02:19:48 +01:00
switch ( addr )
{
case 0x00 :
return 0xec ;
case 0x01 :
return 0x10 ;
case 0x02 :
return 0x29 ;
case 0x03 :
return 0x80 ;
case 0x2C :
return 0xF4 ;
case 0x2D :
return 0x1A ;
case 0x2E :
return 0x00 ;
case 0x2F :
return 0x11 ;
case 0x04 :
return ne2000_pci_regs [ 0x04 ] ; /*Respond to IO and memory accesses*/
case 0x05 :
return ne2000_pci_regs [ 0x05 ] ;
case 0x07 :
return 2 ;
case 0x08 :
return 0 ; /*Revision ID*/
case 0x09 :
return 0 ; /*Programming interface*/
case 0x0B :
return ne2000_pci_regs [ 0x0B ] ;
case 0x10 :
return 1 ; /*I/O space*/
case 0x11 :
return ne2000_pci_bar [ 0 ] . addr_regs [ 1 ] ;
case 0x12 :
return ne2000_pci_bar [ 0 ] . addr_regs [ 2 ] ;
case 0x13 :
return ne2000_pci_bar [ 0 ] . addr_regs [ 3 ] ;
case 0x30 :
return ne2000_pci_bar [ 1 ] . addr_regs [ 0 ] & 0x01 ; /*BIOS ROM address*/
case 0x31 :
return ( ne2000_pci_bar [ 1 ] . addr_regs [ 1 ] & bios_mask ) | 0x18 ;
case 0x32 :
return ne2000_pci_bar [ 1 ] . addr_regs [ 2 ] ;
case 0x33 :
return ne2000_pci_bar [ 1 ] . addr_regs [ 3 ] ;
case 0x3C :
return ne2000_pci_regs [ 0x3C ] ;
case 0x3D :
return ne2000_pci_regs [ 0x3D ] ;
}
return 0 ;
2016-06-26 00:34:39 +02:00
}
void ne2000_update_bios ( ne2000_t * ne2000 )
{
int reg_bios_enable ;
reg_bios_enable = 1 ;
/* PCI BIOS stuff, just enable_disable. */
if ( ! disable_netbios & & reg_bios_enable )
{
mem_mapping_enable ( & ne2000 - > bios_rom . mapping ) ;
2016-08-13 03:32:38 +02:00
mem_mapping_set_addr ( & ne2000 - > bios_rom . mapping , bios_addr , 0x10000 ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " Network BIOS now at: %08X \n " , bios_addr ) ;
2016-06-26 00:34:39 +02:00
}
else
{
mem_mapping_disable ( & ne2000 - > bios_rom . mapping ) ;
2016-08-13 03:32:38 +02:00
if ( network_card_current = = 2 ) ne2000_pci_bar [ 1 ] . addr = 0 ;
2016-06-26 00:34:39 +02:00
}
}
void ne2000_pci_write ( int func , int addr , uint8_t val , void * p )
{
2017-02-07 02:19:48 +01:00
ne2000_t * ne2000 = ( ne2000_t * ) p ;
2016-06-26 00:34:39 +02:00
2017-02-07 02:19:48 +01:00
switch ( addr )
{
case 0x04 :
ne2000_io_remove ( ne2000 - > base_address , ne2000 ) ;
if ( val & PCI_COMMAND_IO )
{
ne2000_io_set ( ne2000 - > base_address , ne2000 ) ;
}
ne2000_pci_regs [ addr ] = val ;
break ;
case 0x10 :
val & = 0xfc ;
val | = 1 ;
case 0x11 : case 0x12 : case 0x13 :
/* I/O Base set. */
/* First, remove the old I/O, if old base was >= 0x280. */
ne2000_io_remove ( ne2000 - > base_address , ne2000 ) ;
/* Then let's set the PCI regs. */
ne2000_pci_bar [ 0 ] . addr_regs [ addr & 3 ] = val ;
/* Then let's calculate the new I/O base. */
ne2000 - > base_address = ne2000_pci_bar [ 0 ] . addr & 0xff00 ;
/* Log the new base. */
ne2000_log ( " NE2000 RTL8029AS PCI: New I/O base is %04X \n " , ne2000 - > base_address ) ;
/* We're done, so get out of the here. */
2017-02-14 23:46:50 +01:00
if ( val & PCI_COMMAND_IO )
{
ne2000_io_set ( ne2000 - > base_address , ne2000 ) ;
}
2017-02-07 02:19:48 +01:00
return ;
case 0x30 : case 0x31 : case 0x32 : case 0x33 :
ne2000_pci_bar [ 1 ] . addr_regs [ addr & 3 ] = val ;
ne2000_pci_bar [ 1 ] . addr_regs [ 1 ] & = bios_mask ;
bios_addr = ne2000_pci_bar [ 1 ] . addr & 0xffffe000 ;
ne2000_pci_bar [ 1 ] . addr & = 0xffffe000 ;
ne2000_pci_bar [ 1 ] . addr | = 0x1801 ;
ne2000_update_bios ( ne2000 ) ;
return ;
/* Commented out until an APIC controller is emulated for the PIIX3,
otherwise the RTL - 8029 / AS will not get an IRQ on boards using the PIIX3 . */
2016-11-05 07:17:08 +01:00
#if 0
2017-02-07 02:19:48 +01:00
case 0x3C :
ne2000_pci_regs [ addr ] = val ;
if ( val ! = 0xFF )
{
ne2000_log ( " NE2000 IRQ now: %i \n " , val ) ;
ne2000_setirq ( ne2000 , val ) ;
}
return ;
2016-11-05 07:17:08 +01:00
# endif
2017-02-07 02:19:48 +01:00
}
2016-06-26 00:34:39 +02:00
}
2017-05-06 04:02:03 +02:00
void ne2000_rom_init ( ne2000_t * ne2000 , wchar_t * s )
2016-06-26 00:34:39 +02:00
{
2017-05-06 04:02:03 +02:00
FILE * f = romfopen ( s , " rb " ) ;
2016-08-13 03:32:38 +02:00
uint32_t temp ;
if ( ! f )
{
disable_netbios = 1 ;
ne2000_update_bios ( ne2000 ) ;
return ;
}
fseek ( f , 0 , SEEK_END ) ;
temp = ftell ( f ) ;
fclose ( f ) ;
bios_size = 0x10000 ;
if ( temp < = 0x8000 )
{
bios_size = 0x8000 ;
}
if ( temp < = 0x4000 )
{
bios_size = 0x4000 ;
}
if ( temp < = 0x2000 )
{
bios_size = 0x2000 ;
}
bios_mask = ( bios_size > > 8 ) & 0xff ;
bios_mask = ( 0x100 - bios_mask ) & 0xff ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
rom_init ( & ne2000 - > bios_rom , s , 0xd0000 , bios_size , bios_size - 1 , 0 , MEM_MAPPING_EXTERNAL ) ;
}
2016-06-26 00:34:39 +02:00
2017-02-07 02:19:48 +01:00
static char errbuf [ 32768 ] ;
2016-08-13 03:32:38 +02:00
void * ne2000_init ( )
{
int rc ;
2017-05-05 01:49:42 +02:00
int config_net_type ;
2017-02-07 02:19:48 +01:00
int irq ;
int pcap_device_available = 0 ;
int is_rtl8029as = 0 ;
2016-08-13 03:32:38 +02:00
ne2000_t * ne2000 = malloc ( sizeof ( ne2000_t ) ) ;
memset ( ne2000 , 0 , sizeof ( ne2000_t ) ) ;
2017-02-07 02:19:48 +01:00
if ( PCI & & ( network_card_current = = 2 ) )
2016-12-30 01:03:40 +01:00
{
2017-02-07 02:19:48 +01:00
is_rtl8029as = 1 ;
}
else
{
network_card_current = 1 ;
is_rtl8029as = 0 ;
2016-12-30 01:03:40 +01:00
}
2016-08-13 03:32:38 +02:00
2017-02-07 02:19:48 +01:00
if ( is_rtl8029as )
{
ne2000 - > base_address = 0x340 ;
}
else
{
ne2000 - > base_address = device_get_config_int ( " addr " ) ;
}
2016-06-26 00:34:39 +02:00
disable_netbios = device_get_config_int ( " disable_netbios " ) ;
2017-02-07 02:19:48 +01:00
2016-12-30 01:32:33 +01:00
irq = device_get_config_int ( " irq " ) ;
ne2000_setirq ( ne2000 , irq ) ;
2016-06-26 00:34:39 +02:00
config_net_type = device_get_config_int ( " net_type " ) ;
/* Network type is now specified in device config. */
2016-12-30 01:03:40 +01:00
net_is_pcap = config_net_type ? 0 : 1 ;
if ( ! strcmp ( " nothing " , config_get_string ( NULL , " pcap_device " , " nothing " ) ) )
{
net_is_pcap = 0 ;
2017-02-07 02:19:48 +01:00
pcap_device_available = 0 ;
}
else
{
pcap_device_available = 1 ;
}
ne2000_log ( " net_is_pcap = %i \n " , net_is_pcap ) ;
if ( is_rtl8029as )
{
pci_add ( ne2000_pci_read , ne2000_pci_write , ne2000 ) ;
2016-12-30 01:03:40 +01:00
}
2016-12-30 01:32:33 +01:00
2017-02-07 02:19:48 +01:00
ne2000_io_set ( ne2000 - > base_address , ne2000 ) ;
2017-05-05 01:49:42 +02:00
memcpy ( ne2000 - > physaddr , ne2000_mac ( ) , 6 ) ;
2016-06-26 00:34:39 +02:00
if ( ! disable_netbios )
{
2017-05-06 04:02:03 +02:00
ne2000_rom_init ( ne2000 , is_rtl8029as ? L " roms/rtl8029as.rom " : L " roms/ne2000.rom " ) ;
2016-08-13 03:32:38 +02:00
2017-02-07 02:19:48 +01:00
if ( is_rtl8029as )
{
mem_mapping_disable ( & ne2000 - > bios_rom . mapping ) ;
}
2016-08-13 03:32:38 +02:00
}
2017-02-07 02:19:48 +01:00
if ( is_rtl8029as )
{
2016-08-13 03:32:38 +02:00
ne2000_pci_regs [ 0x04 ] = 1 ;
ne2000_pci_regs [ 0x05 ] = 0 ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
ne2000_pci_regs [ 0x07 ] = 2 ;
/* Network controller. */
ne2000_pci_regs [ 0x0B ] = 2 ;
ne2000_pci_bar [ 0 ] . addr_regs [ 0 ] = 1 ;
if ( disable_netbios )
{
ne2000_pci_bar [ 1 ] . addr = 0 ;
bios_addr = 0 ;
2016-06-26 00:34:39 +02:00
}
else
{
2016-08-13 03:32:38 +02:00
ne2000_pci_bar [ 1 ] . addr = 0x000F8000 ;
ne2000_pci_bar [ 1 ] . addr_regs [ 1 ] = bios_mask ;
ne2000_pci_bar [ 1 ] . addr | = 0x1801 ;
bios_addr = 0xD0000 ;
2016-06-26 00:34:39 +02:00
}
2016-12-30 01:32:33 +01:00
ne2000_pci_regs [ 0x3C ] = irq ;
pclog ( " RTL8029AS IRQ: %i \n " , ne2000_pci_regs [ 0x3C ] ) ;
2016-08-13 03:32:38 +02:00
ne2000_pci_regs [ 0x3D ] = 1 ;
memset ( rtl8029as_eeprom , 0 , 128 ) ;
rtl8029as_eeprom [ 0x76 ] = rtl8029as_eeprom [ 0x7A ] = rtl8029as_eeprom [ 0x7E ] = 0x29 ;
rtl8029as_eeprom [ 0x77 ] = rtl8029as_eeprom [ 0x7B ] = rtl8029as_eeprom [ 0x7F ] = 0x80 ;
rtl8029as_eeprom [ 0x78 ] = rtl8029as_eeprom [ 0x7C ] = 0x10 ;
rtl8029as_eeprom [ 0x79 ] = rtl8029as_eeprom [ 0x7D ] = 0xEC ;
2017-02-07 02:19:48 +01:00
}
2016-08-13 03:32:38 +02:00
2017-02-07 02:19:48 +01:00
ne2000_reset ( ne2000 , BX_RESET_HARDWARE ) ;
vlan_handler ( ne2000_poller , ne2000 ) ;
2016-06-26 00:34:39 +02:00
2017-02-07 02:19:48 +01:00
ne2000_log ( " ne2000 %s init 0x%X %d \t net_is_pcap is %d \n " , is_rtl8029as ? " pci " : " isa " , ne2000 - > base_address , device_get_config_int ( " irq " ) , net_is_pcap ) ;
2016-06-26 00:34:39 +02:00
2017-05-05 01:49:42 +02:00
/* need a switch statment for more network types. */
2017-02-07 02:19:48 +01:00
if ( ! net_is_pcap )
{
initialize_slirp :
ne2000_log ( " ne2000 initalizing SLiRP \n " ) ;
net_is_pcap = 0 ;
rc = slirp_init ( ) ;
ne2000_log ( " ne2000 slirp_init returned: %d \n " , rc ) ;
if ( ! rc )
2016-06-26 00:34:39 +02:00
{
2017-02-07 02:19:48 +01:00
ne2000_log ( " ne2000 slirp initalized! \n " ) ;
2016-06-26 00:34:39 +02:00
2017-02-07 02:19:48 +01:00
net_slirp_inited = 1 ;
slirpq = QueueCreate ( ) ;
fizz = 0 ;
ne2000_log ( " ne2000 slirpq is %x \n " , & slirpq ) ;
}
else
{
net_slirp_inited = 0 ;
if ( pcap_device_available )
{
net_is_pcap = 1 ;
goto initialize_pcap ;
}
else
{
ne2000_log ( " Neither SLiRP nor PCap is available on your host, disabling network adapter... \n " ) ;
free ( ne2000 ) ;
network_card_current = 0 ;
resetpchard ( ) ;
return NULL ;
}
}
}
else
{
initialize_pcap :
ne2000_log ( " ne2000 initalizing libpcap \n " ) ;
2016-08-13 03:32:38 +02:00
2017-02-07 02:19:48 +01:00
ne2000_log ( " ne2000 Pcap version [%s] \n " , pcap_lib_version ( ) ) ;
if ( ( net_pcap = pcap_open_live ( config_get_string ( NULL , " pcap_device " , " nothing " ) , 1518 , 1 , 15 , errbuf ) ) = = 0 )
{
ne2000_log ( " ne2000 pcap_open_live error on %s! \n " , config_get_string ( NULL , " pcap_device " , " whatever the ethernet is " ) ) ;
net_is_pcap = 0 ;
2017-05-05 01:49:42 +02:00
return ( ne2000 ) ; /* YUCK!!! */
2017-02-07 02:19:48 +01:00
}
2017-05-05 01:49:42 +02:00
/* Time to check that we are in non-blocking mode. */
2017-02-07 02:19:48 +01:00
rc = pcap_getnonblock ( net_pcap , errbuf ) ;
ne2000_log ( " ne2000 pcap is currently in %s mode \n " , rc ? " non-blocking " : " blocking " ) ;
switch ( rc )
{
case 0 :
ne2000_log ( " ne2000 Setting interface to non-blocking mode.. " ) ;
rc = pcap_setnonblock ( net_pcap , 1 , errbuf ) ;
if ( rc = = 0 )
2017-05-05 01:49:42 +02:00
{ /* no errors! */
2017-02-07 02:19:48 +01:00
ne2000_log ( " .. " ) ;
rc = pcap_getnonblock ( net_pcap , errbuf ) ;
if ( rc = = 1 )
{
ne2000_log ( " ..! " , rc ) ;
net_is_pcap = 1 ;
}
else
{
ne2000_log ( " \t unable to set pcap into non-blocking mode! \n Continuining without pcap. \n " ) ;
net_is_pcap = 0 ;
}
2017-05-05 01:49:42 +02:00
} /* end set nonblock */
2017-02-07 02:19:48 +01:00
else
2016-08-13 03:32:38 +02:00
{
2017-02-07 02:19:48 +01:00
ne2000_log ( " There was an unexpected error of [%s] \n \n exiting. \n " , errbuf ) ; net_is_pcap = 0 ; }
ne2000_log ( " \n " ) ;
break ;
case 1 :
ne2000_log ( " non blocking \n " ) ;
break ;
default :
ne2000_log ( " this isn't right!!! \n " ) ;
net_is_pcap = 0 ;
break ;
}
if ( net_is_pcap )
{
struct bpf_program fp ;
char filter_exp [ 255 ] ;
ne2000_log ( " ne2000 Building packet filter... " ) ;
sprintf ( filter_exp , " ( ((ether dst ff:ff:ff:ff:ff:ff) or (ether dst %02x:%02x:%02x:%02x:%02x:%02x)) and not (ether src %02x:%02x:%02x:%02x:%02x:%02x) ) " , \
2017-05-05 01:49:42 +02:00
ne2000_mac ( ) [ 0 ] , ne2000_mac ( ) [ 1 ] , ne2000_mac ( ) [ 2 ] , ne2000_mac ( ) [ 3 ] , ne2000_mac ( ) [ 4 ] , ne2000_mac ( ) [ 5 ] , \
ne2000_mac ( ) [ 0 ] , ne2000_mac ( ) [ 1 ] , ne2000_mac ( ) [ 2 ] , ne2000_mac ( ) [ 3 ] , ne2000_mac ( ) [ 4 ] , ne2000_mac ( ) [ 5 ] ) ;
2017-02-07 02:19:48 +01:00
2017-05-05 01:49:42 +02:00
/* I'm doing a MAC level filter so TCP/IP doesn't matter. */
2017-02-07 02:19:48 +01:00
if ( pcap_compile ( net_pcap , & fp , filter_exp , 0 , 0xffffffff ) = = - 1 )
{
ne2000_log ( " \n ne2000 Couldn't compile filter \n " ) ;
}
else
{
ne2000_log ( " ... " ) ;
if ( pcap_setfilter ( net_pcap , & fp ) = = - 1 )
{
ne2000_log ( " \n Error installing pcap filter. \n " ) ;
2017-05-05 01:49:42 +02:00
} /* end of set_filter failure */
2017-02-07 02:19:48 +01:00
else
{
ne2000_log ( " ...! \n " ) ;
2016-08-13 03:32:38 +02:00
}
2017-02-07 02:19:48 +01:00
}
ne2000_log ( " ne2000 Using filter \t [%s] \n " , filter_exp ) ;
}
else
{
pcap_device_available = 0 ;
goto initialize_slirp ;
}
ne2000_log ( " ne2000 net_is_pcap is %d and net_pcap is %x \n " , net_is_pcap , net_pcap ) ;
2017-05-05 01:49:42 +02:00
} /* end pcap setup */
2017-02-07 02:19:48 +01:00
ne2000_log ( " ne2000 is_pcap %d \n " , net_is_pcap ) ;
return ne2000 ;
}
void ne2000_close ( void * p )
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
ne2000_io_remove ( ne2000 - > base_address , ne2000 ) ;
free ( ne2000 ) ;
if ( ! net_is_pcap )
{
QueueDestroy ( slirpq ) ;
slirp_exit ( 0 ) ;
net_slirp_inited = 0 ;
ne2000_log ( " ne2000 exiting slirp \n " ) ;
}
else if ( net_is_pcap & & ( net_pcap ! = NULL ) )
{
pcap_close ( net_pcap ) ;
ne2000_log ( " ne2000 closing pcap \n " ) ;
}
ne2000_log ( " ne2000 close \n " ) ;
2016-06-26 00:34:39 +02:00
}
static device_config_t ne2000_config [ ] =
{
2017-02-07 02:19:48 +01:00
{
2017-05-05 01:49:42 +02:00
" addr " , " Address " , CONFIG_SELECTION , " " , 0x300 ,
2017-02-07 02:19:48 +01:00
{
{
2017-05-05 01:49:42 +02:00
" 0x280 " , 0x280
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" 0x300 " , 0x300
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" 0x320 " , 0x320
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" 0x340 " , 0x340
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" 0x360 " , 0x360
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" 0x380 " , 0x380
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" "
2017-02-07 02:19:48 +01:00
}
} ,
} ,
{
2017-05-05 01:49:42 +02:00
" irq " , " IRQ " , CONFIG_SELECTION , " " , 10 ,
2017-02-07 02:19:48 +01:00
{
{
2017-05-05 01:49:42 +02:00
" IRQ 3 " , 3
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" IRQ 5 " , 5
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" IRQ 7 " , 7
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" IRQ 10 " , 10
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" IRQ 11 " , 11
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" "
2017-02-07 02:19:48 +01:00
}
} ,
} ,
{
2017-05-05 01:49:42 +02:00
" net_type " , " Network type " , CONFIG_SELECTION , " " , 0 ,
2017-02-07 02:19:48 +01:00
{
{
2017-05-05 01:49:42 +02:00
" PCap " , 0
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" SLiRP " , 1
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" "
2017-02-07 02:19:48 +01:00
}
} ,
} ,
{
2017-05-05 01:49:42 +02:00
" disable_netbios " , " Disable network BIOS " , CONFIG_BINARY , " " , 0
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" " , " " , - 1
2017-02-07 02:19:48 +01:00
}
2016-06-26 00:34:39 +02:00
} ;
static device_config_t rtl8029as_config [ ] =
{
2017-02-07 02:19:48 +01:00
{
2017-05-05 01:49:42 +02:00
" irq " , " IRQ " , CONFIG_SELECTION , " " , 10 ,
2017-02-07 02:19:48 +01:00
{
{
2017-05-05 01:49:42 +02:00
" IRQ 3 " , 3
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" IRQ 5 " , 5
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" IRQ 7 " , 7
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" IRQ 10 " , 10
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" IRQ 11 " , 11
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" "
2017-02-07 02:19:48 +01:00
}
} ,
} ,
{
2017-05-05 01:49:42 +02:00
" net_type " , " Network type " , CONFIG_SELECTION , " " , 0 ,
2017-02-07 02:19:48 +01:00
{
{
2017-05-05 01:49:42 +02:00
" PCap " , 0
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" SLiRP " , 1
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" "
2017-02-07 02:19:48 +01:00
}
} ,
} ,
{
2017-05-05 01:49:42 +02:00
" disable_netbios " , " Disable network BIOS " , CONFIG_BINARY , " " , 0
2017-02-07 02:19:48 +01:00
} ,
{
2017-05-05 01:49:42 +02:00
" " , " " , - 1
2017-02-07 02:19:48 +01:00
}
2016-06-26 00:34:39 +02:00
} ;
device_t ne2000_device =
{
2017-02-07 02:19:48 +01:00
" Novell NE2000 " ,
0 ,
ne2000_init ,
ne2000_close ,
NULL ,
NULL ,
NULL ,
NULL ,
ne2000_config
2016-06-26 00:34:39 +02:00
} ;
device_t rtl8029as_device =
{
2017-02-07 02:19:48 +01:00
" Realtek RTL8029AS " ,
0 ,
ne2000_init ,
ne2000_close ,
NULL ,
NULL ,
NULL ,
NULL ,
rtl8029as_config
2016-06-26 00:34:39 +02:00
} ;
2017-05-05 01:49:42 +02:00
/* SLIRP stuff */
2016-06-26 00:34:39 +02:00
int slirp_can_output ( void )
{
2017-02-07 02:19:48 +01:00
return net_slirp_inited ;
2016-06-26 00:34:39 +02:00
}
void slirp_output ( const unsigned char * pkt , int pkt_len )
{
2017-02-07 02:19:48 +01:00
struct queuepacket * p ;
p = ( struct queuepacket * ) malloc ( sizeof ( struct queuepacket ) ) ;
p - > len = pkt_len ;
memcpy ( p - > data , pkt , pkt_len ) ;
QueueEnter ( slirpq , p ) ;
ne2000_log ( " ne2000 slirp_output %d @%d \n " , pkt_len , p ) ;
2016-06-26 00:34:39 +02:00
}
2017-05-05 01:49:42 +02:00
/* Instead of calling this and crashing some times
or experencing jitter , this is called by the
60 Hz clock which seems to do the job . */
2016-06-26 00:34:39 +02:00
void slirp_tic ( )
{
2017-02-07 02:19:48 +01:00
int ret2 , nfds ;
struct timeval tv ;
fd_set rfds , wfds , xfds ;
int timeout ;
nfds = - 1 ;
if ( net_slirp_inited )
{
FD_ZERO ( & rfds ) ;
FD_ZERO ( & wfds ) ;
FD_ZERO ( & xfds ) ;
2017-05-05 01:49:42 +02:00
timeout = slirp_select_fill ( & nfds , & rfds , & wfds , & xfds ) ; /* this can crash */
2017-02-07 02:19:48 +01:00
if ( timeout < 0 )
{
timeout = 500 ;
}
tv . tv_sec = 0 ;
2017-05-05 01:49:42 +02:00
tv . tv_usec = timeout ; /* basilisk default 10000 */
2017-02-07 02:19:48 +01:00
ret2 = select ( nfds + 1 , & rfds , & wfds , & xfds , & tv ) ;
if ( ret2 > = 0 )
{
slirp_select_poll ( & rfds , & wfds , & xfds ) ;
}
2017-05-05 01:49:42 +02:00
} /* end if slirp inited */
2016-06-26 00:34:39 +02:00
}