2017-05-05 01:49:42 +02:00
/*
2017-05-09 22:09:55 -04:00
* 86 Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus .
*
* This file is part of the 86 Box distribution .
*
* Implementation of an NE2000 / RTL8029AS network controller .
*
* NOTE : Its still a mess , but we ' re getting there . The file will
* also implement an NE1000 for 8 - bit ISA systems .
*
* Version : @ ( # ) net_ne2000 . c 1.0 .1 2017 / 05 / 09
*
* Authors : Fred N . van Kempen , < decwiz @ yahoo . com >
* Peter Grehan , grehan @ iprg . nokia . com >
* SA1988 , Tenshi
*
* Based on @ ( # ) ne2k . cc v1 .56 .2 .1 2004 / 02 / 02 22 : 37 : 22 cbothamy
* Portions Copyright ( C ) 2002 MandrakeSoft S . A .
*/
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>
2017-05-06 17:48:33 +02:00
# include <pcap.h>
2016-06-26 00:34:39 +02:00
# include "slirp/slirp.h"
# include "slirp/queue.h"
# include "ibm.h"
# include "io.h"
# include "mem.h"
# include "rom.h"
# include "pci.h"
# include "pic.h"
# include "timer.h"
2017-05-06 17:48:33 +02:00
# include "device.h"
# include "config.h"
# include "disc_random.h"
# include "network.h"
# include "net_ne2000.h"
2017-05-09 22:09:55 -04:00
# include "bswap.h"
2017-05-06 17:48:33 +02:00
2016-06-26 00:34:39 +02:00
2017-05-09 22:09:55 -04:00
# ifdef WALTJE
# define ENABLE_NE2000_LOG 1
# endif
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
2017-05-09 22:09:55 -04:00
/* For PCI. */
typedef union {
uint32_t addr ;
uint8_t addr_regs [ 4 ] ;
} bar_t ;
/* Most of this stuff should go into the struct. --FvK */
static uint8_t maclocal [ 6 ] = { 0xac , 0xde , 0x48 , 0x88 , 0xbb , 0xaa } ;
static uint8_t maclocal_pci [ 6 ] = { 0xac , 0xde , 0x48 , 0x88 , 0xbb , 0xaa } ;
static uint8_t rtl8029as_eeprom [ 128 ] ;
static uint8_t pci_regs [ 256 ] ;
static bar_t pci_bar [ 2 ] ;
static uint32_t bios_addr = 0xD0000 ;
static uint32_t old_base_addr = 0 ;
static uint32_t bios_size = 0 ;
static uint32_t bios_mask = 0 ;
static pcap_t * net_pcap ;
static queueADT slirpq ;
static int disable_netbios = 0 ;
static int net_slirp_inited = 0 ;
static int net_is_pcap = 0 ; /* and pretend pcap is dead. */
static int fizz = 0 ;
# ifdef ENABLE_NE2000_LOG
static int ne2000_do_log = ENABLE_NE2000_LOG ;
# else
static int ne2000_do_log = 0 ;
# endif
2016-06-26 00:34:39 +02:00
# 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)
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* ne2k register state */
typedef struct {
/* 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 txed with no errors */
int rx_err ; /* RXE - packet rxed with 1 or more errors */
int tx_err ; /* TXE - packet txed " " " " " */
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 pkts 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 regr */
uint8_t page_stop ; /* 02h write ; page stop regr */
uint8_t bound_ptr ; /* 03h read/write ; boundary pointer */
uint8_t tx_page_start ; /* 04h write ; transmit page start reg */
uint8_t num_coll ; /* 05h read ; number-of-collisions reg */
uint16_t tx_bytes ; /* 05,06h write ; transmit byte-count reg */
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 reg */
uint16_t remote_bytes ; /* 0a,0bh write ; remote byte-count reg */
uint8_t tallycnt_0 ; /* 0dh read ; tally ctr 0 (frame align errs) */
uint8_t tallycnt_1 ; /* 0eh read ; tally ctr 1 (CRC errors) */
uint8_t tallycnt_2 ; /* 0fh read ; tally ctr 2 (missed pkt errs) */
/* 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 ptr */
uint8_t localpkt_ptr ; /* 05h read/write ; local next-packet ptr */
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 ;
2016-06-26 00:34:39 +02:00
} ne2000_t ;
2017-05-08 18:27:42 -04:00
2017-05-09 22:09:55 -04:00
static void ne2000_tx_event ( void * , uint32_t ) ;
static void ne2000_rx_frame ( void * , const void * , int ) ;
2017-05-08 18:27:42 -04:00
2017-05-09 22:09:55 -04:00
void slirp_tic ( void ) ;
2016-08-15 02:26:54 +02:00
2017-05-06 17:48:33 +02:00
2017-05-09 22:09:55 -04:00
static void
nelog ( int lvl , const char * fmt , . . . )
2016-08-15 02:26:54 +02:00
{
2017-01-16 01:49:19 +01:00
# ifdef ENABLE_NE2000_LOG
2017-05-09 22:09:55 -04:00
va_list ap ;
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
if ( ne2000_do_log > = lvl ) {
va_start ( ap , fmt ) ;
vprintf ( fmt , ap ) ;
va_end ( ap ) ;
}
2017-05-05 01:49:42 +02:00
}
2017-05-09 22:09:55 -04:00
# endif
# define pclog nelog
2017-05-05 01:49:42 +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 */
2017-05-09 22:09:55 -04:00
static void
ne2000_reset ( void * priv , int reset )
2016-06-26 00:34:39 +02:00
{
2017-05-09 22:09:55 -04:00
ne2000_t * dev = ( ne2000_t * ) priv ;
int i ;
pclog ( 1 , " ne2000 reset \n " ) ;
/* Initialize the MAC address area by doubling the physical address */
dev - > macaddr [ 0 ] = dev - > physaddr [ 0 ] ;
dev - > macaddr [ 1 ] = dev - > physaddr [ 0 ] ;
dev - > macaddr [ 2 ] = dev - > physaddr [ 1 ] ;
dev - > macaddr [ 3 ] = dev - > physaddr [ 1 ] ;
dev - > macaddr [ 4 ] = dev - > physaddr [ 2 ] ;
dev - > macaddr [ 5 ] = dev - > physaddr [ 2 ] ;
dev - > macaddr [ 6 ] = dev - > physaddr [ 3 ] ;
dev - > macaddr [ 7 ] = dev - > physaddr [ 3 ] ;
dev - > macaddr [ 8 ] = dev - > physaddr [ 4 ] ;
dev - > macaddr [ 9 ] = dev - > physaddr [ 4 ] ;
dev - > macaddr [ 10 ] = dev - > physaddr [ 5 ] ;
dev - > macaddr [ 11 ] = dev - > physaddr [ 5 ] ;
/* ne2k signature */
for ( i = 12 ; i < 32 ; i + + ) {
dev - > macaddr [ i ] = 0x57 ;
}
/* Zero out registers and memory */
memset ( & dev - > CR , 0x00 , sizeof ( dev - > CR ) ) ;
memset ( & dev - > ISR , 0x00 , sizeof ( dev - > ISR ) ) ;
memset ( & dev - > IMR , 0x00 , sizeof ( dev - > IMR ) ) ;
memset ( & dev - > DCR , 0x00 , sizeof ( dev - > DCR ) ) ;
memset ( & dev - > TCR , 0x00 , sizeof ( dev - > TCR ) ) ;
memset ( & dev - > TSR , 0x00 , sizeof ( dev - > TSR ) ) ;
memset ( & dev - > RSR , 0x00 , sizeof ( dev - > RSR ) ) ;
dev - > tx_timer_active = 0 ;
dev - > local_dma = 0 ;
dev - > page_start = 0 ;
dev - > page_stop = 0 ;
dev - > bound_ptr = 0 ;
dev - > tx_page_start = 0 ;
dev - > num_coll = 0 ;
dev - > tx_bytes = 0 ;
dev - > fifo = 0 ;
dev - > remote_dma = 0 ;
dev - > remote_start = 0 ;
dev - > remote_bytes = 0 ;
dev - > tallycnt_0 = 0 ;
dev - > tallycnt_1 = 0 ;
dev - > tallycnt_2 = 0 ;
dev - > curr_page = 0 ;
dev - > rempkt_ptr = 0 ;
dev - > localpkt_ptr = 0 ;
dev - > address_cnt = 0 ;
memset ( & dev - > mem , 0x00 , sizeof ( dev - > mem ) ) ;
/* Set power-up conditions */
dev - > CR . stop = 1 ;
dev - > CR . rdma_cmd = 4 ;
dev - > ISR . reset = 1 ;
dev - > DCR . longaddr = 1 ;
picint ( 1 < < dev - > base_irq ) ;
picintc ( 1 < < dev - > base_irq ) ;
2016-06-26 00:34:39 +02:00
}
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
*/
2017-05-09 22:09:55 -04:00
static uint32_t
chipmem_read ( ne2000_t * dev , uint32_t addr , unsigned int len )
2016-08-13 03:32:38 +02:00
{
2017-05-09 22:09:55 -04:00
uint32_t retval = 0 ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( ( len = = 2 ) & & ( addr & 0x1 ) ) {
pclog ( 1 , " unaligned chipmem word read \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* ROM'd MAC address */
if ( ( addr > = 0 ) & & ( addr < = 31 ) ) {
retval = dev - > macaddr [ addr % 32 ] ;
if ( ( len = = 2 ) | | ( len = = 4 ) ) {
retval | = ( dev - > macaddr [ ( addr + 1 ) % 32 ] < < 8 ) ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
if ( len = = 4 ) {
retval | = ( dev - > macaddr [ ( addr + 2 ) % 32 ] < < 16 ) ;
retval | = ( dev - > macaddr [ ( addr + 3 ) % 32 ] < < 24 ) ;
}
return ( retval ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( ( addr > = BX_NE2K_MEMSTART ) & & ( addr < BX_NE2K_MEMEND ) ) {
retval = dev - > mem [ addr - BX_NE2K_MEMSTART ] ;
if ( ( len = = 2 ) | | ( len = = 4 ) ) {
retval | = ( dev - > mem [ addr - BX_NE2K_MEMSTART + 1 ] < < 8 ) ;
}
if ( len = = 4 ) {
retval | = ( dev - > mem [ addr - BX_NE2K_MEMSTART + 2 ] < < 16 ) ;
retval | = ( dev - > mem [ addr - BX_NE2K_MEMSTART + 3 ] < < 24 ) ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
return ( retval ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
pclog ( 1 , " out-of-bounds chipmem read, %04X \n " , addr ) ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( network_card_current = = 1 ) {
switch ( len ) {
case 1 :
return ( 0xff ) ;
case 2 :
return ( 0xffff ) ;
2017-02-14 07:06:24 +01:00
}
2017-05-09 22:09:55 -04:00
} else {
return ( 0xff ) ;
}
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
return ( 0xffff ) ;
2016-08-13 03:32:38 +02:00
}
2016-06-26 00:34:39 +02:00
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static void
chipmem_write ( ne2000_t * dev , uint32_t addr , uint32_t val , unsigned len )
{
if ( ( len = = 2 ) & & ( addr & 0x1 ) ) {
pclog ( 1 , " unaligned chipmem word write \n " ) ;
}
if ( ( addr > = BX_NE2K_MEMSTART ) & & ( addr < BX_NE2K_MEMEND ) ) {
dev - > mem [ addr - BX_NE2K_MEMSTART ] = val & 0xff ;
if ( ( len = = 2 ) | | ( len = = 4 ) ) {
dev - > mem [ addr - BX_NE2K_MEMSTART + 1 ] = val > > 8 ;
}
if ( len = = 4 ) {
dev - > mem [ addr - BX_NE2K_MEMSTART + 2 ] = val > > 16 ;
dev - > mem [ addr - BX_NE2K_MEMSTART + 3 ] = val > > 24 ;
}
} else {
pclog ( 1 , " out-of-bounds chipmem write, %04X \n " , addr ) ;
}
2016-06-26 00:34:39 +02:00
}
2017-05-09 22:09:55 -04: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 .
*/
2017-05-09 22:09:55 -04:00
static uint32_t
asic_read ( ne2000_t * dev , uint32_t off , unsigned int len )
2016-06-26 00:34:39 +02:00
{
2017-05-09 22:09:55 -04:00
uint32_t retval = 0 ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
switch ( off ) {
case 0x0 : /* Data register */
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
/* 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
2017-05-09 22:09:55 -04:00
if ( len > dev - > remote_bytes ) {
pclog ( 1 , " dma read underrun iolen=%d remote_bytes=%d \n " ,
len , dev - > remote_bytes ) ;
}
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
pclog ( 2 , " %s read DMA: addr=%4x remote_bytes=%d \n " ,
( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " ,
dev - > remote_dma , dev - > remote_bytes ) ;
retval = chipmem_read ( dev , dev - > remote_dma , len ) ;
/* 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 ) . */
if ( len = = 4 ) {
dev - > remote_dma + = len ;
} else {
dev - > remote_dma + = ( dev - > DCR . wdsize + 1 ) ;
}
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
if ( dev - > remote_dma = = dev - > page_stop < < 8 ) {
dev - > remote_dma = dev - > page_start < < 8 ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* keep s.remote_bytes from underflowing */
if ( dev - > remote_bytes > dev - > DCR . wdsize ) {
if ( len = = 4 ) {
dev - > remote_bytes - = len ;
} else {
dev - > remote_bytes - = ( dev - > DCR . wdsize + 1 ) ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
} else {
dev - > remote_bytes = 0 ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* If all bytes have been written, signal remote-DMA complete */
if ( dev - > remote_bytes = = 0 ) {
dev - > ISR . rdma_done = 1 ;
if ( dev - > IMR . rdma_inte ) {
picint ( 1 < < dev - > base_irq ) ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
}
break ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
case 0xf : /* Reset register */
ne2000_reset ( dev , BX_RESET_SOFTWARE ) ;
break ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
default :
pclog ( 1 , " asic read invalid address %04x \n " , ( unsigned ) off ) ;
break ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
return ( retval ) ;
2016-06-26 00:34:39 +02:00
}
2017-05-09 22:09:55 -04:00
static void
asic_write ( ne2000_t * dev , uint32_t off , uint32_t val , unsigned len )
2016-06-26 00:34:39 +02:00
{
2017-05-09 22:09:55 -04:00
pclog ( 2 , " %s: asic write addr=0x%02x, value=0x%04x \n " ,
( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , ( unsigned ) off , ( unsigned ) val ) ;
switch ( off ) {
case 0x0 : /* Data register - see asic_read for a description */
if ( ( len > 1 ) & & ( dev - > DCR . wdsize = = 0 ) ) {
pclog ( 2 , " dma write length %d on byte mode operation \n " ,
len ) ;
break ;
}
if ( dev - > remote_bytes = = 0 ) {
pclog ( 2 , " dma write, byte count 0 \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
chipmem_write ( dev , dev - > remote_dma , val , len ) ;
if ( len = = 4 ) {
dev - > remote_dma + = len ;
} else {
dev - > remote_dma + = ( dev - > DCR . wdsize + 1 ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( dev - > remote_dma = = dev - > page_stop < < 8 ) {
dev - > remote_dma = dev - > page_start < < 8 ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( len = = 4 ) {
dev - > remote_bytes - = len ;
} else {
dev - > remote_bytes - = ( dev - > DCR . wdsize + 1 ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( dev - > remote_bytes > BX_NE2K_MEMSIZ ) {
dev - > remote_bytes = 0 ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* If all bytes have been written, signal remote-DMA complete */
if ( dev - > remote_bytes = = 0 ) {
dev - > ISR . rdma_done = 1 ;
if ( dev - > IMR . rdma_inte ) {
picint ( 1 < < dev - > base_irq ) ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
}
break ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
case 0xf : /* Reset register */
/* end of reset pulse */
break ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
default : /* this is invalid, but happens under win95 device detection */
pclog ( 1 , " asic write invalid address %04x, ignoring \n " ,
( unsigned ) off ) ;
break ;
}
2016-06-26 00:34:39 +02:00
}
2017-05-09 22:09:55 -04: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 */
2017-05-09 22:09:55 -04:00
static uint32_t
page0_read ( ne2000_t * dev , uint32_t off , unsigned int len )
2016-06-26 00:34:39 +02:00
{
2017-05-09 22:09:55 -04:00
uint8_t retval = 0 ;
if ( len > 1 ) {
/* encountered with win98 hardware probe */
pclog ( 1 , " bad length! page 0 read from register 0x%02x, len=%u \n " ,
off , len ) ;
return ( retval ) ;
}
switch ( off ) {
case 0x01 : /* CLDA0 */
retval = ( dev - > local_dma & 0xff ) ;
break ;
case 0x02 : /* CLDA1 */
retval = ( dev - > local_dma > > 8 ) ;
break ;
case 0x03 : /* BNRY */
retval = dev - > bound_ptr ;
break ;
case 0x04 : /* TSR */
retval = ( ( dev - > TSR . ow_coll < < 7 ) |
( dev - > TSR . cd_hbeat < < 6 ) |
( dev - > TSR . fifo_ur < < 5 ) |
( dev - > TSR . no_carrier < < 4 ) |
( dev - > TSR . aborted < < 3 ) |
( dev - > TSR . collided < < 2 ) |
( dev - > TSR . tx_ok ) ) ;
break ;
case 0x05 : /* NCR */
retval = dev - > num_coll ;
break ;
case 0x06 : /* FIFO */
/* reading FIFO is only valid in loopback mode */
pclog ( 1 , " reading FIFO not supported yet \n " ) ;
retval = dev - > fifo ;
break ;
case 0x07 : /* ISR */
retval = ( ( dev - > ISR . reset < < 7 ) |
( dev - > ISR . rdma_done < < 6 ) |
( dev - > ISR . cnt_oflow < < 5 ) |
( dev - > ISR . overwrite < < 4 ) |
( dev - > ISR . tx_err < < 3 ) |
( dev - > ISR . rx_err < < 2 ) |
( dev - > ISR . pkt_tx < < 1 ) |
( dev - > ISR . pkt_rx ) ) ;
break ;
case 0x08 : /* CRDA0 */
retval = ( dev - > remote_dma & 0xff ) ;
break ;
case 0x09 : /* CRDA1 */
retval = ( dev - > remote_dma > > 8 ) ;
break ;
case 0x0a : /* reserved / RTL8029ID0 */
if ( network_card_current = = 2 ) {
retval = 0x50 ;
} else {
pclog ( 1 , " reserved read - page 0, 0x0a \n " ) ;
retval = 0xff ;
}
break ;
case 0x0b : /* reserved / RTL8029ID1 */
if ( network_card_current = = 2 ) {
retval = 0x43 ;
} else {
pclog ( 1 , " reserved read - page 0, 0xb \n " ) ;
retval = 0xff ;
}
break ;
case 0x0c : /* RSR */
retval = ( ( dev - > RSR . deferred < < 7 ) |
( dev - > RSR . rx_disabled < < 6 ) |
( dev - > RSR . rx_mbit < < 5 ) |
( dev - > RSR . rx_missed < < 4 ) |
( dev - > RSR . fifo_or < < 3 ) |
( dev - > RSR . bad_falign < < 2 ) |
( dev - > RSR . bad_crc < < 1 ) |
( dev - > RSR . rx_ok ) ) ;
break ;
case 0x0d : /* CNTR0 */
retval = dev - > tallycnt_0 ;
break ;
case 0x0e : /* CNTR1 */
retval = dev - > tallycnt_1 ;
break ;
case 0x0f : /* CNTR2 */
retval = dev - > tallycnt_2 ;
break ;
default :
pclog ( 1 , " page 0 register 0x%02x out of range \n " , off ) ;
break ;
}
pclog ( 2 , " page 0 read from register 0x%02x, value=0x%02x \n " , off , retval ) ;
return ( retval ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static void
page0_write ( ne2000_t * dev , uint32_t off , uint32_t val , unsigned len )
{
uint8_t val2 ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* It appears to be a common practice to use outw on page0 regs... */
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* break up outw into two outb's */
if ( len = = 2 ) {
page0_write ( dev , off , ( val & 0xff ) , 1 ) ;
if ( off < 0x0f )
page0_write ( dev , off + 1 , ( ( val > > 8 ) & 0xff ) , 1 ) ;
return ;
}
pclog ( 2 , " page 0 write to register 0x%02x, value=0x%02x \n " , off , val ) ;
switch ( off ) {
case 0x01 : /* PSTART */
dev - > page_start = val ;
break ;
case 0x02 : /* PSTOP */
dev - > page_stop = val ;
break ;
case 0x03 : /* BNRY */
dev - > bound_ptr = val ;
break ;
case 0x04 : /* TPSR */
dev - > tx_page_start = val ;
break ;
case 0x05 : /* TBCR0 */
/* Clear out low byte and re-insert */
dev - > tx_bytes & = 0xff00 ;
dev - > tx_bytes | = ( val & 0xff ) ;
break ;
case 0x06 : /* TBCR1 */
/* Clear out high byte and re-insert */
dev - > tx_bytes & = 0x00ff ;
dev - > tx_bytes | = ( ( val & 0xff ) < < 8 ) ;
break ;
case 0x07 : /* ISR */
val & = 0x7f ; /* clear RST bit - status-only bit */
/* All other values are cleared iff the ISR bit is 1 */
dev - > ISR . pkt_rx & = ~ ( ( int ) ( ( val & 0x01 ) = = 0x01 ) ) ;
dev - > ISR . pkt_tx & = ~ ( ( int ) ( ( val & 0x02 ) = = 0x02 ) ) ;
dev - > ISR . rx_err & = ~ ( ( int ) ( ( val & 0x04 ) = = 0x04 ) ) ;
dev - > ISR . tx_err & = ~ ( ( int ) ( ( val & 0x08 ) = = 0x08 ) ) ;
dev - > ISR . overwrite & = ~ ( ( int ) ( ( val & 0x10 ) = = 0x10 ) ) ;
dev - > ISR . cnt_oflow & = ~ ( ( int ) ( ( val & 0x20 ) = = 0x20 ) ) ;
dev - > ISR . rdma_done & = ~ ( ( int ) ( ( val & 0x40 ) = = 0x40 ) ) ;
val = ( ( dev - > ISR . rdma_done < < 6 ) |
( dev - > ISR . cnt_oflow < < 5 ) |
( dev - > ISR . overwrite < < 4 ) |
( dev - > ISR . tx_err < < 3 ) |
( dev - > ISR . rx_err < < 2 ) |
( dev - > ISR . pkt_tx < < 1 ) |
( dev - > ISR . pkt_rx ) ) ;
val & = ( ( dev - > IMR . rdma_inte < < 6 ) |
( dev - > IMR . cofl_inte < < 5 ) |
( dev - > IMR . overw_inte < < 4 ) |
( dev - > IMR . txerr_inte < < 3 ) |
( dev - > IMR . rxerr_inte < < 2 ) |
( dev - > IMR . tx_inte < < 1 ) |
( dev - > IMR . rx_inte ) ) ;
if ( val = = 0x00 ) {
picintc ( 1 < < dev - > base_irq ) ;
}
break ;
case 0x08 : /* RSAR0 */
/* Clear out low byte and re-insert */
dev - > remote_start & = 0xff00 ;
dev - > remote_start | = ( val & 0xff ) ;
dev - > remote_dma = dev - > remote_start ;
break ;
case 0x09 : /* RSAR1 */
/* Clear out high byte and re-insert */
dev - > remote_start & = 0x00ff ;
dev - > remote_start | = ( ( val & 0xff ) < < 8 ) ;
dev - > remote_dma = dev - > remote_start ;
break ;
case 0x0a : /* RBCR0 */
/* Clear out low byte and re-insert */
dev - > remote_bytes & = 0xff00 ;
dev - > remote_bytes | = ( val & 0xff ) ;
break ;
case 0x0b : /* RBCR1 */
/* Clear out high byte and re-insert */
dev - > remote_bytes & = 0x00ff ;
dev - > remote_bytes | = ( ( val & 0xff ) < < 8 ) ;
break ;
case 0x0c : /* RCR */
/* Check if the reserved bits are set */
if ( val & 0xc0 ) {
pclog ( 1 , " RCR write, reserved bits set \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* Set all other bit-fields */
dev - > RCR . errors_ok = ( ( val & 0x01 ) = = 0x01 ) ;
dev - > RCR . runts_ok = ( ( val & 0x02 ) = = 0x02 ) ;
dev - > RCR . broadcast = ( ( val & 0x04 ) = = 0x04 ) ;
dev - > RCR . multicast = ( ( val & 0x08 ) = = 0x08 ) ;
dev - > RCR . promisc = ( ( val & 0x10 ) = = 0x10 ) ;
dev - > RCR . monitor = ( ( val & 0x20 ) = = 0x20 ) ;
/* Monitor bit is a little suspicious... */
if ( val & 0x20 ) {
pclog ( 1 , " RCR write, monitor bit set! \n " ) ;
}
break ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
case 0x0d : /* TCR */
/* Check reserved bits */
if ( val & 0xe0 ) {
pclog ( 1 , " TCR write, reserved bits set \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* Test loop mode (not supported) */
if ( val & 0x06 ) {
dev - > TCR . loop_cntl = ( val & 0x6 ) > > 1 ;
pclog ( 1 , " TCR write, loop mode %d not supported \n " ,
dev - > TCR . loop_cntl ) ;
} else {
dev - > TCR . loop_cntl = 0 ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* Inhibit-CRC not supported. */
if ( val & 0x01 ) {
pclog ( 1 , " TCR write, inhibit-CRC not supported \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* Auto-transmit disable very suspicious */
if ( val & 0x08 ) {
pclog ( 1 , " TCR write, auto transmit disable not supported \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* Allow collision-offset to be set, although not used */
dev - > TCR . coll_prio = ( ( val & 0x08 ) = = 0x08 ) ;
break ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
case 0x0e : /* DCR */
/* the loopback mode is not suppported yet */
if ( ! ( val & 0x08 ) ) {
pclog ( 1 , " DCR write, loopback mode selected \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* It is questionable to set longaddr and auto_rx, since
* they are not supported on the NE2000 . Print a warning
* and continue . */
if ( val & 0x04 ) {
pclog ( 1 , " DCR write - LAS set ??? \n " ) ;
}
if ( val & 0x10 ) {
pclog ( 1 , " DCR write - AR set ??? \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* Set other values. */
dev - > DCR . wdsize = ( ( val & 0x01 ) = = 0x01 ) ;
dev - > DCR . endian = ( ( val & 0x02 ) = = 0x02 ) ;
dev - > DCR . longaddr = ( ( val & 0x04 ) = = 0x04 ) ; /* illegal ? */
dev - > DCR . loop = ( ( val & 0x08 ) = = 0x08 ) ;
dev - > DCR . auto_rx = ( ( val & 0x10 ) = = 0x10 ) ; /* also illegal ? */
dev - > DCR . fifo_size = ( val & 0x50 ) > > 5 ;
break ;
case 0x0f : /* IMR */
/* Check for reserved bit */
if ( val & 0x80 ) {
pclog ( 1 , " IMR write, reserved bit set \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* Set other values */
dev - > IMR . rx_inte = ( ( val & 0x01 ) = = 0x01 ) ;
dev - > IMR . tx_inte = ( ( val & 0x02 ) = = 0x02 ) ;
dev - > IMR . rxerr_inte = ( ( val & 0x04 ) = = 0x04 ) ;
dev - > IMR . txerr_inte = ( ( val & 0x08 ) = = 0x08 ) ;
dev - > IMR . overw_inte = ( ( val & 0x10 ) = = 0x10 ) ;
dev - > IMR . cofl_inte = ( ( val & 0x20 ) = = 0x20 ) ;
dev - > IMR . rdma_inte = ( ( val & 0x40 ) = = 0x40 ) ;
val2 = ( ( dev - > ISR . rdma_done < < 6 ) |
( dev - > ISR . cnt_oflow < < 5 ) |
( dev - > ISR . overwrite < < 4 ) |
( dev - > ISR . tx_err < < 3 ) |
( dev - > ISR . rx_err < < 2 ) |
( dev - > ISR . pkt_tx < < 1 ) |
( dev - > ISR . pkt_rx ) ) ;
if ( ( ( val & val2 ) & 0x7f ) = = 0 ) {
picintc ( 1 < < dev - > base_irq ) ;
} else {
picint ( 1 < < dev - > base_irq ) ;
}
break ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
default :
pclog ( 1 , " page 0 write, bad register 0x%02x \n " , off ) ;
break ;
}
2016-06-26 00:34:39 +02:00
}
2017-05-09 22:09:55 -04:00
/* page1_read/page1_write - These routines handle reads/writes to
the first page of the DS8390 register file */
static uint32_t
page1_read ( ne2000_t * dev , uint32_t off , unsigned int len )
2016-06-26 00:34:39 +02:00
{
2017-05-09 22:09:55 -04:00
pclog ( 2 , " page 1 read from register 0x%02x, len=%u \n " , off , len ) ;
switch ( off ) {
case 0x01 : /* PAR0-5 */
case 0x02 :
case 0x03 :
case 0x04 :
case 0x05 :
case 0x06 :
return ( dev - > physaddr [ off - 1 ] ) ;
case 0x07 : /* CURR */
pclog ( 2 , " returning current page: 0x%02x \n " , ( dev - > curr_page ) ) ;
return ( dev - > curr_page ) ;
case 0x08 : /* MAR0-7 */
case 0x09 :
case 0x0a :
case 0x0b :
case 0x0c :
case 0x0d :
case 0x0e :
case 0x0f :
return ( dev - > mchash [ off - 8 ] ) ;
default :
pclog ( 1 , " page 1 read register 0x%02x out of range \n " , off ) ;
return ( 0 ) ;
}
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static void
page1_write ( ne2000_t * dev , uint32_t off , uint32_t val , unsigned len )
{
pclog ( 2 , " page 1 write to register 0x%02x, len=%u, value=0x%04x \n " ,
off , len , val ) ;
switch ( off ) {
case 0x01 : /* PAR0-5 */
case 0x02 :
case 0x03 :
case 0x04 :
case 0x05 :
case 0x06 :
dev - > physaddr [ off - 1 ] = val ;
if ( off = = 6 ) {
pclog ( 1 , " Physical address set to %02x:%02x:%02x:%02x:%02x:%02x \n " ,
dev - > physaddr [ 0 ] , dev - > physaddr [ 1 ] ,
dev - > physaddr [ 2 ] , dev - > physaddr [ 3 ] ,
dev - > physaddr [ 4 ] , dev - > physaddr [ 5 ] ) ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
break ;
case 0x07 : /* CURR */
dev - > curr_page = val ;
break ;
case 0x08 : /* MAR0-7 */
case 0x09 :
case 0x0a :
case 0x0b :
case 0x0c :
case 0x0d :
case 0x0e :
case 0x0f :
dev - > mchash [ off - 8 ] = val ;
break ;
default :
pclog ( 1 , " page 1 write register 0x%02x out of range \n " , off ) ;
break ;
}
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* page2_read/page2_write - These routines handle reads/writes to
the second page of the DS8390 register file */
static uint32_t
page2_read ( ne2000_t * dev , uint32_t off , unsigned int len )
{
pclog ( 2 , " page 2 read from register 0x%02x, len=%u \n " , off , len ) ;
switch ( off ) {
case 0x01 : /* PSTART */
return ( dev - > page_start ) ;
case 0x02 : /* PSTOP */
return ( dev - > page_stop ) ;
case 0x03 : /* Remote Next-packet pointer */
return ( dev - > rempkt_ptr ) ;
case 0x04 : /* TPSR */
return ( dev - > tx_page_start ) ;
case 0x05 : /* Local Next-packet pointer */
return ( dev - > localpkt_ptr ) ;
case 0x06 : /* Address counter (upper) */
return ( dev - > address_cnt > > 8 ) ;
case 0x07 : /* Address counter (lower) */
return ( dev - > address_cnt & 0xff ) ;
case 0x08 : /* Reserved */
case 0x09 :
case 0x0a :
case 0x0b :
pclog ( 1 , " reserved read - page 2, register 0x%02x \n " , off ) ;
return ( 0xff ) ;
case 0x0c : /* RCR */
return ( ( dev - > RCR . monitor < < 5 ) |
( dev - > RCR . promisc < < 4 ) |
( dev - > RCR . multicast < < 3 ) |
( dev - > RCR . broadcast < < 2 ) |
( dev - > RCR . runts_ok < < 1 ) |
( dev - > RCR . errors_ok ) ) ;
case 0x0d : /* TCR */
return ( ( dev - > TCR . coll_prio < < 4 ) |
( dev - > TCR . ext_stoptx < < 3 ) |
( ( dev - > TCR . loop_cntl & 0x3 ) < < 1 ) |
( dev - > TCR . crc_disable ) ) ;
case 0x0e : /* DCR */
return ( ( ( dev - > DCR . fifo_size & 0x3 ) < < 5 ) |
( dev - > DCR . auto_rx < < 4 ) |
( dev - > DCR . loop < < 3 ) |
( dev - > DCR . longaddr < < 2 ) |
( dev - > DCR . endian < < 1 ) |
( dev - > DCR . wdsize ) ) ;
case 0x0f : /* IMR */
return ( ( dev - > IMR . rdma_inte < < 6 ) |
( dev - > IMR . cofl_inte < < 5 ) |
( dev - > IMR . overw_inte < < 4 ) |
( dev - > IMR . txerr_inte < < 3 ) |
( dev - > IMR . rxerr_inte < < 2 ) |
( dev - > IMR . tx_inte < < 1 ) |
( dev - > IMR . rx_inte ) ) ;
default :
pclog ( 1 , " page 2 register 0x%02x out of range \n " , off ) ;
break ;
}
return ( 0 ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static void
page2_write ( ne2000_t * dev , uint32_t off , uint32_t val , unsigned 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 . */
pclog ( 2 , " page 2 write to register 0x%02x, len=%u, value=0x%04x \n " ,
off , len , val ) ;
switch ( off ) {
case 0x01 : /* CLDA0 */
/* Clear out low byte and re-insert */
dev - > local_dma & = 0xff00 ;
dev - > local_dma | = ( val & 0xff ) ;
break ;
case 0x02 : /* CLDA1 */
/* Clear out high byte and re-insert */
dev - > local_dma & = 0x00ff ;
dev - > local_dma | = ( ( val & 0xff ) < < 8 ) ;
break ;
case 0x03 : /* Remote Next-pkt pointer */
dev - > rempkt_ptr = val ;
break ;
case 0x04 :
pclog ( 1 , " page 2 write to reserved register 0x04 \n " ) ;
break ;
case 0x05 : /* Local Next-packet pointer */
dev - > localpkt_ptr = val ;
break ;
case 0x06 : /* Address counter (upper) */
/* Clear out high byte and re-insert */
dev - > address_cnt & = 0x00ff ;
dev - > address_cnt | = ( ( val & 0xff ) < < 8 ) ;
break ;
case 0x07 : /* Address counter (lower) */
/* Clear out low byte and re-insert */
dev - > address_cnt & = 0xff00 ;
dev - > address_cnt | = ( val & 0xff ) ;
break ;
case 0x08 :
case 0x09 :
case 0x0a :
case 0x0b :
case 0x0c :
case 0x0d :
case 0x0e :
case 0x0f :
pclog ( 1 , " page 2 write to reserved register 0x%02x \n " , off ) ;
break ;
default :
pclog ( 1 , " page 2 write, illegal register 0x%02x \n " , off ) ;
break ;
}
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* page3_read/page3_write - writes to this page are illegal */
static uint32_t
page3_read ( ne2000_t * dev , uint32_t off , unsigned int len )
{
if ( network_card_current = = 2 ) switch ( off ) {
case 0x3 : /* CONFIG0 */
return ( 0x00 ) ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
case 0x5 : /* CONFIG2 */
return ( 0x40 ) ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
case 0x6 : /* CONFIG3 */
return ( 0x40 ) ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
default :
break ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
pclog ( 1 , " page 3 read register 0x%02x attempted \n " , off ) ;
return ( 0x00 ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static void
page3_write ( ne2000_t * dev , uint32_t off , uint32_t val , unsigned len )
{
pclog ( 1 , " page 3 write register 0x%02x attempted \n " , off ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* read_cr/write_cr - utility routines for handling reads/writes to
the Command Register */
static uint32_t
read_cr ( ne2000_t * dev )
{
uint32_t retval ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
retval = ( ( ( dev - > CR . pgsel & 0x03 ) < < 6 ) |
( ( dev - > CR . rdma_cmd & 0x07 ) < < 3 ) |
( dev - > CR . tx_packet < < 2 ) |
( dev - > CR . start < < 1 ) |
( dev - > CR . stop ) ) ;
pclog ( 2 , " %s: read CR returns 0x%02x \n " ,
( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , retval ) ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
return ( retval ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static void
write_cr ( ne2000_t * dev , uint32_t val )
{
pclog ( 2 , " %s: wrote 0x%02x to CR \n " ,
( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , val ) ;
/* Validate remote-DMA */
if ( ( val & 0x38 ) = = 0x00 ) {
pclog ( 1 , " CR write - invalid rDMA value 0 \n " ) ;
val | = 0x20 ; /* dma_cmd == 4 is a safe default */
}
/* Check for s/w reset */
if ( val & 0x01 ) {
dev - > ISR . reset = 1 ;
dev - > CR . stop = 1 ;
} else {
dev - > CR . stop = 0 ;
}
dev - > CR . rdma_cmd = ( val & 0x38 ) > > 3 ;
/* If start command issued, the RST bit in the ISR */
/* must be cleared */
if ( ( val & 0x02 ) & & ! dev - > CR . start ) {
dev - > ISR . reset = 0 ;
}
dev - > CR . start = ( ( val & 0x02 ) = = 0x02 ) ;
dev - > CR . pgsel = ( val & 0xc0 ) > > 6 ;
/* Check for send-packet command */
if ( dev - > CR . rdma_cmd = = 3 ) {
/* Set up DMA read from receive ring */
dev - > remote_start = dev - > remote_dma = dev - > bound_ptr * 256 ;
dev - > remote_bytes = ( uint16_t ) chipmem_read ( dev , dev - > bound_ptr * 256 + 2 , 2 ) ;
pclog ( 2 , " Sending buffer #x%x length %d \n " , dev - > remote_start , dev - > remote_bytes ) ;
}
/* Check for start-tx */
if ( ( val & 0x04 ) & & dev - > TCR . loop_cntl ) {
if ( dev - > TCR . loop_cntl ! = 1 ) {
pclog ( 1 , " Loop mode %d not supported \n " , dev - > TCR . loop_cntl ) ;
} else {
ne2000_rx_frame ( dev , & dev - > mem [ dev - > tx_page_start * 256 - BX_NE2K_MEMSTART ] , dev - > tx_bytes ) ;
}
} else if ( val & 0x04 ) {
if ( dev - > CR . stop | | ( ! dev - > CR . start & & ( network_card_current = = 1 ) ) ) {
if ( dev - > tx_bytes = = 0 ) /* njh@bandsman.co.uk */ {
return ; /* Solaris9 probe */
}
pclog ( 1 , " CR write - tx start, dev in reset \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( dev - > tx_bytes = = 0 ) {
pclog ( 1 , " CR write - tx start, tx bytes == 0 \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* Send the packet to the system driver */
dev - > CR . tx_packet = 1 ;
if ( ! net_is_pcap ) {
slirp_input ( & dev - > mem [ dev - > tx_page_start * 256 - BX_NE2K_MEMSTART ] , dev - > tx_bytes ) ;
pclog ( 1 , " ne2000 slirp sending packet \n " ) ;
} else if ( net_is_pcap & & ( net_pcap ! = NULL ) ) {
pcap_sendpacket ( net_pcap , & dev - > mem [ dev - > tx_page_start * 256 - BX_NE2K_MEMSTART ] , dev - > tx_bytes ) ;
pclog ( 1 , " ne2000 pcap sending packet \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* some more debug */
if ( dev - > tx_timer_active ) {
pclog ( 1 , " CR write, tx timer still active \n " ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
ne2000_tx_event ( dev , val ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04: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 */
if ( dev - > CR . rdma_cmd = = 0x01 & & dev - > CR . start & & dev - > remote_bytes = = 0 ) {
dev - > ISR . rdma_done = 1 ;
if ( dev - > IMR . rdma_inte ) {
picint ( 1 < < dev - > base_irq ) ;
if ( network_card_current = = 1 ) {
picintc ( 1 < < dev - > base_irq ) ;
}
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
}
2016-08-13 03:32:38 +02:00
}
2016-06-26 00:34:39 +02:00
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
static uint32_t
ne2000_read ( ne2000_t * dev , uint32_t addr , unsigned len )
2016-08-13 03:32:38 +02:00
{
2017-05-09 22:09:55 -04:00
uint32_t retval = 0 ;
int off = addr - dev - > base_address ;
pclog ( 2 , " %s: read addr %x, len %d \n " ,
( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , addr , len ) ;
if ( off > = 0x10 ) {
retval = asic_read ( dev , off - 0x10 , len ) ;
} else if ( off = = 0x00 ) {
retval = read_cr ( dev ) ;
} else switch ( dev - > CR . pgsel ) {
case 0x00 :
retval = page0_read ( dev , off , len ) ;
break ;
case 0x01 :
retval = page1_read ( dev , off , len ) ;
break ;
case 0x02 :
retval = page2_read ( dev , off , len ) ;
break ;
case 0x03 :
retval = page3_read ( dev , off , len ) ;
break ;
default :
pclog ( 1 , " unknown value of pgsel in read - %d \n " , dev - > CR . pgsel ) ;
break ;
}
return ( retval ) ;
2016-08-13 03:32:38 +02:00
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static uint8_t
ne2000_readb ( uint16_t addr , void * priv )
{
return ( ne2000_read ( ( ne2000_t * ) priv , addr , 1 ) ) ;
2016-08-13 03:32:38 +02:00
}
2016-06-26 00:34:39 +02:00
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
static uint16_t
ne2000_readw ( uint16_t addr , void * priv )
2016-08-13 03:32:38 +02:00
{
2017-05-09 22:09:55 -04:00
ne2000_t * dev = ( ne2000_t * ) priv ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( dev - > DCR . wdsize & 1 )
return ( ne2000_read ( dev , addr , 2 ) ) ;
else
return ( ne2000_read ( dev , addr , 1 ) ) ;
2016-08-13 03:32:38 +02:00
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static uint32_t
ne2000_readl ( uint16_t addr , void * priv )
{
return ( ne2000_read ( ( ne2000_t * ) priv , addr , 4 ) ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static void
ne2000_write ( ne2000_t * dev , uint32_t addr , uint32_t val , unsigned len )
{
int off = addr - dev - > base_address ;
pclog ( 2 , " %s: write addr %x, value %x len %d \n " ,
( network_card_current = = 1 ) ? " NE2000 " : " RTL8029AS " , addr , val , 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 */
if ( off > = 0x10 ) {
asic_write ( dev , off - 0x10 , val , len ) ;
} else if ( off = = 0x00 ) {
write_cr ( dev , val ) ;
} else switch ( dev - > CR . pgsel ) {
case 0x00 :
page0_write ( dev , off , val , len ) ;
break ;
case 0x01 :
page1_write ( dev , off , val , len ) ;
break ;
case 0x02 :
page2_write ( dev , off , val , len ) ;
break ;
case 0x03 :
page3_write ( dev , off , val , len ) ;
break ;
default :
pclog ( 1 , " unknown value of pgsel in write - %d \n " , dev - > CR . pgsel ) ;
break ;
}
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static void
ne2000_writeb ( uint16_t addr , uint8_t val , void * priv )
{
ne2000_write ( ( ne2000_t * ) priv , addr , val , 1 ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static void
ne2000_writew ( uint16_t addr , uint16_t val , void * priv )
{
ne2000_t * dev = ( ne2000_t * ) priv ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( dev - > DCR . wdsize & 1 )
ne2000_write ( dev , addr , val , 2 ) ;
else
ne2000_write ( dev , addr , val , 1 ) ;
2016-08-13 03:32:38 +02:00
}
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
static void
ne2000_writel ( uint16_t addr , uint32_t val , void * priv )
2016-08-13 03:32:38 +02:00
{
2017-05-09 22:09:55 -04:00
ne2000_write ( ( ne2000_t * ) priv , addr , val , 4 ) ;
2016-08-13 03:32:38 +02:00
}
2017-05-09 22:09:55 -04:00
static void
ne2000_ioset ( uint16_t addr , ne2000_t * dev )
{
old_base_addr = addr ;
if ( network_card_current = = 1 ) {
io_sethandler ( addr , 16 ,
ne2000_readb , NULL , NULL ,
ne2000_writeb , NULL , NULL , dev ) ;
io_sethandler ( addr + 16 , 16 ,
ne2000_readb , ne2000_readw , NULL ,
ne2000_writeb , ne2000_writew , NULL , dev ) ;
io_sethandler ( addr + 0x1f , 1 ,
ne2000_readb , NULL , NULL ,
ne2000_writeb , NULL , NULL , dev ) ;
} else {
io_sethandler ( addr , 16 ,
ne2000_readb , ne2000_readw , ne2000_readl ,
ne2000_writeb , ne2000_writew , ne2000_writel , dev ) ;
io_sethandler ( addr + 16 , 16 ,
ne2000_readb , ne2000_readw , ne2000_readl ,
ne2000_writeb , ne2000_writew , ne2000_writel , dev ) ;
io_sethandler ( addr + 0x1f , 1 ,
ne2000_readb , ne2000_readw , ne2000_readl ,
ne2000_writeb , ne2000_writew , ne2000_writel , dev ) ;
}
2016-08-13 03:32:38 +02:00
}
2017-05-09 22:09:55 -04:00
static void
ne2000_ioremove ( int16_t addr , ne2000_t * dev )
2016-08-13 03:32:38 +02:00
{
2017-05-09 22:09:55 -04:00
if ( network_card_current = = 1 ) {
io_removehandler ( addr , 16 ,
ne2000_readb , NULL , NULL ,
ne2000_writeb , NULL , NULL , dev ) ;
io_removehandler ( addr + 16 , 16 ,
ne2000_readb , ne2000_readw , NULL ,
ne2000_writeb , ne2000_writew , NULL , dev ) ;
io_removehandler ( addr + 0x1f , 1 ,
ne2000_readb , NULL , NULL ,
ne2000_writeb , NULL , NULL , dev ) ;
} else {
io_removehandler ( addr , 16 ,
ne2000_readb , ne2000_readw , ne2000_readl ,
ne2000_writeb , ne2000_writew , ne2000_writel , dev ) ;
io_removehandler ( addr + 16 , 16 ,
ne2000_readb , ne2000_readw , ne2000_readl ,
ne2000_writeb , ne2000_writew , ne2000_writel , dev ) ;
io_removehandler ( addr + 0x1f , 1 ,
ne2000_readb , ne2000_readw , ne2000_readl ,
ne2000_writeb , ne2000_writew , ne2000_writel , dev ) ;
}
2016-08-13 03:32:38 +02:00
}
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
static void
ne2000_update_bios ( ne2000_t * dev )
2016-08-13 03:32:38 +02:00
{
2017-05-09 22:09:55 -04:00
int reg_bios_enable ;
reg_bios_enable = 1 ;
/* PCI BIOS stuff, just enable_disable. */
if ( ! disable_netbios & & reg_bios_enable ) {
mem_mapping_enable ( & dev - > bios_rom . mapping ) ;
mem_mapping_set_addr ( & dev - > bios_rom . mapping , bios_addr , 0x10000 ) ;
pclog ( 1 , " NE2000 BIOS now at: %08X \n " , bios_addr ) ;
} else {
mem_mapping_disable ( & dev - > bios_rom . mapping ) ;
if ( network_card_current = = 2 )
pci_bar [ 1 ] . addr = 0 ;
}
}
2017-02-07 02:19:48 +01:00
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
static uint8_t
ne2000_pci_read ( int func , int addr , void * priv )
{
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 pci_regs [ 0x04 ] ; /*Respond to IO and memory accesses*/
case 0x05 :
return pci_regs [ 0x05 ] ;
case 0x07 :
return 2 ;
case 0x08 :
return 0 ; /*Revision ID*/
case 0x09 :
return 0 ; /*Programming interface*/
case 0x0B :
return pci_regs [ 0x0B ] ;
case 0x10 :
return 1 ; /*I/O space*/
case 0x11 :
return pci_bar [ 0 ] . addr_regs [ 1 ] ;
case 0x12 :
return pci_bar [ 0 ] . addr_regs [ 2 ] ;
case 0x13 :
return pci_bar [ 0 ] . addr_regs [ 3 ] ;
case 0x30 :
return pci_bar [ 1 ] . addr_regs [ 0 ] & 0x01 ; /*BIOS ROM address*/
case 0x31 :
return ( pci_bar [ 1 ] . addr_regs [ 1 ] & bios_mask ) | 0x18 ;
case 0x32 :
return pci_bar [ 1 ] . addr_regs [ 2 ] ;
case 0x33 :
return pci_bar [ 1 ] . addr_regs [ 3 ] ;
case 0x3C :
return pci_regs [ 0x3C ] ;
case 0x3D :
return pci_regs [ 0x3D ] ;
}
return 0 ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static void
ne2000_pci_write ( int func , int addr , uint8_t val , void * priv )
{
ne2000_t * dev = ( ne2000_t * ) priv ;
switch ( addr ) {
case 0x04 :
ne2000_ioremove ( dev - > base_address , dev ) ;
if ( val & PCI_COMMAND_IO ) {
ne2000_ioset ( dev - > base_address , dev ) ;
}
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_ioremove ( dev - > base_address , dev ) ;
/* Then let's set the PCI regs. */
pci_bar [ 0 ] . addr_regs [ addr & 3 ] = val ;
/* Then let's calculate the new I/O base. */
dev - > base_address = pci_bar [ 0 ] . addr & 0xff00 ;
/* Log the new base. */
pclog ( 1 , " NE2000 RTL8029AS PCI: New I/O base is %04X \n " ,
dev - > base_address ) ;
/* We're done, so get out of the here. */
if ( val & PCI_COMMAND_IO ) {
ne2000_ioset ( dev - > base_address , dev ) ;
}
return ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
case 0x30 : case 0x31 : case 0x32 : case 0x33 :
pci_bar [ 1 ] . addr_regs [ addr & 3 ] = val ;
pci_bar [ 1 ] . addr_regs [ 1 ] & = bios_mask ;
bios_addr = pci_bar [ 1 ] . addr & 0xffffe000 ;
pci_bar [ 1 ] . addr & = 0xffffe000 ;
pci_bar [ 1 ] . addr | = 0x1801 ;
ne2000_update_bios ( dev ) ;
return ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
#if 0
/* 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 . */
case 0x3C :
pci_regs [ addr ] = val ;
if ( val ! = 0xFF ) {
pclog ( 1 , " NE2000 IRQ now: %i \n " , val ) ;
dev - > base_irq = irq ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
return ;
# endif
2017-02-07 02:19:48 +01:00
}
2016-08-13 03:32:38 +02:00
}
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
static uint8_t *
ne2000_mac ( void )
{
if ( network_card_current = = 2 )
return ( maclocal_pci ) ;
2017-05-05 01:49:42 +02:00
2017-05-09 22:09:55 -04:00
return ( maclocal ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
static void
ne2000_tx_event ( void * priv , uint32_t val )
{
ne2000_t * dev = ( ne2000_t * ) priv ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
pclog ( 1 , " tx_timer \n " ) ;
dev - > CR . tx_packet = 0 ;
dev - > TSR . tx_ok = 1 ;
dev - > ISR . pkt_tx = 1 ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* Generate an interrupt if not masked */
if ( dev - > IMR . tx_inte )
picint ( 1 < < dev - > base_irq ) ;
dev - > tx_timer_active = 0 ;
2016-06-26 00:34:39 +02:00
}
2017-05-09 22:09:55 -04: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
*/
2017-05-09 22:09:55 -04:00
static int
mcast_index ( const void * dst )
2016-06-26 00:34:39 +02:00
{
# 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-05-09 22:09:55 -04:00
ne2000_t * dev = ( ne2000_t * ) p ;
2017-02-07 02:19:48 +01:00
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 )
{
2017-05-09 22:09:55 -04:00
pclog ( 1 , " rx_frame with length %d \n " , io_len ) ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
if ( ( dev - > CR . stop ! = 0 ) | |
( dev - > page_start = = 0 ) )
2017-02-07 02:19:48 +01:00
{
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 ;
2017-05-09 22:09:55 -04:00
if ( dev - > curr_page < dev - > bound_ptr )
2017-02-07 02:19:48 +01:00
{
2017-05-09 22:09:55 -04:00
avail = dev - > bound_ptr - dev - > curr_page ;
2017-02-07 02:19:48 +01:00
}
else
{
2017-05-09 22:09:55 -04:00
avail = ( dev - > page_stop - dev - > page_start ) - ( dev - > curr_page - dev - > bound_ptr ) ;
2017-02-07 02:19:48 +01:00
}
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
)
{
2017-05-09 22:09:55 -04:00
pclog ( 1 , " no space \n " ) ;
2017-02-07 02:19:48 +01:00
return ;
}
2016-06-26 00:34:39 +02:00
2017-05-09 22:09:55 -04:00
if ( ( io_len < 40 /*60*/ ) & & ! dev - > RCR . runts_ok )
2017-02-07 02:19:48 +01:00
{
2017-05-09 22:09:55 -04:00
pclog ( 1 , " rejected small packet, length %d \n " , io_len ) ;
2017-02-07 02:19:48 +01:00
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-05-09 22:09:55 -04:00
if ( ! dev - > RCR . promisc )
2017-02-07 02:19:48 +01:00
{
/* 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 ] ) )
{
2017-05-09 22:09:55 -04:00
if ( ! dev - > RCR . broadcast )
2017-02-07 02:19:48 +01:00
{
return ;
}
}
else if ( pktbuf [ 0 ] & 0x01 )
{
2017-05-09 22:09:55 -04:00
if ( ! dev - > RCR . multicast )
2017-02-07 02:19:48 +01:00
{
return ;
}
idx = mcast_index ( buf ) ;
2017-05-09 22:09:55 -04:00
if ( ! ( dev - > mchash [ idx > > 3 ] & ( 1 < < ( idx & 0x7 ) ) ) )
2017-02-07 02:19:48 +01:00
{
return ;
}
}
2017-05-09 22:09:55 -04:00
else if ( 0 ! = memcmp ( buf , dev - > physaddr , 6 ) )
2017-02-07 02:19:48 +01:00
{
return ;
}
}
else
{
2017-05-09 22:09:55 -04:00
pclog ( 1 , " rx_frame promiscuous receive \n " ) ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
pclog ( 1 , " 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 ] ) ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
nextpage = dev - > curr_page + pages ;
if ( nextpage > = dev - > page_stop )
2017-02-07 02:19:48 +01:00
{
2017-05-09 22:09:55 -04:00
nextpage - = dev - > page_stop - dev - > page_start ;
2017-02-07 02:19:48 +01:00
}
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-05-09 22:09:55 -04:00
startptr = & dev - > mem [ dev - > curr_page * 256 - BX_NE2K_MEMSTART ] ;
if ( ( nextpage > dev - > curr_page ) | | ( ( dev - > curr_page + pages ) = = dev - > page_stop ) )
2017-02-07 02:19:48 +01:00
{
* ( uint32_t * ) startptr = * ( uint32_t * ) pkthdr ;
memcpy ( startptr + 4 , buf , io_len ) ;
2017-05-09 22:09:55 -04:00
dev - > curr_page = nextpage ;
2017-02-07 02:19:48 +01:00
}
else
{
2017-05-09 22:09:55 -04:00
int endbytes = ( dev - > page_stop - dev - > curr_page ) * 256 ;
2017-02-07 02:19:48 +01:00
* ( uint32_t * ) startptr = * ( uint32_t * ) pkthdr ;
memcpy ( startptr + 4 , buf , endbytes - 4 ) ;
2017-05-09 22:09:55 -04:00
startptr = & dev - > mem [ dev - > page_start * 256 - BX_NE2K_MEMSTART ] ;
2017-02-07 02:19:48 +01:00
memcpy ( startptr , ( void * ) ( pktbuf + endbytes - 4 ) , io_len - endbytes + 8 ) ;
2017-05-09 22:09:55 -04:00
dev - > curr_page = nextpage ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
dev - > RSR . rx_ok = 1 ;
2017-02-07 02:19:48 +01:00
if ( pktbuf [ 0 ] & 0x80 )
{
2017-05-09 22:09:55 -04:00
dev - > RSR . rx_mbit = 1 ;
2017-02-07 02:19:48 +01:00
}
2016-06-26 00:34:39 +02:00
2017-05-09 22:09:55 -04:00
dev - > ISR . pkt_rx = 1 ;
2016-08-13 03:32:38 +02:00
2017-05-09 22:09:55 -04:00
if ( dev - > IMR . rx_inte )
2017-02-07 02:19:48 +01:00
{
2017-05-09 22:09:55 -04:00
picint ( 1 < < dev - > base_irq ) ;
2017-02-07 02:19:48 +01:00
}
2016-08-13 03:32:38 +02:00
}
2017-05-09 22:09:55 -04:00
void
ne2000_poller ( void * priv )
2016-06-26 00:34:39 +02:00
{
2017-05-09 22:09:55 -04:00
ne2000_t * dev = ( ne2000_t * ) priv ;
2016-06-26 00:34:39 +02:00
struct queuepacket * qp ;
const unsigned char * data ;
struct pcap_pkthdr h ;
2017-05-09 22:09:55 -04:00
uint32_t mac_cmp32 [ 2 ] ;
uint16_t mac_cmp16 [ 2 ] ;
2016-06-26 00:34:39 +02:00
2017-05-09 22:09:55 -04:00
if ( ! net_is_pcap ) {
while ( QueuePeek ( slirpq ) > 0 ) {
qp = QueueDelete ( slirpq ) ;
if ( ( dev - > DCR . loop = = 0 ) | | ( dev - > TCR . loop_cntl ! = 0 ) ) {
2017-02-07 02:19:48 +01:00
free ( qp ) ;
2017-01-05 02:43:54 +01:00
return ;
}
2017-05-09 22:09:55 -04:00
ne2000_rx_frame ( dev , & qp - > data , qp - > len ) ;
pclog ( 1 , " ne2000 inQ:%d got a %dbyte packet @%d \n " , QueuePeek ( slirpq ) , qp - > len , qp ) ;
free ( qp ) ;
2017-02-14 07:06:24 +01:00
}
2017-05-09 22:09:55 -04:00
fizz + + ;
if ( fizz > 1200 ) {
fizz = 0 ;
slirp_tic ( ) ;
2017-02-14 07:06:24 +01:00
}
2016-06-26 00:34:39 +02:00
2017-05-09 22:09:55 -04:00
return ;
}
2016-06-26 00:34:39 +02:00
2017-05-09 22:09:55 -04:00
if ( net_pcap ! = NULL ) {
if ( ( dev - > DCR . loop = = 0 ) | | ( dev - > TCR . loop_cntl ! = 0 ) ) {
return ;
2016-06-26 00:34:39 +02:00
}
2017-05-09 22:09:55 -04:00
data = pcap_next ( net_pcap , & h ) ;
if ( data = = NULL ) {
return ;
2016-06-26 00:34:39 +02:00
}
2017-05-09 22:09:55 -04:00
/* Received. */
mac_cmp32 [ 0 ] = * ( uint32_t * ) ( data + 6 ) ;
mac_cmp16 [ 0 ] = * ( uint16_t * ) ( data + 10 ) ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
/* Local. */
mac_cmp32 [ 1 ] = * ( uint32_t * ) ( ne2000_mac ( ) ) ;
mac_cmp16 [ 1 ] = * ( uint16_t * ) ( ne2000_mac ( ) + 4 ) ;
if ( ( mac_cmp32 [ 0 ] ! = mac_cmp32 [ 1 ] ) | | ( mac_cmp16 [ 0 ] ! = mac_cmp16 [ 1 ] ) ) {
ne2000_rx_frame ( dev , data , h . caplen ) ;
} else {
pclog ( 1 , " NE2000: RX pkt, not for me! \n " ) ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
}
2016-06-26 00:34:39 +02:00
}
2017-05-09 22:09:55 -04:00
static void
ne2000_rom_init ( ne2000_t * dev , wchar_t * s )
2016-06-26 00:34:39 +02:00
{
2017-05-09 22:09:55 -04:00
FILE * f = romfopen ( s , L " rb " ) ;
uint32_t temp ;
2016-06-26 00:34:39 +02:00
2017-05-09 22:09:55 -04:00
if ( f ! = NULL ) {
disable_netbios = 1 ;
ne2000_update_bios ( dev ) ;
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 ;
rom_init ( & dev - > bios_rom , s , 0xd0000 ,
bios_size , bios_size - 1 , 0 , MEM_MAPPING_EXTERNAL ) ;
2016-08-13 03:32:38 +02:00
}
2016-06-26 00:34:39 +02:00
2017-05-06 17:48:33 +02:00
2017-05-09 22:09:55 -04:00
static void *
ne2000_init ( void )
2016-08-13 03:32:38 +02:00
{
2017-05-09 22:09:55 -04:00
char errbuf [ 32768 ] ;
2016-08-13 03:32:38 +02:00
int rc ;
2017-05-05 01:49:42 +02:00
int config_net_type ;
2017-05-09 22:09:55 -04:00
int irq ;
int pcap_device_available = 0 ;
int is_rtl8029as = 0 ;
ne2000_t * dev ;
char * pcap_dev ;
dev = malloc ( sizeof ( ne2000_t ) ) ;
memset ( dev , 0x00 , sizeof ( ne2000_t ) ) ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( PCI & & ( network_card_current = = 2 ) ) {
is_rtl8029as = 1 ;
} else {
network_card_current = 1 ;
is_rtl8029as = 0 ;
}
if ( is_rtl8029as ) {
dev - > base_address = 0x340 ;
} else {
dev - > base_address = device_get_config_int ( " addr " ) ;
}
irq = device_get_config_int ( " irq " ) ;
dev - > base_irq = irq ;
disable_netbios = device_get_config_int ( " disable_netbios " ) ;
/* Network type is now specified in device config. */
config_net_type = device_get_config_int ( " net_type " ) ;
net_is_pcap = config_net_type ? 0 : 1 ;
if ( net_is_pcap ) {
pcap_dev = config_get_string ( NULL , " pcap_device " , " nothing " ) ;
if ( ! strcmp ( pcap_dev , " nothing " ) ) {
2016-12-30 01:03:40 +01:00
net_is_pcap = 0 ;
2017-02-07 02:19:48 +01:00
pcap_device_available = 0 ;
2017-05-09 22:09:55 -04:00
} else {
2017-02-07 02:19:48 +01:00
pcap_device_available = 1 ;
}
2017-05-09 22:09:55 -04:00
}
pclog ( 1 , " net_is_pcap = %i \n " , net_is_pcap ) ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( is_rtl8029as ) {
pci_add ( ne2000_pci_read , ne2000_pci_write , dev ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
ne2000_ioset ( dev - > base_address , dev ) ;
2016-06-26 00:34:39 +02:00
2017-05-09 22:09:55 -04:00
memcpy ( dev - > physaddr , ne2000_mac ( ) , 6 ) ;
2016-08-13 03:32:38 +02:00
2017-05-09 22:09:55 -04:00
if ( ! disable_netbios ) {
ne2000_rom_init ( dev , is_rtl8029as ? L " roms/rtl8029as.rom "
: L " roms/ne2000.rom " ) ;
if ( is_rtl8029as ) {
mem_mapping_disable ( & dev - > bios_rom . mapping ) ;
2016-08-13 03:32:38 +02:00
}
2017-05-09 22:09:55 -04:00
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( is_rtl8029as ) {
pci_regs [ 0x04 ] = 1 ;
pci_regs [ 0x05 ] = 0 ;
2016-06-26 00:34:39 +02:00
2017-05-09 22:09:55 -04:00
pci_regs [ 0x07 ] = 2 ;
2016-08-13 03:32:38 +02:00
/* Network controller. */
2017-05-09 22:09:55 -04:00
pci_regs [ 0x0B ] = 2 ;
2016-08-13 03:32:38 +02:00
2017-05-09 22:09:55 -04:00
pci_bar [ 0 ] . addr_regs [ 0 ] = 1 ;
2016-08-13 03:32:38 +02:00
2017-05-09 22:09:55 -04:00
if ( disable_netbios ) {
pci_bar [ 1 ] . addr = 0 ;
bios_addr = 0 ;
} else {
pci_bar [ 1 ] . addr = 0x000F8000 ;
pci_bar [ 1 ] . addr_regs [ 1 ] = bios_mask ;
pci_bar [ 1 ] . addr | = 0x1801 ;
bios_addr = 0xD0000 ;
2017-02-07 02:19:48 +01:00
}
2016-08-13 03:32:38 +02:00
2017-05-09 22:09:55 -04:00
pci_regs [ 0x3C ] = irq ;
pclog ( 1 , " RTL8029AS IRQ: %i \n " , pci_regs [ 0x3C ] ) ;
pci_regs [ 0x3D ] = 1 ;
2016-06-26 00:34:39 +02:00
2017-05-09 22:09:55 -04:00
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_reset ( dev , BX_RESET_HARDWARE ) ;
network_add_handler ( ne2000_poller , dev ) ;
pclog ( 1 , " ne2000 %s init 0x%X %d \t net_is_pcap is %d \n " ,
is_rtl8029as ? " PCI " : " ISA " ,
dev - > 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-05-09 22:09:55 -04:00
if ( ! net_is_pcap ) {
2017-02-07 02:19:48 +01:00
initialize_slirp :
2017-05-09 22:09:55 -04:00
pclog ( 1 , " ne2000 initalizing SLiRP \n " ) ;
net_is_pcap = 0 ;
rc = slirp_init ( ) ;
pclog ( 1 , " ne2000 slirp_init returned: %d \n " , rc ) ;
if ( ! rc ) {
pclog ( 1 , " ne2000 slirp initalized! \n " ) ;
net_slirp_inited = 1 ;
slirpq = QueueCreate ( ) ;
fizz = 0 ;
pclog ( 1 , " ne2000 slirpq is %x \n " , & slirpq ) ;
} else {
net_slirp_inited = 0 ;
if ( pcap_device_available ) {
net_is_pcap = 1 ;
goto initialize_pcap ;
} else {
pclog ( 1 , " Neither SLiRP nor PCap available, disabling network adapter... \n " ) ;
free ( dev ) ;
network_card_current = 0 ;
resetpchard ( ) ;
return ( NULL ) ;
2017-02-07 02:19:48 +01:00
}
}
2017-05-09 22:09:55 -04:00
} else {
2017-02-07 02:19:48 +01:00
initialize_pcap :
2017-05-09 22:09:55 -04:00
pclog ( 1 , " ne2000 initalizing libpcap \n " ) ;
2016-08-13 03:32:38 +02:00
2017-05-09 22:09:55 -04:00
pclog ( 1 , " ne2000 Pcap version [%s] \n " , pcap_lib_version ( ) ) ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
net_pcap = pcap_open_live ( pcap_dev , 1518 , 1 , 15 , errbuf ) ;
if ( net_pcap = = NULL ) {
pclog ( 1 , " NE2000 pcap_open_live error on %s! \n " , pcap_dev ) ;
net_is_pcap = 0 ;
return ( dev ) ; /* YUCK!!! */
}
/* Time to check that we are in non-blocking mode. */
rc = pcap_getnonblock ( net_pcap , errbuf ) ;
pclog ( 1 , " ne2000 pcap is currently in %s mode \n " ,
rc ? " non-blocking " : " blocking " ) ;
switch ( rc ) {
case 0 :
pclog ( 1 , " NE2000: setting to non-blocking mode.. " ) ;
rc = pcap_setnonblock ( net_pcap , 1 , errbuf ) ;
if ( rc = = 0 ) {
/* no errors! */
pclog ( 1 , " .. " ) ;
rc = pcap_getnonblock ( net_pcap , errbuf ) ;
if ( rc = = 1 ) {
pclog ( 1 , " ..! " ) ;
net_is_pcap = 1 ;
} else {
pclog ( 1 , " \t unable to set pcap into non-blocking mode! \n Continuining without pcap. \n " ) ;
net_is_pcap = 0 ;
2016-08-13 03:32:38 +02:00
}
2017-05-09 22:09:55 -04:00
} else {
pclog ( 1 , " There was an unexpected error of [%s] \n \n exiting. \n " , errbuf ) ;
net_is_pcap = 0 ;
}
pclog ( 1 , " \n " ) ;
break ;
case 1 :
pclog ( 1 , " non blocking \n " ) ;
break ;
default :
pclog ( 1 , " this isn't right!!! \n " ) ;
net_is_pcap = 0 ;
break ;
}
if ( net_is_pcap ) {
char filter_exp [ 255 ] ;
struct bpf_program fp ;
uint8_t * mac ;
mac = ne2000_mac ( ) ;
pclog ( 1 , " 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) ) " ,
mac [ 0 ] , mac [ 1 ] , mac [ 2 ] , mac [ 3 ] , mac [ 4 ] , mac [ 5 ] ,
mac [ 0 ] , mac [ 1 ] , mac [ 2 ] , mac [ 3 ] , mac [ 4 ] , mac [ 5 ] ) ;
if ( pcap_compile ( net_pcap , & fp , filter_exp , 0 , 0xffffffff ) = = - 1 ) {
pclog ( 1 , " \n ne2000 Couldn't compile filter \n " ) ;
} else {
pclog ( 1 , " ... " ) ;
if ( pcap_setfilter ( net_pcap , & fp ) = = - 1 ) {
pclog ( 1 , " \n Error installing pcap filter. \n " ) ;
} else {
pclog ( 1 , " ...! \n " ) ;
2017-02-07 02:19:48 +01:00
}
}
2017-05-09 22:09:55 -04:00
pclog ( 1 , " ne2000 Using filter \t [%s] \n " , filter_exp ) ;
} else {
pcap_device_available = 0 ;
goto initialize_slirp ;
}
pclog ( 1 , " ne2000 net_is_pcap is %d and net_pcap is %x \n " ,
net_is_pcap , net_pcap ) ;
}
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
pclog ( 1 , " ne2000 is_pcap %d \n " , net_is_pcap ) ;
return ( dev ) ;
2017-02-07 02:19:48 +01:00
}
2017-05-09 22:09:55 -04:00
static void
ne2000_close ( void * priv )
2017-02-07 02:19:48 +01:00
{
2017-05-09 22:09:55 -04:00
ne2000_t * dev = ( ne2000_t * ) priv ;
2017-02-07 02:19:48 +01:00
2017-05-09 22:09:55 -04:00
if ( ! net_is_pcap ) {
QueueDestroy ( slirpq ) ;
slirp_exit ( 0 ) ;
net_slirp_inited = 0 ;
pclog ( 1 , " NE2000 exiting slirp \n " ) ;
} else if ( net_is_pcap & & ( net_pcap ! = NULL ) ) {
pcap_close ( net_pcap ) ;
pclog ( 1 , " NE2000 closing pcap \n " ) ;
}
ne2000_ioremove ( dev - > base_address , dev ) ;
free ( dev ) ;
pclog ( 1 , " Ne2000 close \n " ) ;
}
void
ne2000_generate_maclocal ( uint32_t mac )
{
maclocal [ 0 ] = 0x00 ; /* 00:00:D8 (NE2000 ISA vendor prefix). */
maclocal [ 1 ] = 0x00 ;
maclocal [ 2 ] = 0xD8 ;
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 ;
}
}
uint32_t
ne2000_get_maclocal ( void )
{
uint32_t temp ;
temp = ( ( ( int ) maclocal [ 3 ] ) < < 16 ) ;
temp | = ( ( ( int ) maclocal [ 4 ] ) < < 8 ) ;
temp | = ( ( int ) maclocal [ 5 ] ) ;
return ( temp ) ;
}
void
ne2000_generate_maclocal_pci ( uint32_t 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 ;
}
}
uint32_t
ne2000_get_maclocal_pci ( void )
{
uint32_t 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
}
2017-05-09 22:09:55 -04:00
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
} ;
2017-05-09 22:09:55 -04: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-09 22:09:55 -04:00
2017-05-05 01:49:42 +02:00
/* SLIRP stuff */
2017-05-09 22:09:55 -04:00
int
slirp_can_output ( void )
2016-06-26 00:34:39 +02:00
{
2017-05-09 22:09:55 -04:00
return ( net_slirp_inited ) ;
2016-06-26 00:34:39 +02:00
}
2017-05-09 22:09:55 -04:00
void
slirp_output ( const unsigned char * pkt , int pkt_len )
2016-06-26 00:34:39 +02:00
{
2017-05-09 22:09:55 -04:00
struct queuepacket * p ;
p = ( struct queuepacket * ) malloc ( sizeof ( struct queuepacket ) ) ;
p - > len = pkt_len ;
memcpy ( p - > data , pkt , pkt_len ) ;
QueueEnter ( slirpq , p ) ;
pclog ( 1 , " ne2000 slirp_output %d @%d \n " , pkt_len , p ) ;
2016-06-26 00:34:39 +02:00
}
2017-05-09 22:09:55 -04: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 . */
2017-05-09 22:09:55 -04:00
void
slirp_tic ( void )
2016-06-26 00:34:39 +02:00
{
2017-05-09 22:09:55 -04:00
int ret2 , nfds ;
struct timeval tv ;
fd_set rfds , wfds , xfds ;
int tmo ;
nfds = - 1 ;
if ( ! net_slirp_inited ) return ;
FD_ZERO ( & rfds ) ;
FD_ZERO ( & wfds ) ;
FD_ZERO ( & xfds ) ;
tmo = slirp_select_fill ( & nfds , & rfds , & wfds , & xfds ) ; /* this can crash */
if ( tmo < 0 ) {
tmo = 500 ;
}
tv . tv_sec = 0 ;
tv . tv_usec = tmo ; /* basilisk default 10000 */
ret2 = select ( nfds + 1 , & rfds , & wfds , & xfds , & tv ) ;
if ( ret2 > = 0 ) {
slirp_select_poll ( & rfds , & wfds , & xfds ) ;
}
2016-06-26 00:34:39 +02:00
}