2017-05-05 01:49:42 +02:00
|
|
|
/*
|
2018-03-19 01:02:04 +01:00
|
|
|
* VARCem Virtual ARchaeological Computer EMulator.
|
|
|
|
|
* An emulator of (mostly) x86-based PC systems and devices,
|
|
|
|
|
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
|
|
|
|
* spanning the era between 1981 and 1995.
|
2017-05-09 22:09:55 -04:00
|
|
|
*
|
2018-03-19 01:02:04 +01:00
|
|
|
* This file is part of the VARCem Project.
|
2017-05-09 22:09:55 -04:00
|
|
|
*
|
2018-01-28 03:15:01 +01:00
|
|
|
* Implementation of the following network controllers:
|
2018-01-28 12:15:57 +01:00
|
|
|
* - Novell NE1000 (ISA 8-bit);
|
2018-01-28 03:15:01 +01:00
|
|
|
* - Novell NE2000 (ISA 16-bit);
|
|
|
|
|
* - Realtek RTL8019AS (ISA 16-bit, PnP);
|
|
|
|
|
* - Realtek RTL8029AS (PCI).
|
2017-05-09 22:09:55 -04:00
|
|
|
*
|
2018-07-24 01:53:46 +02:00
|
|
|
* Version: @(#)net_ne2000.c 1.0.7 2018/07/24
|
2017-05-09 22:09:55 -04:00
|
|
|
*
|
2018-03-19 01:02:04 +01:00
|
|
|
* Based on @(#)ne2k.cc v1.56.2.1 2004/02/02 22:37:22 cbothamy
|
2017-05-09 22:09:55 -04:00
|
|
|
*
|
|
|
|
|
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
2018-03-19 01:02:04 +01:00
|
|
|
* TheCollector1995, <mariogplayer@gmail.com>
|
2018-01-13 22:56:13 +01:00
|
|
|
* Miran Grca, <mgrca8@gmail.com>
|
2018-03-19 01:02:04 +01:00
|
|
|
* Peter Grehan, <grehan@iprg.nokia.com>
|
2017-11-24 02:23:00 -05:00
|
|
|
*
|
2018-02-02 00:14:17 +01:00
|
|
|
* Copyright 2017,2018 Fred N. van Kempen.
|
2018-03-19 01:02:04 +01:00
|
|
|
* Copyright 2016-2018 Miran Grca.
|
|
|
|
|
* Portions Copyright (C) 2002 MandrakeSoft S.A.
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
* General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the:
|
|
|
|
|
*
|
|
|
|
|
* Free Software Foundation, Inc.
|
|
|
|
|
* 59 Temple Place - Suite 330
|
|
|
|
|
* Boston, MA 02111-1307
|
|
|
|
|
* USA.
|
2017-05-09 22:09:55 -04:00
|
|
|
*/
|
2016-06-26 00:34:39 +02:00
|
|
|
#include <stdio.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <stdint.h>
|
2016-06-26 00:34:39 +02:00
|
|
|
#include <string.h>
|
2017-09-25 04:31:20 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <wchar.h>
|
2016-06-26 00:34:39 +02:00
|
|
|
#include <time.h>
|
2017-12-10 02:53:10 -05:00
|
|
|
#define HAVE_STDARG_H
|
2017-10-17 01:59:09 -04:00
|
|
|
#include "../86box.h"
|
2017-09-04 01:52:29 -04:00
|
|
|
#include "../config.h"
|
2017-11-02 02:28:00 -05:00
|
|
|
#include "../machine/machine.h"
|
2017-06-14 07:21:01 +02:00
|
|
|
#include "../io.h"
|
|
|
|
|
#include "../mem.h"
|
|
|
|
|
#include "../rom.h"
|
2018-07-19 16:01:31 +02:00
|
|
|
#include "../mca.h"
|
2017-06-14 07:21:01 +02:00
|
|
|
#include "../pci.h"
|
|
|
|
|
#include "../pic.h"
|
2017-09-04 01:52:29 -04:00
|
|
|
#include "../random.h"
|
2017-06-14 07:21:01 +02:00
|
|
|
#include "../device.h"
|
2017-10-10 03:07:29 -04:00
|
|
|
#include "../ui.h"
|
2017-05-06 17:48:33 +02:00
|
|
|
#include "network.h"
|
2018-07-15 01:41:53 +02:00
|
|
|
#include "net_dp8390.h"
|
2017-05-06 17:48:33 +02:00
|
|
|
#include "net_ne2000.h"
|
2017-05-09 22:09:55 -04:00
|
|
|
#include "bswap.h"
|
2017-05-24 00:27:42 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
|
2018-01-28 03:15:01 +01:00
|
|
|
enum {
|
|
|
|
|
PNP_PHASE_WAIT_FOR_KEY = 0,
|
|
|
|
|
PNP_PHASE_CONFIG,
|
|
|
|
|
PNP_PHASE_ISOLATION,
|
|
|
|
|
PNP_PHASE_SLEEP
|
|
|
|
|
};
|
|
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
/* ROM BIOS file paths. */
|
|
|
|
|
#define ROM_PATH_NE1000 L"roms/network/ne1000/ne1000.rom"
|
|
|
|
|
#define ROM_PATH_NE2000 L"roms/network/ne2000/ne2000.rom"
|
2018-01-28 03:15:01 +01:00
|
|
|
#define ROM_PATH_RTL8019 L"roms/network/rtl8019as/rtl8019as.rom"
|
2017-05-26 13:12:31 -04:00
|
|
|
#define ROM_PATH_RTL8029 L"roms/network/rtl8029as/rtl8029as.rom"
|
|
|
|
|
|
|
|
|
|
/* PCI info. */
|
2018-01-28 03:15:01 +01:00
|
|
|
#define PNP_VENDID 0x4a8c /* Realtek, Inc */
|
2017-05-26 13:12:31 -04:00
|
|
|
#define PCI_VENDID 0x10ec /* Realtek, Inc */
|
2018-01-28 03:15:01 +01:00
|
|
|
#define PNP_DEVID 0x8019 /* RTL8029AS */
|
2017-05-26 13:12:31 -04:00
|
|
|
#define PCI_DEVID 0x8029 /* RTL8029AS */
|
|
|
|
|
#define PCI_REGSIZE 256 /* size of PCI space */
|
|
|
|
|
|
|
|
|
|
|
2018-01-28 03:15:01 +01:00
|
|
|
uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE,
|
|
|
|
|
0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61,
|
|
|
|
|
0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1,
|
|
|
|
|
0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 };
|
|
|
|
|
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
typedef struct {
|
2018-07-15 01:41:53 +02:00
|
|
|
dp8390_t dp8390;
|
|
|
|
|
uint8_t macaddr[32]; /* ASIC ROM'd MAC address, even bytes */
|
2017-05-12 17:33:28 -04:00
|
|
|
int board;
|
2018-07-19 16:01:31 +02:00
|
|
|
int is_pci, is_mca, is_8bit;
|
2017-12-10 02:53:10 -05:00
|
|
|
const char *name;
|
2017-05-09 22:09:55 -04:00
|
|
|
uint32_t base_address;
|
|
|
|
|
int base_irq;
|
2017-05-12 05:05:20 -04:00
|
|
|
uint32_t bios_addr,
|
|
|
|
|
bios_size,
|
|
|
|
|
bios_mask;
|
2018-01-28 03:15:01 +01:00
|
|
|
uint8_t pnp_regs[256];
|
|
|
|
|
uint8_t pnp_res_data[256];
|
2017-05-12 17:33:28 -04:00
|
|
|
bar_t pci_bar[2];
|
2017-05-26 13:12:31 -04:00
|
|
|
uint8_t pci_regs[PCI_REGSIZE];
|
2017-05-18 01:57:16 -04:00
|
|
|
uint8_t maclocal[6]; /* configured MAC (local) address */
|
2017-05-12 17:33:28 -04:00
|
|
|
uint8_t eeprom[128]; /* for RTL8029AS */
|
2017-05-09 22:09:55 -04:00
|
|
|
rom_t bios_rom;
|
2017-06-01 21:49:57 -04:00
|
|
|
int card; /* PCI card slot */
|
2017-08-17 23:16:26 +02:00
|
|
|
int has_bios;
|
2018-01-28 03:15:01 +01:00
|
|
|
uint8_t pnp_phase;
|
|
|
|
|
uint8_t pnp_magic_count;
|
|
|
|
|
uint8_t pnp_address;
|
|
|
|
|
uint8_t pnp_res_pos;
|
|
|
|
|
uint8_t pnp_csn;
|
|
|
|
|
uint8_t pnp_activate;
|
|
|
|
|
uint8_t pnp_io_check;
|
|
|
|
|
uint8_t pnp_csnsav;
|
|
|
|
|
uint16_t pnp_read;
|
|
|
|
|
uint64_t pnp_id;
|
|
|
|
|
uint8_t pnp_id_checksum;
|
|
|
|
|
uint8_t pnp_serial_read_pos;
|
|
|
|
|
uint8_t pnp_serial_read_pair;
|
|
|
|
|
uint8_t pnp_serial_read;
|
|
|
|
|
|
|
|
|
|
/* RTL8019AS/RTL8029AS registers */
|
2018-01-13 22:56:13 +01:00
|
|
|
uint8_t config0, config2, config3;
|
|
|
|
|
uint8_t _9346cr;
|
2018-07-19 16:01:31 +02:00
|
|
|
|
|
|
|
|
/* POS registers, MCA boards only */
|
|
|
|
|
uint8_t pos_regs[8];
|
2017-05-12 05:05:20 -04:00
|
|
|
} nic_t;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-05-08 18:27:42 -04:00
|
|
|
|
2017-05-12 05:05:20 -04:00
|
|
|
static void nic_rx(void *, uint8_t *, int);
|
|
|
|
|
static void nic_tx(nic_t *, uint32_t);
|
2016-08-15 02:26:54 +02:00
|
|
|
|
2018-07-19 16:01:31 +02:00
|
|
|
#ifdef ENABLE_NIC_LOG
|
|
|
|
|
int nic_do_log = ENABLE_NIC_LOG;
|
|
|
|
|
#endif
|
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-06-04 02:11:19 -04:00
|
|
|
#ifdef ENABLE_NIC_LOG
|
2017-05-09 22:09:55 -04:00
|
|
|
va_list ap;
|
2017-05-05 01:49:42 +02:00
|
|
|
|
2017-05-12 05:05:20 -04:00
|
|
|
if (nic_do_log >= lvl) {
|
2017-05-09 22:09:55 -04:00
|
|
|
va_start(ap, fmt);
|
2017-12-10 02:53:10 -05:00
|
|
|
pclog_ex(fmt, ap);
|
2017-05-09 22:09:55 -04:00
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2017-05-10 04:36:19 +02:00
|
|
|
}
|
2017-05-05 01:49:42 +02:00
|
|
|
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-06-02 02:22:38 +02:00
|
|
|
static void
|
2017-06-01 21:49:57 -04:00
|
|
|
nic_interrupt(nic_t *dev, int set)
|
2017-06-02 02:22:38 +02:00
|
|
|
{
|
2017-06-19 06:46:08 +02:00
|
|
|
if (PCI && dev->is_pci) {
|
2017-06-01 21:49:57 -04:00
|
|
|
if (set)
|
2017-09-04 05:15:12 +02:00
|
|
|
pci_set_irq(dev->card, PCI_INTA);
|
2017-06-01 21:49:57 -04:00
|
|
|
else
|
2017-09-04 05:15:12 +02:00
|
|
|
pci_clear_irq(dev->card, PCI_INTA);
|
2017-06-01 21:49:57 -04:00
|
|
|
} else {
|
|
|
|
|
if (set)
|
|
|
|
|
picint(1<<dev->base_irq);
|
|
|
|
|
else
|
|
|
|
|
picintc(1<<dev->base_irq);
|
2017-06-02 02:22:38 +02: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
|
2017-05-26 13:12:31 -04:00
|
|
|
nic_reset(void *priv)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_t *dev = (nic_t *)priv;
|
2017-05-09 22:09:55 -04:00
|
|
|
int i;
|
|
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(1, "%s: reset\n", dev->name);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2018-07-19 16:01:31 +02:00
|
|
|
if (dev->board == NE2K_NE1000)
|
|
|
|
|
{
|
|
|
|
|
/* Initialize the MAC address area by doubling the physical address */
|
|
|
|
|
dev->macaddr[0] = dev->dp8390.physaddr[0];
|
|
|
|
|
dev->macaddr[1] = dev->dp8390.physaddr[1];
|
|
|
|
|
dev->macaddr[2] = dev->dp8390.physaddr[2];
|
|
|
|
|
dev->macaddr[3] = dev->dp8390.physaddr[3];
|
|
|
|
|
dev->macaddr[4] = dev->dp8390.physaddr[4];
|
|
|
|
|
dev->macaddr[5] = dev->dp8390.physaddr[5];
|
|
|
|
|
|
|
|
|
|
/* ne1k signature */
|
|
|
|
|
for (i=6; i<16; i++)
|
|
|
|
|
dev->macaddr[i] = 0x57;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Initialize the MAC address area by doubling the physical address */
|
|
|
|
|
dev->macaddr[0] = dev->dp8390.physaddr[0];
|
|
|
|
|
dev->macaddr[1] = dev->dp8390.physaddr[0];
|
|
|
|
|
dev->macaddr[2] = dev->dp8390.physaddr[1];
|
|
|
|
|
dev->macaddr[3] = dev->dp8390.physaddr[1];
|
|
|
|
|
dev->macaddr[4] = dev->dp8390.physaddr[2];
|
|
|
|
|
dev->macaddr[5] = dev->dp8390.physaddr[2];
|
|
|
|
|
dev->macaddr[6] = dev->dp8390.physaddr[3];
|
|
|
|
|
dev->macaddr[7] = dev->dp8390.physaddr[3];
|
|
|
|
|
dev->macaddr[8] = dev->dp8390.physaddr[4];
|
|
|
|
|
dev->macaddr[9] = dev->dp8390.physaddr[4];
|
|
|
|
|
dev->macaddr[10] = dev->dp8390.physaddr[5];
|
|
|
|
|
dev->macaddr[11] = dev->dp8390.physaddr[5];
|
|
|
|
|
|
|
|
|
|
/* ne2k signature */
|
|
|
|
|
for (i=12; i<32; i++)
|
|
|
|
|
dev->macaddr[i] = 0x57;
|
|
|
|
|
}
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
/* Zero out registers and memory */
|
2018-07-15 01:41:53 +02:00
|
|
|
memset(&dev->dp8390.CR, 0x00, sizeof(dev->dp8390.CR) );
|
|
|
|
|
memset(&dev->dp8390.ISR, 0x00, sizeof(dev->dp8390.ISR));
|
|
|
|
|
memset(&dev->dp8390.IMR, 0x00, sizeof(dev->dp8390.IMR));
|
|
|
|
|
memset(&dev->dp8390.DCR, 0x00, sizeof(dev->dp8390.DCR));
|
|
|
|
|
memset(&dev->dp8390.TCR, 0x00, sizeof(dev->dp8390.TCR));
|
|
|
|
|
memset(&dev->dp8390.TSR, 0x00, sizeof(dev->dp8390.TSR));
|
|
|
|
|
memset(&dev->dp8390.RSR, 0x00, sizeof(dev->dp8390.RSR));
|
|
|
|
|
dev->dp8390.tx_timer_active = 0;
|
|
|
|
|
dev->dp8390.local_dma = 0;
|
|
|
|
|
dev->dp8390.page_start = 0;
|
|
|
|
|
dev->dp8390.page_stop = 0;
|
|
|
|
|
dev->dp8390.bound_ptr = 0;
|
|
|
|
|
dev->dp8390.tx_page_start = 0;
|
|
|
|
|
dev->dp8390.num_coll = 0;
|
|
|
|
|
dev->dp8390.tx_bytes = 0;
|
|
|
|
|
dev->dp8390.fifo = 0;
|
|
|
|
|
dev->dp8390.remote_dma = 0;
|
|
|
|
|
dev->dp8390.remote_start = 0;
|
2018-07-19 16:01:31 +02:00
|
|
|
|
|
|
|
|
dev->dp8390.remote_bytes = 0;
|
|
|
|
|
|
|
|
|
|
dev->dp8390.tallycnt_0 = 0;
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.tallycnt_1 = 0;
|
|
|
|
|
dev->dp8390.tallycnt_2 = 0;
|
|
|
|
|
|
|
|
|
|
dev->dp8390.curr_page = 0;
|
|
|
|
|
|
|
|
|
|
dev->dp8390.rempkt_ptr = 0;
|
|
|
|
|
dev->dp8390.localpkt_ptr = 0;
|
|
|
|
|
dev->dp8390.address_cnt = 0;
|
|
|
|
|
|
|
|
|
|
memset(&dev->dp8390.mem, 0x00, sizeof(dev->dp8390.mem));
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
/* Set power-up conditions */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.CR.stop = 1;
|
|
|
|
|
dev->dp8390.CR.rdma_cmd = 4;
|
|
|
|
|
dev->dp8390.ISR.reset = 1;
|
|
|
|
|
dev->dp8390.DCR.longaddr = 1;
|
2017-05-12 05:05:20 -04:00
|
|
|
|
2017-06-02 02:22:38 +02:00
|
|
|
nic_interrupt(dev, 0);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-13 03:32:38 +02:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
static void
|
|
|
|
|
nic_soft_reset(void *priv)
|
|
|
|
|
{
|
|
|
|
|
nic_t *dev = (nic_t *)priv;
|
|
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
memset(&(dev->dp8390.ISR), 0x00, sizeof(dev->dp8390.ISR));
|
|
|
|
|
dev->dp8390.ISR.reset = 1;
|
2017-05-26 13:12:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Access the 32K 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.
|
2018-07-19 16:01:31 +02:00
|
|
|
* The first 16 bytes contain the MAC address at even locations,
|
2017-05-26 13:12:31 -04:00
|
|
|
* and there is 16K of buffer memory starting at 16K.
|
|
|
|
|
*/
|
2017-05-09 22:09:55 -04:00
|
|
|
static uint32_t
|
2017-05-12 05:05:20 -04:00
|
|
|
chipmem_read(nic_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)) {
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: unaligned chipmem word read\n", dev->name);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2018-07-24 01:53:46 +02:00
|
|
|
nelog(3, "Chipmem Read Address=%04x\n", addr);
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
/* ROM'd MAC address */
|
2018-07-19 16:01:31 +02:00
|
|
|
if (dev->board != NE2K_NE1000) {
|
2018-01-28 03:15:01 +01:00
|
|
|
if (addr <= 31) {
|
|
|
|
|
retval = dev->macaddr[addr % 32];
|
|
|
|
|
if ((len == 2) || (len == 4)) {
|
|
|
|
|
retval |= (dev->macaddr[(addr + 1) % 32] << 8);
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if ((addr >= DP8390_DWORD_MEMSTART) && (addr < DP8390_DWORD_MEMEND)) {
|
|
|
|
|
retval = dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART];
|
2018-01-28 03:15:01 +01:00
|
|
|
if ((len == 2) || (len == 4)) {
|
2018-07-15 01:41:53 +02:00
|
|
|
retval |= (dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART + 1] << 8);
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
|
|
|
|
if (len == 4) {
|
2018-07-15 01:41:53 +02:00
|
|
|
retval |= (dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART + 2] << 16);
|
|
|
|
|
retval |= (dev->dp8390.mem[addr - DP8390_DWORD_MEMSTART + 3] << 24);
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
|
|
|
|
return(retval);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (addr <= 15) {
|
|
|
|
|
retval = dev->macaddr[addr % 16];
|
|
|
|
|
if (len == 2) {
|
|
|
|
|
retval |= (dev->macaddr[(addr + 1) % 16] << 8);
|
|
|
|
|
}
|
|
|
|
|
return(retval);
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if ((addr >= DP8390_WORD_MEMSTART) && (addr < DP8390_WORD_MEMEND)) {
|
|
|
|
|
retval = dev->dp8390.mem[addr - DP8390_WORD_MEMSTART];
|
2018-01-28 03:15:01 +01:00
|
|
|
if (len == 2) {
|
2018-07-15 01:41:53 +02:00
|
|
|
retval |= (dev->dp8390.mem[addr - DP8390_WORD_MEMSTART + 1] << 8);
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
|
|
|
|
return(retval);
|
|
|
|
|
}
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: out-of-bounds chipmem read, %04X\n", dev->name, addr);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
if (dev->is_pci) {
|
2017-05-12 05:05:20 -04:00
|
|
|
return(0xff);
|
|
|
|
|
} else {
|
2017-05-09 22:09:55 -04:00
|
|
|
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
|
|
|
}
|
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
|
2017-05-12 05:05:20 -04:00
|
|
|
chipmem_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
|
|
|
|
if ((len == 2) && (addr & 0x1)) {
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: unaligned chipmem word write\n", dev->name);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
|
|
|
|
|
2018-07-24 01:53:46 +02:00
|
|
|
nelog(3, "Chipmem Write Address=%04x\n", addr);
|
|
|
|
|
|
2018-07-19 16:01:31 +02:00
|
|
|
if (dev->board != NE2K_NE1000) {
|
2018-07-15 01:41:53 +02:00
|
|
|
if ((addr >= DP8390_DWORD_MEMSTART) && (addr < DP8390_DWORD_MEMEND)) {
|
|
|
|
|
dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART] = val & 0xff;
|
2018-01-28 03:15:01 +01:00
|
|
|
if ((len == 2) || (len == 4)) {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART+1] = val >> 8;
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
|
|
|
|
if (len == 4) {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART+2] = val >> 16;
|
|
|
|
|
dev->dp8390.mem[addr-DP8390_DWORD_MEMSTART+3] = val >> 24;
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
nelog(3, "%s: out-of-bounds chipmem write, %04X\n", dev->name, addr);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
|
|
|
|
} else {
|
2018-07-15 01:41:53 +02:00
|
|
|
if ((addr >= DP8390_WORD_MEMSTART) && (addr < DP8390_WORD_MEMEND)) {
|
|
|
|
|
dev->dp8390.mem[addr-DP8390_WORD_MEMSTART] = val & 0xff;
|
2018-01-28 03:15:01 +01:00
|
|
|
if (len == 2) {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.mem[addr-DP8390_WORD_MEMSTART+1] = val >> 8;
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
nelog(3, "%s: out-of-bounds chipmem write, %04X\n", dev->name, addr);
|
|
|
|
|
}
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
/*
|
|
|
|
|
* Access the ASIC I/O space.
|
|
|
|
|
*
|
|
|
|
|
* 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 0x0f, 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
|
2017-05-12 05:05:20 -04:00
|
|
|
asic_read(nic_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-12 05:05:20 -04:00
|
|
|
switch(off) {
|
|
|
|
|
case 0x00: /* Data register */
|
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. */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (len > dev->dp8390.remote_bytes) {
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: DMA read underrun iolen=%d remote_bytes=%d\n",
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->name, len, dev->dp8390.remote_bytes);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-05-05 01:49:42 +02:00
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: DMA read: addr=%4x remote_bytes=%d\n",
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->name, dev->dp8390.remote_dma,dev->dp8390.remote_bytes);
|
|
|
|
|
retval = chipmem_read(dev, dev->dp8390.remote_dma, len);
|
2017-05-09 22:09:55 -04: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). */
|
|
|
|
|
if (len == 4) {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_dma += len;
|
2017-05-09 22:09:55 -04:00
|
|
|
} else {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_dma += (dev->dp8390.DCR.wdsize + 1);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-05-05 01:49:42 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.remote_dma == dev->dp8390.page_stop << 8) {
|
|
|
|
|
dev->dp8390.remote_dma = dev->dp8390.page_start << 8;
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
/* keep s.remote_bytes from underflowing */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.remote_bytes > dev->dp8390.DCR.wdsize) {
|
2017-05-09 22:09:55 -04:00
|
|
|
if (len == 4) {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_bytes -= len;
|
2017-05-09 22:09:55 -04:00
|
|
|
} else {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_bytes -= (dev->dp8390.DCR.wdsize + 1);
|
2017-02-07 02:19:48 +01:00
|
|
|
}
|
2017-05-09 22:09:55 -04:00
|
|
|
} else {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_bytes = 0;
|
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 all bytes have been written, signal remote-DMA complete */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.remote_bytes == 0) {
|
|
|
|
|
dev->dp8390.ISR.rdma_done = 1;
|
|
|
|
|
if (dev->dp8390.IMR.rdma_inte)
|
2017-06-02 02:22:38 +02:00
|
|
|
nic_interrupt(dev, 1);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
|
|
|
|
break;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-12 05:05:20 -04:00
|
|
|
case 0x0f: /* Reset register */
|
2017-05-26 13:12:31 -04:00
|
|
|
nic_soft_reset(dev);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
2018-07-19 16:01:31 +02:00
|
|
|
|
|
|
|
|
case 0x10:
|
|
|
|
|
case 0x11:
|
|
|
|
|
case 0x12:
|
|
|
|
|
case 0x13:
|
|
|
|
|
case 0x14:
|
|
|
|
|
case 0x15:
|
|
|
|
|
case 0x16:
|
|
|
|
|
case 0x17:
|
|
|
|
|
case 0x18:
|
|
|
|
|
case 0x19:
|
|
|
|
|
case 0x1a:
|
|
|
|
|
case 0x1b:
|
|
|
|
|
case 0x1c:
|
|
|
|
|
case 0x1d:
|
|
|
|
|
case 0x1e:
|
|
|
|
|
case 0x1f:
|
|
|
|
|
retval = 0;
|
|
|
|
|
break;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
default:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: ASIC read invalid address %04x\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, (unsigned)off);
|
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
|
|
|
return(retval);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
static void
|
2017-05-12 05:05:20 -04:00
|
|
|
asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(3, "%s: ASIC write addr=0x%02x, value=0x%04x\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, (unsigned)off, (unsigned) val);
|
2017-10-07 00:46:54 -04:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
switch(off) {
|
2017-05-12 05:05:20 -04:00
|
|
|
case 0x00: /* Data register - see asic_read for a description */
|
2018-07-15 01:41:53 +02:00
|
|
|
if ((len > 1) && (dev->dp8390.DCR.wdsize == 0)) {
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: DMA write length %d on byte mode operation\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, len);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.remote_bytes == 0)
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: DMA write, byte count 0\n", dev->name);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
chipmem_write(dev, dev->dp8390.remote_dma, val, len);
|
2017-10-07 00:46:54 -04:00
|
|
|
if (len == 4)
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_dma += len;
|
2017-10-07 00:46:54 -04:00
|
|
|
else
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_dma += (dev->dp8390.DCR.wdsize + 1);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.remote_dma == dev->dp8390.page_stop << 8)
|
|
|
|
|
dev->dp8390.remote_dma = dev->dp8390.page_start << 8;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
if (len == 4)
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_bytes -= len;
|
2017-10-07 00:46:54 -04:00
|
|
|
else
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_bytes -= (dev->dp8390.DCR.wdsize + 1);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.remote_bytes > DP8390_DWORD_MEMSIZ)
|
|
|
|
|
dev->dp8390.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 */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.remote_bytes == 0) {
|
|
|
|
|
dev->dp8390.ISR.rdma_done = 1;
|
|
|
|
|
if (dev->dp8390.IMR.rdma_inte)
|
2017-06-02 02:22:38 +02:00
|
|
|
nic_interrupt(dev, 1);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
|
|
|
|
break;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-12 05:05:20 -04:00
|
|
|
case 0x0f: /* Reset register */
|
2017-05-09 22:09:55 -04:00
|
|
|
/* end of reset pulse */
|
|
|
|
|
break;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2018-07-19 16:01:31 +02:00
|
|
|
case 0x10:
|
|
|
|
|
case 0x11:
|
|
|
|
|
case 0x12:
|
|
|
|
|
case 0x13:
|
|
|
|
|
case 0x14:
|
|
|
|
|
case 0x15:
|
|
|
|
|
case 0x16:
|
|
|
|
|
case 0x17:
|
|
|
|
|
case 0x18:
|
|
|
|
|
case 0x19:
|
|
|
|
|
case 0x1a:
|
|
|
|
|
case 0x1b:
|
|
|
|
|
case 0x1c:
|
|
|
|
|
case 0x1d:
|
|
|
|
|
case 0x1e:
|
|
|
|
|
case 0x1f:
|
|
|
|
|
break;
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
default: /* this is invalid, but happens under win95 device detection */
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: ASIC write invalid address %04x, ignoring\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, (unsigned)off);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */
|
2017-05-09 22:09:55 -04:00
|
|
|
static uint32_t
|
2017-05-12 05:05:20 -04:00
|
|
|
page0_read(nic_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 */
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: bad length! Page0 read from register 0x%02x, len=%u\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off, len);
|
2017-05-09 22:09:55 -04:00
|
|
|
return(retval);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch(off) {
|
|
|
|
|
case 0x01: /* CLDA0 */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = (dev->dp8390.local_dma & 0xff);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x02: /* CLDA1 */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = (dev->dp8390.local_dma >> 8);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x03: /* BNRY */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = dev->dp8390.bound_ptr;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x04: /* TSR */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = ((dev->dp8390.TSR.ow_coll << 7) |
|
|
|
|
|
(dev->dp8390.TSR.cd_hbeat << 6) |
|
|
|
|
|
(dev->dp8390.TSR.fifo_ur << 5) |
|
|
|
|
|
(dev->dp8390.TSR.no_carrier << 4) |
|
|
|
|
|
(dev->dp8390.TSR.aborted << 3) |
|
|
|
|
|
(dev->dp8390.TSR.collided << 2) |
|
|
|
|
|
(dev->dp8390.TSR.tx_ok));
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x05: /* NCR */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = dev->dp8390.num_coll;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x06: /* FIFO */
|
|
|
|
|
/* reading FIFO is only valid in loopback mode */
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: reading FIFO not supported yet\n", dev->name);
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = dev->dp8390.fifo;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x07: /* ISR */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = ((dev->dp8390.ISR.reset << 7) |
|
|
|
|
|
(dev->dp8390.ISR.rdma_done << 6) |
|
|
|
|
|
(dev->dp8390.ISR.cnt_oflow << 5) |
|
|
|
|
|
(dev->dp8390.ISR.overwrite << 4) |
|
|
|
|
|
(dev->dp8390.ISR.tx_err << 3) |
|
|
|
|
|
(dev->dp8390.ISR.rx_err << 2) |
|
|
|
|
|
(dev->dp8390.ISR.pkt_tx << 1) |
|
|
|
|
|
(dev->dp8390.ISR.pkt_rx));
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x08: /* CRDA0 */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = (dev->dp8390.remote_dma & 0xff);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x09: /* CRDA1 */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = (dev->dp8390.remote_dma >> 8);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0a: /* reserved / RTL8029ID0 */
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->board == NE2K_RTL8019AS) {
|
|
|
|
|
retval = 0x50;
|
|
|
|
|
} else if (dev->board == NE2K_RTL8029AS) {
|
2017-05-09 22:09:55 -04:00
|
|
|
retval = 0x50;
|
|
|
|
|
} else {
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: reserved Page0 read - 0x0a\n", dev->name);
|
2017-05-09 22:09:55 -04:00
|
|
|
retval = 0xff;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0b: /* reserved / RTL8029ID1 */
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->board == NE2K_RTL8019AS) {
|
|
|
|
|
retval = 0x70;
|
|
|
|
|
} else if (dev->board == NE2K_RTL8029AS) {
|
2017-05-09 22:09:55 -04:00
|
|
|
retval = 0x43;
|
|
|
|
|
} else {
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: reserved Page0 read - 0x0b\n", dev->name);
|
2017-05-09 22:09:55 -04:00
|
|
|
retval = 0xff;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0c: /* RSR */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = ((dev->dp8390.RSR.deferred << 7) |
|
|
|
|
|
(dev->dp8390.RSR.rx_disabled << 6) |
|
|
|
|
|
(dev->dp8390.RSR.rx_mbit << 5) |
|
|
|
|
|
(dev->dp8390.RSR.rx_missed << 4) |
|
|
|
|
|
(dev->dp8390.RSR.fifo_or << 3) |
|
|
|
|
|
(dev->dp8390.RSR.bad_falign << 2) |
|
|
|
|
|
(dev->dp8390.RSR.bad_crc << 1) |
|
|
|
|
|
(dev->dp8390.RSR.rx_ok));
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0d: /* CNTR0 */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = dev->dp8390.tallycnt_0;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0e: /* CNTR1 */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = dev->dp8390.tallycnt_1;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0f: /* CNTR2 */
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = dev->dp8390.tallycnt_2;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page0 register 0x%02x out of range\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page0 read from register 0x%02x, value=0x%02x\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off, retval);
|
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
|
2017-05-12 05:05:20 -04:00
|
|
|
page0_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
|
|
|
|
uint8_t val2;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page0 write to register 0x%02x, value=0x%02x\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off, val);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
switch(off) {
|
|
|
|
|
case 0x01: /* PSTART */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.page_start = val;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x02: /* PSTOP */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.page_stop = val;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x03: /* BNRY */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.bound_ptr = val;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x04: /* TPSR */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.tx_page_start = val;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x05: /* TBCR0 */
|
|
|
|
|
/* Clear out low byte and re-insert */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.tx_bytes &= 0xff00;
|
|
|
|
|
dev->dp8390.tx_bytes |= (val & 0xff);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x06: /* TBCR1 */
|
|
|
|
|
/* Clear out high byte and re-insert */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.tx_bytes &= 0x00ff;
|
|
|
|
|
dev->dp8390.tx_bytes |= ((val & 0xff) << 8);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x07: /* ISR */
|
|
|
|
|
val &= 0x7f; /* clear RST bit - status-only bit */
|
|
|
|
|
/* All other values are cleared iff the ISR bit is 1 */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.ISR.pkt_rx &= !((int)((val & 0x01) == 0x01));
|
|
|
|
|
dev->dp8390.ISR.pkt_tx &= !((int)((val & 0x02) == 0x02));
|
|
|
|
|
dev->dp8390.ISR.rx_err &= !((int)((val & 0x04) == 0x04));
|
|
|
|
|
dev->dp8390.ISR.tx_err &= !((int)((val & 0x08) == 0x08));
|
|
|
|
|
dev->dp8390.ISR.overwrite &= !((int)((val & 0x10) == 0x10));
|
|
|
|
|
dev->dp8390.ISR.cnt_oflow &= !((int)((val & 0x20) == 0x20));
|
|
|
|
|
dev->dp8390.ISR.rdma_done &= !((int)((val & 0x40) == 0x40));
|
|
|
|
|
val = ((dev->dp8390.ISR.rdma_done << 6) |
|
|
|
|
|
(dev->dp8390.ISR.cnt_oflow << 5) |
|
|
|
|
|
(dev->dp8390.ISR.overwrite << 4) |
|
|
|
|
|
(dev->dp8390.ISR.tx_err << 3) |
|
|
|
|
|
(dev->dp8390.ISR.rx_err << 2) |
|
|
|
|
|
(dev->dp8390.ISR.pkt_tx << 1) |
|
|
|
|
|
(dev->dp8390.ISR.pkt_rx));
|
|
|
|
|
val &= ((dev->dp8390.IMR.rdma_inte << 6) |
|
|
|
|
|
(dev->dp8390.IMR.cofl_inte << 5) |
|
|
|
|
|
(dev->dp8390.IMR.overw_inte << 4) |
|
|
|
|
|
(dev->dp8390.IMR.txerr_inte << 3) |
|
|
|
|
|
(dev->dp8390.IMR.rxerr_inte << 2) |
|
|
|
|
|
(dev->dp8390.IMR.tx_inte << 1) |
|
|
|
|
|
(dev->dp8390.IMR.rx_inte));
|
2017-06-01 21:49:57 -04:00
|
|
|
if (val == 0x00)
|
2017-06-02 02:22:38 +02:00
|
|
|
nic_interrupt(dev, 0);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x08: /* RSAR0 */
|
|
|
|
|
/* Clear out low byte and re-insert */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_start &= 0xff00;
|
|
|
|
|
dev->dp8390.remote_start |= (val & 0xff);
|
|
|
|
|
dev->dp8390.remote_dma = dev->dp8390.remote_start;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x09: /* RSAR1 */
|
|
|
|
|
/* Clear out high byte and re-insert */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_start &= 0x00ff;
|
|
|
|
|
dev->dp8390.remote_start |= ((val & 0xff) << 8);
|
|
|
|
|
dev->dp8390.remote_dma = dev->dp8390.remote_start;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0a: /* RBCR0 */
|
|
|
|
|
/* Clear out low byte and re-insert */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_bytes &= 0xff00;
|
|
|
|
|
dev->dp8390.remote_bytes |= (val & 0xff);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0b: /* RBCR1 */
|
|
|
|
|
/* Clear out high byte and re-insert */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_bytes &= 0x00ff;
|
|
|
|
|
dev->dp8390.remote_bytes |= ((val & 0xff) << 8);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0c: /* RCR */
|
|
|
|
|
/* Check if the reserved bits are set */
|
|
|
|
|
if (val & 0xc0) {
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: RCR write, reserved bits set\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
/* Set all other bit-fields */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.RCR.errors_ok = ((val & 0x01) == 0x01);
|
|
|
|
|
dev->dp8390.RCR.runts_ok = ((val & 0x02) == 0x02);
|
|
|
|
|
dev->dp8390.RCR.broadcast = ((val & 0x04) == 0x04);
|
|
|
|
|
dev->dp8390.RCR.multicast = ((val & 0x08) == 0x08);
|
|
|
|
|
dev->dp8390.RCR.promisc = ((val & 0x10) == 0x10);
|
|
|
|
|
dev->dp8390.RCR.monitor = ((val & 0x20) == 0x20);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
/* Monitor bit is a little suspicious... */
|
2017-05-24 00:27:42 -04:00
|
|
|
if (val & 0x20) nelog(3, "%s: RCR write, monitor bit set!\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name);
|
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 0x0d: /* TCR */
|
|
|
|
|
/* Check reserved bits */
|
2017-05-24 00:27:42 -04:00
|
|
|
if (val & 0xe0) nelog(3, "%s: TCR write, reserved bits set\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
/* Test loop mode (not supported) */
|
|
|
|
|
if (val & 0x06) {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.TCR.loop_cntl = (val & 0x6) >> 1;
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: TCR write, loop mode %d not supported\n",
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->name, dev->dp8390.TCR.loop_cntl);
|
2017-05-09 22:09:55 -04:00
|
|
|
} else {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.TCR.loop_cntl = 0;
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
/* Inhibit-CRC not supported. */
|
2017-05-24 00:27:42 -04:00
|
|
|
if (val & 0x01) nelog(3,
|
2017-05-12 05:05:20 -04:00
|
|
|
"%s: TCR write, inhibit-CRC not supported\n",dev->name);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
/* Auto-transmit disable very suspicious */
|
2017-05-24 00:27:42 -04:00
|
|
|
if (val & 0x08) nelog(3,
|
2017-05-12 05:05:20 -04:00
|
|
|
"%s: TCR write, auto transmit disable not supported\n",
|
|
|
|
|
dev->name);
|
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 */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.TCR.coll_prio = ((val & 0x08) == 0x08);
|
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 0x0e: /* DCR */
|
|
|
|
|
/* the loopback mode is not suppported yet */
|
2017-05-24 00:27:42 -04:00
|
|
|
if (! (val & 0x08)) nelog(3,
|
2017-05-12 05:05:20 -04:00
|
|
|
"%s: DCR write, loopback mode selected\n", dev->name);
|
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. */
|
2017-05-12 05:05:20 -04:00
|
|
|
if (val & 0x04)
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: DCR write - LAS set ???\n", dev->name);
|
2017-05-12 05:05:20 -04:00
|
|
|
if (val & 0x10)
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: DCR write - AR set ???\n", dev->name);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
/* Set other values. */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.DCR.wdsize = ((val & 0x01) == 0x01);
|
|
|
|
|
dev->dp8390.DCR.endian = ((val & 0x02) == 0x02);
|
|
|
|
|
dev->dp8390.DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */
|
|
|
|
|
dev->dp8390.DCR.loop = ((val & 0x08) == 0x08);
|
|
|
|
|
dev->dp8390.DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */
|
|
|
|
|
dev->dp8390.DCR.fifo_size = (val & 0x50) >> 5;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0f: /* IMR */
|
|
|
|
|
/* Check for reserved bit */
|
2017-05-12 05:05:20 -04:00
|
|
|
if (val & 0x80)
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: IMR write, reserved bit set\n",dev->name);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
/* Set other values */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.IMR.rx_inte = ((val & 0x01) == 0x01);
|
|
|
|
|
dev->dp8390.IMR.tx_inte = ((val & 0x02) == 0x02);
|
|
|
|
|
dev->dp8390.IMR.rxerr_inte = ((val & 0x04) == 0x04);
|
|
|
|
|
dev->dp8390.IMR.txerr_inte = ((val & 0x08) == 0x08);
|
|
|
|
|
dev->dp8390.IMR.overw_inte = ((val & 0x10) == 0x10);
|
|
|
|
|
dev->dp8390.IMR.cofl_inte = ((val & 0x20) == 0x20);
|
|
|
|
|
dev->dp8390.IMR.rdma_inte = ((val & 0x40) == 0x40);
|
|
|
|
|
val2 = ((dev->dp8390.ISR.rdma_done << 6) |
|
|
|
|
|
(dev->dp8390.ISR.cnt_oflow << 5) |
|
|
|
|
|
(dev->dp8390.ISR.overwrite << 4) |
|
|
|
|
|
(dev->dp8390.ISR.tx_err << 3) |
|
|
|
|
|
(dev->dp8390.ISR.rx_err << 2) |
|
|
|
|
|
(dev->dp8390.ISR.pkt_tx << 1) |
|
|
|
|
|
(dev->dp8390.ISR.pkt_rx));
|
2017-06-01 21:49:57 -04:00
|
|
|
if (((val & val2) & 0x7f) == 0)
|
2017-06-02 02:22:38 +02:00
|
|
|
nic_interrupt(dev, 0);
|
2017-06-01 21:49:57 -04:00
|
|
|
else
|
2017-06-02 02:22:38 +02:00
|
|
|
nic_interrupt(dev, 1);
|
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
|
|
|
default:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page0 write, bad register 0x%02x\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
/* Handle reads/writes to the first page of the DS8390 register file. */
|
2017-05-09 22:09:55 -04:00
|
|
|
static uint32_t
|
2017-05-12 05:05:20 -04:00
|
|
|
page1_read(nic_t *dev, uint32_t off, unsigned int len)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page1 read from register 0x%02x, len=%u\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off, len);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
switch(off) {
|
|
|
|
|
case 0x01: /* PAR0-5 */
|
|
|
|
|
case 0x02:
|
|
|
|
|
case 0x03:
|
|
|
|
|
case 0x04:
|
|
|
|
|
case 0x05:
|
|
|
|
|
case 0x06:
|
2018-07-15 01:41:53 +02:00
|
|
|
return(dev->dp8390.physaddr[off - 1]);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x07: /* CURR */
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: returning current page: 0x%02x\n",
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->name, (dev->dp8390.curr_page));
|
|
|
|
|
return(dev->dp8390.curr_page);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x08: /* MAR0-7 */
|
|
|
|
|
case 0x09:
|
|
|
|
|
case 0x0a:
|
|
|
|
|
case 0x0b:
|
|
|
|
|
case 0x0c:
|
|
|
|
|
case 0x0d:
|
|
|
|
|
case 0x0e:
|
|
|
|
|
case 0x0f:
|
2018-07-15 01:41:53 +02:00
|
|
|
return(dev->dp8390.mchash[off - 8]);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
default:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page1 read register 0x%02x out of range\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off);
|
2017-05-09 22:09:55 -04:00
|
|
|
return(0);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
static void
|
2017-05-12 05:05:20 -04:00
|
|
|
page1_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page1 write to register 0x%02x, len=%u, value=0x%04x\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off, len, val);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
switch(off) {
|
|
|
|
|
case 0x01: /* PAR0-5 */
|
|
|
|
|
case 0x02:
|
|
|
|
|
case 0x03:
|
|
|
|
|
case 0x04:
|
|
|
|
|
case 0x05:
|
|
|
|
|
case 0x06:
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.physaddr[off - 1] = val;
|
2017-05-24 00:27:42 -04:00
|
|
|
if (off == 6) nelog(3,
|
2017-05-12 05:05:20 -04:00
|
|
|
"%s: physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n",
|
|
|
|
|
dev->name,
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.physaddr[0], dev->dp8390.physaddr[1],
|
|
|
|
|
dev->dp8390.physaddr[2], dev->dp8390.physaddr[3],
|
|
|
|
|
dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x07: /* CURR */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.curr_page = val;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x08: /* MAR0-7 */
|
|
|
|
|
case 0x09:
|
|
|
|
|
case 0x0a:
|
|
|
|
|
case 0x0b:
|
|
|
|
|
case 0x0c:
|
|
|
|
|
case 0x0d:
|
|
|
|
|
case 0x0e:
|
|
|
|
|
case 0x0f:
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.mchash[off - 8] = val;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page1 write register 0x%02x out of range\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
|
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
/* Handle reads/writes to the second page of the DS8390 register file. */
|
2017-05-09 22:09:55 -04:00
|
|
|
static uint32_t
|
2017-05-12 05:05:20 -04:00
|
|
|
page2_read(nic_t *dev, uint32_t off, unsigned int len)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page2 read from register 0x%02x, len=%u\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off, len);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
switch(off) {
|
|
|
|
|
case 0x01: /* PSTART */
|
2018-07-15 01:41:53 +02:00
|
|
|
return(dev->dp8390.page_start);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x02: /* PSTOP */
|
2018-07-15 01:41:53 +02:00
|
|
|
return(dev->dp8390.page_stop);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x03: /* Remote Next-packet pointer */
|
2018-07-15 01:41:53 +02:00
|
|
|
return(dev->dp8390.rempkt_ptr);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x04: /* TPSR */
|
2018-07-15 01:41:53 +02:00
|
|
|
return(dev->dp8390.tx_page_start);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x05: /* Local Next-packet pointer */
|
2018-07-15 01:41:53 +02:00
|
|
|
return(dev->dp8390.localpkt_ptr);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x06: /* Address counter (upper) */
|
2018-07-15 01:41:53 +02:00
|
|
|
return(dev->dp8390.address_cnt >> 8);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x07: /* Address counter (lower) */
|
2018-07-15 01:41:53 +02:00
|
|
|
return(dev->dp8390.address_cnt & 0xff);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x08: /* Reserved */
|
|
|
|
|
case 0x09:
|
|
|
|
|
case 0x0a:
|
|
|
|
|
case 0x0b:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: reserved Page2 read - register 0x%02x\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off);
|
2017-05-09 22:09:55 -04:00
|
|
|
return(0xff);
|
|
|
|
|
|
|
|
|
|
case 0x0c: /* RCR */
|
2018-07-15 01:41:53 +02:00
|
|
|
return ((dev->dp8390.RCR.monitor << 5) |
|
|
|
|
|
(dev->dp8390.RCR.promisc << 4) |
|
|
|
|
|
(dev->dp8390.RCR.multicast << 3) |
|
|
|
|
|
(dev->dp8390.RCR.broadcast << 2) |
|
|
|
|
|
(dev->dp8390.RCR.runts_ok << 1) |
|
|
|
|
|
(dev->dp8390.RCR.errors_ok));
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x0d: /* TCR */
|
2018-07-15 01:41:53 +02:00
|
|
|
return ((dev->dp8390.TCR.coll_prio << 4) |
|
|
|
|
|
(dev->dp8390.TCR.ext_stoptx << 3) |
|
|
|
|
|
((dev->dp8390.TCR.loop_cntl & 0x3) << 1) |
|
|
|
|
|
(dev->dp8390.TCR.crc_disable));
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x0e: /* DCR */
|
2018-07-15 01:41:53 +02:00
|
|
|
return (((dev->dp8390.DCR.fifo_size & 0x3) << 5) |
|
|
|
|
|
(dev->dp8390.DCR.auto_rx << 4) |
|
|
|
|
|
(dev->dp8390.DCR.loop << 3) |
|
|
|
|
|
(dev->dp8390.DCR.longaddr << 2) |
|
|
|
|
|
(dev->dp8390.DCR.endian << 1) |
|
|
|
|
|
(dev->dp8390.DCR.wdsize));
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
case 0x0f: /* IMR */
|
2018-07-15 01:41:53 +02:00
|
|
|
return ((dev->dp8390.IMR.rdma_inte << 6) |
|
|
|
|
|
(dev->dp8390.IMR.cofl_inte << 5) |
|
|
|
|
|
(dev->dp8390.IMR.overw_inte << 4) |
|
|
|
|
|
(dev->dp8390.IMR.txerr_inte << 3) |
|
|
|
|
|
(dev->dp8390.IMR.rxerr_inte << 2) |
|
|
|
|
|
(dev->dp8390.IMR.tx_inte << 1) |
|
|
|
|
|
(dev->dp8390.IMR.rx_inte));
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
default:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page2 register 0x%02x out of range\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return(0);
|
|
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
static void
|
2017-05-12 05:05:20 -04:00
|
|
|
page2_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
|
|
|
|
/* Maybe all writes here should be BX_PANIC()'d, since they
|
|
|
|
|
affect internal operation, but let them through for now
|
|
|
|
|
and print a warning. */
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page2 write to register 0x%02x, len=%u, value=0x%04x\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off, len, val);
|
2017-05-09 22:09:55 -04:00
|
|
|
switch(off) {
|
|
|
|
|
case 0x01: /* CLDA0 */
|
|
|
|
|
/* Clear out low byte and re-insert */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.local_dma &= 0xff00;
|
|
|
|
|
dev->dp8390.local_dma |= (val & 0xff);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x02: /* CLDA1 */
|
|
|
|
|
/* Clear out high byte and re-insert */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.local_dma &= 0x00ff;
|
|
|
|
|
dev->dp8390.local_dma |= ((val & 0xff) << 8);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x03: /* Remote Next-pkt pointer */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.rempkt_ptr = val;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x04:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "page 2 write to reserved register 0x04\n");
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x05: /* Local Next-packet pointer */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.localpkt_ptr = val;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x06: /* Address counter (upper) */
|
|
|
|
|
/* Clear out high byte and re-insert */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.address_cnt &= 0x00ff;
|
|
|
|
|
dev->dp8390.address_cnt |= ((val & 0xff) << 8);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x07: /* Address counter (lower) */
|
|
|
|
|
/* Clear out low byte and re-insert */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.address_cnt &= 0xff00;
|
|
|
|
|
dev->dp8390.address_cnt |= (val & 0xff);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x08:
|
|
|
|
|
case 0x09:
|
|
|
|
|
case 0x0a:
|
|
|
|
|
case 0x0b:
|
|
|
|
|
case 0x0c:
|
|
|
|
|
case 0x0d:
|
|
|
|
|
case 0x0e:
|
|
|
|
|
case 0x0f:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page2 write to reserved register 0x%02x\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page2 write, illegal register 0x%02x\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, off);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
|
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
/* Writes to this page are illegal. */
|
2017-05-09 22:09:55 -04:00
|
|
|
static uint32_t
|
2017-05-12 05:05:20 -04:00
|
|
|
page3_read(nic_t *dev, uint32_t off, unsigned int len)
|
|
|
|
|
{
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->board >= NE2K_RTL8019AS) switch(off) {
|
2018-01-13 22:56:13 +01:00
|
|
|
case 0x1: /* 9346CR */
|
|
|
|
|
return(dev->_9346cr);
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
case 0x3: /* CONFIG0 */
|
2018-01-13 22:56:13 +01:00
|
|
|
return(0x00); /* Cable not BNC */
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
case 0x5: /* CONFIG2 */
|
2018-01-13 22:56:13 +01:00
|
|
|
return(dev->config2 & 0xe0);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
case 0x6: /* CONFIG3 */
|
2018-01-13 22:56:13 +01:00
|
|
|
return(dev->config3 & 0x46);
|
|
|
|
|
|
2018-01-28 03:15:01 +01:00
|
|
|
case 0x8: /* CSNSAV */
|
|
|
|
|
return((dev->board == NE2K_RTL8019AS) ? dev->pnp_csnsav : 0x00);
|
|
|
|
|
|
2018-01-13 22:56:13 +01:00
|
|
|
case 0xe: /* 8029ASID0 */
|
|
|
|
|
return(0x29);
|
|
|
|
|
|
|
|
|
|
case 0xf: /* 8029ASID1 */
|
|
|
|
|
return(0x08);
|
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-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: Page3 read register 0x%02x attempted\n", dev->name, off);
|
2017-05-09 22:09:55 -04:00
|
|
|
return(0x00);
|
|
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
static void
|
2017-05-12 05:05:20 -04:00
|
|
|
page3_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->board >= NE2K_RTL8019AS) {
|
2018-01-13 22:56:13 +01:00
|
|
|
nelog(3, "%s: Page2 write to register 0x%02x, len=%u, value=0x%04x\n",
|
|
|
|
|
dev->name, off, len, val);
|
|
|
|
|
|
|
|
|
|
switch(off) {
|
|
|
|
|
case 0x01: /* 9346CR */
|
|
|
|
|
dev->_9346cr = (val & 0xfe);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x05: /* CONFIG2 */
|
|
|
|
|
dev->config2 = (val & 0xe0);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x06: /* CONFIG3 */
|
|
|
|
|
dev->config3 = (val & 0x46);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x09: /* HLTCLK */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
nelog(3, "%s: Page3 write to reserved register 0x%02x\n",
|
|
|
|
|
dev->name, off);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
nelog(3, "%s: Page3 write register 0x%02x attempted\n", dev->name, off);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
|
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
/* Routines for handling reads/writes to the Command Register. */
|
2017-05-09 22:09:55 -04:00
|
|
|
static uint32_t
|
2017-05-12 05:05:20 -04:00
|
|
|
read_cr(nic_t *dev)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
|
|
|
|
uint32_t retval;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
retval = (((dev->dp8390.CR.pgsel & 0x03) << 6) |
|
|
|
|
|
((dev->dp8390.CR.rdma_cmd & 0x07) << 3) |
|
|
|
|
|
(dev->dp8390.CR.tx_packet << 2) |
|
|
|
|
|
(dev->dp8390.CR.start << 1) |
|
|
|
|
|
(dev->dp8390.CR.stop));
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: read CR returns 0x%02x\n", dev->name, 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
|
2017-05-12 05:05:20 -04:00
|
|
|
write_cr(nic_t *dev, uint32_t val)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: wrote 0x%02x to CR\n", dev->name, val);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
/* Validate remote-DMA */
|
|
|
|
|
if ((val & 0x38) == 0x00) {
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: CR write - invalid rDMA value 0\n", dev->name);
|
2017-05-09 22:09:55 -04:00
|
|
|
val |= 0x20; /* dma_cmd == 4 is a safe default */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check for s/w reset */
|
|
|
|
|
if (val & 0x01) {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.ISR.reset = 1;
|
|
|
|
|
dev->dp8390.CR.stop = 1;
|
2017-05-09 22:09:55 -04:00
|
|
|
} else {
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.CR.stop = 0;
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
|
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.CR.rdma_cmd = (val & 0x38) >> 3;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
/* If start command issued, the RST bit in the ISR */
|
|
|
|
|
/* must be cleared */
|
2018-07-15 01:41:53 +02:00
|
|
|
if ((val & 0x02) && !dev->dp8390.CR.start)
|
|
|
|
|
dev->dp8390.ISR.reset = 0;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.CR.start = ((val & 0x02) == 0x02);
|
|
|
|
|
dev->dp8390.CR.pgsel = (val & 0xc0) >> 6;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
/* Check for send-packet command */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.CR.rdma_cmd == 3) {
|
2017-05-09 22:09:55 -04:00
|
|
|
/* Set up DMA read from receive ring */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.remote_start = dev->dp8390.remote_dma = dev->dp8390.bound_ptr * 256;
|
|
|
|
|
dev->dp8390.remote_bytes = (uint16_t) chipmem_read(dev, dev->dp8390.bound_ptr * 256 + 2, 2);
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: sending buffer #x%x length %d\n",
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->name, dev->dp8390.remote_start, dev->dp8390.remote_bytes);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Check for start-tx */
|
2018-07-15 01:41:53 +02:00
|
|
|
if ((val & 0x04) && dev->dp8390.TCR.loop_cntl) {
|
|
|
|
|
if (dev->dp8390.TCR.loop_cntl != 1) {
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: loop mode %d not supported\n",
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->name, dev->dp8390.TCR.loop_cntl);
|
2017-05-09 22:09:55 -04:00
|
|
|
} else {
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->board >= NE2K_NE2000) {
|
|
|
|
|
nic_rx(dev,
|
2018-07-15 01:41:53 +02:00
|
|
|
&dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_DWORD_MEMSTART],
|
|
|
|
|
dev->dp8390.tx_bytes);
|
2018-01-28 03:15:01 +01:00
|
|
|
} else {
|
|
|
|
|
nic_rx(dev,
|
2018-07-15 01:41:53 +02:00
|
|
|
&dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART],
|
|
|
|
|
dev->dp8390.tx_bytes);
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
|
|
|
|
} else if (val & 0x04) {
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.CR.stop || (!dev->dp8390.CR.start && (dev->board < NE2K_RTL8019AS))) {
|
|
|
|
|
if (dev->dp8390.tx_bytes == 0) /* njh@bandsman.co.uk */ {
|
2017-05-09 22:09:55 -04:00
|
|
|
return; /* Solaris9 probe */
|
|
|
|
|
}
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: CR write - tx start, dev in reset\n", dev->name);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.tx_bytes == 0)
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: CR write - tx start, tx bytes == 0\n", dev->name);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
/* Send the packet to the system driver */
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.CR.tx_packet = 1;
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->board >= NE2K_NE2000) {
|
2018-07-15 01:41:53 +02:00
|
|
|
network_tx(&dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_DWORD_MEMSTART],
|
|
|
|
|
dev->dp8390.tx_bytes);
|
2018-01-28 03:15:01 +01:00
|
|
|
} else {
|
2018-07-15 01:41:53 +02:00
|
|
|
network_tx(&dev->dp8390.mem[dev->dp8390.tx_page_start*256 - DP8390_WORD_MEMSTART],
|
|
|
|
|
dev->dp8390.tx_bytes);
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
/* some more debug */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.tx_timer_active)
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: CR write, tx timer still active\n", dev->name);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_tx(dev, val);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
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 */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.CR.rdma_cmd == 0x01 && dev->dp8390.CR.start && dev->dp8390.remote_bytes == 0) {
|
|
|
|
|
dev->dp8390.ISR.rdma_done = 1;
|
|
|
|
|
if (dev->dp8390.IMR.rdma_inte) {
|
2017-06-02 02:22:38 +02:00
|
|
|
nic_interrupt(dev, 1);
|
2018-07-19 16:01:31 +02:00
|
|
|
if (!dev->is_pci)
|
2017-06-02 02:22:38 +02:00
|
|
|
nic_interrupt(dev, 0);
|
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
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_read(nic_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;
|
|
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: read addr %x, len %d\n", dev->name, addr, len);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2018-07-19 16:01:31 +02:00
|
|
|
if (off >= 0x10) {
|
|
|
|
|
retval = asic_read(dev, off - 0x10, len);
|
|
|
|
|
} else if (off == 0x00) {
|
2017-05-09 22:09:55 -04:00
|
|
|
retval = read_cr(dev);
|
2018-07-19 16:01:31 +02:00
|
|
|
} else switch(dev->dp8390.CR.pgsel) {
|
2017-05-09 22:09:55 -04:00
|
|
|
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:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: unknown value of pgsel in read - %d\n",
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->name, dev->dp8390.CR.pgsel);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
2018-07-19 16:01:31 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
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
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_readb(uint16_t addr, void *priv)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
return(nic_read((nic_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
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_readw(uint16_t addr, void *priv)
|
2016-08-13 03:32:38 +02:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_t *dev = (nic_t *)priv;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.DCR.wdsize & 1)
|
2017-05-12 05:05:20 -04:00
|
|
|
return(nic_read(dev, addr, 2));
|
2017-05-09 22:09:55 -04:00
|
|
|
else
|
2017-05-12 05:05:20 -04:00
|
|
|
return(nic_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
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_readl(uint16_t addr, void *priv)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
return(nic_read((nic_t *)priv, addr, 4));
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
static void
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
|
|
|
|
int off = addr - dev->base_address;
|
|
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: write addr %x, value %x len %d\n", dev->name, addr, val, len);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2018-07-19 16:01:31 +02:00
|
|
|
/* 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) {
|
2017-05-09 22:09:55 -04:00
|
|
|
write_cr(dev, val);
|
2018-07-19 16:01:31 +02:00
|
|
|
} else switch(dev->dp8390.CR.pgsel) {
|
2017-05-09 22:09:55 -04:00
|
|
|
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:
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(3, "%s: unknown value of pgsel in write - %d\n",
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->name, dev->dp8390.CR.pgsel);
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
2018-07-19 16:01:31 +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
|
|
|
static void
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_writeb(uint16_t addr, uint8_t val, void *priv)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_write((nic_t *)priv, addr, val, 1);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
static void
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_writew(uint16_t addr, uint16_t val, void *priv)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_t *dev = (nic_t *)priv;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.DCR.wdsize & 1)
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_write(dev, addr, val, 2);
|
2017-05-09 22:09:55 -04:00
|
|
|
else
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_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
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_writel(uint16_t addr, uint32_t val, void *priv)
|
2016-08-13 03:32:38 +02:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_write((nic_t *)priv, addr, val, 4);
|
2016-08-13 03:32:38 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2018-01-28 03:15:01 +01:00
|
|
|
static void nic_iocheckset(nic_t *dev, uint16_t addr);
|
|
|
|
|
static void nic_iocheckremove(nic_t *dev, uint16_t addr);
|
|
|
|
|
static void nic_ioset(nic_t *dev, uint16_t addr);
|
|
|
|
|
static void nic_ioremove(nic_t *dev, uint16_t addr);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t
|
|
|
|
|
nic_pnp_io_check_readb(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
nic_t *dev = (nic_t *) priv;
|
|
|
|
|
|
|
|
|
|
return((dev->pnp_io_check & 0x01) ? 0x55 : 0xAA);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static uint8_t
|
|
|
|
|
nic_pnp_readb(uint16_t addr, void *priv)
|
|
|
|
|
{
|
|
|
|
|
nic_t *dev = (nic_t *) priv;
|
|
|
|
|
uint8_t bit, next_shift;
|
|
|
|
|
uint8_t ret = 0xFF;
|
|
|
|
|
|
|
|
|
|
/* Plug and Play Registers */
|
|
|
|
|
switch(dev->pnp_address) {
|
|
|
|
|
/* Card Control Registers */
|
|
|
|
|
case 0x01: /* Serial Isolation */
|
|
|
|
|
if (dev->pnp_phase != PNP_PHASE_ISOLATION) {
|
|
|
|
|
ret = 0x00;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (dev->pnp_serial_read_pair) {
|
|
|
|
|
dev->pnp_serial_read <<= 1;
|
|
|
|
|
/* TODO: Support for multiple PnP devices.
|
|
|
|
|
if (pnp_get_bus_data() != dev->pnp_serial_read)
|
|
|
|
|
dev->pnp_phase = PNP_PHASE_SLEEP;
|
|
|
|
|
} else {
|
|
|
|
|
*/
|
|
|
|
|
if (!dev->pnp_serial_read_pos) {
|
|
|
|
|
dev->pnp_res_pos = 0x1B;
|
|
|
|
|
dev->pnp_phase = PNP_PHASE_CONFIG;
|
|
|
|
|
nelog(1, "\nASSIGN CSN phase\n");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (dev->pnp_serial_read_pos < 64) {
|
|
|
|
|
bit = (dev->pnp_id >> dev->pnp_serial_read_pos) & 0x01;
|
|
|
|
|
next_shift = (!!(dev->pnp_id_checksum & 0x02) ^ !!(dev->pnp_id_checksum & 0x01) ^ bit) & 0x01;
|
|
|
|
|
dev->pnp_id_checksum >>= 1;
|
|
|
|
|
dev->pnp_id_checksum |= (next_shift << 7);
|
|
|
|
|
} else {
|
|
|
|
|
if (dev->pnp_serial_read_pos == 64)
|
|
|
|
|
dev->eeprom[0x1A] = dev->pnp_id_checksum;
|
|
|
|
|
bit = (dev->pnp_id_checksum >> (dev->pnp_serial_read_pos & 0x07)) & 0x01;
|
|
|
|
|
}
|
|
|
|
|
dev->pnp_serial_read = bit ? 0x55 : 0x00;
|
|
|
|
|
dev->pnp_serial_read_pos = (dev->pnp_serial_read_pos + 1) % 72;
|
|
|
|
|
}
|
|
|
|
|
dev->pnp_serial_read_pair ^= 1;
|
|
|
|
|
ret = dev->pnp_serial_read;
|
|
|
|
|
break;
|
|
|
|
|
case 0x04: /* Resource Data */
|
|
|
|
|
ret = dev->eeprom[dev->pnp_res_pos];
|
|
|
|
|
dev->pnp_res_pos++;
|
|
|
|
|
break;
|
|
|
|
|
case 0x05: /* Status */
|
|
|
|
|
ret = 0x01;
|
|
|
|
|
break;
|
|
|
|
|
case 0x06: /* Card Select Number (CSN) */
|
|
|
|
|
nelog(1, "Card Select Number (CSN)\n");
|
|
|
|
|
ret = dev->pnp_csn;
|
|
|
|
|
break;
|
|
|
|
|
case 0x07: /* Logical Device Number */
|
|
|
|
|
nelog(1, "Logical Device Number\n");
|
|
|
|
|
ret = 0x00;
|
|
|
|
|
break;
|
|
|
|
|
case 0x30: /* Activate */
|
|
|
|
|
nelog(1, "Activate\n");
|
|
|
|
|
ret = dev->pnp_activate;
|
|
|
|
|
break;
|
|
|
|
|
case 0x31: /* I/O Range Check */
|
|
|
|
|
nelog(1, "I/O Range Check\n");
|
|
|
|
|
ret = dev->pnp_io_check;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Logical Device Configuration Registers */
|
|
|
|
|
/* Memory Configuration Registers
|
|
|
|
|
We currently force them to stay 0x00 because we currently do not
|
|
|
|
|
support a RTL8019AS BIOS. */
|
|
|
|
|
case 0x40: /* BROM base address bits[23:16] */
|
|
|
|
|
case 0x41: /* BROM base address bits[15:0] */
|
|
|
|
|
case 0x42: /* Memory Control */
|
|
|
|
|
ret = 0x00;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* I/O Configuration Registers */
|
|
|
|
|
case 0x60: /* I/O base address bits[15:8] */
|
|
|
|
|
ret = (dev->base_address >> 8);
|
|
|
|
|
break;
|
|
|
|
|
case 0x61: /* I/O base address bits[7:0] */
|
|
|
|
|
ret = (dev->base_address & 0xFF);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Interrupt Configuration Registers */
|
|
|
|
|
case 0x70: /* IRQ level */
|
|
|
|
|
ret = dev->base_irq;
|
|
|
|
|
break;
|
|
|
|
|
case 0x71: /* IRQ type */
|
|
|
|
|
ret = 0x02; /* high, edge */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* DMA Configuration Registers */
|
|
|
|
|
case 0x74: /* DMA channel select 0 */
|
|
|
|
|
case 0x75: /* DMA channel select 1 */
|
|
|
|
|
ret = 0x04; /* indicating no DMA channel is needed */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Vendor Defined Registers */
|
|
|
|
|
case 0xF0: /* CONFIG0 */
|
|
|
|
|
case 0xF1: /* CONFIG1 */
|
|
|
|
|
ret = 0x00;
|
|
|
|
|
break;
|
|
|
|
|
case 0xF2: /* CONFIG2 */
|
|
|
|
|
ret = (dev->config2 & 0xe0);
|
|
|
|
|
break;
|
|
|
|
|
case 0xF3: /* CONFIG3 */
|
|
|
|
|
ret = (dev->config3 & 0x46);
|
|
|
|
|
break;
|
|
|
|
|
case 0xF5: /* CSNSAV */
|
|
|
|
|
ret = (dev->pnp_csnsav);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nelog(1, "nic_pnp_readb(%04X) = %02X\n", addr, ret);
|
|
|
|
|
return(ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void nic_pnp_io_set(nic_t *dev, uint16_t read_addr);
|
|
|
|
|
static void nic_pnp_io_remove(nic_t *dev);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nic_pnp_writeb(uint16_t addr, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
nic_t *dev = (nic_t *) priv;
|
|
|
|
|
uint16_t new_addr = 0;
|
|
|
|
|
|
|
|
|
|
nelog(1, "nic_pnp_writeb(%04X, %02X)\n", addr, val);
|
|
|
|
|
|
|
|
|
|
/* Plug and Play Registers */
|
|
|
|
|
switch(dev->pnp_address) {
|
|
|
|
|
/* Card Control Registers */
|
|
|
|
|
case 0x00: /* Set RD_DATA port */
|
|
|
|
|
new_addr = val;
|
|
|
|
|
new_addr <<= 2;
|
|
|
|
|
new_addr |= 3;
|
|
|
|
|
nic_pnp_io_remove(dev);
|
|
|
|
|
nic_pnp_io_set(dev, new_addr);
|
|
|
|
|
nelog(1, "PnP read data address now: %04X\n", new_addr);
|
|
|
|
|
break;
|
|
|
|
|
case 0x02: /* Config Control */
|
|
|
|
|
if (val & 0x01) {
|
|
|
|
|
/* Reset command */
|
|
|
|
|
nic_pnp_io_remove(dev);
|
|
|
|
|
memset(dev->pnp_regs, 0, 256);
|
|
|
|
|
nelog(1, "All logical devices reset\n");
|
|
|
|
|
}
|
|
|
|
|
if (val & 0x02) {
|
|
|
|
|
/* Wait for Key command */
|
|
|
|
|
dev->pnp_phase = PNP_PHASE_WAIT_FOR_KEY;
|
|
|
|
|
nelog(1, "WAIT FOR KEY phase\n");
|
|
|
|
|
}
|
|
|
|
|
if (val & 0x04) {
|
|
|
|
|
/* PnP Reset CSN command */
|
|
|
|
|
dev->pnp_csn = dev->pnp_csnsav = 0;
|
|
|
|
|
nelog(1, "CSN reset\n");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0x03: /* Wake[CSN] */
|
|
|
|
|
nelog(1, "Wake[%02X]\n", val);
|
|
|
|
|
if (val == dev->pnp_csn) {
|
|
|
|
|
dev->pnp_res_pos = 0x12;
|
|
|
|
|
dev->pnp_id_checksum = 0x6A;
|
|
|
|
|
if (dev->pnp_phase == PNP_PHASE_SLEEP) {
|
|
|
|
|
dev->pnp_phase = val ? PNP_PHASE_CONFIG : PNP_PHASE_ISOLATION;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if ((dev->pnp_phase == PNP_PHASE_CONFIG) || (dev->pnp_phase == PNP_PHASE_ISOLATION))
|
|
|
|
|
dev->pnp_phase = PNP_PHASE_SLEEP;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 0x06: /* Card Select Number (CSN) */
|
|
|
|
|
dev->pnp_csn = dev->pnp_csnsav = val;
|
|
|
|
|
dev->pnp_phase = PNP_PHASE_CONFIG;
|
|
|
|
|
nelog(1, "CSN set to %02X\n", dev->pnp_csn);
|
|
|
|
|
break;
|
|
|
|
|
case 0x30: /* Activate */
|
|
|
|
|
if ((dev->pnp_activate ^ val) & 0x01) {
|
|
|
|
|
nic_ioremove(dev, dev->base_address);
|
|
|
|
|
if (val & 0x01)
|
|
|
|
|
nic_ioset(dev, dev->base_address);
|
|
|
|
|
|
|
|
|
|
nelog(1, "I/O range %sabled\n", val & 0x02 ? "en" : "dis");
|
|
|
|
|
}
|
|
|
|
|
dev->pnp_activate = val;
|
|
|
|
|
break;
|
|
|
|
|
case 0x31: /* I/O Range Check */
|
|
|
|
|
if ((dev->pnp_io_check ^ val) & 0x02) {
|
|
|
|
|
nic_iocheckremove(dev, dev->base_address);
|
|
|
|
|
if (val & 0x02)
|
|
|
|
|
nic_iocheckset(dev, dev->base_address);
|
|
|
|
|
|
|
|
|
|
nelog(1, "I/O range check %sabled\n", val & 0x02 ? "en" : "dis");
|
|
|
|
|
}
|
|
|
|
|
dev->pnp_io_check = val;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Logical Device Configuration Registers */
|
|
|
|
|
/* Memory Configuration Registers
|
|
|
|
|
We currently force them to stay 0x00 because we currently do not
|
|
|
|
|
support a RTL8019AS BIOS. */
|
|
|
|
|
|
|
|
|
|
/* I/O Configuration Registers */
|
|
|
|
|
case 0x60: /* I/O base address bits[15:8] */
|
|
|
|
|
if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02))
|
|
|
|
|
nic_ioremove(dev, dev->base_address);
|
|
|
|
|
dev->base_address &= 0x00ff;
|
|
|
|
|
dev->base_address |= (((uint16_t) val) << 8);
|
|
|
|
|
if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02))
|
|
|
|
|
nic_ioset(dev, dev->base_address);
|
|
|
|
|
nelog(1, "Base address now: %04X\n", dev->base_address);
|
|
|
|
|
break;
|
|
|
|
|
case 0x61: /* I/O base address bits[7:0] */
|
|
|
|
|
if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02))
|
|
|
|
|
nic_ioremove(dev, dev->base_address);
|
|
|
|
|
dev->base_address &= 0xff00;
|
|
|
|
|
dev->base_address |= val;
|
|
|
|
|
if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02))
|
|
|
|
|
nic_ioset(dev, dev->base_address);
|
|
|
|
|
nelog(1, "Base address now: %04X\n", dev->base_address);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Interrupt Configuration Registers */
|
|
|
|
|
case 0x70: /* IRQ level */
|
|
|
|
|
dev->base_irq = val;
|
|
|
|
|
nelog(1, "IRQ now: %02i\n", dev->base_irq);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Vendor Defined Registers */
|
|
|
|
|
case 0xF6: /* Vendor Control */
|
|
|
|
|
dev->pnp_csn = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nic_pnp_io_set(nic_t *dev, uint16_t read_addr)
|
|
|
|
|
{
|
|
|
|
|
if ((read_addr >= 0x0200) && (read_addr <= 0x03FF)) {
|
|
|
|
|
io_sethandler(read_addr, 1,
|
|
|
|
|
nic_pnp_readb, NULL, NULL,
|
|
|
|
|
NULL, NULL, NULL, dev);
|
|
|
|
|
}
|
|
|
|
|
dev->pnp_read = read_addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nic_pnp_io_remove(nic_t *dev)
|
|
|
|
|
{
|
2018-02-02 00:14:17 +01:00
|
|
|
if ((dev->pnp_read >= 0x0200) && (dev->pnp_read <= 0x03FF)) {
|
|
|
|
|
io_removehandler(dev->pnp_read, 1,
|
|
|
|
|
nic_pnp_readb, NULL, NULL,
|
|
|
|
|
NULL, NULL, NULL, dev);
|
|
|
|
|
}
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nic_pnp_address_writeb(uint16_t addr, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
nic_t *dev = (nic_t *) priv;
|
|
|
|
|
|
|
|
|
|
/* nelog(1, "nic_pnp_address_writeb(%04X, %02X)\n", addr, val); */
|
|
|
|
|
|
|
|
|
|
switch(dev->pnp_phase) {
|
|
|
|
|
case PNP_PHASE_WAIT_FOR_KEY:
|
|
|
|
|
if (val == pnp_init_key[dev->pnp_magic_count]) {
|
|
|
|
|
dev->pnp_magic_count = (dev->pnp_magic_count + 1) & 0x1f;
|
2018-02-02 00:14:17 +01:00
|
|
|
if (!dev->pnp_magic_count)
|
2018-01-28 03:15:01 +01:00
|
|
|
dev->pnp_phase = PNP_PHASE_SLEEP;
|
|
|
|
|
} else
|
|
|
|
|
dev->pnp_magic_count = 0;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
dev->pnp_address = val;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nic_iocheckset(nic_t *dev, uint16_t addr)
|
|
|
|
|
{
|
|
|
|
|
io_sethandler(addr, 32,
|
|
|
|
|
nic_pnp_io_check_readb, NULL, NULL,
|
|
|
|
|
NULL, NULL, NULL, dev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nic_iocheckremove(nic_t *dev, uint16_t addr)
|
|
|
|
|
{
|
|
|
|
|
io_removehandler(addr, 32,
|
|
|
|
|
nic_pnp_io_check_readb, NULL, NULL,
|
|
|
|
|
NULL, NULL, NULL, dev);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
static void
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_ioset(nic_t *dev, uint16_t addr)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
2018-07-19 16:01:31 +02:00
|
|
|
if (dev->is_mca) {
|
2017-05-09 22:09:55 -04:00
|
|
|
io_sethandler(addr, 16,
|
2018-07-19 16:01:31 +02:00
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
|
|
|
|
io_sethandler(addr+16, 16,
|
|
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
|
|
|
|
io_sethandler(addr+0x1f, 16,
|
|
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
|
|
|
|
}
|
|
|
|
|
else if (dev->is_pci) {
|
|
|
|
|
io_sethandler(addr, 16,
|
|
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
2017-05-09 22:09:55 -04:00
|
|
|
io_sethandler(addr+16, 16,
|
2018-07-19 16:01:31 +02:00
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
2017-05-09 22:09:55 -04:00
|
|
|
io_sethandler(addr+0x1f, 1,
|
2018-07-19 16:01:31 +02:00
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
2017-05-09 22:09:55 -04:00
|
|
|
} else {
|
|
|
|
|
io_sethandler(addr, 16,
|
2018-07-19 16:01:31 +02:00
|
|
|
nic_readb, NULL, NULL,
|
|
|
|
|
nic_writeb, NULL, NULL, dev);
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->is_8bit) {
|
|
|
|
|
io_sethandler(addr+16, 16,
|
2018-07-19 16:01:31 +02:00
|
|
|
nic_readb, NULL, NULL,
|
|
|
|
|
nic_writeb, NULL, NULL, dev);
|
2018-01-28 03:15:01 +01:00
|
|
|
} else {
|
|
|
|
|
io_sethandler(addr+16, 16,
|
2018-07-19 16:01:31 +02:00
|
|
|
nic_readb, nic_readw, NULL,
|
|
|
|
|
nic_writeb, nic_writew, NULL, dev);
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
2017-05-09 22:09:55 -04:00
|
|
|
io_sethandler(addr+0x1f, 1,
|
2018-07-19 16:01:31 +02:00
|
|
|
nic_readb, NULL, NULL,
|
|
|
|
|
nic_writeb, NULL, NULL, dev);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2016-08-13 03:32:38 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
static void
|
2018-01-28 03:15:01 +01:00
|
|
|
nic_ioremove(nic_t *dev, uint16_t addr)
|
2016-08-13 03:32:38 +02:00
|
|
|
{
|
2018-07-19 16:01:31 +02:00
|
|
|
if (dev->is_mca) {
|
|
|
|
|
io_removehandler(addr, 16,
|
|
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
|
|
|
|
io_removehandler(addr+16, 16,
|
|
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
|
|
|
|
io_removehandler(addr+0x1f, 16,
|
|
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
|
|
|
|
}
|
|
|
|
|
else if (dev->is_pci) {
|
2017-05-09 22:09:55 -04:00
|
|
|
io_removehandler(addr, 16,
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
2017-05-09 22:09:55 -04:00
|
|
|
io_removehandler(addr+16, 16,
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
2017-05-09 22:09:55 -04:00
|
|
|
io_removehandler(addr+0x1f, 1,
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_readb, nic_readw, nic_readl,
|
|
|
|
|
nic_writeb, nic_writew, nic_writel, dev);
|
2017-05-09 22:09:55 -04:00
|
|
|
} else {
|
|
|
|
|
io_removehandler(addr, 16,
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_readb, NULL, NULL,
|
|
|
|
|
nic_writeb, NULL, NULL, dev);
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->is_8bit) {
|
|
|
|
|
io_removehandler(addr+16, 16,
|
|
|
|
|
nic_readb, NULL, NULL,
|
|
|
|
|
nic_writeb, NULL, NULL, dev);
|
|
|
|
|
} else {
|
|
|
|
|
io_removehandler(addr+16, 16,
|
|
|
|
|
nic_readb, nic_readw, NULL,
|
|
|
|
|
nic_writeb, nic_writew, NULL, dev);
|
|
|
|
|
}
|
2017-05-09 22:09:55 -04:00
|
|
|
io_removehandler(addr+0x1f, 1,
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_readb, NULL, NULL,
|
|
|
|
|
nic_writeb, NULL, NULL, dev);
|
2017-05-09 22:09:55 -04: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 void
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_update_bios(nic_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;
|
2017-08-17 23:16:26 +02:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
if (! dev->has_bios) return;
|
2017-08-17 23:16:26 +02:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
if (PCI && dev->is_pci)
|
2017-08-17 23:16:26 +02:00
|
|
|
reg_bios_enable = dev->pci_bar[1].addr_regs[0] & 0x01;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
/* PCI BIOS stuff, just enable_disable. */
|
2017-08-17 23:16:26 +02:00
|
|
|
if (reg_bios_enable) {
|
2017-05-24 00:27:42 -04:00
|
|
|
mem_mapping_set_addr(&dev->bios_rom.mapping,
|
|
|
|
|
dev->bios_addr, dev->bios_size);
|
|
|
|
|
nelog(1, "%s: BIOS now at: %06X\n", dev->name, dev->bios_addr);
|
2017-05-09 22:09:55 -04:00
|
|
|
} else {
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(1, "%s: BIOS disabled\n", dev->name);
|
2017-05-09 22:09:55 -04:00
|
|
|
mem_mapping_disable(&dev->bios_rom.mapping);
|
|
|
|
|
}
|
|
|
|
|
}
|
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
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_pci_read(int func, int addr, void *priv)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_t *dev = (nic_t *)priv;
|
2017-05-26 13:12:31 -04:00
|
|
|
uint8_t ret = 0x00;
|
2017-05-12 05:05:20 -04:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
switch(addr) {
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x00: /* PCI_VID_LO */
|
|
|
|
|
case 0x01: /* PCI_VID_HI */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x02: /* PCI_DID_LO */
|
|
|
|
|
case 0x03: /* PCI_DID_HI */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x04: /* PCI_COMMAND_LO */
|
|
|
|
|
case 0x05: /* PCI_COMMAND_HI */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x06: /* PCI_STATUS_LO */
|
|
|
|
|
case 0x07: /* PCI_STATUS_HI */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x08: /* PCI_REVID */
|
|
|
|
|
ret = 0x00; /* Rev. 00 */
|
|
|
|
|
break;
|
|
|
|
|
case 0x09: /* PCI_PIFR */
|
|
|
|
|
ret = 0x00; /* Rev. 00 */
|
|
|
|
|
break;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x0A: /* PCI_SCR */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0B: /* PCI_BCR */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
|
|
|
|
|
2017-06-19 22:18:35 +02:00
|
|
|
#if 0
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x0C: /* (reserved) */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0D: /* PCI_LTR */
|
|
|
|
|
case 0x0E: /* PCI_HTR */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0F: /* (reserved) */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
2017-06-19 22:18:35 +02:00
|
|
|
#endif
|
2017-05-26 13:12:31 -04:00
|
|
|
|
|
|
|
|
case 0x10: /* PCI_BAR 7:5 */
|
2017-08-29 22:58:21 +02:00
|
|
|
ret = (dev->pci_bar[0].addr_regs[0] & 0xe0) | 0x01;
|
2017-05-26 13:12:31 -04:00
|
|
|
break;
|
|
|
|
|
case 0x11: /* PCI_BAR 15:8 */
|
|
|
|
|
ret = dev->pci_bar[0].addr_regs[1];
|
|
|
|
|
break;
|
|
|
|
|
case 0x12: /* PCI_BAR 23:16 */
|
|
|
|
|
ret = dev->pci_bar[0].addr_regs[2];
|
|
|
|
|
break;
|
|
|
|
|
case 0x13: /* PCI_BAR 31:24 */
|
|
|
|
|
ret = dev->pci_bar[0].addr_regs[3];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x2C: /* PCI_SVID_LO */
|
|
|
|
|
case 0x2D: /* PCI_SVID_HI */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x2E: /* PCI_SID_LO */
|
|
|
|
|
case 0x2F: /* PCI_SID_HI */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x30: /* PCI_ROMBAR */
|
|
|
|
|
ret = dev->pci_bar[1].addr_regs[0] & 0x01;
|
|
|
|
|
break;
|
|
|
|
|
case 0x31: /* PCI_ROMBAR 15:11 */
|
2017-08-28 06:50:13 +02:00
|
|
|
ret = dev->pci_bar[1].addr_regs[1] & 0x80;
|
2017-05-26 13:12:31 -04:00
|
|
|
break;
|
|
|
|
|
case 0x32: /* PCI_ROMBAR 23:16 */
|
|
|
|
|
ret = dev->pci_bar[1].addr_regs[2];
|
|
|
|
|
break;
|
|
|
|
|
case 0x33: /* PCI_ROMBAR 31:24 */
|
|
|
|
|
ret = dev->pci_bar[1].addr_regs[3];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x3C: /* PCI_ILR */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x3D: /* PCI_IPR */
|
|
|
|
|
ret = dev->pci_regs[addr];
|
|
|
|
|
break;
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
|
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(2, "%s: PCI_Read(%d, %04x) = %02x\n", dev->name, func, addr, ret);
|
|
|
|
|
|
|
|
|
|
return(ret);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
static void
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_pci_write(int func, int addr, uint8_t val, void *priv)
|
2017-05-09 22:09:55 -04:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_t *dev = (nic_t *)priv;
|
2017-06-19 22:18:35 +02:00
|
|
|
uint8_t valxor;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(2, "%s: PCI_Write(%d, %04x, %02x)\n", dev->name, func, addr, val);
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
switch(addr) {
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x04: /* PCI_COMMAND_LO */
|
2017-08-28 06:50:13 +02:00
|
|
|
valxor = (val & 0x03) ^ dev->pci_regs[addr];
|
2017-06-19 22:18:35 +02:00
|
|
|
if (valxor & PCI_COMMAND_IO)
|
|
|
|
|
{
|
|
|
|
|
nic_ioremove(dev, dev->base_address);
|
|
|
|
|
if ((dev->base_address != 0) && (val & PCI_COMMAND_IO))
|
|
|
|
|
{
|
|
|
|
|
nic_ioset(dev, dev->base_address);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-26 13:12:31 -04:00
|
|
|
#if 0
|
|
|
|
|
if (val & PCI_COMMAND_MEMORY) {
|
|
|
|
|
...
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2017-05-26 13:12:31 -04:00
|
|
|
#endif
|
2017-08-28 06:50:13 +02:00
|
|
|
dev->pci_regs[addr] = val & 0x03;
|
2017-05-26 13:12:31 -04:00
|
|
|
break;
|
|
|
|
|
|
2017-06-19 22:18:35 +02:00
|
|
|
#if 0
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x0C: /* (reserved) */
|
|
|
|
|
dev->pci_regs[addr] = val;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0D: /* PCI_LTR */
|
|
|
|
|
dev->pci_regs[addr] = val;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0E: /* PCI_HTR */
|
|
|
|
|
dev->pci_regs[addr] = val;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x0F: /* (reserved) */
|
2017-05-12 17:33:28 -04:00
|
|
|
dev->pci_regs[addr] = val;
|
2017-05-09 22:09:55 -04:00
|
|
|
break;
|
2017-06-19 22:18:35 +02:00
|
|
|
#endif
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x10: /* PCI_BAR */
|
2017-08-28 06:50:13 +02:00
|
|
|
val &= 0xe0; /* 0xe0 acc to RTL DS */
|
2017-05-26 13:12:31 -04:00
|
|
|
val |= 0x01; /* re-enable IOIN bit */
|
|
|
|
|
/*FALLTHROUGH*/
|
|
|
|
|
|
2017-06-16 06:44:11 +02:00
|
|
|
case 0x11: /* PCI_BAR */
|
|
|
|
|
case 0x12: /* PCI_BAR */
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x13: /* PCI_BAR */
|
|
|
|
|
/* Remove old I/O. */
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_ioremove(dev, dev->base_address);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
/* Set new I/O as per PCI request. */
|
2017-05-12 17:33:28 -04:00
|
|
|
dev->pci_bar[0].addr_regs[addr & 3] = val;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
/* Then let's calculate the new I/O base. */
|
2017-05-26 13:12:31 -04:00
|
|
|
dev->base_address = dev->pci_bar[0].addr & 0xffe0;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
/* Log the new base. */
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(1, "%s: PCI: new I/O base is %04X\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, dev->base_address);
|
2017-05-09 22:09:55 -04:00
|
|
|
/* We're done, so get out of the here. */
|
2017-06-19 22:18:35 +02:00
|
|
|
if (dev->pci_regs[4] & PCI_COMMAND_IO)
|
|
|
|
|
{
|
|
|
|
|
if (dev->base_address != 0)
|
|
|
|
|
{
|
|
|
|
|
nic_ioset(dev, dev->base_address);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-26 13:12:31 -04:00
|
|
|
break;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x30: /* PCI_ROMBAR */
|
|
|
|
|
case 0x31: /* PCI_ROMBAR */
|
|
|
|
|
case 0x32: /* PCI_ROMBAR */
|
|
|
|
|
case 0x33: /* PCI_ROMBAR */
|
2017-05-12 17:33:28 -04:00
|
|
|
dev->pci_bar[1].addr_regs[addr & 3] = val;
|
2017-08-28 06:50:13 +02:00
|
|
|
/* dev->pci_bar[1].addr_regs[1] &= dev->bios_mask; */
|
|
|
|
|
dev->pci_bar[1].addr &= 0xffff8001;
|
2017-05-24 00:27:42 -04:00
|
|
|
dev->bios_addr = dev->pci_bar[1].addr;
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_update_bios(dev);
|
2017-05-09 22:09:55 -04:00
|
|
|
return;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
case 0x3C: /* PCI_ILR */
|
2017-06-04 02:59:30 +02:00
|
|
|
nelog(1, "%s: IRQ now: %i\n", dev->name, val);
|
|
|
|
|
dev->base_irq = val;
|
2017-05-26 13:12:31 -04:00
|
|
|
dev->pci_regs[addr] = dev->base_irq;
|
2017-05-09 22:09:55 -04:00
|
|
|
return;
|
2017-05-26 13:12:31 -04:00
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
static void
|
|
|
|
|
nic_tx(nic_t *dev, uint32_t val)
|
|
|
|
|
{
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.CR.tx_packet = 0;
|
|
|
|
|
dev->dp8390.TSR.tx_ok = 1;
|
|
|
|
|
dev->dp8390.ISR.pkt_tx = 1;
|
2017-05-26 13:12:31 -04:00
|
|
|
|
|
|
|
|
/* Generate an interrupt if not masked */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.IMR.tx_inte)
|
2017-06-02 02:22:38 +02:00
|
|
|
nic_interrupt(dev, 1);
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.tx_timer_active = 0;
|
2017-05-26 13:12:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-06-26 00:34:39 +02:00
|
|
|
/*
|
2017-05-26 13:12:31 -04:00
|
|
|
* 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.
|
2016-06-26 00:34:39 +02:00
|
|
|
*/
|
2017-05-12 05:05:20 -04:00
|
|
|
static void
|
|
|
|
|
nic_rx(void *priv, uint8_t *buf, int io_len)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff};
|
|
|
|
|
nic_t *dev = (nic_t *)priv;
|
|
|
|
|
uint8_t pkthdr[4];
|
|
|
|
|
uint8_t *startptr;
|
2017-05-24 00:27:42 -04:00
|
|
|
int pages, avail;
|
|
|
|
|
int idx, nextpage;
|
|
|
|
|
int endbytes;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-10-29 04:20:20 -05:00
|
|
|
//FIXME: move to upper layer
|
2017-10-10 03:07:29 -04:00
|
|
|
ui_sb_update_icon(SB_NETWORK, 1);
|
2017-08-22 02:16:15 +02:00
|
|
|
|
2017-05-12 05:05:20 -04:00
|
|
|
if (io_len != 60)
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(2, "%s: rx_frame with length %d\n", dev->name, io_len);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if ((dev->dp8390.CR.stop != 0) || (dev->dp8390.page_start == 0)) return;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
/*
|
|
|
|
|
* Add the pkt header + CRC to the length, and work
|
|
|
|
|
* out how many 256-byte pages the frame would occupy.
|
|
|
|
|
*/
|
2017-05-24 00:27:42 -04:00
|
|
|
pages = (io_len + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256;
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.curr_page < dev->dp8390.bound_ptr) {
|
|
|
|
|
avail = dev->dp8390.bound_ptr - dev->dp8390.curr_page;
|
2017-05-12 05:05:20 -04:00
|
|
|
} else {
|
2018-07-15 01:41:53 +02:00
|
|
|
avail = (dev->dp8390.page_stop - dev->dp8390.page_start) -
|
|
|
|
|
(dev->dp8390.curr_page - dev->dp8390.bound_ptr);
|
2017-05-12 05:05:20 -04:00
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-26 13:12:31 -04: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-05-12 05:05:20 -04:00
|
|
|
if ((avail < pages)
|
|
|
|
|
#if NE2K_NEVER_FULL_RING
|
2017-02-07 02:19:48 +01:00
|
|
|
|| (avail == pages)
|
2016-06-26 00:34:39 +02:00
|
|
|
#endif
|
2017-05-12 05:05:20 -04:00
|
|
|
) {
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(1, "%s: no space\n", dev->name);
|
2017-08-22 02:16:15 +02:00
|
|
|
|
2017-10-29 04:20:20 -05:00
|
|
|
//FIXME: move to upper layer
|
2017-10-10 03:07:29 -04:00
|
|
|
ui_sb_update_icon(SB_NETWORK, 0);
|
2017-05-12 05:05:20 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if ((io_len < 40/*60*/) && !dev->dp8390.RCR.runts_ok) {
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(1, "%s: rejected small packet, length %d\n", dev->name, io_len);
|
2017-08-22 02:16:15 +02:00
|
|
|
|
2017-10-29 04:20:20 -05:00
|
|
|
//FIXME: move to upper layer
|
2017-10-10 03:07:29 -04:00
|
|
|
ui_sb_update_icon(SB_NETWORK, 0);
|
2017-05-12 05:05:20 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
/* Some computers don't care... */
|
|
|
|
|
if (io_len < 60)
|
|
|
|
|
io_len = 60;
|
|
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(2, "%s: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n",
|
2017-05-24 00:27:42 -04:00
|
|
|
dev->name,
|
|
|
|
|
buf[6], buf[7], buf[8], buf[9], buf[10], buf[11],
|
|
|
|
|
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
|
|
|
|
|
io_len);
|
2017-05-12 05:05:20 -04:00
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
/* Do address filtering if not in promiscuous mode. */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (! dev->dp8390.RCR.promisc) {
|
2017-05-24 00:27:42 -04:00
|
|
|
/* If this is a broadcast frame.. */
|
|
|
|
|
if (! memcmp(buf, bcast_addr, 6)) {
|
|
|
|
|
/* Broadcast not enabled, we're done. */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (! dev->dp8390.RCR.broadcast) {
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(2, "%s: RX BC disabled\n", dev->name);
|
2017-08-22 02:16:15 +02:00
|
|
|
|
2017-10-29 04:20:20 -05:00
|
|
|
//FIXME: move to upper layer
|
2017-10-10 03:07:29 -04:00
|
|
|
ui_sb_update_icon(SB_NETWORK, 0);
|
2017-05-12 05:05:20 -04:00
|
|
|
return;
|
2017-02-07 02:19:48 +01:00
|
|
|
}
|
2017-05-24 00:27:42 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If this is a multicast frame.. */
|
|
|
|
|
else if (buf[0] & 0x01) {
|
|
|
|
|
/* Multicast not enabled, we're done. */
|
2018-07-15 01:41:53 +02:00
|
|
|
if (! dev->dp8390.RCR.multicast) {
|
2017-05-24 00:27:42 -04:00
|
|
|
#if 1
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(2, "%s: RX MC disabled\n", dev->name);
|
2017-05-24 00:27:42 -04:00
|
|
|
#endif
|
2017-08-22 02:16:15 +02:00
|
|
|
|
2017-10-29 04:20:20 -05:00
|
|
|
//FIXME: move to upper layer
|
2017-10-10 03:07:29 -04:00
|
|
|
ui_sb_update_icon(SB_NETWORK, 0);
|
2017-05-12 05:05:20 -04:00
|
|
|
return;
|
2017-02-07 02:19:48 +01:00
|
|
|
}
|
2017-05-24 00:27:42 -04:00
|
|
|
|
|
|
|
|
/* Are we listening to this multicast address? */
|
2017-05-12 05:05:20 -04:00
|
|
|
idx = mcast_index(buf);
|
2018-07-15 01:41:53 +02:00
|
|
|
if (! (dev->dp8390.mchash[idx>>3] & (1<<(idx&0x7)))) {
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(2, "%s: RX MC not listed\n", dev->name);
|
2017-08-22 02:16:15 +02:00
|
|
|
|
2017-10-29 04:20:20 -05:00
|
|
|
//FIXME: move to upper layer
|
2017-10-10 03:07:29 -04:00
|
|
|
ui_sb_update_icon(SB_NETWORK, 0);
|
2017-02-07 02:19:48 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-24 00:27:42 -04:00
|
|
|
|
|
|
|
|
/* Unicast, must be for us.. */
|
2018-07-15 01:41:53 +02:00
|
|
|
else if (memcmp(buf, dev->dp8390.physaddr, 6)) return;
|
2017-05-12 05:05:20 -04:00
|
|
|
} else {
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(2, "%s: RX promiscuous receive\n", dev->name);
|
2017-05-12 05:05:20 -04:00
|
|
|
}
|
2016-08-13 03:32:38 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
nextpage = dev->dp8390.curr_page + pages;
|
|
|
|
|
if (nextpage >= dev->dp8390.page_stop)
|
|
|
|
|
nextpage -= (dev->dp8390.page_stop - dev->dp8390.page_start);
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
/* Set up packet header. */
|
|
|
|
|
pkthdr[0] = 0x01; /* RXOK - packet is OK */
|
|
|
|
|
if (buf[0] & 0x01)
|
|
|
|
|
pkthdr[0] |= 0x20; /* MULTICAST packet */
|
2017-05-12 05:05:20 -04:00
|
|
|
pkthdr[1] = nextpage; /* ptr to next packet */
|
2017-05-24 00:27:42 -04:00
|
|
|
pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */
|
|
|
|
|
pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(2, "%s: RX pkthdr [%02x %02x %02x %02x]\n",
|
2017-05-24 00:27:42 -04:00
|
|
|
dev->name, pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]);
|
|
|
|
|
|
|
|
|
|
/* Copy into buffer, update curpage, and signal interrupt if config'd */
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->board >= NE2K_NE2000)
|
2018-07-15 01:41:53 +02:00
|
|
|
startptr = &dev->dp8390.mem[(dev->dp8390.curr_page * 256) - DP8390_DWORD_MEMSTART];
|
2018-01-28 03:15:01 +01:00
|
|
|
else
|
2018-07-15 01:41:53 +02:00
|
|
|
startptr = &dev->dp8390.mem[(dev->dp8390.curr_page * 256) - DP8390_WORD_MEMSTART];
|
2017-05-24 00:27:42 -04:00
|
|
|
memcpy(startptr, pkthdr, sizeof(pkthdr));
|
2018-07-15 01:41:53 +02:00
|
|
|
if ((nextpage > dev->dp8390.curr_page) ||
|
|
|
|
|
((dev->dp8390.curr_page + pages) == dev->dp8390.page_stop)) {
|
2017-05-24 00:27:42 -04:00
|
|
|
memcpy(startptr+sizeof(pkthdr), buf, io_len);
|
2017-05-12 05:05:20 -04:00
|
|
|
} else {
|
2018-07-15 01:41:53 +02:00
|
|
|
endbytes = (dev->dp8390.page_stop - dev->dp8390.curr_page) * 256;
|
2017-05-24 00:27:42 -04:00
|
|
|
memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr));
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->board >= NE2K_NE2000)
|
2018-07-15 01:41:53 +02:00
|
|
|
startptr = &dev->dp8390.mem[(dev->dp8390.page_start * 256) - DP8390_DWORD_MEMSTART];
|
2018-01-28 03:15:01 +01:00
|
|
|
else
|
2018-07-15 01:41:53 +02:00
|
|
|
startptr = &dev->dp8390.mem[(dev->dp8390.page_start * 256) - DP8390_WORD_MEMSTART];
|
2017-05-24 00:27:42 -04:00
|
|
|
memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.curr_page = nextpage;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.RSR.rx_ok = 1;
|
|
|
|
|
dev->dp8390.RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0;
|
|
|
|
|
dev->dp8390.ISR.pkt_rx = 1;
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2018-07-15 01:41:53 +02:00
|
|
|
if (dev->dp8390.IMR.rx_inte)
|
2017-06-02 02:22:38 +02:00
|
|
|
nic_interrupt(dev, 1);
|
2017-08-22 02:16:15 +02:00
|
|
|
|
2017-10-29 04:20:20 -05:00
|
|
|
//FIXME: move to upper layer
|
2017-10-10 03:07:29 -04:00
|
|
|
ui_sb_update_icon(SB_NETWORK, 0);
|
2016-06-26 00:34:39 +02:00
|
|
|
}
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
static void
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_rom_init(nic_t *dev, wchar_t *s)
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-05-09 22:09:55 -04:00
|
|
|
uint32_t temp;
|
2017-05-26 13:12:31 -04:00
|
|
|
FILE *f;
|
2016-06-26 00:34:39 +02:00
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
if (s == NULL) return;
|
|
|
|
|
|
|
|
|
|
if (dev->bios_addr == 0) return;
|
|
|
|
|
|
|
|
|
|
if ((f = rom_fopen(s, L"rb")) != NULL) {
|
|
|
|
|
fseek(f, 0L, SEEK_END);
|
|
|
|
|
temp = ftell(f);
|
|
|
|
|
fclose(f);
|
|
|
|
|
dev->bios_size = 0x10000;
|
|
|
|
|
if (temp <= 0x8000)
|
|
|
|
|
dev->bios_size = 0x8000;
|
|
|
|
|
if (temp <= 0x4000)
|
|
|
|
|
dev->bios_size = 0x4000;
|
|
|
|
|
if (temp <= 0x2000)
|
|
|
|
|
dev->bios_size = 0x2000;
|
|
|
|
|
dev->bios_mask = (dev->bios_size >> 8) & 0xff;
|
|
|
|
|
dev->bios_mask = (0x100 - dev->bios_mask) & 0xff;
|
|
|
|
|
} else {
|
|
|
|
|
dev->bios_addr = 0x00000;
|
|
|
|
|
dev->bios_size = 0;
|
2017-06-16 06:44:11 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-07 00:46:54 -04:00
|
|
|
/* Create a memory mapping for the space. */
|
|
|
|
|
rom_init(&dev->bios_rom, s, dev->bios_addr,
|
|
|
|
|
dev->bios_size, dev->bios_size-1, 0, MEM_MAPPING_EXTERNAL);
|
2017-05-17 21:56:31 +02:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(1, "%s: BIOS configured at %06lX (size %ld)\n",
|
|
|
|
|
dev->name, dev->bios_addr, dev->bios_size);
|
2017-05-17 21:56:31 +02:00
|
|
|
}
|
|
|
|
|
|
2018-07-19 16:01:31 +02:00
|
|
|
static uint8_t
|
|
|
|
|
nic_mca_read(int port, void *priv)
|
|
|
|
|
{
|
|
|
|
|
nic_t *dev = (nic_t *)priv;
|
|
|
|
|
|
|
|
|
|
return(dev->pos_regs[port & 7]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define MCA_7154_IO_PORTS { 0x1000, 0x2020, 0x8020, 0xa0a0, 0xb0b0, 0xc0c0, \
|
|
|
|
|
0xc3d0 }
|
|
|
|
|
|
|
|
|
|
#define MCA_7154_IRQS { 3, 4, 5, 9 }
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nic_mca_write(int port, uint8_t val, void *priv)
|
|
|
|
|
{
|
|
|
|
|
nic_t *dev = (nic_t *)priv;
|
|
|
|
|
uint16_t novell_base[7] = MCA_7154_IO_PORTS;
|
|
|
|
|
int8_t novell_irq[4] = MCA_7154_IRQS;
|
|
|
|
|
|
|
|
|
|
/* MCA does not write registers below 0x0100. */
|
|
|
|
|
if (port < 0x0102) return;
|
|
|
|
|
|
|
|
|
|
/* Save the MCA register value. */
|
|
|
|
|
dev->pos_regs[port & 7] = val;
|
|
|
|
|
|
|
|
|
|
nic_ioremove(dev, dev->base_address);
|
|
|
|
|
|
|
|
|
|
/* This is always necessary so that the old handler doesn't remain. */
|
|
|
|
|
/* Get the new assigned I/O base address. */
|
|
|
|
|
dev->base_address = novell_base[((dev->pos_regs[2] & 0xE) >> 1) - 1];
|
|
|
|
|
|
|
|
|
|
/* Save the new IRQ values. */
|
|
|
|
|
dev->base_irq = novell_irq[(dev->pos_regs[2] & 0x60) >> 5];
|
|
|
|
|
|
|
|
|
|
dev->bios_addr = 0x0000;
|
|
|
|
|
dev->has_bios = 0;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The PS/2 Model 80 BIOS always enables a card if it finds one,
|
|
|
|
|
* even if no resources were assigned yet (because we only added
|
|
|
|
|
* the card, but have not run AutoConfig yet...)
|
|
|
|
|
*
|
|
|
|
|
* So, remove current address, if any.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Initialize the device if fully configured. */
|
|
|
|
|
if (dev->pos_regs[2] & 0x01) {
|
|
|
|
|
/* Card enabled; register (new) I/O handler. */
|
|
|
|
|
|
|
|
|
|
nic_ioset(dev, dev->base_address);
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-17 21:56:31 +02:00
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
static void *
|
2018-03-19 01:02:04 +01:00
|
|
|
nic_init(const device_t *info)
|
2016-08-13 03:32:38 +02:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
uint32_t mac;
|
2017-05-26 13:12:31 -04:00
|
|
|
wchar_t *rom;
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_t *dev;
|
2017-10-20 07:00:48 +02:00
|
|
|
#ifdef ENABLE_NIC_LOG
|
2017-05-26 13:12:31 -04:00
|
|
|
int i;
|
2017-10-20 07:00:48 +02:00
|
|
|
#endif
|
2018-03-19 01:02:04 +01:00
|
|
|
int c;
|
|
|
|
|
char *ansi_id = "REALTEK PLUG & PLAY ETHERNET CARD";
|
|
|
|
|
uint64_t *eeprom_pnp_id;
|
2017-05-26 13:12:31 -04:00
|
|
|
|
|
|
|
|
/* Get the desired debug level. */
|
2017-10-19 21:30:31 -04:00
|
|
|
#ifdef ENABLE_NIC_LOG
|
2017-05-26 13:12:31 -04:00
|
|
|
i = device_get_config_int("debug");
|
|
|
|
|
if (i > 0) nic_do_log = i;
|
2017-10-19 21:30:31 -04:00
|
|
|
#endif
|
2017-05-12 05:05:20 -04:00
|
|
|
|
|
|
|
|
dev = malloc(sizeof(nic_t));
|
|
|
|
|
memset(dev, 0x00, sizeof(nic_t));
|
2017-12-10 02:53:10 -05:00
|
|
|
dev->name = info->name;
|
2017-10-07 22:18:30 -04:00
|
|
|
dev->board = info->local;
|
2017-06-16 06:44:11 +02:00
|
|
|
rom = NULL;
|
2017-05-24 00:27:42 -04:00
|
|
|
switch(dev->board) {
|
|
|
|
|
case NE2K_NE1000:
|
2018-01-28 03:15:01 +01:00
|
|
|
dev->is_8bit = 1;
|
2018-03-19 01:02:04 +01:00
|
|
|
/*FALLTHROUGH*/
|
|
|
|
|
|
2018-01-28 11:59:44 +01:00
|
|
|
case NE2K_NE2000:
|
2018-01-28 03:15:01 +01:00
|
|
|
dev->maclocal[0] = 0x00; /* 00:00:D8 (Novell OID) */
|
2017-05-24 00:27:42 -04:00
|
|
|
dev->maclocal[1] = 0x00;
|
|
|
|
|
dev->maclocal[2] = 0xD8;
|
2018-01-28 03:15:01 +01:00
|
|
|
rom = (dev->board == NE2K_NE1000) ? NULL : ROM_PATH_NE2000;
|
2017-05-24 00:27:42 -04:00
|
|
|
break;
|
2018-07-19 16:01:31 +02:00
|
|
|
|
|
|
|
|
case NE2K_NE2_MCA:
|
2018-07-24 01:53:46 +02:00
|
|
|
nelog(3, "NE/2 adapter\n");
|
2018-07-19 16:01:31 +02:00
|
|
|
dev->is_mca = 1;
|
|
|
|
|
dev->maclocal[0] = 0x00; /* 00:00:D8 (Novell OID) */
|
|
|
|
|
dev->maclocal[1] = 0x00;
|
|
|
|
|
dev->maclocal[2] = 0xD8;
|
|
|
|
|
dev->pos_regs[0] = 0x54;
|
|
|
|
|
dev->pos_regs[1] = 0x71;
|
|
|
|
|
rom = NULL;
|
|
|
|
|
break;
|
2017-05-24 00:27:42 -04:00
|
|
|
|
2018-01-28 03:15:01 +01:00
|
|
|
case NE2K_RTL8019AS:
|
2017-05-24 00:27:42 -04:00
|
|
|
case NE2K_RTL8029AS:
|
2018-01-28 03:15:01 +01:00
|
|
|
dev->is_pci = (dev->board == NE2K_RTL8029AS) ? 1 : 0;
|
|
|
|
|
dev->maclocal[0] = 0x00; /* 00:E0:4C (Realtek OID) */
|
|
|
|
|
dev->maclocal[1] = 0xE0;
|
|
|
|
|
dev->maclocal[2] = 0x4C;
|
|
|
|
|
rom = (dev->board == NE2K_RTL8019AS) ? ROM_PATH_RTL8019 : ROM_PATH_RTL8029;
|
2017-05-24 00:27:42 -04:00
|
|
|
break;
|
2017-05-17 21:56:31 +02:00
|
|
|
}
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->board >= NE2K_RTL8019AS) {
|
2017-05-09 22:09:55 -04:00
|
|
|
dev->base_address = 0x340;
|
2018-01-28 03:15:01 +01:00
|
|
|
dev->base_irq = 12;
|
|
|
|
|
if (dev->board == NE2K_RTL8029AS) {
|
|
|
|
|
dev->bios_addr = 0xD0000;
|
|
|
|
|
dev->has_bios = device_get_config_int("bios");
|
|
|
|
|
} else {
|
|
|
|
|
dev->bios_addr = 0x00000;
|
|
|
|
|
dev->has_bios = 0;
|
|
|
|
|
}
|
2017-05-26 13:12:31 -04:00
|
|
|
} else {
|
2018-07-19 16:01:31 +02:00
|
|
|
if (dev->board != NE2K_NE2_MCA) {
|
|
|
|
|
dev->base_address = device_get_config_hex16("base");
|
|
|
|
|
dev->base_irq = device_get_config_int("irq");
|
|
|
|
|
if (dev->board == NE2K_NE2000) {
|
|
|
|
|
dev->bios_addr = device_get_config_hex20("bios_addr");
|
|
|
|
|
dev->has_bios = !!dev->bios_addr;
|
|
|
|
|
} else {
|
|
|
|
|
dev->bios_addr = 0x00000;
|
|
|
|
|
dev->has_bios = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
mca_add(nic_mca_read, nic_mca_write, dev);
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
2017-05-26 13:12:31 -04:00
|
|
|
}
|
2017-05-12 05:05:20 -04:00
|
|
|
|
2017-05-18 01:57:16 -04:00
|
|
|
/* See if we have a local MAC address configured. */
|
2017-05-27 03:53:32 +02:00
|
|
|
mac = device_get_config_mac("mac", -1);
|
2017-05-17 21:56:31 +02:00
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
/*
|
|
|
|
|
* Make this device known to the I/O system.
|
|
|
|
|
* PnP and PCI devices start with address spaces inactive.
|
|
|
|
|
*/
|
2018-07-19 16:01:31 +02:00
|
|
|
if (dev->board < NE2K_RTL8019AS && dev->board != NE2K_NE2_MCA)
|
2018-01-28 03:15:01 +01:00
|
|
|
nic_ioset(dev, dev->base_address);
|
2017-05-26 13:12:31 -04:00
|
|
|
|
|
|
|
|
/* Set up our BIOS ROM space, if any. */
|
|
|
|
|
nic_rom_init(dev, rom);
|
|
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
/* Set up our BIA. */
|
2017-05-12 05:05:20 -04:00
|
|
|
if (mac & 0xff000000) {
|
2017-05-26 13:12:31 -04:00
|
|
|
/* Generate new local MAC. */
|
2017-09-04 01:52:29 -04:00
|
|
|
dev->maclocal[3] = random_generate();
|
|
|
|
|
dev->maclocal[4] = random_generate();
|
|
|
|
|
dev->maclocal[5] = random_generate();
|
2017-05-26 13:12:31 -04:00
|
|
|
mac = (((int) dev->maclocal[3]) << 16);
|
|
|
|
|
mac |= (((int) dev->maclocal[4]) << 8);
|
|
|
|
|
mac |= ((int) dev->maclocal[5]);
|
2017-05-27 03:53:32 +02:00
|
|
|
device_set_config_mac("mac", mac);
|
2017-05-12 05:05:20 -04:00
|
|
|
} else {
|
2017-05-18 01:57:16 -04:00
|
|
|
dev->maclocal[3] = (mac>>16) & 0xff;
|
|
|
|
|
dev->maclocal[4] = (mac>>8) & 0xff;
|
2017-05-26 13:12:31 -04:00
|
|
|
dev->maclocal[5] = (mac & 0xff);
|
2017-05-12 05:05:20 -04:00
|
|
|
}
|
2018-07-15 01:41:53 +02:00
|
|
|
memcpy(dev->dp8390.physaddr, dev->maclocal, sizeof(dev->maclocal));
|
2017-05-12 05:05:20 -04:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(0, "%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n",
|
2017-05-12 05:05:20 -04:00
|
|
|
dev->name, dev->base_address, dev->base_irq,
|
2018-07-15 01:41:53 +02:00
|
|
|
dev->dp8390.physaddr[0], dev->dp8390.physaddr[1], dev->dp8390.physaddr[2],
|
|
|
|
|
dev->dp8390.physaddr[3], dev->dp8390.physaddr[4], dev->dp8390.physaddr[5]);
|
2017-05-12 05:05:20 -04:00
|
|
|
|
2018-01-28 03:15:01 +01:00
|
|
|
if (dev->board >= NE2K_RTL8019AS) {
|
|
|
|
|
if (dev->is_pci) {
|
|
|
|
|
/*
|
|
|
|
|
* Configure the PCI space registers.
|
|
|
|
|
*
|
|
|
|
|
* We do this here, so the I/O routines are generic.
|
|
|
|
|
*/
|
|
|
|
|
memset(dev->pci_regs, 0, PCI_REGSIZE);
|
|
|
|
|
|
|
|
|
|
dev->pci_regs[0x00] = (PCI_VENDID&0xff);
|
|
|
|
|
dev->pci_regs[0x01] = (PCI_VENDID>>8);
|
|
|
|
|
dev->pci_regs[0x02] = (PCI_DEVID&0xff);
|
|
|
|
|
dev->pci_regs[0x03] = (PCI_DEVID>>8);
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->pci_regs[0x04] = 0x03; /* IOEN */
|
2018-01-28 03:15:01 +01:00
|
|
|
dev->pci_regs[0x05] = 0x00;
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->pci_regs[0x07] = 0x02; /* DST0, medium devsel */
|
2018-01-28 03:15:01 +01:00
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->pci_regs[0x09] = 0x00; /* PIFR */
|
2018-01-28 03:15:01 +01:00
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->pci_regs[0x0B] = 0x02; /* BCR: Network Controller */
|
|
|
|
|
dev->pci_regs[0x0A] = 0x00; /* SCR: Ethernet */
|
2018-01-28 03:15:01 +01:00
|
|
|
|
|
|
|
|
dev->pci_regs[0x2C] = (PCI_VENDID&0xff);
|
|
|
|
|
dev->pci_regs[0x2D] = (PCI_VENDID>>8);
|
|
|
|
|
dev->pci_regs[0x2E] = (PCI_DEVID&0xff);
|
|
|
|
|
dev->pci_regs[0x2F] = (PCI_DEVID>>8);
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
dev->pci_regs[0x3D] = PCI_INTA; /* PCI_IPR */
|
2018-01-28 03:15:01 +01:00
|
|
|
|
|
|
|
|
/* Enable our address space in PCI. */
|
|
|
|
|
dev->pci_bar[0].addr_regs[0] = 0x01;
|
|
|
|
|
|
|
|
|
|
/* Enable our BIOS space in PCI, if needed. */
|
|
|
|
|
if (dev->bios_addr > 0) {
|
|
|
|
|
dev->pci_bar[1].addr = 0xFFFF8000;
|
|
|
|
|
dev->pci_bar[1].addr_regs[1] = dev->bios_mask;
|
|
|
|
|
} else {
|
|
|
|
|
dev->pci_bar[1].addr = 0;
|
|
|
|
|
dev->bios_size = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mem_mapping_disable(&dev->bios_rom.mapping);
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
/* Add device to the PCI bus, keep its slot number. */
|
|
|
|
|
dev->card = pci_add_card(PCI_ADD_NORMAL,
|
|
|
|
|
nic_pci_read, nic_pci_write, dev);
|
2018-01-28 03:15:01 +01:00
|
|
|
} else {
|
|
|
|
|
io_sethandler(0x0279, 1,
|
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
|
nic_pnp_address_writeb, NULL, NULL, dev);
|
|
|
|
|
|
|
|
|
|
dev->pnp_id = PNP_DEVID;
|
|
|
|
|
dev->pnp_id <<= 32LL;
|
|
|
|
|
dev->pnp_id |= PNP_VENDID;
|
|
|
|
|
dev->pnp_phase = PNP_PHASE_WAIT_FOR_KEY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Initialize the RTL8029 EEPROM. */
|
|
|
|
|
memset(dev->eeprom, 0x00, sizeof(dev->eeprom));
|
|
|
|
|
|
|
|
|
|
if (dev->board == NE2K_RTL8029AS) {
|
|
|
|
|
memcpy(&dev->eeprom[0x02], dev->maclocal, 6);
|
|
|
|
|
|
|
|
|
|
dev->eeprom[0x76] =
|
|
|
|
|
dev->eeprom[0x7A] =
|
|
|
|
|
dev->eeprom[0x7E] = (PCI_DEVID&0xff);
|
|
|
|
|
dev->eeprom[0x77] =
|
|
|
|
|
dev->eeprom[0x7B] =
|
|
|
|
|
dev->eeprom[0x7F] = (dev->board == NE2K_RTL8019AS) ? (PNP_DEVID>>8) : (PCI_DEVID>>8);
|
|
|
|
|
dev->eeprom[0x78] =
|
|
|
|
|
dev->eeprom[0x7C] = (PCI_VENDID&0xff);
|
|
|
|
|
dev->eeprom[0x79] =
|
|
|
|
|
dev->eeprom[0x7D] = (PCI_VENDID>>8);
|
|
|
|
|
} else {
|
|
|
|
|
eeprom_pnp_id = (uint64_t *) &dev->eeprom[0x12];
|
|
|
|
|
*eeprom_pnp_id = dev->pnp_id;
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
/* TAG: Plug and Play Version Number. */
|
|
|
|
|
dev->eeprom[0x1B] = 0x0A; /* Item byte */
|
|
|
|
|
dev->eeprom[0x1C] = 0x10; /* PnP version */
|
|
|
|
|
dev->eeprom[0x1D] = 0x10; /* Vendor version */
|
|
|
|
|
|
|
|
|
|
/* TAG: ANSI Identifier String. */
|
|
|
|
|
dev->eeprom[0x1E] = 0x82; /* Item byte */
|
|
|
|
|
dev->eeprom[0x1F] = 0x22; /* Length bits 7-0 */
|
|
|
|
|
dev->eeprom[0x20] = 0x00; /* Length bits 15-8 */
|
|
|
|
|
memcpy(&dev->eeprom[0x21], ansi_id, 0x22);
|
|
|
|
|
|
|
|
|
|
/* TAG: Logical Device ID. */
|
|
|
|
|
dev->eeprom[0x43] = 0x16; /* Item byte */
|
|
|
|
|
dev->eeprom[0x44] = 0x4A; /* Logical device ID0 */
|
|
|
|
|
dev->eeprom[0x45] = 0x8C; /* Logical device ID1 */
|
|
|
|
|
dev->eeprom[0x46] = 0x80; /* Logical device ID2 */
|
|
|
|
|
dev->eeprom[0x47] = 0x19; /* Logical device ID3 */
|
|
|
|
|
dev->eeprom[0x48] = 0x02; /* Flag0 (02=BROM/disabled) */
|
|
|
|
|
dev->eeprom[0x49] = 0x00; /* Flag 1 */
|
|
|
|
|
|
|
|
|
|
/* TAG: Compatible Device ID (NE2000) */
|
|
|
|
|
dev->eeprom[0x4A] = 0x1C; /* Item byte */
|
|
|
|
|
dev->eeprom[0x4B] = 0x41; /* Compatible ID0 */
|
|
|
|
|
dev->eeprom[0x4C] = 0xD0; /* Compatible ID1 */
|
|
|
|
|
dev->eeprom[0x4D] = 0x80; /* Compatible ID2 */
|
|
|
|
|
dev->eeprom[0x4E] = 0xD6; /* Compatible ID3 */
|
|
|
|
|
|
|
|
|
|
/* TAG: I/O Format */
|
|
|
|
|
dev->eeprom[0x4F] = 0x47; /* Item byte */
|
|
|
|
|
dev->eeprom[0x50] = 0x00; /* I/O information */
|
|
|
|
|
dev->eeprom[0x51] = 0x20; /* Min. I/O base bits 7-0 */
|
|
|
|
|
dev->eeprom[0x52] = 0x02; /* Min. I/O base bits 15-8 */
|
|
|
|
|
dev->eeprom[0x53] = 0x80; /* Max. I/O base bits 7-0 */
|
|
|
|
|
dev->eeprom[0x54] = 0x03; /* Max. I/O base bits 15-8 */
|
|
|
|
|
dev->eeprom[0x55] = 0x20; /* Base alignment */
|
|
|
|
|
dev->eeprom[0x56] = 0x20; /* Range length */
|
|
|
|
|
|
|
|
|
|
/* TAG: IRQ Format. */
|
|
|
|
|
dev->eeprom[0x57] = 0x23; /* Item byte */
|
|
|
|
|
dev->eeprom[0x58] = 0x38; /* IRQ mask bits 7-0 */
|
|
|
|
|
dev->eeprom[0x59] = 0x9E; /* IRQ mask bits 15-8 */
|
|
|
|
|
dev->eeprom[0x5A] = 0x01; /* IRQ information */
|
|
|
|
|
|
|
|
|
|
/* TAG: END Tag */
|
|
|
|
|
dev->eeprom[0x5B] = 0x79; /* Item byte */
|
|
|
|
|
for (c = 0x1b; c < 0x5c; c++) /* Checksum (2's compl) */
|
2018-01-28 03:15:01 +01:00
|
|
|
dev->eeprom[0x5C] += dev->eeprom[c];
|
|
|
|
|
dev->eeprom[0x5C] = -dev->eeprom[0x5C];
|
|
|
|
|
|
2018-02-02 00:14:17 +01:00
|
|
|
io_sethandler(0x0A79, 1,
|
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
|
nic_pnp_writeb, NULL, NULL, dev);
|
2018-01-28 03:15:01 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
/* Reset the board. */
|
2018-07-19 16:01:31 +02:00
|
|
|
nic_reset(dev);
|
2017-05-26 13:12:31 -04:00
|
|
|
|
2017-10-29 04:20:20 -05:00
|
|
|
/* Attach ourselves to the network module. */
|
2018-07-15 01:41:53 +02:00
|
|
|
network_attach(dev, dev->dp8390.physaddr, nic_rx);
|
2017-02-07 02:19:48 +01:00
|
|
|
|
2017-05-26 13:12:31 -04:00
|
|
|
nelog(1, "%s: %s attached IO=0x%X IRQ=%d\n", dev->name,
|
2017-05-24 00:27:42 -04:00
|
|
|
dev->is_pci?"PCI":"ISA", dev->base_address, dev->base_irq);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
return(dev);
|
2017-02-07 02:19:48 +01:00
|
|
|
}
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
|
|
|
|
|
static void
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_close(void *priv)
|
2017-02-07 02:19:48 +01:00
|
|
|
{
|
2017-05-12 05:05:20 -04:00
|
|
|
nic_t *dev = (nic_t *)priv;
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-12 05:05:20 -04:00
|
|
|
/* Make sure the platform layer is shut down. */
|
|
|
|
|
network_close();
|
|
|
|
|
|
|
|
|
|
nic_ioremove(dev, dev->base_address);
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2017-05-24 00:27:42 -04:00
|
|
|
nelog(1, "%s: closed\n", dev->name);
|
2017-08-24 02:35:04 -04:00
|
|
|
|
|
|
|
|
free(dev);
|
2017-05-09 22:09:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
static const device_config_t ne1000_config[] =
|
2017-05-12 05:05:20 -04:00
|
|
|
{
|
|
|
|
|
{
|
2017-05-27 03:53:32 +02:00
|
|
|
"base", "Address", CONFIG_HEX16, "", 0x300,
|
2017-05-12 05:05:20 -04:00
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
"0x280", 0x280
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"0x300", 0x300
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"0x320", 0x320
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"0x340", 0x340
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"0x360", 0x360
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"0x380", 0x380
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
""
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"irq", "IRQ", CONFIG_SELECTION, "", 3,
|
|
|
|
|
{
|
2018-02-09 22:49:31 +01:00
|
|
|
{
|
|
|
|
|
"IRQ 2", 2
|
|
|
|
|
},
|
2017-05-12 05:05:20 -04:00
|
|
|
{
|
|
|
|
|
"IRQ 3", 3
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"IRQ 5", 5
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"IRQ 7", 7
|
|
|
|
|
},
|
2018-07-19 16:01:31 +02:00
|
|
|
{
|
|
|
|
|
"IRQ 10", 10
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"IRQ 11", 11
|
|
|
|
|
},
|
2017-05-12 05:05:20 -04:00
|
|
|
{
|
|
|
|
|
""
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
},
|
2017-05-17 21:56:31 +02:00
|
|
|
{
|
|
|
|
|
"mac", "MAC Address", CONFIG_MAC, "", -1
|
|
|
|
|
},
|
2017-05-12 05:05:20 -04:00
|
|
|
{
|
|
|
|
|
"", "", -1
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
static const device_config_t ne2000_config[] =
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-02-07 02:19:48 +01:00
|
|
|
{
|
2017-05-27 03:53:32 +02:00
|
|
|
"base", "Address", CONFIG_HEX16, "", 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
|
|
|
{
|
2018-02-09 22:49:31 +01:00
|
|
|
{
|
|
|
|
|
"IRQ 2", 2
|
|
|
|
|
},
|
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-17 21:56:31 +02:00
|
|
|
{
|
|
|
|
|
"mac", "MAC Address", CONFIG_MAC, "", -1
|
|
|
|
|
},
|
2017-02-07 02:19:48 +01:00
|
|
|
{
|
2017-05-27 03:53:32 +02:00
|
|
|
"bios_addr", "BIOS address", CONFIG_HEX20, "", 0,
|
2017-05-24 00:27:42 -04:00
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
"Disabled", 0x00000
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"D000", 0xD0000
|
|
|
|
|
},
|
|
|
|
|
{
|
2017-06-01 21:49:57 -04:00
|
|
|
"D800", 0xD8000
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"C800", 0xC8000
|
2017-05-24 00:27:42 -04:00
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
""
|
|
|
|
|
}
|
|
|
|
|
},
|
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
|
|
|
};
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
static const device_config_t rtl8019as_config[] =
|
2018-01-28 03:15:01 +01:00
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
"mac", "MAC Address", CONFIG_MAC, "", -1
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"", "", -1
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
static const device_config_t rtl8029as_config[] =
|
2016-06-26 00:34:39 +02:00
|
|
|
{
|
2017-06-01 21:49:57 -04:00
|
|
|
{
|
2017-10-08 05:38:45 +02:00
|
|
|
"bios", "Enable BIOS", CONFIG_BINARY, "", 0
|
2017-06-01 21:49:57 -04:00
|
|
|
},
|
2017-05-17 21:56:31 +02:00
|
|
|
{
|
|
|
|
|
"mac", "MAC Address", CONFIG_MAC, "", -1
|
|
|
|
|
},
|
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
|
|
|
};
|
|
|
|
|
|
2018-07-19 16:01:31 +02:00
|
|
|
static const device_config_t mca_mac_config[] =
|
|
|
|
|
{
|
|
|
|
|
{
|
|
|
|
|
"mac", "MAC Address", CONFIG_MAC, "", -1
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"", "", -1
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
const device_t ne1000_device = {
|
2017-05-12 05:05:20 -04:00
|
|
|
"Novell NE1000",
|
2018-01-28 03:15:01 +01:00
|
|
|
DEVICE_ISA,
|
2017-10-07 00:46:54 -04:00
|
|
|
NE2K_NE1000,
|
2017-10-07 22:18:30 -04:00
|
|
|
nic_init, nic_close, NULL,
|
2018-04-26 13:33:29 +02:00
|
|
|
NULL, NULL, NULL,
|
2017-05-12 05:05:20 -04:00
|
|
|
ne1000_config
|
2016-06-26 00:34:39 +02:00
|
|
|
};
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
const device_t ne2000_device = {
|
2017-05-12 05:05:20 -04:00
|
|
|
"Novell NE2000",
|
2018-01-28 03:15:01 +01:00
|
|
|
DEVICE_ISA | DEVICE_AT,
|
2017-10-07 00:46:54 -04:00
|
|
|
NE2K_NE2000,
|
2017-10-07 22:18:30 -04:00
|
|
|
nic_init, nic_close, NULL,
|
2018-04-26 13:33:29 +02:00
|
|
|
NULL, NULL, NULL,
|
2017-05-12 05:05:20 -04:00
|
|
|
ne2000_config
|
|
|
|
|
};
|
2017-05-09 22:09:55 -04:00
|
|
|
|
2018-07-19 16:01:31 +02:00
|
|
|
const device_t ne2_device = {
|
|
|
|
|
"Novell NE/2",
|
|
|
|
|
DEVICE_MCA,
|
|
|
|
|
NE2K_NE2_MCA,
|
|
|
|
|
nic_init, nic_close, NULL,
|
|
|
|
|
NULL, NULL, NULL,
|
|
|
|
|
mca_mac_config
|
|
|
|
|
};
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
const device_t rtl8019as_device = {
|
2018-01-28 03:15:01 +01:00
|
|
|
"Realtek RTL8019AS",
|
|
|
|
|
DEVICE_ISA | DEVICE_AT,
|
|
|
|
|
NE2K_RTL8019AS,
|
|
|
|
|
nic_init, nic_close, NULL,
|
2018-04-26 13:33:29 +02:00
|
|
|
NULL, NULL, NULL,
|
2018-01-28 03:15:01 +01:00
|
|
|
rtl8019as_config
|
|
|
|
|
};
|
|
|
|
|
|
2018-03-19 01:02:04 +01:00
|
|
|
const device_t rtl8029as_device = {
|
2017-05-12 05:05:20 -04:00
|
|
|
"Realtek RTL8029AS",
|
2017-10-08 05:38:45 +02:00
|
|
|
DEVICE_PCI,
|
2017-10-07 00:46:54 -04:00
|
|
|
NE2K_RTL8029AS,
|
2017-10-07 22:18:30 -04:00
|
|
|
nic_init, nic_close, NULL,
|
2018-04-26 13:33:29 +02:00
|
|
|
NULL, NULL, NULL,
|
2017-05-12 05:05:20 -04:00
|
|
|
rtl8029as_config
|
|
|
|
|
};
|