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
*/
2016-06-26 00:34:39 +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.
//#include "vl.h"
# 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"
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"
//THIS IS THE DEFAULT MAC ADDRESS .... so it wont place nice with multiple VMs. YET.
uint8_t maclocal [ 6 ] = { 0xac , 0xde , 0x48 , 0x88 , 0xbb , 0xaa } ;
# define NETBLOCKING 0 //we won't block our pcap
static HINSTANCE net_hLib = 0 ; /* handle to DLL */
static char * net_lib_name = " wpcap.dll " ;
pcap_t * net_pcap ;
typedef pcap_t * ( __cdecl * PCAP_OPEN_LIVE ) ( const char * , int , int , int , char * ) ;
typedef int ( __cdecl * PCAP_SENDPACKET ) ( pcap_t * handle , const u_char * msg , int len ) ;
typedef int ( __cdecl * PCAP_SETNONBLOCK ) ( pcap_t * , int , char * ) ;
typedef const u_char * ( __cdecl * PCAP_NEXT ) ( pcap_t * , struct pcap_pkthdr * ) ;
typedef const char * ( __cdecl * PCAP_LIB_VERSION ) ( void ) ;
typedef void ( __cdecl * PCAP_CLOSE ) ( pcap_t * ) ;
typedef int ( __cdecl * PCAP_GETNONBLOCK ) ( pcap_t * p , char * errbuf ) ;
typedef int ( __cdecl * PCAP_COMPILE ) ( pcap_t * p , struct bpf_program * fp , const char * str , int optimize , bpf_u_int32 netmask ) ;
typedef int ( __cdecl * PCAP_SETFILTER ) ( pcap_t * p , struct bpf_program * fp ) ;
PCAP_LIB_VERSION _pcap_lib_version ;
PCAP_OPEN_LIVE _pcap_open_live ;
PCAP_SENDPACKET _pcap_sendpacket ;
PCAP_SETNONBLOCK _pcap_setnonblock ;
PCAP_NEXT _pcap_next ;
PCAP_CLOSE _pcap_close ;
PCAP_GETNONBLOCK _pcap_getnonblock ;
PCAP_COMPILE _pcap_compile ;
PCAP_SETFILTER _pcap_setfilter ;
queueADT slirpq ;
int net_slirp_inited = 0 ;
int net_is_slirp = 1 ; //by default we go with slirp
int net_is_pcap = 0 ; //and pretend pcap is dead.
int fizz = 0 ;
void slirp_tic ( ) ;
# define BX_RESET_HARDWARE 0
# define BX_RESET_SOFTWARE 1
//Never completely fill the ne2k ring so that we never
// hit the unclear completely full buffer condition.
# 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
{
//
// ne2k register state
//
// Page 0
//
// Command Register - 00h read/write
struct CR_t {
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
} CR ;
// Interrupt Status Register - 07h read/write
struct ISR_t {
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
} ISR ;
// Interrupt Mask Register - 0fh write
struct IMR_t {
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
} IMR ;
// Data Configuration Register - 0eh write
struct DCR_t {
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
} DCR ;
// Transmit Configuration Register - 0dh write
struct TCR_t {
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
} TCR ;
// Transmit Status Register - 04h read
struct TSR_t {
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
} TSR ;
// Receive Configuration Register - 0ch write
struct RCR_t {
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
} RCR ;
// Receive Status Register - 0ch read
struct RSR_t {
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
} RSR ;
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 02h read (repeated)
// Current Local DMA Address 01,02h write (repeated)
// Transmit Page start address 04h read (repeated)
// Receive Configuration Register 0ch read (repeated)
// Transmit Configuration Register 0dh read (repeated)
// Data Configuration Register 0eh read (repeated)
// Interrupt Mask Register 0fh 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
uint32_t base_address ;
int base_irq ;
int tx_timer_index ;
int tx_timer_active ;
rom_t bios_rom ;
} 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 , . . . )
{
if ( ne2000_do_log )
{
va_list ap ;
va_start ( ap , format ) ;
vprintf ( format , ap ) ;
va_end ( ap ) ;
fflush ( stdout ) ;
}
}
2016-06-26 00:34:39 +02:00
static void ne2000_setirq ( ne2000_t * ne2000 , int irq )
{
ne2000 - > base_irq = irq ;
}
//
// 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
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
2016-08-01 19:14:54 +02:00
int i ;
2016-06-26 00:34:39 +02:00
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 reset \n " ) ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
// Initialise the mac address area by doubling the physical address
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 ] ;
// ne2k signature
for ( i = 12 ; i < 32 ; i + + )
ne2000 - > macaddr [ i ] = 0x57 ;
2016-06-26 00:34:39 +02:00
// Zero out registers and memory
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->RCR, 0, sizeof(ne2000->RCR));
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 ;
//memset( & ne2000->physaddr, 0, sizeof(ne2000->physaddr));
//memset( & ne2000->mchash, 0, sizeof(ne2000->mchash));
ne2000 - > curr_page = 0 ;
ne2000 - > rempkt_ptr = 0 ;
ne2000 - > localpkt_ptr = 0 ;
ne2000 - > address_cnt = 0 ;
memset ( & ne2000 - > mem , 0 , sizeof ( ne2000 - > mem ) ) ;
// Set power-up conditions
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 ) ;
//DEV_pic_lower_irq(ne2000->base_irq);
}
# include "bswap.h"
2016-08-13 03:32:38 +02:00
//
// read_cr/write_cr - utility routines for handling reads/writes to
// the Command Register
//
uint32_t ne2000_read_cr ( ne2000_t * ne2000 )
{
uint32_t val ;
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
// Validate remote-DMA
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 */
}
// Check for s/w reset
if ( value & 0x01 ) {
ne2000 - > ISR . reset = 1 ;
ne2000 - > CR . stop = 1 ;
} else {
ne2000 - > CR . stop = 0 ;
}
ne2000 - > CR . rdma_cmd = ( value & 0x38 ) > > 3 ;
// If start command issued, the RST bit in the ISR
// must be cleared
if ( ( value & 0x02 ) & & ! ne2000 - > CR . start ) {
ne2000 - > ISR . reset = 0 ;
}
ne2000 - > CR . start = ( ( value & 0x02 ) = = 0x02 ) ;
ne2000 - > CR . pgsel = ( value & 0xc0 ) > > 6 ;
// Check for send-packet command
if ( ne2000 - > CR . rdma_cmd = = 3 ) {
// Set up DMA read from receive ring
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
}
// Check for start-tx
if ( ( value & 0x04 ) & & ne2000 - > TCR . loop_cntl ) {
if ( ne2000 - > TCR . loop_cntl ! = 1 ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " Loop mode %d not supported \n " , ne2000 - > TCR . loop_cntl ) ;
2016-08-13 03:32:38 +02: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 */
2016-08-15 02:26:54 +02:00
ne2000_log ( " CR write - tx start, dev in reset \n " ) ;
2016-08-13 03:32:38 +02:00
}
if ( ne2000 - > tx_bytes = = 0 )
2016-08-15 02:26:54 +02:00
ne2000_log ( " CR write - tx start, tx bytes == 0 \n " ) ;
2016-08-13 03:32:38 +02:00
// Send the packet to the system driver
ne2000 - > CR . tx_packet = 1 ;
if ( net_is_slirp )
{
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
}
if ( net_is_pcap & & net_pcap ! = NULL )
{
_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
}
// some more debug
if ( ne2000 - > tx_timer_active )
2016-08-15 02:26:54 +02:00
ne2000_log ( " CR write, tx timer still active \n " ) ;
2016-08-13 03:32:38 +02:00
ne2000_tx_event ( ne2000 , value ) ;
}
// Linux probes for an interrupt by setting up a remote-DMA read
// of 0 bytes with remote-DMA completion interrupts enabled.
// Detect this here
if ( ne2000 - > CR . rdma_cmd = = 0x01 & &
ne2000 - > CR . start & &
ne2000 - > remote_bytes = = 0 ) {
ne2000 - > ISR . rdma_done = 1 ;
if ( ne2000 - > IMR . rdma_inte ) {
picint ( 1 < < ne2000 - > base_irq ) ;
}
}
}
2016-06-26 00:34:39 +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 16K of buffer memory starting at 16K
//
2016-08-13 03:32:38 +02:00
uint32_t ne2000_chipmem_read ( ne2000_t * ne2000 , uint32_t address , unsigned int io_len )
{
uint32_t retval = 0 ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
if ( ( io_len = = 2 ) & & ( address & 0x1 ) )
2016-08-15 02:26:54 +02:00
ne2000_log ( " unaligned chipmem word read \n " ) ;
2016-06-26 00:34:39 +02:00
// ROM'd MAC address
if ( ( address > = 0 ) & & ( address < = 31 ) ) {
2016-11-02 22:39:07 +01:00
retval = ne2000 - > macaddr [ address % 32 ] ;
2016-08-13 03:32:38 +02:00
if ( ( io_len = = 2 ) | | ( io_len = = 4 ) ) {
2016-11-02 22:39:07 +01:00
retval | = ( ne2000 - > macaddr [ ( address + 1 ) % 32 ] < < 8 ) ;
2016-08-13 03:32:38 +02:00
}
if ( io_len = = 4 ) {
2016-11-02 22:39:07 +01:00
retval | = ( ne2000 - > macaddr [ ( address + 2 ) % 32 ] < < 16 ) ;
retval | = ( ne2000 - > macaddr [ ( address + 3 ) % 32 ] < < 24 ) ;
2016-08-13 03:32:38 +02:00
}
return ( retval ) ;
2016-06-26 00:34:39 +02:00
}
if ( ( address > = BX_NE2K_MEMSTART ) & & ( address < BX_NE2K_MEMEND ) ) {
2016-08-13 03:32:38 +02:00
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 ) ;
2016-06-26 00:34:39 +02:00
}
2016-08-15 02:26:54 +02:00
ne2000_log ( " out-of-bounds chipmem read, %04X \n " , address ) ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
return ( 0xff ) ;
}
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
{
2016-08-13 03:32:38 +02:00
if ( ( io_len = = 2 ) & & ( address & 0x1 ) )
2016-08-15 02:26:54 +02:00
ne2000_log ( " unaligned chipmem word write \n " ) ;
2016-08-13 03:32:38 +02:00
2016-06-26 00:34:39 +02:00
if ( ( address > = BX_NE2K_MEMSTART ) & & ( address < BX_NE2K_MEMEND ) ) {
2016-08-13 03:32:38 +02:00
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
2016-08-15 02:26:54 +02:00
ne2000_log ( " out-of-bounds chipmem write, %04X \n " , address ) ;
2016-06-26 00:34:39 +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
{
2016-08-13 03:32:38 +02:00
uint32_t retval = 0 ;
switch ( offset ) {
case 0x0 : // Data register
//
// A read remote-DMA command must have been issued,
// and the source-address and length registers must
// have been initialised.
//
if ( io_len > ne2000 - > remote_bytes ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " dma read underrun iolen=%d remote_bytes=%d \n " , io_len , ne2000 - > remote_bytes ) ;
2016-08-13 03:32:38 +02:00
//return 0;
}
2016-06-26 00:34:39 +02:00
2016-08-15 02:26:54 +02:00
ne2000_log ( " %s read DMA: addr=%4x remote_bytes=%d \n " , ( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , ne2000 - > remote_dma , ne2000 - > remote_bytes ) ;
2016-08-13 03:32:38 +02:00
retval = ne2000_chipmem_read ( ne2000 , ne2000 - > remote_dma , io_len ) ;
2016-06-26 00:34:39 +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).
//
2016-08-13 03:32:38 +02:00
if ( io_len = = 4 ) {
ne2000 - > remote_dma + = io_len ;
} else {
ne2000 - > remote_dma + = ( ne2000 - > DCR . wdsize + 1 ) ;
}
2016-06-26 00:34:39 +02:00
if ( ne2000 - > remote_dma = = ne2000 - > page_stop < < 8 ) {
ne2000 - > remote_dma = ne2000 - > page_start < < 8 ;
}
// keep s.remote_bytes from underflowing
2016-08-13 03:32:38 +02: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 ) ;
}
2016-06-26 00:34:39 +02:00
else
ne2000 - > remote_bytes = 0 ;
2016-08-13 03:32:38 +02:00
// If all bytes have been written, signal remote-DMA complete
if ( ne2000 - > remote_bytes = = 0 ) {
ne2000 - > ISR . rdma_done = 1 ;
if ( ne2000 - > IMR . rdma_inte ) {
picint ( 1 < < ne2000 - > base_irq ) ;
}
2016-06-26 00:34:39 +02:00
}
2016-08-13 03:32:38 +02:00
break ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
case 0xf : // Reset register
ne2000_reset ( ne2000 , BX_RESET_SOFTWARE ) ;
break ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
default :
2016-08-15 02:26:54 +02:00
ne2000_log ( " asic read invalid address %04x \n " , ( unsigned ) offset ) ;
2016-08-13 03:32:38 +02:00
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
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " %s: asic write addr=0x%02x, value=0x%04x \n " , ( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , ( unsigned ) offset , ( unsigned ) value ) ;
2016-08-13 03:32:38 +02:00
switch ( offset ) {
case 0x0 : // Data register - see asic_read for a description
if ( ( io_len > 1 ) & & ( ne2000 - > DCR . wdsize = = 0 ) ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " dma write length %d on byte mode operation \n " , io_len ) ;
2016-08-13 03:32:38 +02:00
break ;
}
if ( ne2000 - > remote_bytes = = 0 ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " dma write, byte count 0 \n " ) ;
2016-08-13 03:32:38 +02:00
}
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
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 ) ;
}
2016-06-26 00:34:39 +02:00
if ( ne2000 - > remote_dma = = ne2000 - > page_stop < < 8 ) {
ne2000 - > remote_dma = ne2000 - > page_start < < 8 ;
}
2016-08-13 03:32:38 +02:00
if ( io_len = = 4 ) {
ne2000 - > remote_bytes - = io_len ;
} else {
ne2000 - > remote_bytes - = ( ne2000 - > DCR . wdsize + 1 ) ;
}
2016-06-26 00:34:39 +02:00
if ( ne2000 - > remote_bytes > BX_NE2K_MEMSIZ )
ne2000 - > remote_bytes = 0 ;
// If all bytes have been written, signal remote-DMA complete
if ( ne2000 - > remote_bytes = = 0 ) {
ne2000 - > ISR . rdma_done = 1 ;
if ( ne2000 - > IMR . rdma_inte ) {
2016-08-13 03:32:38 +02:00
picint ( 1 < < ne2000 - > base_irq ) ;
2016-06-26 00:34:39 +02:00
}
}
2016-08-13 03:32:38 +02:00
break ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
case 0xf : // Reset register
// end of reset pulse
break ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
default : // this is invalid, but happens under win95 device detection
2016-08-15 02:26:54 +02:00
ne2000_log ( " asic write invalid address %04x, ignoring \n " , ( unsigned ) offset ) ;
2016-08-13 03:32:38 +02:00
break ;
}
2016-06-26 00:34:39 +02:00
}
//
2016-08-13 03:32:38 +02:00
// page0_read/page0_write - These routines handle reads/writes to
// the 'zeroth' page of the DS8390 register file
2016-06-26 00:34:39 +02:00
//
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
{
2016-08-13 03:32:38 +02:00
uint8_t value = 0 ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
if ( io_len > 1 ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " bad length! page 0 read from register 0x%02x, len=%u \n " , offset ,
2016-08-13 03:32:38 +02:00
io_len ) ; /* encountered with win98 hardware probe */
return value ;
}
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
switch ( offset ) {
2016-06-26 00:34:39 +02:00
case 0x1 : // CLDA0
2016-08-13 03:32:38 +02:00
value = ( ne2000 - > local_dma & 0xff ) ;
2016-06-26 00:34:39 +02:00
break ;
case 0x2 : // CLDA1
2016-08-13 03:32:38 +02:00
value = ( ne2000 - > local_dma > > 8 ) ;
2016-06-26 00:34:39 +02:00
break ;
case 0x3 : // BNRY
2016-08-13 03:32:38 +02:00
value = ne2000 - > bound_ptr ;
2016-06-26 00:34:39 +02:00
break ;
case 0x4 : // TSR
2016-08-13 03:32:38 +02: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 ) ) ;
2016-06-26 00:34:39 +02:00
break ;
case 0x5 : // NCR
2016-08-13 03:32:38 +02:00
value = ne2000 - > num_coll ;
2016-06-26 00:34:39 +02:00
break ;
case 0x6 : // FIFO
// reading FIFO is only valid in loopback mode
2016-08-15 02:26:54 +02:00
ne2000_log ( " reading FIFO not supported yet \n " ) ;
2016-08-13 03:32:38 +02:00
value = ne2000 - > fifo ;
2016-06-26 00:34:39 +02:00
break ;
case 0x7 : // ISR
2016-08-13 03:32:38 +02: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 ) ) ;
2016-06-26 00:34:39 +02:00
break ;
case 0x8 : // CRDA0
2016-08-13 03:32:38 +02:00
value = ( ne2000 - > remote_dma & 0xff ) ;
2016-06-26 00:34:39 +02:00
break ;
case 0x9 : // CRDA1
2016-08-13 03:32:38 +02:00
value = ( ne2000 - > remote_dma > > 8 ) ;
2016-06-26 00:34:39 +02:00
break ;
2016-08-13 03:32:38 +02:00
case 0xa : // reserved / RTL8029ID0
if ( network_card_current = = 2 ) {
value = 0x50 ;
} else {
2016-08-15 02:26:54 +02:00
ne2000_log ( " reserved read - page 0, 0xa \n " ) ;
2016-08-13 03:32:38 +02:00
value = 0xff ;
}
2016-06-26 00:34:39 +02:00
break ;
2016-08-13 03:32:38 +02:00
case 0xb : // reserved / RTL8029ID1
if ( network_card_current = = 2 ) {
value = 0x43 ;
} else {
2016-08-15 02:26:54 +02:00
ne2000_log ( " reserved read - page 0, 0xb \n " ) ;
2016-08-13 03:32:38 +02:00
value = 0xff ;
}
2016-06-26 00:34:39 +02:00
break ;
case 0xc : // RSR
2016-08-13 03:32:38 +02: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 ) ) ;
2016-06-26 00:34:39 +02:00
break ;
case 0xd : // CNTR0
2016-08-13 03:32:38 +02:00
value = ne2000 - > tallycnt_0 ;
2016-06-26 00:34:39 +02:00
break ;
case 0xe : // CNTR1
2016-08-13 03:32:38 +02:00
value = ne2000 - > tallycnt_1 ;
2016-06-26 00:34:39 +02:00
break ;
case 0xf : // CNTR2
2016-08-13 03:32:38 +02:00
value = ne2000 - > tallycnt_2 ;
2016-06-26 00:34:39 +02:00
break ;
2016-08-13 03:32:38 +02:00
default :
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 0 register 0x%02x out of range \n " , offset ) ;
2016-08-13 03:32:38 +02:00
break ;
2016-06-26 00:34:39 +02:00
}
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 0 read from register 0x%02x, value=0x%02x \n " , offset , value ) ;
2016-08-13 03:32:38 +02:00
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
{
2016-08-13 03:32:38 +02:00
uint8_t value2 ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
// It appears to be a common practice to use outw on page0 regs...
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
// break up outw into two outb's
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 ) ;
2016-06-26 00:34:39 +02:00
}
2016-08-13 03:32:38 +02:00
return ;
2016-06-26 00:34:39 +02:00
}
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 0 write to register 0x%02x, value=0x%02x \n " , offset , value ) ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
switch ( offset ) {
2016-06-26 00:34:39 +02:00
case 0x1 : // PSTART
ne2000 - > page_start = value ;
break ;
case 0x2 : // PSTOP
ne2000 - > page_stop = value ;
break ;
case 0x3 : // BNRY
ne2000 - > bound_ptr = value ;
break ;
case 0x4 : // TPSR
ne2000 - > tx_page_start = value ;
break ;
case 0x5 : // TBCR0
// Clear out low byte and re-insert
ne2000 - > tx_bytes & = 0xff00 ;
ne2000 - > tx_bytes | = ( value & 0xff ) ;
break ;
case 0x6 : // TBCR1
// Clear out high byte and re-insert
ne2000 - > tx_bytes & = 0x00ff ;
ne2000 - > tx_bytes | = ( ( value & 0xff ) < < 8 ) ;
break ;
case 0x7 : // ISR
value & = 0x7f ; // clear RST bit - status-only bit
// All other values are cleared iff the ISR bit is 1
ne2000 - > ISR . pkt_rx & = ~ ( ( int ) ( ( value & 0x01 ) = = 0x01 ) ) ;
2016-08-13 03:32:38 +02:00
ne2000 - > ISR . pkt_tx & = ~ ( ( int ) ( ( value & 0x02 ) = = 0x02 ) ) ;
2016-06-26 00:34:39 +02:00
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 )
2016-08-13 03:32:38 +02:00
picintc ( 1 < < ne2000 - > base_irq ) ;
2016-06-26 00:34:39 +02:00
break ;
case 0x8 : // RSAR0
// Clear out low byte and re-insert
ne2000 - > remote_start & = 0xff00 ;
ne2000 - > remote_start | = ( value & 0xff ) ;
ne2000 - > remote_dma = ne2000 - > remote_start ;
break ;
case 0x9 : // RSAR1
// Clear out high byte and re-insert
ne2000 - > remote_start & = 0x00ff ;
ne2000 - > remote_start | = ( ( value & 0xff ) < < 8 ) ;
ne2000 - > remote_dma = ne2000 - > remote_start ;
break ;
case 0xa : // RBCR0
// Clear out low byte and re-insert
ne2000 - > remote_bytes & = 0xff00 ;
ne2000 - > remote_bytes | = ( value & 0xff ) ;
break ;
case 0xb : // RBCR1
// Clear out high byte and re-insert
ne2000 - > remote_bytes & = 0x00ff ;
ne2000 - > remote_bytes | = ( ( value & 0xff ) < < 8 ) ;
break ;
case 0xc : // RCR
// Check if the reserved bits are set
if ( value & 0xc0 )
2016-08-15 02:26:54 +02:00
ne2000_log ( " RCR write, reserved bits set \n " ) ;
2016-06-26 00:34:39 +02:00
// Set all other bit-fields
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 ) ;
// Monitor bit is a little suspicious...
if ( value & 0x20 )
2016-08-15 02:26:54 +02:00
ne2000_log ( " RCR write, monitor bit set! \n " ) ;
2016-06-26 00:34:39 +02:00
break ;
case 0xd : // TCR
// Check reserved bits
if ( value & 0xe0 )
2016-08-15 02:26:54 +02:00
ne2000_log ( " TCR write, reserved bits set \n " ) ;
2016-06-26 00:34:39 +02:00
// Test loop mode (not supported)
if ( value & 0x06 ) {
ne2000 - > TCR . loop_cntl = ( value & 0x6 ) > > 1 ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " TCR write, loop mode %d not supported \n " , ne2000 - > TCR . loop_cntl ) ;
2016-06-26 00:34:39 +02:00
} else {
ne2000 - > TCR . loop_cntl = 0 ;
}
// Inhibit-CRC not supported.
if ( value & 0x01 )
2016-08-15 02:26:54 +02:00
ne2000_log ( " TCR write, inhibit-CRC not supported \n " ) ;
2016-06-26 00:34:39 +02:00
// Auto-transmit disable very suspicious
2016-08-13 03:32:38 +02:00
if ( value & 0x08 )
2016-08-15 02:26:54 +02:00
ne2000_log ( " TCR write, auto transmit disable not supported \n " ) ;
2016-06-26 00:34:39 +02:00
// Allow collision-offset to be set, although not used
ne2000 - > TCR . coll_prio = ( ( value & 0x08 ) = = 0x08 ) ;
break ;
case 0xe : // DCR
// the loopback mode is not suppported yet
if ( ! ( value & 0x08 ) ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " DCR write, loopback mode selected \n " ) ;
2016-06-26 00:34:39 +02:00
}
// It is questionable to set longaddr and auto_rx, since they
// aren't supported on the ne2000. Print a warning and continue
if ( value & 0x04 )
2016-08-15 02:26:54 +02:00
ne2000_log ( " DCR write - LAS set ??? \n " ) ;
2016-06-26 00:34:39 +02:00
if ( value & 0x10 )
2016-08-15 02:26:54 +02:00
ne2000_log ( " DCR write - AR set ??? \n " ) ;
2016-06-26 00:34:39 +02:00
// Set other values.
ne2000 - > DCR . wdsize = ( ( value & 0x01 ) = = 0x01 ) ;
ne2000 - > DCR . endian = ( ( value & 0x02 ) = = 0x02 ) ;
ne2000 - > DCR . longaddr = ( ( value & 0x04 ) = = 0x04 ) ; // illegal ?
ne2000 - > DCR . loop = ( ( value & 0x08 ) = = 0x08 ) ;
ne2000 - > DCR . auto_rx = ( ( value & 0x10 ) = = 0x10 ) ; // also illegal ?
ne2000 - > DCR . fifo_size = ( value & 0x50 ) > > 5 ;
break ;
case 0xf : // IMR
// Check for reserved bit
2016-08-13 03:32:38 +02:00
if ( value & 0x80 )
2016-08-15 02:26:54 +02:00
ne2000_log ( " IMR write, reserved bit set \n " ) ;
2016-06-26 00:34:39 +02:00
// Set other values
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 ) ;
2016-08-13 03:32:38 +02:00
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 ) ;
}
2016-06-26 00:34:39 +02:00
break ;
2016-08-13 03:32:38 +02:00
default :
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 0 write, bad register 0x%02x \n " , offset ) ;
2016-08-13 03:32:38 +02:00
break ;
2016-06-26 00:34:39 +02:00
}
2016-08-13 03:32:38 +02:00
}
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
//
// page1_read/page1_write - These routines handle reads/writes to
// the first page of the DS8390 register file
//
uint32_t ne2000_page1_read ( ne2000_t * ne2000 , uint32_t offset , unsigned int io_len )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 1 read from register 0x%02x, len=%u \n " , offset , io_len ) ;
2016-08-13 03:32:38 +02:00
switch ( offset ) {
case 0x1 : // PAR0-5
case 0x2 :
case 0x3 :
case 0x4 :
case 0x5 :
case 0x6 :
return ( ne2000 - > physaddr [ offset - 1 ] ) ;
break ;
case 0x7 : // CURR
2016-08-15 02:26:54 +02:00
ne2000_log ( " returning current page: 0x%02x \n " , ( ne2000 - > curr_page ) ) ;
2016-08-13 03:32:38 +02:00
return ( ne2000 - > curr_page ) ;
case 0x8 : // MAR0-7
case 0x9 :
case 0xa :
case 0xb :
case 0xc :
case 0xd :
case 0xe :
case 0xf :
return ( ne2000 - > mchash [ offset - 8 ] ) ;
break ;
default :
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 1 read register 0x%02x out of range \n " , offset ) ;
2016-08-13 03:32:38 +02:00
break ;
}
return ( 0 ) ;
}
void ne2000_page1_write ( ne2000_t * ne2000 , uint32_t offset , uint32_t value , unsigned io_len )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 1 write to register 0x%02x, len=%u, value=0x%04x \n " , offset ,
2016-08-13 03:32:38 +02:00
io_len , value ) ;
switch ( offset ) {
2016-06-26 00:34:39 +02:00
case 0x1 : // PAR0-5
case 0x2 :
case 0x3 :
case 0x4 :
case 0x5 :
case 0x6 :
2016-08-13 03:32:38 +02:00
ne2000 - > physaddr [ offset - 1 ] = value ;
if ( offset = = 6 ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " Physical address set to %02x:%02x:%02x:%02x:%02x:%02x \n " ,
2016-08-13 03:32:38 +02:00
ne2000 - > physaddr [ 0 ] ,
ne2000 - > physaddr [ 1 ] ,
ne2000 - > physaddr [ 2 ] ,
ne2000 - > physaddr [ 3 ] ,
ne2000 - > physaddr [ 4 ] ,
ne2000 - > physaddr [ 5 ] ) ;
}
2016-06-26 00:34:39 +02:00
break ;
case 0x7 : // CURR
ne2000 - > curr_page = value ;
break ;
case 0x8 : // MAR0-7
case 0x9 :
case 0xa :
case 0xb :
case 0xc :
case 0xd :
case 0xe :
case 0xf :
2016-08-13 03:32:38 +02:00
ne2000 - > mchash [ offset - 8 ] = value ;
2016-06-26 00:34:39 +02:00
break ;
2016-08-13 03:32:38 +02:00
default :
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 1 write register 0x%02x out of range \n " , offset ) ;
2016-08-13 03:32:38 +02:00
break ;
2016-06-26 00:34:39 +02:00
}
2016-08-13 03:32:38 +02:00
}
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
//
// page2_read/page2_write - These routines handle reads/writes to
// the second page of the DS8390 register file
//
uint32_t ne2000_page2_read ( ne2000_t * ne2000 , uint32_t offset , unsigned int io_len )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 2 read from register 0x%02x, len=%u \n " , offset , io_len ) ;
2016-08-13 03:32:38 +02:00
switch ( offset ) {
case 0x1 : // PSTART
return ( ne2000 - > page_start ) ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
case 0x2 : // PSTOP
return ( ne2000 - > page_stop ) ;
case 0x3 : // Remote Next-packet pointer
return ( ne2000 - > rempkt_ptr ) ;
case 0x4 : // TPSR
return ( ne2000 - > tx_page_start ) ;
case 0x5 : // Local Next-packet pointer
return ( ne2000 - > localpkt_ptr ) ;
case 0x6 : // Address counter (upper)
return ( ne2000 - > address_cnt > > 8 ) ;
case 0x7 : // Address counter (lower)
return ( ne2000 - > address_cnt & 0xff ) ;
case 0x8 : // Reserved
case 0x9 :
case 0xa :
case 0xb :
2016-08-15 02:26:54 +02:00
ne2000_log ( " reserved read - page 2, register 0x%02x \n " , offset ) ;
2016-08-13 03:32:38 +02:00
return ( 0xff ) ;
case 0xc : // RCR
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 ) ) ;
case 0xd : // TCR
return ( ( ne2000 - > TCR . coll_prio < < 4 ) |
( ne2000 - > TCR . ext_stoptx < < 3 ) |
( ( ne2000 - > TCR . loop_cntl & 0x3 ) < < 1 ) |
( ne2000 - > TCR . crc_disable ) ) ;
case 0xe : // DCR
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 ) ) ;
case 0xf : // IMR
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 :
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 2 register 0x%02x out of range \n " , offset ) ;
2016-08-13 03:32:38 +02:00
break ;
}
return ( 0 ) ;
}
void ne2000_page2_write ( ne2000_t * ne2000 , uint32_t offset , uint32_t value , unsigned io_len )
{
// Maybe all writes here should be BX_PANIC()'d, since they
// affect internal operation, but let them through for now
// and print a warning.
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 2 write to register 0x%02x, len=%u, value=0x%04x \n " , offset ,
2016-08-13 03:32:38 +02:00
io_len , value ) ;
switch ( offset ) {
2016-06-26 00:34:39 +02:00
case 0x1 : // CLDA0
// Clear out low byte and re-insert
ne2000 - > local_dma & = 0xff00 ;
ne2000 - > local_dma | = ( value & 0xff ) ;
break ;
case 0x2 : // CLDA1
// Clear out high byte and re-insert
ne2000 - > local_dma & = 0x00ff ;
ne2000 - > local_dma | = ( ( value & 0xff ) < < 8 ) ;
break ;
case 0x3 : // Remote Next-pkt pointer
ne2000 - > rempkt_ptr = value ;
break ;
case 0x4 :
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 2 write to reserved register 0x04 \n " ) ;
2016-06-26 00:34:39 +02:00
break ;
case 0x5 : // Local Next-packet pointer
ne2000 - > localpkt_ptr = value ;
break ;
case 0x6 : // Address counter (upper)
// Clear out high byte and re-insert
ne2000 - > address_cnt & = 0x00ff ;
ne2000 - > address_cnt | = ( ( value & 0xff ) < < 8 ) ;
break ;
case 0x7 : // Address counter (lower)
// Clear out low byte and re-insert
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 :
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 2 write to reserved register 0x%02x \n " , offset ) ;
2016-08-13 03:32:38 +02:00
break ;
2016-06-26 00:34:39 +02:00
default :
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 2 write, illegal register 0x%02x \n " , offset ) ;
2016-06-26 00:34:39 +02:00
break ;
}
2016-08-13 03:32:38 +02:00
}
//
// page3_read/page3_write - writes to this page are illegal
//
uint32_t ne2000_page3_read ( ne2000_t * ne2000 , uint32_t offset , unsigned int io_len )
{
if ( network_card_current = = 2 ) {
switch ( offset ) {
case 0x3 : // CONFIG0
return ( 0 ) ;
case 0x5 : // CONFIG2
return ( 0x40 ) ;
case 0x6 : // CONFIG3
return ( 0x40 ) ;
default :
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 3 read register 0x%02x attempted \n " , offset ) ;
2016-08-13 03:32:38 +02:00
return ( 0 ) ;
}
} else {
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 3 read register 0x%02x attempted \n " , offset ) ;
2016-08-13 03:32:38 +02:00
return ( 0 ) ;
}
}
void ne2000_page3_write ( ne2000_t * ne2000 , uint32_t offset , uint32_t value , unsigned io_len )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " page 3 write register 0x%02x attempted \n " , offset ) ;
2016-08-13 03:32:38 +02:00
return ;
}
void ne2000_tx_timer ( void * p )
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " tx_timer \n " ) ;
2016-08-13 03:32:38 +02:00
ne2000 - > CR . tx_packet = 0 ;
ne2000 - > TSR . tx_ok = 1 ;
ne2000 - > ISR . pkt_tx = 1 ;
// Generate an interrupt if not masked
if ( ne2000 - > IMR . tx_inte ) {
picint ( 1 < < ne2000 - > base_irq ) ;
}
ne2000 - > tx_timer_active = 0 ;
}
void ne2000_tx_event ( void * p , uint32_t val )
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
ne2000_tx_timer ( ne2000 ) ;
}
//
// 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
//
uint32_t ne2000_read ( ne2000_t * ne2000 , uint32_t address , unsigned io_len )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " %s: read addr %x, len %d \n " , ( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , address , io_len ) ;
2016-08-13 03:32:38 +02:00
uint32_t retval = 0 ;
int offset = address - ne2000 - > base_address ;
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 ) ;
2016-06-26 00:34:39 +02:00
break ;
2016-08-13 03:32:38 +02:00
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 ;
2016-06-26 00:34:39 +02:00
default :
2016-08-15 02:26:54 +02:00
ne2000_log ( " unknown value of pgsel in read - %d \n " , ne2000 - > CR . pgsel ) ;
2016-08-13 03:32:38 +02:00
break ;
}
}
return ( retval ) ;
}
void ne2000_write ( ne2000_t * ne2000 , uint32_t address , uint32_t value , unsigned io_len )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " %s: write addr %x, value %x len %d \n " , ( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , address , value , io_len ) ;
2016-08-13 03:32:38 +02:00
int offset = address - ne2000 - > base_address ;
//
// 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
//
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 ) ;
2016-06-26 00:34:39 +02:00
break ;
2016-08-13 03:32:38 +02:00
default :
2016-08-15 02:26:54 +02:00
ne2000_log ( " unknown value of pgsel in write - %d \n " , ne2000 - > CR . pgsel ) ;
2016-08-13 03:32:38 +02:00
break ;
2016-06-26 00:34:39 +02:00
}
2016-08-13 03:32:38 +02:00
}
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
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 ) ;
# 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 )
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
int pages ;
int avail ;
int idx ;
int wrapped ;
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 } ;
2017-01-05 01:48:55 +01:00
uint32_t mac_cmp32 [ 2 ] ;
uint16_t mac_cmp16 [ 2 ] ;
2016-06-26 00:34:39 +02:00
if ( io_len ! = 60 ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " rx_frame with length %d \n " , io_len ) ;
2016-06-26 00:34:39 +02:00
}
//LOG_MSG("stop=%d, pagestart=%x, dcr_loop=%x, tcr_loopcntl=%x",
// ne2000->CR.stop, ne2000->page_start,
// ne2000->DCR.loop, ne2000->TCR.loop_cntl);
if ( ( ne2000 - > CR . stop ! = 0 ) | |
( ne2000 - > page_start = = 0 ) /*||
( ( ne2000 - > DCR . loop = = 0 ) & &
( ne2000 - > TCR . loop_cntl ! = 0 ) ) */ ) {
return ;
}
// Add the pkt header + CRC to the length, and work
// out how many 256-byte pages the frame would occupy
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 ) ;
wrapped = 1 ;
}
// Avoid getting into a buffer overflow condition by not attempting
// to do partial receives. The emulation to handle this condition
// seems particularly painful.
if ( ( avail < pages )
# if BX_NE2K_NEVER_FULL_RING
| | ( avail = = pages )
# endif
) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " no space \n " ) ;
2016-06-26 00:34:39 +02:00
return ;
}
if ( ( io_len < 40 /*60*/ ) & & ! ne2000 - > RCR . runts_ok ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " rejected small packet, length %d \n " , io_len ) ;
2016-06-26 00:34:39 +02:00
return ;
}
// some computers don't care...
if ( io_len < 60 ) io_len = 60 ;
// Do address filtering if not in promiscuous mode
if ( ! ne2000 - > RCR . promisc ) {
2017-01-05 01:48:55 +01:00
/* Received. */
mac_cmp32 [ 0 ] = * ( uint32_t * ) ( buf ) ;
mac_cmp16 [ 0 ] = * ( uint16_t * ) ( buf + 4 ) ;
/* Local. */
mac_cmp32 [ 1 ] = * ( uint32_t * ) ( bcast_addr ) ;
mac_cmp16 [ 1 ] = * ( uint16_t * ) ( bcast_addr + 4 ) ;
// if (!memcmp(buf, bcast_addr, 6)) {
2017-01-05 01:51:11 +01:00
if ( ( mac_cmp32 [ 0 ] = = mac_cmp32 [ 1 ] ) & & ( mac_cmp16 [ 0 ] = = mac_cmp16 [ 1 ] ) ) {
2016-06-26 00:34:39 +02:00
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 {
2016-08-15 02:26:54 +02:00
ne2000_log ( " rx_frame promiscuous receive \n " ) ;
2016-06-26 00:34:39 +02:00
}
2016-08-15 02:26:54 +02:00
ne2000_log ( " rx_frame %d to %x:%x:%x:%x:%x:%x from %x:%x:%x:%x:%x:%x \n " ,
2016-06-26 00:34:39 +02:00
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 ;
}
// 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.
if ( pktbuf [ 0 ] & 0x01 ) {
pkthdr [ 0 ] | = 0x20 ; // rx status += multicast packet
}
pkthdr [ 1 ] = nextpage ; // ptr to next packet
pkthdr [ 2 ] = ( io_len + 4 ) & 0xff ; // length-low
pkthdr [ 3 ] = ( io_len + 4 ) > > 8 ; // length-hi
// copy into buffer, update curpage, and signal interrupt if config'd
startptr = & ne2000 - > mem [ ne2000 - > curr_page * 256 -
BX_NE2K_MEMSTART ] ;
if ( ( nextpage > ne2000 - > curr_page ) | |
( ( ne2000 - > curr_page + pages ) = = ne2000 - > page_stop ) ) {
2017-01-05 01:48:55 +01:00
// memcpy(startptr, pkthdr, 4);
* ( uint32_t * ) startptr = * ( uint32_t * ) pkthdr ;
2016-06-26 00:34:39 +02:00
memcpy ( startptr + 4 , buf , io_len ) ;
ne2000 - > curr_page = nextpage ;
} else {
int endbytes = ( ne2000 - > page_stop - ne2000 - > curr_page )
* 256 ;
2017-01-05 01:48:55 +01:00
// memcpy(startptr, pkthdr, 4);
* ( uint32_t * ) startptr = * ( uint32_t * ) pkthdr ;
2016-06-26 00:34:39 +02:00
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 ) {
//LOG_MSG("packet rx interrupt");
picint ( 1 < < ne2000 - > base_irq ) ;
//DEV_pic_raise_irq(ne2000->base_irq);
} //else LOG_MSG("no packet rx interrupt");
}
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 )
return ne2000_read ( ne2000 , addr , 2 ) ;
else
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 )
ne2000_write ( ne2000 , addr , val , 2 ) ;
else
ne2000_write ( ne2000 , addr , val , 1 ) ;
}
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
int res ;
if ( net_is_slirp ) {
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 ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 inQ:%d got a %dbyte packet @%d \n " , QueuePeek ( slirpq ) , qp - > len , qp ) ;
2016-06-26 00:34:39 +02:00
free ( qp ) ;
}
fizz + + ;
if ( fizz > 1200 ) { fizz = 0 ; slirp_tic ( ) ; }
} //end slirp
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 ;
}
2016-06-26 00:34:39 +02:00
data = _pcap_next ( net_pcap , & h ) ;
2017-01-05 02:43:54 +01:00
if ( data = = 0x0 )
{
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. */
mac_cmp32 [ 1 ] = * ( uint32_t * ) ( maclocal ) ;
mac_cmp16 [ 1 ] = * ( uint16_t * ) ( maclocal + 4 ) ;
// if((memcmp(data+6,maclocal,6))==0)
2017-01-05 02:39:35 +01:00
/* if ((mac_cmp32[0] == mac_cmp32[1]) && (mac_cmp16[0] == mac_cmp16[1]))
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 we just saw ourselves \n " ) ;
2017-01-05 02:39:35 +01:00
}
else { */
if ( ( mac_cmp32 [ 0 ] ! = mac_cmp32 [ 1 ] ) | | ( mac_cmp16 [ 0 ] ! = mac_cmp16 [ 1 ] ) )
{
// ne2000_log("ne2000 pcap received a frame %d bytes\n",h.caplen);
ne2000_rx_frame ( ne2000 , data , h . caplen ) ;
}
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
{
2016-08-13 17:29:14 +02:00
old_base_addr = addr ;
2016-08-13 03:32:38 +02:00
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 ) ;
2016-08-13 17:29:14 +02:00
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
{
2016-08-15 01:34:46 +02:00
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 )
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
2016-08-15 02:26:54 +02:00
// ne2000_log("NE2000 PCI read %08X\n", addr);
2016-06-26 00:34:39 +02:00
switch ( addr )
{
case 0x00 : /* case 0x2C:*/ return 0xec ;
case 0x01 : /* case 0x2D:*/ return 0x10 ;
case 0x02 : /* case 0x2E:*/ return 0x29 ;
case 0x03 : /* case 0x2F:*/ return 0x80 ;
case 0x2C : return 0xF4 ;
case 0x2D : return 0x1A ;
case 0x2E : return 0x00 ;
case 0x2F : return 0x11 ;
case 0x04 :
2016-08-13 03:32:38 +02:00
return ne2000_pci_regs [ 0x04 ] ; /*Respond to IO and memory accesses*/
2016-06-26 00:34:39 +02:00
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*/
2016-08-13 03:32:38 +02:00
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 ] ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
case 0x30 : return ne2000_pci_bar [ 1 ] . addr_regs [ 0 ] & 0x01 ; /*BIOS ROM address*/
// case 0x31: return (ne2000_pci_bar[1].addr_regs[1] & 0xE0) | 0x18;
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 ] ;
2016-06-26 00:34:39 +02:00
case 0x3C : return ne2000_pci_regs [ 0x3C ] ;
case 0x3D : return ne2000_pci_regs [ 0x3D ] ;
}
return 0 ;
}
void ne2000_update_bios ( ne2000_t * ne2000 )
{
int reg_bios_enable ;
// reg_bios_enable = ne2000_pci_regs[0x30];
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 )
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
2016-08-15 02:26:54 +02:00
// ne2000_log("ne2000_pci_write: addr=%02x val=%02x\n", addr, val);
2016-06-26 00:34:39 +02:00
switch ( addr )
{
case 0x04 :
if ( val & PCI_COMMAND_IO )
2016-08-13 17:29:14 +02:00
{
2016-08-15 01:34:46 +02:00
ne2000_io_remove ( ne2000 - > base_address , ne2000 ) ;
2016-08-13 03:32:38 +02:00
ne2000_io_set ( ne2000 - > base_address , ne2000 ) ;
2016-08-13 17:29:14 +02:00
}
2016-06-26 00:34:39 +02:00
else
2016-08-13 17:29:14 +02:00
{
2016-08-15 01:34:46 +02:00
ne2000_io_remove ( ne2000 - > base_address , ne2000 ) ;
2016-08-13 17:29:14 +02:00
}
2016-08-15 01:34:46 +02:00
ne2000_pci_regs [ addr ] = val ;
2016-06-26 00:34:39 +02:00
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. */
2016-08-15 01:34:46 +02:00
ne2000_io_remove ( ne2000 - > base_address , ne2000 ) ;
2016-06-26 00:34:39 +02:00
/* Then let's set the PCI regs. */
2016-08-13 03:32:38 +02:00
ne2000_pci_bar [ 0 ] . addr_regs [ addr & 3 ] = val ;
2016-06-26 00:34:39 +02:00
/* Then let's calculate the new I/O base. */
2016-08-13 03:32:38 +02:00
ne2000 - > base_address = ne2000_pci_bar [ 0 ] . addr & 0xff00 ;
2016-06-26 00:34:39 +02:00
/* If the base is below 0x280, return. */
/* Log the new base. */
2016-08-15 02:26:54 +02:00
ne2000_log ( " NE2000 RTL8029AS PCI: New I/O base is %04X \n " , ne2000 - > base_address ) ;
2016-06-26 00:34:39 +02:00
/* We're done, so get out of the here. */
return ;
2016-08-13 03:32:38 +02:00
2016-06-26 00:34:39 +02:00
case 0x30 : case 0x31 : case 0x32 : case 0x33 :
2016-08-13 03:32:38 +02:00
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 ;
2016-06-26 00:34:39 +02:00
ne2000_update_bios ( ne2000 ) ;
return ;
2016-11-05 07:17:08 +01:00
/* 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 . */
#if 0
2016-06-26 00:34:39 +02:00
case 0x3C :
ne2000_pci_regs [ addr ] = val ;
if ( val ! = 0xFF )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " NE2000 IRQ now: %i \n " , val ) ;
2016-06-26 00:34:39 +02:00
ne2000_setirq ( ne2000 , val ) ;
}
return ;
2016-11-05 07:17:08 +01:00
# endif
}
2016-06-26 00:34:39 +02:00
}
2016-08-13 03:32:38 +02:00
void ne2000_rom_init ( ne2000_t * ne2000 , char * s )
2016-06-26 00:34:39 +02:00
{
2016-08-13 03:32:38 +02:00
FILE * f = fopen ( s , " rb " ) ;
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
2016-08-13 03:32:38 +02:00
void * ne2000_init ( )
{
int rc ;
int config_net_type ;
int net_type ;
ne2000_t * ne2000 = malloc ( sizeof ( ne2000_t ) ) ;
memset ( ne2000 , 0 , sizeof ( ne2000_t ) ) ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
ne2000 - > base_address = device_get_config_int ( " addr " ) ;
disable_netbios = device_get_config_int ( " disable_netbios " ) ;
ne2000_setirq ( ne2000 , device_get_config_int ( " irq " ) ) ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
//net_type
//0 pcap
//1 slirp
//
config_net_type = device_get_config_int ( " net_type " ) ;
// net_is_slirp = config_get_int(NULL, "net_type", 1);
/* Network type is now specified in device config. */
net_is_slirp = config_net_type ? 1 : 0 ;
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 ;
net_is_slirp = 1 ;
}
pclog ( " net_is_pcap = %i, net_is_slirp = %i \n " , net_is_pcap , net_is_slirp ) ;
2016-08-15 02:26:54 +02:00
// ne2000_log("ne2000 pcap device %s\n",config_get_string(NULL,"pcap_device","nothing"));
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
ne2000_io_set ( ne2000 - > base_address , ne2000 ) ;
memcpy ( ne2000 - > physaddr , maclocal , 6 ) ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
if ( ! disable_netbios )
ne2000_rom_init ( ne2000 , " roms/ne2000.rom " ) ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
ne2000_reset ( ne2000 , BX_RESET_HARDWARE ) ;
vlan_handler ( ne2000_poller , ne2000 ) ;
2016-06-26 00:34:39 +02:00
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 isa init 0x%X %d \t slirp is %d net_is_pcap is %d \n " , ne2000 - > base_address , device_get_config_int ( " irq " ) , net_is_slirp , net_is_pcap ) ;
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
//need a switch statment for more network types.
if ( net_is_slirp ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 initalizing SLiRP \n " ) ;
2016-08-13 03:32:38 +02:00
net_is_pcap = 0 ;
rc = slirp_init ( ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 slirp_init returned: %d \n " , rc ) ;
2016-08-13 03:32:38 +02:00
if ( rc = = 0 )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 slirp initalized! \n " ) ;
2016-08-13 03:32:38 +02:00
net_slirp_inited = 1 ;
slirpq = QueueCreate ( ) ;
net_is_slirp = 1 ;
fizz = 0 ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 slirpq is %x \n " , & slirpq ) ;
2016-08-13 03:32:38 +02:00
}
else {
net_slirp_inited = 0 ;
net_is_slirp = 0 ;
}
}
if ( net_is_pcap ) { //pcap
char errbuf [ 32768 ] ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 initalizing libpcap \n " ) ;
2016-08-13 03:32:38 +02:00
net_is_slirp = 0 ;
net_hLib = LoadLibraryA ( net_lib_name ) ;
if ( net_hLib = = 0 )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Failed to load %s \n " , net_lib_name ) ;
2016-08-13 03:32:38 +02:00
net_is_pcap = 0 ;
//return;
}
_pcap_lib_version = ( PCAP_LIB_VERSION ) GetProcAddress ( net_hLib , " pcap_lib_version " ) ;
_pcap_open_live = ( PCAP_OPEN_LIVE ) GetProcAddress ( net_hLib , " pcap_open_live " ) ;
_pcap_sendpacket = ( PCAP_SENDPACKET ) GetProcAddress ( net_hLib , " pcap_sendpacket " ) ;
_pcap_setnonblock = ( PCAP_SETNONBLOCK ) GetProcAddress ( net_hLib , " pcap_setnonblock " ) ;
_pcap_next = ( PCAP_NEXT ) GetProcAddress ( net_hLib , " pcap_next " ) ;
_pcap_close = ( PCAP_CLOSE ) GetProcAddress ( net_hLib , " pcap_close " ) ;
_pcap_getnonblock = ( PCAP_GETNONBLOCK ) GetProcAddress ( net_hLib , " pcap_getnonblock " ) ;
_pcap_compile = ( PCAP_COMPILE ) GetProcAddress ( net_hLib , " pcap_compile " ) ;
_pcap_setfilter = ( PCAP_SETFILTER ) GetProcAddress ( net_hLib , " pcap_setfilter " ) ;
if ( _pcap_lib_version & & _pcap_open_live & & _pcap_sendpacket & & _pcap_setnonblock & & _pcap_next & & _pcap_close & & _pcap_getnonblock )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Pcap version [%s] \n " , _pcap_lib_version ( ) ) ;
2016-08-13 03:32:38 +02:00
//if((net_pcap=_pcap_open_live("\\Device\\NPF_{0CFA803F-F443-4BB9-A83A-657029A98195}",1518,1,15,errbuf))==0)
if ( ( net_pcap = _pcap_open_live ( config_get_string ( NULL , " pcap_device " , " nothing " ) , 1518 , 1 , 15 , errbuf ) ) = = 0 )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 pcap_open_live error on %s! \n " , config_get_string ( NULL , " pcap_device " , " whatever the ethernet is " ) ) ;
2016-08-13 03:32:38 +02:00
net_is_pcap = 0 ; return ( ne2000 ) ; //YUCK!!!
}
}
else {
2016-08-15 02:26:54 +02:00
ne2000_log ( " %d %d %d %d %d %d %d \n " , _pcap_lib_version , _pcap_open_live , _pcap_sendpacket , _pcap_setnonblock , _pcap_next , _pcap_close , _pcap_getnonblock ) ;
2016-08-13 03:32:38 +02:00
net_is_pcap = 1 ;
}
//Time to check that we are in non-blocking mode.
rc = _pcap_getnonblock ( net_pcap , errbuf ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 pcap is currently in %s mode \n " , rc ? " non-blocking " : " blocking " ) ;
2016-08-13 03:32:38 +02:00
switch ( rc )
{
case 0 :
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Setting interface to non-blocking mode.. " ) ;
2016-08-13 03:32:38 +02:00
rc = _pcap_setnonblock ( net_pcap , 1 , errbuf ) ;
if ( rc = = 0 ) { //no errors!
2016-08-15 02:26:54 +02:00
ne2000_log ( " .. " ) ;
2016-08-13 03:32:38 +02:00
rc = _pcap_getnonblock ( net_pcap , errbuf ) ;
if ( rc = = 1 ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " ..! " , rc ) ;
2016-08-13 03:32:38 +02:00
net_is_pcap = 1 ;
}
else {
2016-08-15 02:26:54 +02:00
ne2000_log ( " \t unable to set pcap into non-blocking mode! \n Continuining without pcap. \n " ) ;
2016-08-13 03:32:38 +02:00
net_is_pcap = 0 ;
}
} //end set nonblock
2016-08-15 02:26:54 +02:00
else { ne2000_log ( " There was an unexpected error of [%s] \n \n exiting. \n " , errbuf ) ; net_is_pcap = 0 ; }
ne2000_log ( " \n " ) ;
2016-08-13 03:32:38 +02:00
break ;
case 1 :
2016-08-15 02:26:54 +02:00
ne2000_log ( " non blocking \n " ) ;
2016-08-13 03:32:38 +02:00
break ;
default :
2016-08-15 02:26:54 +02:00
ne2000_log ( " this isn't right!!! \n " ) ;
2016-08-13 03:32:38 +02:00
net_is_pcap = 0 ;
break ;
}
if ( net_is_pcap ) {
if ( _pcap_compile & & _pcap_setfilter ) { //we can do this!
struct bpf_program fp ;
char filter_exp [ 255 ] ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Building packet filter... " ) ;
2016-08-13 03:32:38 +02:00
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) ) " , \
maclocal [ 0 ] , maclocal [ 1 ] , maclocal [ 2 ] , maclocal [ 3 ] , maclocal [ 4 ] , maclocal [ 5 ] , \
maclocal [ 0 ] , maclocal [ 1 ] , maclocal [ 2 ] , maclocal [ 3 ] , maclocal [ 4 ] , maclocal [ 5 ] ) ;
//I'm doing a MAC level filter so TCP/IP doesn't matter.
if ( _pcap_compile ( net_pcap , & fp , filter_exp , 0 , 0xffffffff ) = = - 1 ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " \n ne2000 Couldn't compile filter \n " ) ;
2016-08-13 03:32:38 +02:00
}
else {
2016-08-15 02:26:54 +02:00
ne2000_log ( " ... " ) ;
2016-08-13 03:32:38 +02:00
if ( _pcap_setfilter ( net_pcap , & fp ) = = - 1 ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " \n Error installing pcap filter. \n " ) ;
2016-08-13 03:32:38 +02:00
} //end of set_filter failure
else {
2016-08-15 02:26:54 +02:00
ne2000_log ( " ...! \n " ) ;
2016-08-13 03:32:38 +02:00
}
}
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Using filter \t [%s] \n " , filter_exp ) ;
2016-08-13 03:32:38 +02:00
//scanf(filter_exp); //pause
}
else
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Your platform lacks pcap_compile & pcap_setfilter \n " ) ;
2016-08-13 03:32:38 +02:00
net_is_pcap = 0 ;
}
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 net_is_pcap is %d and net_pcap is %x \n " , net_is_pcap , net_pcap ) ;
2016-08-13 03:32:38 +02:00
}
} //end pcap setup
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
//timer_add(slirp_tic,&delay,TIMER_ALWAYS_ENABLED,NULL);
//timer_add(keyboard_amstrad_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL);
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 is_slirp %d is_pcap %d \n " , net_is_slirp , net_is_pcap ) ;
2016-08-13 03:32:38 +02:00
//exit(0);
return ne2000 ;
2016-06-26 00:34:39 +02:00
}
2016-08-13 03:32:38 +02:00
void * rtl8029as_init ( )
2016-06-26 00:34:39 +02:00
{
int rc ;
int config_net_type ;
int net_type ;
2016-12-30 01:32:33 +01:00
int irq ;
2016-06-26 00:34:39 +02:00
ne2000_t * ne2000 = malloc ( sizeof ( ne2000_t ) ) ;
memset ( ne2000 , 0 , sizeof ( ne2000_t ) ) ;
2016-08-13 03:32:38 +02:00
2016-06-26 00:34:39 +02:00
disable_netbios = device_get_config_int ( " disable_netbios " ) ;
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
//net_type
//0 pcap
//1 slirp
//
config_net_type = device_get_config_int ( " net_type " ) ;
// net_is_slirp = config_get_int(NULL, "net_type", 1);
/* Network type is now specified in device config. */
net_is_slirp = config_net_type ? 1 : 0 ;
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 ;
net_is_slirp = 1 ;
}
2016-12-30 01:32:33 +01:00
pclog ( " net_is_pcap = %i, net_is_slirp = %i \n " , net_is_pcap , net_is_slirp ) ;
2016-08-15 02:26:54 +02:00
// ne2000_log("ne2000 pcap device %s\n",config_get_string(NULL,"pcap_device","nothing"));
2016-06-26 00:34:39 +02:00
2016-08-13 03:32:38 +02:00
pci_add ( ne2000_pci_read , ne2000_pci_write , ne2000 ) ;
2016-06-26 00:34:39 +02:00
if ( ! disable_netbios )
{
2016-08-13 03:32:38 +02:00
ne2000_rom_init ( ne2000 , " roms/rtl8029as.rom " ) ;
if ( PCI ) mem_mapping_disable ( & ne2000 - > bios_rom . mapping ) ;
}
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-28 23:34:00 +01:00
// ne2000_pci_regs[0x3C] = ide_ter_enabled ? 11 : 10;
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 ;
ne2000 - > base_address = 0x340 ;
ne2000_io_set ( ne2000 - > base_address , ne2000 ) ;
memcpy ( ne2000 - > physaddr , maclocal , 6 ) ;
ne2000_reset ( ne2000 , BX_RESET_HARDWARE ) ;
2016-06-26 00:34:39 +02:00
vlan_handler ( ne2000_poller , ne2000 ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 pci init 0x%X \t slirp is %d net_is_pcap is %d \n " , ne2000 - > base_address , net_is_slirp , net_is_pcap ) ;
2016-06-26 00:34:39 +02:00
//need a switch statment for more network types.
if ( net_is_slirp ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 initalizing SLiRP \n " ) ;
2016-06-26 00:34:39 +02:00
net_is_pcap = 0 ;
rc = slirp_init ( ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 slirp_init returned: %d \n " , rc ) ;
2016-06-26 00:34:39 +02:00
if ( rc = = 0 )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 slirp initalized! \n " ) ;
2016-06-26 00:34:39 +02:00
net_slirp_inited = 1 ;
slirpq = QueueCreate ( ) ;
net_is_slirp = 1 ;
fizz = 0 ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 slirpq is %x \n " , & slirpq ) ;
2016-06-26 00:34:39 +02:00
}
else {
net_slirp_inited = 0 ;
net_is_slirp = 0 ;
}
}
if ( net_is_pcap ) { //pcap
char errbuf [ 32768 ] ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 initalizing libpcap \n " ) ;
2016-06-26 00:34:39 +02:00
net_is_slirp = 0 ;
net_hLib = LoadLibraryA ( net_lib_name ) ;
if ( net_hLib = = 0 )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Failed to load %s \n " , net_lib_name ) ;
2016-06-26 00:34:39 +02:00
net_is_pcap = 0 ;
//return;
}
_pcap_lib_version = ( PCAP_LIB_VERSION ) GetProcAddress ( net_hLib , " pcap_lib_version " ) ;
_pcap_open_live = ( PCAP_OPEN_LIVE ) GetProcAddress ( net_hLib , " pcap_open_live " ) ;
_pcap_sendpacket = ( PCAP_SENDPACKET ) GetProcAddress ( net_hLib , " pcap_sendpacket " ) ;
_pcap_setnonblock = ( PCAP_SETNONBLOCK ) GetProcAddress ( net_hLib , " pcap_setnonblock " ) ;
_pcap_next = ( PCAP_NEXT ) GetProcAddress ( net_hLib , " pcap_next " ) ;
_pcap_close = ( PCAP_CLOSE ) GetProcAddress ( net_hLib , " pcap_close " ) ;
_pcap_getnonblock = ( PCAP_GETNONBLOCK ) GetProcAddress ( net_hLib , " pcap_getnonblock " ) ;
_pcap_compile = ( PCAP_COMPILE ) GetProcAddress ( net_hLib , " pcap_compile " ) ;
_pcap_setfilter = ( PCAP_SETFILTER ) GetProcAddress ( net_hLib , " pcap_setfilter " ) ;
if ( _pcap_lib_version & & _pcap_open_live & & _pcap_sendpacket & & _pcap_setnonblock & & _pcap_next & & _pcap_close & & _pcap_getnonblock )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Pcap version [%s] \n " , _pcap_lib_version ( ) ) ;
2016-06-26 00:34:39 +02:00
//if((net_pcap=_pcap_open_live("\\Device\\NPF_{0CFA803F-F443-4BB9-A83A-657029A98195}",1518,1,15,errbuf))==0)
if ( ( net_pcap = _pcap_open_live ( config_get_string ( NULL , " pcap_device " , " nothing " ) , 1518 , 1 , 15 , errbuf ) ) = = 0 )
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 pcap_open_live error on %s! \n " , config_get_string ( NULL , " pcap_device " , " whatever the ethernet is " ) ) ;
2016-06-26 00:34:39 +02:00
net_is_pcap = 0 ; return ( ne2000 ) ; //YUCK!!!
}
}
else {
2016-08-15 02:26:54 +02:00
ne2000_log ( " %d %d %d %d %d %d %d \n " , _pcap_lib_version , _pcap_open_live , _pcap_sendpacket , _pcap_setnonblock , _pcap_next , _pcap_close , _pcap_getnonblock ) ;
2016-06-26 00:34:39 +02:00
net_is_pcap = 1 ;
}
//Time to check that we are in non-blocking mode.
rc = _pcap_getnonblock ( net_pcap , errbuf ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 pcap is currently in %s mode \n " , rc ? " non-blocking " : " blocking " ) ;
2016-06-26 00:34:39 +02:00
switch ( rc )
{
case 0 :
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Setting interface to non-blocking mode.. " ) ;
2016-06-26 00:34:39 +02:00
rc = _pcap_setnonblock ( net_pcap , 1 , errbuf ) ;
if ( rc = = 0 ) { //no errors!
2016-08-15 02:26:54 +02:00
ne2000_log ( " .. " ) ;
2016-06-26 00:34:39 +02:00
rc = _pcap_getnonblock ( net_pcap , errbuf ) ;
if ( rc = = 1 ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " ..! " , rc ) ;
2016-06-26 00:34:39 +02:00
net_is_pcap = 1 ;
}
else {
2016-08-15 02:26:54 +02:00
ne2000_log ( " \t unable to set pcap into non-blocking mode! \n Continuining without pcap. \n " ) ;
2016-06-26 00:34:39 +02:00
net_is_pcap = 0 ;
}
} //end set nonblock
2016-08-15 02:26:54 +02:00
else { ne2000_log ( " There was an unexpected error of [%s] \n \n exiting. \n " , errbuf ) ; net_is_pcap = 0 ; }
ne2000_log ( " \n " ) ;
2016-06-26 00:34:39 +02:00
break ;
case 1 :
2016-08-15 02:26:54 +02:00
ne2000_log ( " non blocking \n " ) ;
2016-06-26 00:34:39 +02:00
break ;
default :
2016-08-15 02:26:54 +02:00
ne2000_log ( " this isn't right!!! \n " ) ;
2016-06-26 00:34:39 +02:00
net_is_pcap = 0 ;
break ;
}
if ( net_is_pcap ) {
if ( _pcap_compile & & _pcap_setfilter ) { //we can do this!
struct bpf_program fp ;
char filter_exp [ 255 ] ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Building packet filter... " ) ;
2016-06-26 00:34:39 +02:00
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) ) " , \
maclocal [ 0 ] , maclocal [ 1 ] , maclocal [ 2 ] , maclocal [ 3 ] , maclocal [ 4 ] , maclocal [ 5 ] , \
maclocal [ 0 ] , maclocal [ 1 ] , maclocal [ 2 ] , maclocal [ 3 ] , maclocal [ 4 ] , maclocal [ 5 ] ) ;
//I'm doing a MAC level filter so TCP/IP doesn't matter.
if ( _pcap_compile ( net_pcap , & fp , filter_exp , 0 , 0xffffffff ) = = - 1 ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " \n ne2000 Couldn't compile filter \n " ) ;
2016-06-26 00:34:39 +02:00
}
else {
2016-08-15 02:26:54 +02:00
ne2000_log ( " ... " ) ;
2016-06-26 00:34:39 +02:00
if ( _pcap_setfilter ( net_pcap , & fp ) = = - 1 ) {
2016-08-15 02:26:54 +02:00
ne2000_log ( " \n Error installing pcap filter. \n " ) ;
2016-06-26 00:34:39 +02:00
} //end of set_filter failure
else {
2016-08-15 02:26:54 +02:00
ne2000_log ( " ...! \n " ) ;
2016-06-26 00:34:39 +02:00
}
}
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Using filter \t [%s] \n " , filter_exp ) ;
2016-06-26 00:34:39 +02:00
//scanf(filter_exp); //pause
}
else
{
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 Your platform lacks pcap_compile & pcap_setfilter \n " ) ;
2016-06-26 00:34:39 +02:00
net_is_pcap = 0 ;
}
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 net_is_pcap is %d and net_pcap is %x \n " , net_is_pcap , net_pcap ) ;
2016-06-26 00:34:39 +02:00
}
} //end pcap setup
//timer_add(slirp_tic,&delay,TIMER_ALWAYS_ENABLED,NULL);
//timer_add(keyboard_amstrad_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL);
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 is_slirp %d is_pcap %d \n " , net_is_slirp , net_is_pcap ) ;
2016-06-26 00:34:39 +02:00
//exit(0);
return ne2000 ;
}
2016-08-13 03:32:38 +02:00
2016-06-26 00:34:39 +02:00
void ne2000_close ( void * p )
{
ne2000_t * ne2000 = ( ne2000_t * ) p ;
2016-08-15 01:34:46 +02:00
ne2000_io_remove ( ne2000 - > base_address , ne2000 ) ;
2016-06-26 00:34:39 +02:00
free ( ne2000 ) ;
2016-08-13 03:32:38 +02:00
if ( net_is_slirp ) {
QueueDestroy ( slirpq ) ;
slirp_exit ( 0 ) ;
net_slirp_inited = 0 ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 exiting slirp \n " ) ;
2016-08-13 03:32:38 +02:00
}
if ( net_is_pcap & & net_pcap ! = NULL )
{
_pcap_close ( net_pcap ) ;
FreeLibrary ( net_hLib ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 closing pcap \n " ) ;
2016-08-13 03:32:38 +02:00
}
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 close \n " ) ;
2016-06-26 00:34:39 +02:00
}
static device_config_t ne2000_config [ ] =
{
{
. name = " addr " ,
. description = " Address " ,
. type = CONFIG_BINARY ,
. type = CONFIG_SELECTION ,
. selection =
{
{
. description = " 0x280 " ,
. value = 0x280
} ,
{
. description = " 0x300 " ,
. value = 0x300
} ,
{
. description = " 0x320 " ,
. value = 0x320
} ,
{
. description = " 0x340 " ,
. value = 0x340
} ,
{
. description = " 0x360 " ,
. value = 0x360
} ,
{
. description = " 0x380 " ,
. value = 0x380
} ,
{
. description = " "
}
} ,
. default_int = 0x300
} ,
{
. name = " irq " ,
. description = " IRQ " ,
. type = CONFIG_SELECTION ,
. selection =
{
{
. description = " IRQ 3 " ,
. value = 3
} ,
{
. description = " IRQ 5 " ,
. value = 5
} ,
{
. description = " IRQ 7 " ,
. value = 7
} ,
{
. description = " IRQ 10 " ,
. value = 10
} ,
{
. description = " IRQ 11 " ,
. value = 11
} ,
{
. description = " "
}
} ,
. default_int = 10
} ,
{
. name = " net_type " ,
. description = " Network type " ,
. type = CONFIG_BINARY ,
. type = CONFIG_SELECTION ,
. selection =
{
{
. description = " PCap " ,
. value = 0
} ,
{
. description = " SLiRP " ,
. value = 1
} ,
{
. description = " "
}
} ,
. default_int = 0
} ,
{
. name = " disable_netbios " ,
. description = " Network bios " ,
. type = CONFIG_BINARY ,
. type = CONFIG_SELECTION ,
. selection =
{
{
. description = " Enabled " ,
. value = 0
} ,
{
. description = " Disabled " ,
. value = 1
} ,
{
. description = " "
}
} ,
. default_int = 0
} ,
{
. type = - 1
}
} ;
static device_config_t rtl8029as_config [ ] =
{
2016-12-28 23:34:00 +01:00
{
. name = " irq " ,
. description = " IRQ " ,
. type = CONFIG_SELECTION ,
. selection =
{
{
. description = " IRQ 3 " ,
. value = 3
} ,
{
. description = " IRQ 5 " ,
. value = 5
} ,
{
. description = " IRQ 7 " ,
. value = 7
} ,
{
. description = " IRQ 10 " ,
. value = 10
} ,
{
. description = " IRQ 11 " ,
. value = 11
} ,
{
. description = " "
}
} ,
. default_int = 10
} ,
2016-06-26 00:34:39 +02:00
{
. name = " net_type " ,
. description = " Network type " ,
. type = CONFIG_BINARY ,
. type = CONFIG_SELECTION ,
. selection =
{
{
. description = " PCap " ,
. value = 0
} ,
{
. description = " SLiRP " ,
. value = 1
} ,
{
. description = " "
}
} ,
. default_int = 0
} ,
{
. name = " disable_netbios " ,
. description = " Network bios " ,
. type = CONFIG_BINARY ,
. type = CONFIG_SELECTION ,
. selection =
{
{
. description = " Enabled " ,
. value = 0
} ,
{
. description = " Disabled " ,
. value = 1
} ,
{
. description = " "
}
} ,
. default_int = 0
} ,
{
. type = - 1
}
} ;
device_t ne2000_device =
{
" Novell NE2000 " ,
0 ,
ne2000_init ,
ne2000_close ,
NULL ,
NULL ,
NULL ,
NULL ,
ne2000_config
} ;
device_t rtl8029as_device =
{
" Realtek RTL8029AS " ,
0 ,
2016-08-13 03:32:38 +02:00
rtl8029as_init ,
2016-06-26 00:34:39 +02:00
ne2000_close ,
NULL ,
NULL ,
NULL ,
NULL ,
rtl8029as_config
} ;
//SLIRP stuff
int slirp_can_output ( void )
{
return net_slirp_inited ;
}
void slirp_output ( const unsigned char * pkt , int pkt_len )
{
struct queuepacket * p ;
p = ( struct queuepacket * ) malloc ( sizeof ( struct queuepacket ) ) ;
p - > len = pkt_len ;
memcpy ( p - > data , pkt , pkt_len ) ;
QueueEnter ( slirpq , p ) ;
2016-08-15 02:26:54 +02:00
ne2000_log ( " ne2000 slirp_output %d @%d \n " , pkt_len , p ) ;
2016-06-26 00:34:39 +02:00
}
// Instead of calling this and crashing some times
// or experencing jitter, this is called by the
// 60Hz clock which seems to do the job.
void slirp_tic ( )
{
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 ) ;
timeout = slirp_select_fill ( & nfds , & rfds , & wfds , & xfds ) ; //this can crash
if ( timeout < 0 )
timeout = 500 ;
tv . tv_sec = 0 ;
tv . tv_usec = timeout ; //basilisk default 10000
ret2 = select ( nfds + 1 , & rfds , & wfds , & xfds , & tv ) ;
if ( ret2 > = 0 ) {
slirp_select_poll ( & rfds , & wfds , & xfds ) ;
}
2016-08-15 02:26:54 +02:00
//ne2000_log("ne2000 slirp_tic()\n");
2016-06-26 00:34:39 +02:00
} //end if slirp inited
}