mirror of
https://github.com/holub/mame
synced 2025-04-19 23:12:11 +03:00
(MESS) apollo: Separate 3c505 out into an ISA16 card. [R. Belmont]
This commit is contained in:
parent
5d8ceefb5e
commit
7d678bedea
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -8038,10 +8038,8 @@ src/mess/machine/amstr_pc.c svneol=native#text/plain
|
||||
src/mess/machine/amstrad.c svneol=native#text/plain
|
||||
src/mess/machine/apollo.c svneol=native#text/plain
|
||||
src/mess/machine/apollo_dbg.c svneol=native#text/plain
|
||||
src/mess/machine/apollo_eth.c svneol=native#text/plain
|
||||
src/mess/machine/apollo_kbd.c svneol=native#text/plain
|
||||
src/mess/machine/apollo_kbd.h svneol=native#text/plain
|
||||
src/mess/machine/apollo_net.c svneol=native#text/plain
|
||||
src/mess/machine/appldriv.c svneol=native#text/plain
|
||||
src/mess/machine/appldriv.h svneol=native#text/plain
|
||||
src/mess/machine/apple1.c svneol=native#text/plain
|
||||
|
@ -688,8 +688,6 @@ static ADDRESS_MAP_START(dn3500_map, AS_PROGRAM, 32, apollo_state )
|
||||
AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16(selective_clear_locations_r, selective_clear_locations_w, 0xffffffff )
|
||||
AM_RANGE(0x017000, 0x017fff) AM_READWRITE16(apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff )
|
||||
|
||||
AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8_LEGACY(APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
|
||||
|
||||
AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE8_LEGACY(APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff)
|
||||
AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16_LEGACY(APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff)
|
||||
|
||||
@ -736,8 +734,6 @@ static ADDRESS_MAP_START(dsp3500_map, AS_PROGRAM, 32, apollo_state )
|
||||
AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16(selective_clear_locations_r, selective_clear_locations_w, 0xffffffff )
|
||||
AM_RANGE(0x017000, 0x017fff) AM_READWRITE16(apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff )
|
||||
|
||||
AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8_LEGACY(APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
|
||||
|
||||
AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff)
|
||||
|
||||
AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM */
|
||||
@ -765,7 +761,6 @@ static ADDRESS_MAP_START(dn3000_map, AS_PROGRAM, 32, apollo_state )
|
||||
AM_RANGE(0x009400, 0x0094ff) AM_DEVREADWRITE8(APOLLO_PIC1_TAG, pic8259_device, read, write, 0xffffffff)
|
||||
AM_RANGE(0x009500, 0x0095ff) AM_DEVREADWRITE8(APOLLO_PIC2_TAG, pic8259_device, read, write, 0xffffffff)
|
||||
AM_RANGE(0x009600, 0x0096ff) AM_READWRITE16(apollo_node_id_r, apollo_node_id_w, 0xffffffff)
|
||||
AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8_LEGACY(APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
|
||||
|
||||
AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE8_LEGACY(APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff)
|
||||
AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16_LEGACY(APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff)
|
||||
@ -803,8 +798,6 @@ static ADDRESS_MAP_START(dsp3000_map, AS_PROGRAM, 32, apollo_state )
|
||||
AM_RANGE(0x009500, 0x0095ff) AM_DEVREADWRITE8(APOLLO_PIC2_TAG, pic8259_device, read, write, 0xffffffff)
|
||||
AM_RANGE(0x009600, 0x0096ff) AM_READWRITE16(apollo_node_id_r, apollo_node_id_w, 0xffffffff)
|
||||
|
||||
AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8_LEGACY(APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
|
||||
|
||||
AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff)
|
||||
|
||||
AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM */
|
||||
@ -843,8 +836,6 @@ static ADDRESS_MAP_START(dn5500_map, AS_PROGRAM, 32, apollo_state )
|
||||
AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16(selective_clear_locations_r, selective_clear_locations_w, 0xffffffff )
|
||||
AM_RANGE(0x017000, 0x017fff) AM_READWRITE16(apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff )
|
||||
|
||||
AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8_LEGACY(APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
|
||||
|
||||
AM_RANGE(0x05d800, 0x05dc07) AM_DEVREADWRITE8_LEGACY(APOLLO_SCREEN_TAG, apollo_mcr_r, apollo_mcr_w, 0xffffffff)
|
||||
AM_RANGE(0xfa0000, 0xfdffff) AM_DEVREADWRITE16_LEGACY(APOLLO_SCREEN_TAG, apollo_mgm_r, apollo_mgm_w, 0xffffffff)
|
||||
|
||||
@ -894,8 +885,6 @@ static ADDRESS_MAP_START(dsp5500_map, AS_PROGRAM, 32, apollo_state )
|
||||
AM_RANGE(0x016400, 0x0164ff) AM_READWRITE16(selective_clear_locations_r, selective_clear_locations_w, 0xffffffff )
|
||||
AM_RANGE(0x017000, 0x017fff) AM_READWRITE16(apollo_address_translation_map_r, apollo_address_translation_map_w, 0xffffffff )
|
||||
|
||||
AM_RANGE(0x058000, 0x058007) AM_DEVREADWRITE8_LEGACY(APOLLO_ETH_TAG, threecom3c505_r, threecom3c505_w, 0xffffffff)
|
||||
|
||||
AM_RANGE(ATBUS_IO_BASE, ATBUS_IO_END) AM_READWRITE16(apollo_atbus_io_r, apollo_atbus_io_w, 0xffffffff)
|
||||
|
||||
AM_RANGE(0x080000, 0x081fff) AM_ROM /* 3C505 boot ROM */
|
||||
@ -920,9 +909,6 @@ void apollo_state::machine_reset()
|
||||
|
||||
MACHINE_RESET_CALL_MEMBER(apollo);
|
||||
|
||||
// set configuration
|
||||
threecom3c505_set_verbose(apollo_config(APOLLO_CONF_NET_TRACE));
|
||||
|
||||
// we can't do this any more
|
||||
#if 0
|
||||
if (apollo_config(APOLLO_CONF_NODE_ID))
|
||||
@ -959,7 +945,6 @@ static void apollo_reset_instr_callback(device_t *device)
|
||||
|
||||
// reset the ISA bus devices
|
||||
apollo->m_isa->reset();
|
||||
machine.device(APOLLO_ETH_TAG)->reset();
|
||||
|
||||
if (!apollo_is_dsp3x00())
|
||||
{
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "bus/rs232/rs232.h"
|
||||
#include "machine/terminal.h"
|
||||
#include "machine/ram.h"
|
||||
#include "machine/3c505.h"
|
||||
#include "machine/6840ptm.h"
|
||||
#include "machine/n68681.h"
|
||||
#include "machine/am9517a.h"
|
||||
@ -289,33 +288,6 @@ UINT16 apollo_csr_get_control_register(void);
|
||||
UINT16 apollo_csr_get_status_register(void);
|
||||
void apollo_csr_set_status_register(UINT16 mask, UINT16 data);
|
||||
|
||||
/*----------- machine/apollo_eth.c -----------*/
|
||||
|
||||
// ethernet transmitter
|
||||
|
||||
int apollo_eth_transmit(device_t* device,
|
||||
const UINT8 data_buffer[], const int data_length);
|
||||
|
||||
int apollo_eth_setfilter(device_t *device, int node_id);
|
||||
// ethernet receiver callback
|
||||
|
||||
typedef int (*apollo_eth_receive)(device_t *, const UINT8 *, int);
|
||||
|
||||
void apollo_eth_init(device_t *device, apollo_eth_receive rx_data);
|
||||
|
||||
/*----------- machine/apollo_net.c -----------*/
|
||||
|
||||
// netserver receiver
|
||||
|
||||
int apollo_netserver_receive(device_t* device,
|
||||
const UINT8 rx_data_buffer[], const int rx_data_length);
|
||||
|
||||
// transmitter callback
|
||||
|
||||
typedef int (*apollo_netserver_transmit)(device_t *, const UINT8 *, int);
|
||||
|
||||
void apollo_netserver_init(const char *root_path, apollo_netserver_transmit tx_data);
|
||||
|
||||
/*----------- video/apollo.c -----------*/
|
||||
|
||||
#define APOLLO_SCREEN_TAG "apollo_screen"
|
||||
|
@ -3,7 +3,8 @@
|
||||
*
|
||||
* Created on: August 27, 2010
|
||||
* Author: Hans Ostermeyer
|
||||
*
|
||||
* ISA conversion by R. Belmont
|
||||
*
|
||||
* Released for general non-commercial use under the MAME license
|
||||
* Visit http://mamedev.org for licensing and usage restrictions.
|
||||
*
|
||||
@ -21,7 +22,7 @@
|
||||
|
||||
static int verbose = VERBOSE;
|
||||
|
||||
#define LOG(x) { logerror ("%s: ", m_device->cpu_context()); logerror x; logerror ("\n"); }
|
||||
#define LOG(x) { logerror x; logerror ("\n"); }
|
||||
#define LOG1(x) { if (verbose > 0) LOG(x)}
|
||||
#define LOG2(x) { if (verbose > 1) LOG(x)}
|
||||
|
||||
@ -184,32 +185,119 @@ enum
|
||||
#define INT_LOOPBACK 0x08
|
||||
#define EXT_LOOPBACK 0x10
|
||||
|
||||
static INPUT_PORTS_START( tc3c505_port )
|
||||
PORT_START("IO_BASE")
|
||||
PORT_DIPNAME( 0x3f0, 0x300, "3C505 I/O base")
|
||||
PORT_DIPSETTING( 0x010, "010h" )
|
||||
PORT_DIPSETTING( 0x020, "020h" )
|
||||
PORT_DIPSETTING( 0x030, "030h" )
|
||||
PORT_DIPSETTING( 0x040, "040h" )
|
||||
PORT_DIPSETTING( 0x050, "050h" )
|
||||
PORT_DIPSETTING( 0x060, "060h" )
|
||||
PORT_DIPSETTING( 0x070, "070h" )
|
||||
PORT_DIPSETTING( 0x080, "080h" )
|
||||
PORT_DIPSETTING( 0x090, "090h" )
|
||||
PORT_DIPSETTING( 0x0a0, "0a0h" )
|
||||
PORT_DIPSETTING( 0x0b0, "0b0h" )
|
||||
PORT_DIPSETTING( 0x0c0, "0c0h" )
|
||||
PORT_DIPSETTING( 0x0d0, "0d0h" )
|
||||
PORT_DIPSETTING( 0x0e0, "0e0h" )
|
||||
PORT_DIPSETTING( 0x0f0, "0f0h" )
|
||||
PORT_DIPSETTING( 0x100, "0100h" )
|
||||
PORT_DIPSETTING( 0x110, "0110h" )
|
||||
PORT_DIPSETTING( 0x120, "0120h" )
|
||||
PORT_DIPSETTING( 0x130, "0130h" )
|
||||
PORT_DIPSETTING( 0x140, "0140h" )
|
||||
PORT_DIPSETTING( 0x150, "0150h" )
|
||||
PORT_DIPSETTING( 0x160, "0160h" )
|
||||
PORT_DIPSETTING( 0x170, "0170h" )
|
||||
PORT_DIPSETTING( 0x180, "0180h" )
|
||||
PORT_DIPSETTING( 0x190, "0190h" )
|
||||
PORT_DIPSETTING( 0x1a0, "01a0h" )
|
||||
PORT_DIPSETTING( 0x1b0, "01b0h" )
|
||||
PORT_DIPSETTING( 0x1c0, "01c0h" )
|
||||
PORT_DIPSETTING( 0x1d0, "01d0h" )
|
||||
PORT_DIPSETTING( 0x1e0, "01e0h" )
|
||||
PORT_DIPSETTING( 0x1f0, "01f0h" )
|
||||
PORT_DIPSETTING( 0x200, "0200h" )
|
||||
PORT_DIPSETTING( 0x210, "0210h" )
|
||||
PORT_DIPSETTING( 0x220, "0220h" )
|
||||
PORT_DIPSETTING( 0x230, "0230h" )
|
||||
PORT_DIPSETTING( 0x240, "0240h" )
|
||||
PORT_DIPSETTING( 0x250, "0250h" )
|
||||
PORT_DIPSETTING( 0x260, "0260h" )
|
||||
PORT_DIPSETTING( 0x270, "0270h" )
|
||||
PORT_DIPSETTING( 0x280, "0280h" )
|
||||
PORT_DIPSETTING( 0x290, "0290h" )
|
||||
PORT_DIPSETTING( 0x2a0, "02a0h" )
|
||||
PORT_DIPSETTING( 0x2b0, "02b0h" )
|
||||
PORT_DIPSETTING( 0x2c0, "02c0h" )
|
||||
PORT_DIPSETTING( 0x2d0, "02d0h" )
|
||||
PORT_DIPSETTING( 0x2e0, "02e0h" )
|
||||
PORT_DIPSETTING( 0x2f0, "02f0h" )
|
||||
PORT_DIPSETTING( 0x300, "0300h" )
|
||||
PORT_DIPSETTING( 0x310, "0310h" )
|
||||
PORT_DIPSETTING( 0x320, "0320h" )
|
||||
PORT_DIPSETTING( 0x330, "0330h" )
|
||||
PORT_DIPSETTING( 0x340, "0340h" )
|
||||
PORT_DIPSETTING( 0x350, "0350h" )
|
||||
PORT_DIPSETTING( 0x360, "0360h" )
|
||||
PORT_DIPSETTING( 0x370, "0370h" )
|
||||
PORT_DIPSETTING( 0x380, "0380h" )
|
||||
PORT_DIPSETTING( 0x390, "0390h" )
|
||||
PORT_DIPSETTING( 0x3a0, "03a0h" )
|
||||
PORT_DIPSETTING( 0x3b0, "03b0h" )
|
||||
PORT_DIPSETTING( 0x3c0, "03c0h" )
|
||||
PORT_DIPSETTING( 0x3d0, "03d0h" )
|
||||
PORT_DIPSETTING( 0x3e0, "03e0h" )
|
||||
PORT_DIPSETTING( 0x3f0, "03f0h" )
|
||||
|
||||
PORT_START("IRQ_DRQ")
|
||||
PORT_DIPNAME( 0x0f, 0x0a, "3C505 IRQ")
|
||||
PORT_DIPSETTING( 0x03, "IRQ 3" )
|
||||
PORT_DIPSETTING( 0x04, "IRQ 4" )
|
||||
PORT_DIPSETTING( 0x05, "IRQ 5" )
|
||||
PORT_DIPSETTING( 0x06, "IRQ 6" )
|
||||
PORT_DIPSETTING( 0x07, "IRQ 7" )
|
||||
PORT_DIPSETTING( 0x09, "IRQ 9" )
|
||||
PORT_DIPSETTING( 0x0a, "IRQ 10" )
|
||||
PORT_DIPSETTING( 0x0b, "IRQ 11" )
|
||||
PORT_DIPSETTING( 0x0c, "IRQ 12" )
|
||||
PORT_DIPSETTING( 0x0e, "IRQ 14" )
|
||||
PORT_DIPSETTING( 0x0f, "IRQ 15" )
|
||||
|
||||
PORT_DIPNAME( 0x70, 0x00, "3C505 DMA")
|
||||
PORT_DIPSETTING( 0x10, "DRQ 1" )
|
||||
PORT_DIPSETTING( 0x30, "DRQ 3" )
|
||||
PORT_DIPSETTING( 0x50, "DRQ 5" )
|
||||
PORT_DIPSETTING( 0x60, "DRQ 6" )
|
||||
PORT_DIPSETTING( 0x70, "DRQ 7" )
|
||||
|
||||
INPUT_PORTS_END
|
||||
|
||||
/***************************************************************************
|
||||
IMPLEMENTATION
|
||||
***************************************************************************/
|
||||
|
||||
// device type definition
|
||||
const device_type THREECOM3C505 = &device_creator<threecom3c505_device> ;
|
||||
const device_type ISA16_3C505 = &device_creator<threecom3c505_device> ;
|
||||
|
||||
//-------------------------------------------------
|
||||
// threecom3c505_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
threecom3c505_device::threecom3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, THREECOM3C505, "Threecom 3C505", tag, owner, clock, "threecom3c505", __FILE__),
|
||||
device_network_interface(mconfig, *this, 10.0f)
|
||||
: device_t(mconfig, ISA16_3C505, "3Com 3C505 Network Adaptor", tag, owner, clock, "3c505", __FILE__),
|
||||
device_network_interface(mconfig, *this, 10.0f),
|
||||
device_isa16_card_interface(mconfig, *this),
|
||||
m_iobase(*this, "IO_BASE"),
|
||||
m_irqdrq(*this, "IRQ_DRQ")
|
||||
{
|
||||
memset(static_cast<threecom3c505_interface *>(this), 0, sizeof(threecom3c505_interface));
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// static_set_interface - set the interface struct
|
||||
//-------------------------------------------------
|
||||
|
||||
void threecom3c505_device::static_set_interface(device_t &device, const threecom3c505_interface &interface)
|
||||
ioport_constructor threecom3c505_device::device_input_ports() const
|
||||
{
|
||||
threecom3c505_device &threecom3c505 = downcast<threecom3c505_device &> (device);
|
||||
static_cast<threecom3c505_interface &> (threecom3c505) = interface;
|
||||
return INPUT_PORTS_NAME( tc3c505_port );
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -218,20 +306,18 @@ void threecom3c505_device::static_set_interface(device_t &device, const threecom
|
||||
|
||||
void threecom3c505_device::device_start()
|
||||
{
|
||||
m_device = this;
|
||||
set_isa_device();
|
||||
|
||||
LOG1(("start 3COM 3C505"));
|
||||
|
||||
m_installed = false;
|
||||
|
||||
m_rx_fifo.start(this, RX_FIFO_SIZE, ETH_BUFFER_SIZE);
|
||||
m_rx_data_buffer.start(this, ETH_BUFFER_SIZE);
|
||||
m_tx_data_buffer.start(this, ETH_BUFFER_SIZE);
|
||||
m_program_buffer.start(this, PGM_BUFFER_SIZE);
|
||||
|
||||
if (tx_init != NULL)
|
||||
{
|
||||
(*tx_init)(this);
|
||||
}
|
||||
|
||||
m_do_command_timer = m_device->machine().scheduler().timer_alloc(FUNC(static_do_command), this);
|
||||
m_do_command_timer = timer_alloc(0, NULL);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -275,6 +361,18 @@ void threecom3c505_device::device_reset()
|
||||
memset(m_multicast_list, 0, sizeof(m_multicast_list));
|
||||
set_filter_list();
|
||||
set_promisc(true);
|
||||
|
||||
if (!m_installed)
|
||||
{
|
||||
int base = m_iobase->read();
|
||||
|
||||
m_irq = m_irqdrq->read() & 0xf;
|
||||
m_drq = (m_irqdrq->read() >> 4) & 0x7;
|
||||
|
||||
m_isa->install_device(base, base + ELP_IO_EXTENT - 1, 0, 0, read8_delegate(FUNC(threecom3c505_device::read), this), write8_delegate(FUNC(threecom3c505_device::write), this));
|
||||
|
||||
m_installed = true;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
@ -290,16 +388,7 @@ const char *threecom3c505_device::cpu_context()
|
||||
int s = t / osd_ticks_per_second();
|
||||
int ms = (t % osd_ticks_per_second()) / 1000;
|
||||
|
||||
/* if we have an executing CPU, output data */
|
||||
if (cpu != NULL)
|
||||
{
|
||||
sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(),
|
||||
cpu->safe_pcbase(), tag());
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(statebuf, "%d.%03d", s, ms);
|
||||
}
|
||||
sprintf(statebuf, "%d.%03d:%s:", s, ms, tag());
|
||||
return statebuf;
|
||||
}
|
||||
|
||||
@ -455,14 +544,6 @@ void threecom3c505_device::set_filter_list()
|
||||
memcpy(m_filter_list, m_station_address, ETHERNET_ADDR_SIZE);
|
||||
memset(m_filter_list + ETHERNET_ADDR_SIZE, 0xff, ETHERNET_ADDR_SIZE);
|
||||
memcpy(m_filter_list + ETHERNET_ADDR_SIZE * 2, m_multicast_list, sizeof(m_multicast_list));
|
||||
|
||||
if (setfilter != NULL)
|
||||
{
|
||||
int node_id = (((m_station_address[3] << 8) + m_station_address[4]) << 8) + m_station_address[5];
|
||||
LOG2(("set_filter_list node_id=%x",node_id));
|
||||
(*setfilter)(this, node_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*-------------------------------------------------
|
||||
@ -474,9 +555,20 @@ void threecom3c505_device::set_interrupt(enum line_state state)
|
||||
if (state != irq_state)
|
||||
{
|
||||
LOG2(("set_interrupt(%d)",state));
|
||||
if (set_irq != NULL)
|
||||
switch (m_irq)
|
||||
{
|
||||
(*set_irq)(this, state);
|
||||
case 3: m_isa->irq3_w(state); break;
|
||||
case 4: m_isa->irq4_w(state); break;
|
||||
case 5: m_isa->irq5_w(state); break;
|
||||
case 6: m_isa->irq6_w(state); break;
|
||||
case 7: m_isa->irq7_w(state); break;
|
||||
case 9: m_isa->irq2_w(state); break; // IRQ 9 on ISA16 goes to IRQ 2
|
||||
case 10: m_isa->irq10_w(state); break;
|
||||
case 11: m_isa->irq11_w(state); break;
|
||||
case 12: m_isa->irq12_w(state); break;
|
||||
case 14: m_isa->irq14_w(state); break;
|
||||
case 15: m_isa->irq15_w(state); break;
|
||||
default: logerror("3c505: invalid IRQ %d\n", m_irq); break;
|
||||
}
|
||||
irq_state = state;
|
||||
}
|
||||
@ -745,12 +837,12 @@ void threecom3c505_device::set_command_pending(int state)
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
do_command
|
||||
execute the commands (formerly do_command)
|
||||
***************************************************************************/
|
||||
|
||||
TIMER_CALLBACK( threecom3c505_device::static_do_command )
|
||||
void threecom3c505_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
||||
{
|
||||
reinterpret_cast<threecom3c505_device *> (ptr)->do_command();
|
||||
do_command();
|
||||
}
|
||||
|
||||
void threecom3c505_device::do_command()
|
||||
@ -1134,13 +1226,6 @@ UINT8 threecom3c505_device::read_command_port()
|
||||
LOG(("read_command_port(): !!! failed to send Ethernet packet"));
|
||||
}
|
||||
|
||||
if (tx_data != NULL && //
|
||||
(*tx_data)(this, m_tx_data_buffer.get_data(), m_tx_data_buffer.get_length()) == 0)
|
||||
{
|
||||
// FIXME: failed to transmit the Ethernet packet
|
||||
LOG(("read_command_port(): !!! failed to transmit Ethernet packet"));
|
||||
}
|
||||
|
||||
m_tx_data_buffer.reset();
|
||||
if (m_command_buffer[0] != CMD_TRANSMIT_PACKET_F9)
|
||||
{
|
||||
@ -1420,7 +1505,7 @@ UINT8 threecom3c505_device::read_status_port()
|
||||
write_port
|
||||
***************************************************************************/
|
||||
|
||||
void threecom3c505_device::write_port(offs_t offset, UINT8 data)
|
||||
WRITE8_MEMBER(threecom3c505_device::write)
|
||||
{
|
||||
m_reg[offset & 0x0f] = data;
|
||||
LOG2(("writing 3C505 Register at offset %02x = %02x", offset, data));
|
||||
@ -1448,8 +1533,7 @@ void threecom3c505_device::write_port(offs_t offset, UINT8 data)
|
||||
read_port
|
||||
***************************************************************************/
|
||||
|
||||
//READ8_DEVICE_HANDLER( threecom3c505_r )
|
||||
UINT8 threecom3c505_device::read_port(offs_t offset)
|
||||
READ8_MEMBER(threecom3c505_device::read)
|
||||
{
|
||||
// data to omit excessive logging
|
||||
static UINT8 last_data = 0xff;
|
||||
@ -1492,27 +1576,3 @@ UINT8 threecom3c505_device::read_port(offs_t offset)
|
||||
return data;
|
||||
}
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL STUBS
|
||||
//**************************************************************************
|
||||
|
||||
READ8_DEVICE_HANDLER( threecom3c505_r )
|
||||
{
|
||||
return downcast<threecom3c505_device *> (device)->read_port(offset);
|
||||
}
|
||||
|
||||
WRITE8_DEVICE_HANDLER( threecom3c505_w )
|
||||
{
|
||||
downcast<threecom3c505_device *> (device)->write_port(offset, data);
|
||||
}
|
||||
|
||||
int threecom3c505_receive(device_t *device, const UINT8 data[], int length)
|
||||
{
|
||||
downcast<threecom3c505_device *> (device)->recv_cb((UINT8 *) data, length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void threecom3c505_set_verbose(int on_off)
|
||||
{
|
||||
verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define THREECOM3C505_H_
|
||||
|
||||
#include "emu.h"
|
||||
#include "bus/isa/isa.h"
|
||||
|
||||
#define CMD_BUFFER_SIZE 100
|
||||
#define ETH_BUFFER_SIZE 2048
|
||||
@ -24,44 +25,6 @@
|
||||
|
||||
#define RX_FIFO_SIZE 32
|
||||
|
||||
/***************************************************************************
|
||||
FUNCTION PROTOTYPES
|
||||
***************************************************************************/
|
||||
|
||||
DECLARE_READ8_DEVICE_HANDLER( threecom3c505_r );
|
||||
DECLARE_WRITE8_DEVICE_HANDLER( threecom3c505_w );
|
||||
|
||||
int threecom3c505_receive(device_t *device, const UINT8 *data, int length);
|
||||
|
||||
void threecom3c505_set_verbose(int on_off);
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE CONFIGURATION MACROS
|
||||
//**************************************************************************
|
||||
|
||||
#define MCFG_THREECOM3C505_ADD(_tag, _interface) \
|
||||
MCFG_DEVICE_ADD(_tag, THREECOM3C505, 0) \
|
||||
threecom3c505_device::static_set_interface(*device, _interface);
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
typedef void (*threecom3c505_set_irq)(device_t *, int);
|
||||
typedef void (*threecom3c505_tx_init)(device_t *);
|
||||
typedef int (*threecom3c505_tx_data)(device_t *, const UINT8 *, int);
|
||||
typedef int (*threecom3c505_setfilter)(device_t *, int);
|
||||
|
||||
struct threecom3c505_interface
|
||||
{
|
||||
threecom3c505_set_irq set_irq;
|
||||
threecom3c505_tx_init tx_init;
|
||||
threecom3c505_tx_data tx_data;
|
||||
threecom3c505_setfilter setfilter;
|
||||
};
|
||||
|
||||
#define THREECOM3C505_INTERFACE(name) const struct threecom3c505_interface (name)
|
||||
|
||||
// ======================> PCB data structure
|
||||
|
||||
#pragma pack(1)
|
||||
@ -157,25 +120,25 @@ struct pcb_struct
|
||||
|
||||
class threecom3c505_device: public device_t,
|
||||
public device_network_interface,
|
||||
public threecom3c505_interface
|
||||
public device_isa16_card_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
threecom3c505_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
|
||||
// static configuration helpers
|
||||
static void static_set_interface(device_t &device, const threecom3c505_interface &interface);
|
||||
|
||||
void recv_cb(UINT8 *buf, int len);
|
||||
|
||||
// device register I/O
|
||||
UINT8 read_port(offs_t offset);
|
||||
void write_port(offs_t offset, UINT8 data);
|
||||
DECLARE_READ8_MEMBER(read);
|
||||
DECLARE_WRITE8_MEMBER(write);
|
||||
|
||||
required_ioport m_iobase;
|
||||
required_ioport m_irqdrq;
|
||||
|
||||
private:
|
||||
// device-level overrides
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
virtual ioport_constructor device_input_ports() const;
|
||||
|
||||
const char *cpu_context();
|
||||
|
||||
@ -240,7 +203,6 @@ private:
|
||||
|
||||
void do_receive_command();
|
||||
void set_command_pending(int onoff);
|
||||
void do_command();
|
||||
|
||||
int ethernet_packet_is_for_me(const UINT8 mac_address[]);
|
||||
|
||||
@ -251,8 +213,8 @@ private:
|
||||
void write_control_port( UINT8 data);
|
||||
UINT8 read_status_port();
|
||||
|
||||
// pointer to myself (nasty: used for cpu_context)
|
||||
threecom3c505_device *m_device;
|
||||
void do_command();
|
||||
virtual void recv_cb(UINT8 *data, int length);
|
||||
|
||||
UINT8 m_reg[16];
|
||||
|
||||
@ -297,9 +259,12 @@ private:
|
||||
enum line_state irq_state;
|
||||
|
||||
emu_timer * m_do_command_timer; // timer to delay command execution
|
||||
|
||||
bool m_installed;
|
||||
int m_irq, m_drq;
|
||||
};
|
||||
|
||||
// device type definition
|
||||
extern const device_type THREECOM3C505;
|
||||
extern const device_type ISA16_3C505;
|
||||
|
||||
#endif /* THREECOM3C505_H_ */
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
#include "bus/isa/omti8621.h"
|
||||
#include "bus/isa/sc499.h"
|
||||
#include "machine/3c505.h"
|
||||
|
||||
#define APOLLO_IRQ_VECTOR 0xa0
|
||||
#define APOLLO_IRQ_PTM 0
|
||||
@ -782,53 +783,6 @@ WRITE_LINE_MEMBER(apollo_state::sio2_irq_handler)
|
||||
apollo_pic_set_irq_line(APOLLO_IRQ_SIO2, state);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
DN3500 3c505 DEVICE Configuration
|
||||
***************************************************************************/
|
||||
|
||||
static void apollo_3c505_set_irq(device_t *device, int state) {
|
||||
// DLOG2(("apollo_3c505_interrupt: state=%x", state ));
|
||||
device->machine().driver_data<apollo_state>()->apollo_pic_set_irq_line(APOLLO_IRQ_ETH1, state);
|
||||
}
|
||||
|
||||
static int apollo_3c505_tx_data(device_t *device,
|
||||
const UINT8 tx_data_buffer[], int tx_data_length) {
|
||||
// transmit all transmitted packets to the apollo_netserver
|
||||
apollo_netserver_receive(device, tx_data_buffer, tx_data_length);
|
||||
|
||||
// transmit all transmitted packets to the host ethernet (ignore any errors)
|
||||
return apollo_eth_transmit(device, tx_data_buffer, tx_data_length);
|
||||
}
|
||||
|
||||
static int apollo_3c505_setfilter(device_t *device, int node_id)
|
||||
{
|
||||
return apollo_eth_setfilter(device, node_id);
|
||||
}
|
||||
|
||||
static int apollo_3c505_rx_data(device_t *device,
|
||||
const UINT8 rx_data_buffer[], int rx_data_length) {
|
||||
// transmit all received packets to the threecom3c505 receiver
|
||||
return threecom3c505_receive(device, rx_data_buffer, rx_data_length);
|
||||
}
|
||||
|
||||
static void apollo_3c505_tx_init(device_t *device) {
|
||||
apollo_eth_init(device, apollo_3c505_rx_data);
|
||||
|
||||
// setup to receive all packets from the apollo_netserver
|
||||
apollo_netserver_init(device->machine().options().media_path(), apollo_3c505_rx_data);
|
||||
}
|
||||
|
||||
static THREECOM3C505_INTERFACE(apollo_3c505_config) = {
|
||||
apollo_3c505_set_irq,
|
||||
apollo_3c505_tx_init,
|
||||
apollo_3c505_tx_data,
|
||||
apollo_3c505_setfilter
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
DN3500 Cartridge Tape DEVICE Configuration
|
||||
***************************************************************************/
|
||||
|
||||
//##########################################################################
|
||||
// machine/apollo.c - APOLLO DS3500 CPU Board
|
||||
//##########################################################################
|
||||
@ -866,6 +820,7 @@ static const isa16bus_interface isabus_intf =
|
||||
static SLOT_INTERFACE_START(apollo_isa_cards)
|
||||
SLOT_INTERFACE("wdc", ISA16_OMTI8621) // Combo ESDI/AT floppy controller
|
||||
SLOT_INTERFACE("ctape", ISA8_SC499) // Archive SC499 cartridge tape
|
||||
SLOT_INTERFACE("3c505", ISA16_3C505) // 3Com 3C505 Ethernet card
|
||||
SLOT_INTERFACE_END
|
||||
|
||||
MACHINE_CONFIG_FRAGMENT( common )
|
||||
@ -891,13 +846,11 @@ MACHINE_CONFIG_FRAGMENT( common )
|
||||
MCFG_ISA16_BUS_CUSTOM_SPACES()
|
||||
MCFG_ISA16_SLOT_ADD(APOLLO_ISA_TAG, "isa1", apollo_isa_cards, "wdc", false)
|
||||
MCFG_ISA16_SLOT_ADD(APOLLO_ISA_TAG, "isa2", apollo_isa_cards, "ctape", false)
|
||||
MCFG_ISA16_SLOT_ADD(APOLLO_ISA_TAG, "isa3", apollo_isa_cards, NULL, false)
|
||||
MCFG_ISA16_SLOT_ADD(APOLLO_ISA_TAG, "isa3", apollo_isa_cards, "3c505", false)
|
||||
MCFG_ISA16_SLOT_ADD(APOLLO_ISA_TAG, "isa4", apollo_isa_cards, NULL, false)
|
||||
MCFG_ISA16_SLOT_ADD(APOLLO_ISA_TAG, "isa5", apollo_isa_cards, NULL, false)
|
||||
MCFG_ISA16_SLOT_ADD(APOLLO_ISA_TAG, "isa6", apollo_isa_cards, NULL, false)
|
||||
MCFG_ISA16_SLOT_ADD(APOLLO_ISA_TAG, "isa7", apollo_isa_cards, NULL, false)
|
||||
|
||||
MCFG_THREECOM3C505_ADD(APOLLO_ETH_TAG, apollo_3c505_config)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
// for machines with the keyboard and a graphics head
|
||||
|
@ -1,354 +0,0 @@
|
||||
/*
|
||||
* apollo_eth.c - APOLLO ethernet proxy
|
||||
*
|
||||
* Created on: Sep 19, 2011
|
||||
* Author: Hans Ostermeyer
|
||||
*
|
||||
* Released for general non-commercial use under the MAME license
|
||||
* Visit http://mamedev.org for licensing and usage restrictions.
|
||||
*
|
||||
* see also:
|
||||
* http://www.linuxjournal.com/article/4659
|
||||
*
|
||||
*
|
||||
* TODO:
|
||||
* Scrap this unportable stuff, make 3c505 use the core Ethernet layer directly like the 3c503.
|
||||
*
|
||||
*/
|
||||
|
||||
#define VERBOSE 0
|
||||
|
||||
#include "includes/apollo.h"
|
||||
|
||||
#if !defined(APOLLO_FOR_LINUX)
|
||||
|
||||
int apollo_eth_transmit(device_t *device, const UINT8 data[], int length)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int apollo_eth_setfilter(device_t *device, int node_id)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void apollo_eth_init(device_t *device, apollo_eth_receive rx_data)
|
||||
{
|
||||
}
|
||||
|
||||
#else /* defined(APOLLO_FOR_LINUX) */
|
||||
|
||||
#include "machine/3c505.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netpacket/packet.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/filter.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define ETH_BUFFER_SIZE 2048
|
||||
|
||||
// TODO: should be configurable
|
||||
#define ETH_INTERFACE_NAME "eth0"
|
||||
//#define ETH_INTERFACE_NAME "vmnet0"
|
||||
|
||||
static const char *eth_if_name;
|
||||
static int eth_if_index = -1;
|
||||
static int eth_socket = -1;
|
||||
static UINT8 eth_hw_address[ETHERNET_ADDR_SIZE];
|
||||
|
||||
static apollo_eth_receive rx_callback = NULL;
|
||||
|
||||
/***************************************************************************
|
||||
log data
|
||||
***************************************************************************/
|
||||
|
||||
static void log_data(const device_t *device, const char *type,
|
||||
const UINT8 *data, int data_length) {
|
||||
if (VERBOSE > 0) {
|
||||
int i;
|
||||
logerror("%s - %s: %s (length=%2x)", apollo_cpu_context(
|
||||
device->machine().firstcpu), device->tag(), type, data_length);
|
||||
for (i = 0; i < data_length; i++) {
|
||||
logerror(" %02x", data[i]);
|
||||
}
|
||||
logerror("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
apollo_eth_receive_packet
|
||||
***************************************************************************/
|
||||
|
||||
static int apollo_eth_receive_packet(device_t *device)
|
||||
{
|
||||
u_char rx_buffer[ETH_BUFFER_SIZE];
|
||||
int packet_len;
|
||||
|
||||
do
|
||||
{
|
||||
packet_len = recv(eth_socket, rx_buffer, sizeof(rx_buffer), MSG_TRUNC);
|
||||
} while (packet_len == -1 && errno == EINTR);
|
||||
|
||||
/* Check if an error occurred */
|
||||
if (packet_len == -1)
|
||||
{
|
||||
switch (errno)
|
||||
{
|
||||
case EAGAIN:
|
||||
return 0; /* no packet there */
|
||||
|
||||
case ENETDOWN:
|
||||
// The device on which we're capturing went away.
|
||||
DLOG1(("apollo_eth_receive_packet: the interface went down (error %d - %s)", errno, strerror(errno)));
|
||||
return -1;
|
||||
|
||||
default:
|
||||
DLOG(("apollo_eth_receive_packet: recv failed (error %d - %s)", errno, strerror(errno)));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (packet_len > sizeof(rx_buffer))
|
||||
{
|
||||
DLOG(("apollo_eth_receive_packet: data size (%d) exceeds rx buffer size (%d)!!!", packet_len, (int)sizeof(rx_buffer)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
log_data(device, "apollo_eth_receive_packet", rx_buffer, packet_len);
|
||||
|
||||
/* Call the user supplied callback function */
|
||||
if (rx_callback != NULL)
|
||||
{
|
||||
// threecom3c505_receive(device, tx_data_buffer, tx_data_length);
|
||||
(*rx_callback)(device, rx_buffer, packet_len);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
receive_interrupt
|
||||
***************************************************************************/
|
||||
|
||||
static TIMER_CALLBACK(receive_interrupt)
|
||||
{
|
||||
device_t *device = (device_t *) ptr;
|
||||
|
||||
/*
|
||||
* Save the socket's current mode, and put it in non-blocking mode;
|
||||
* we drain it by reading packets until we get an error
|
||||
* (which is normally a "nothing more to be read" error).
|
||||
*/
|
||||
int save_mode = fcntl(eth_socket, F_GETFL, 0);
|
||||
if (save_mode == -1)
|
||||
{
|
||||
DLOG(("receive_interrupt: fcntl failed (error %d - %s)", errno, strerror(errno)))
|
||||
}
|
||||
else if (fcntl(eth_socket, F_SETFL, save_mode | O_NONBLOCK) < 0)
|
||||
{
|
||||
DLOG(("receive_interrupt: fcntl failed (error %d - %s)", errno, strerror(errno)))
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = 0;
|
||||
while (apollo_eth_receive_packet(device) > 0 && i++ < 4)
|
||||
;
|
||||
|
||||
fcntl(eth_socket, F_SETFL, save_mode);
|
||||
}
|
||||
|
||||
machine.scheduler().timer_set(attotime::from_msec(1), FUNC(receive_interrupt), 0, device);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
apollo_eth_transmit - transmit an packet to the ethernet
|
||||
***************************************************************************/
|
||||
|
||||
int apollo_eth_transmit(device_t *device, const UINT8 data[], int length) {
|
||||
if (eth_socket != -1)
|
||||
{
|
||||
if (memcmp(data, eth_hw_address, ETHERNET_ADDR_SIZE) == 0)
|
||||
{
|
||||
// destination ethernet address is my own mac address
|
||||
// TODO: should send data to "eth0"
|
||||
}
|
||||
|
||||
if (send(eth_socket, data, length, 0) == -1) {
|
||||
DLOG(("apollo_eth_transmit: send failed with error %d (%s)", errno, strerror(errno)));
|
||||
} else {
|
||||
log_data(device, "apollo_eth_transmit", data, length);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
apollo_eth_setfilter - set the socket filter
|
||||
***************************************************************************/
|
||||
|
||||
int apollo_eth_setfilter(device_t *device, int node_id)
|
||||
{
|
||||
/*
|
||||
tcpdump -i eth0 -dd ether dst 08:00:1e:01:ae:a5 or ether dst 09:00:1e:00:00:00 or ether dst 09:00:1e:00:00:01 or ether broadcast
|
||||
|
||||
(000) ld [2]
|
||||
(001) jeq #0x1e01aea5 jt 2 jf 4
|
||||
(002) ldh [0]
|
||||
(003) jeq #0x800 jt 11 jf 12
|
||||
(004) jeq #0x1e000000 jt 6 jf 5
|
||||
(005) jeq #0x1e000001 jt 6 jf 8
|
||||
(006) ldh [0]
|
||||
(007) jeq #0x900 jt 11 jf 12
|
||||
(008) jeq #0xffffffff jt 9 jf 12
|
||||
(009) ldh [0]
|
||||
(010) jeq #0xffff jt 11 jf 12
|
||||
(011) ret #65535
|
||||
(012) ret #0
|
||||
*/
|
||||
static struct sock_filter bpf_code[]= {
|
||||
{ 0x20, 0, 0, 0x00000002 },
|
||||
{ 0x15, 0, 2, 0x1e01aea5 },
|
||||
{ 0x28, 0, 0, 0x00000000 },
|
||||
{ 0x15, 7, 8, 0x00000800 },
|
||||
{ 0x15, 1, 0, 0x1e000000 },
|
||||
{ 0x15, 0, 2, 0x1e000001 },
|
||||
{ 0x28, 0, 0, 0x00000000 },
|
||||
{ 0x15, 3, 4, 0x00000900 },
|
||||
{ 0x15, 0, 3, 0xffffffff },
|
||||
{ 0x28, 0, 0, 0x00000000 },
|
||||
{ 0x15, 0, 1, 0x0000ffff },
|
||||
{ 0x6, 0, 0, 0x0000ffff },
|
||||
{ 0x6, 0, 0, 0x00000000 }
|
||||
};
|
||||
|
||||
if (eth_socket != -1)
|
||||
{
|
||||
struct sock_fprog filter;
|
||||
filter.len = sizeof(bpf_code) / sizeof(sock_filter);
|
||||
filter.filter = bpf_code;
|
||||
|
||||
// set node id in filter
|
||||
bpf_code[1].k = (bpf_code[1].k & 0xff000000) | (node_id & 0x00ffffff);
|
||||
|
||||
/* Attach the filter to the socket */
|
||||
if (setsockopt(eth_socket, SOL_SOCKET, SO_ATTACH_FILTER, &filter,
|
||||
sizeof(filter)) < 0)
|
||||
{
|
||||
DLOG(("apollo_eth_setfilter: failed with error %d (%s)", errno, strerror(errno)));
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG1(("apollo_eth_setfilter: set filter for node id %x", node_id & 0x00ffffff));
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
apollo_eth_init - specify node id and transmitter call back function
|
||||
***************************************************************************/
|
||||
|
||||
void apollo_eth_init(device_t *device, apollo_eth_receive rx_data)
|
||||
{
|
||||
rx_callback = rx_data;
|
||||
|
||||
eth_if_name = ETH_INTERFACE_NAME;
|
||||
eth_if_index = -1;
|
||||
memset(eth_hw_address, 0 , sizeof(eth_hw_address));
|
||||
|
||||
// Note: Only processes with effective UID 0 or the CAP_NET_RAW capability may open packet sockets.
|
||||
// see also: man 7 packet
|
||||
|
||||
eth_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||||
if (eth_socket == -1)
|
||||
{
|
||||
if (errno == EPERM)
|
||||
{
|
||||
DLOG(("apollo_eth_init: %s - Ethernet access disabled", strerror(errno)));
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG1(("apollo_eth_init: socket failed (error %d - %s)", errno, strerror(errno)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, eth_if_name, sizeof(ifr.ifr_name));
|
||||
|
||||
// Get interface index
|
||||
if (ioctl(eth_socket, SIOCGIFINDEX, &ifr) == -1)
|
||||
{
|
||||
DLOG(("apollo_eth_init: interface %s not found (error %d - %s)", eth_if_name, errno, strerror(errno)));
|
||||
close(eth_socket);
|
||||
eth_socket = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
eth_if_index = ifr.ifr_ifindex;
|
||||
|
||||
// Get hardware address
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
(void) strncpy(ifr.ifr_name, eth_if_name, sizeof(ifr.ifr_name));
|
||||
if (ioctl(eth_socket, SIOCGIFHWADDR, (char *) &ifr) < 0)
|
||||
{
|
||||
DLOG(("apollo_eth_init: SIOCGIFHWADDR failed for %s (error %d - %s)", eth_if_name, errno, strerror(errno)));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(eth_hw_address, ifr.ifr_hwaddr.sa_data, sizeof(eth_hw_address));
|
||||
}
|
||||
|
||||
struct sockaddr_ll sll;
|
||||
memset(&sll, 0, sizeof(sll));
|
||||
sll.sll_family = AF_PACKET;
|
||||
sll.sll_ifindex = eth_if_index;
|
||||
sll.sll_protocol = htons(ETH_P_ALL);
|
||||
|
||||
if (bind(eth_socket, (struct sockaddr *) &sll, sizeof(sll)) == -1)
|
||||
{
|
||||
DLOG(("apollo_eth_init: bind to interface %s failed (error %d - %s)", eth_if_name, errno, strerror(errno)));
|
||||
close(eth_socket);
|
||||
eth_socket = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct packet_mreq mr;
|
||||
memset(&mr, 0, sizeof(mr));
|
||||
mr.mr_ifindex = eth_if_index;
|
||||
mr.mr_type = PACKET_MR_PROMISC;
|
||||
if (setsockopt(eth_socket, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof(mr)) == -1)
|
||||
{
|
||||
DLOG(("apollo_eth_init: failed to set promiscuous mode (error %d - %s)", errno, strerror(errno)));
|
||||
close(eth_socket);
|
||||
eth_socket = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set the socket buffer size to the specified value.
|
||||
// by default request 2M for the ring buffer
|
||||
int rx_bufsize = 2*1024*1024;
|
||||
if (setsockopt(eth_socket, SOL_SOCKET, SO_RCVBUF, &rx_bufsize, sizeof(rx_bufsize)) == -1)
|
||||
{
|
||||
DLOG(("apollo_eth_init: failed to set buffer size (error %d - %s)", errno, strerror(errno)));
|
||||
close(eth_socket);
|
||||
eth_socket = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
device->machine().scheduler().timer_set(attotime::from_msec(1), FUNC(receive_interrupt), 0, device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* defined(APOLLO_FOR_LINUX) */
|
@ -1,885 +0,0 @@
|
||||
/*
|
||||
* apollo_net.c - simple APOLLO netserver emulation (netman, ARP, IP echo, ...)
|
||||
*
|
||||
* Created on: May 12, 2010
|
||||
* Author: Hans Ostermeyer
|
||||
*
|
||||
* Released for general non-commercial use under the MAME license
|
||||
* Visit http://mamedev.org for licensing and usage restrictions.
|
||||
*
|
||||
* see also:
|
||||
* - http://www.bitsavers.org/pdf/apollo/AEGIS_Internals_and_Data_Structures_Jan86.pdf
|
||||
*/
|
||||
|
||||
#define VERBOSE 0
|
||||
|
||||
// FIXME: these three should not be hardcoded
|
||||
#define NETSERVER_NODE_ID 0x012340
|
||||
#define NETSERVER_IP_ADDRESS {192,168,2,3} /* 192.168.2.3 */
|
||||
#define NETSERVER_ROOT_PATH "apollo"
|
||||
|
||||
#include "includes/apollo.h"
|
||||
#include "machine/3c505.h"
|
||||
|
||||
struct ethernet_header {
|
||||
UINT8 dest[6];
|
||||
UINT8 source[6];
|
||||
UINT16 proto;
|
||||
};
|
||||
|
||||
struct ip_header
|
||||
{
|
||||
UINT8 version;
|
||||
UINT8 tos;
|
||||
UINT16 tot_len;
|
||||
UINT16 id;
|
||||
UINT16 frag_off;
|
||||
UINT8 ttl;
|
||||
UINT8 protocol;
|
||||
UINT16 check;
|
||||
UINT32 saddr;
|
||||
UINT32 daddr;
|
||||
};
|
||||
|
||||
#define ETHERNET_HEADER_SIZE sizeof(ethernet_header)
|
||||
|
||||
/* Ethernet protocol ID's */
|
||||
#define ETHERNET_PACKET_TYPE_IP 0x0800 /* IP */
|
||||
#define ETHERNET_PACKET_TYPE_ARP 0x0806 /* Address resolution */
|
||||
#define ETHERNET_PACKET_TYPE_APOLLO 0x8019
|
||||
|
||||
#define ETHERNET_APOLLO_PREFIX 0x08001e
|
||||
#define ETHERNET_APOLLO_DOMAIN_PREFIX 0x09001e
|
||||
|
||||
#define ICMP_ECHOREPLY 0 /* Echo Reply */
|
||||
#define ICMP_ECHO 8 /* Echo Request */
|
||||
|
||||
#define PACKET_HEADER_SIZE 64
|
||||
|
||||
// #define ETH_BUFFER_SIZE 2000
|
||||
|
||||
// Note: these three pathnames are hardcoded in Apollo DomainOS; don't change them
|
||||
#define APOLLO_NETBOOT_PATH "/sys/net/netboot"
|
||||
#define APOLLO_SAU7_PATH "/sau7"
|
||||
#define APOLLO_SAU8_PATH "/sau8"
|
||||
#define APOLLO_SAU14_PATH "/sau14"
|
||||
|
||||
static emu_file *current_file = NULL;
|
||||
|
||||
static UINT16 current_sector = 0;
|
||||
static UINT16 current_last_sector = 0;
|
||||
static char current_pathname[256];
|
||||
|
||||
static UINT8 current_rx_data_buffer[ETH_BUFFER_SIZE];
|
||||
static int current_rx_data_length;
|
||||
|
||||
static apollo_netserver_transmit tx_callback = NULL;
|
||||
|
||||
static UINT32 my_node_id;
|
||||
static UINT8 my_ip_address[4] = NETSERVER_IP_ADDRESS; /* 192.168.2.3 */
|
||||
static UINT8 my_mac_address[6];
|
||||
|
||||
static astring root_path;
|
||||
|
||||
// boot_$volun (find partner node)
|
||||
static UINT8 response_0006[] = {
|
||||
0x00,0x01, // 0x40:
|
||||
0x00,0x01,
|
||||
0x00,0x07, // 0x44: packet type (07 = 06+1)
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00
|
||||
};
|
||||
|
||||
static UINT8 list_directory_header[] = {
|
||||
0x00,0x01, // 0x40:
|
||||
0x00,0x01,
|
||||
0x00,0x0d, // 0x44: packet type (0d = 0c+1)
|
||||
0x00,0x00,0x00,0x00, // 0x46:
|
||||
0x00,0x01,0x00,0x01,
|
||||
0x73,0x61,0x6d,0x62,0x61,0x2f,0x73,0x61,0x75,0x37, // "samba/sau7"
|
||||
0x00,0x00,0x28,0xd8,0x00,0x00,0x00,0x00,
|
||||
0x75,0x37,0xd8,0xa0,0x76,0x08,0xb5,0x52,
|
||||
0x75,0x37,0xe6,0xc6,0x75,0x37,0xd8,0xac
|
||||
};
|
||||
|
||||
static UINT8 receive_data_header[] = {
|
||||
0x00,0x01, // 0x40:
|
||||
0x00,0x01, // 0x42:
|
||||
0x00,0x09, // 0x44: packet type (09 = 08+1)
|
||||
0x00,0x00,0x00,0x00, // 0x46:
|
||||
0x00,0x13,0xfc,0xaf, // 0x4A: high
|
||||
0x00,0x13,0xd8,0x00, // 0x4E: low
|
||||
0x00,0x13,0xd8,0x2a, // 0x52: start
|
||||
0x00,0x13,0xd8,0x00, // 0x56: current load address
|
||||
0x00,0x00 // 0x5a:
|
||||
};
|
||||
|
||||
static UINT8 not_found_data_header[] = {
|
||||
0x00,0x01, // 0x40:
|
||||
0x00,0x01, // 0x42: ?
|
||||
0x00,0x13, // 0x44: packet type (13 = 12+1)
|
||||
0x00,0x0e,0x00,0x07,
|
||||
0x00,0x12, // 0x4a = string length
|
||||
0x2f,0x2f,0x73,0x61,0x6d,0x62,0x61,0x2f, 0x73,0x61,0x75,0x37,0x2f,0x78,0x78,0x78, /*//samba/sau7/xxxxx */
|
||||
0x78,0x78,
|
||||
|
||||
0x07,0x48,0x00,0x08,0x07,0x6a,0x00,0x08, 0x07,0x6c,0x00,0x04,0x0c,0x94
|
||||
};
|
||||
|
||||
// boot_$get_uids
|
||||
static UINT8 response_070a[] = {
|
||||
0x00,0x01, // 0x40:
|
||||
0x00,0x01,
|
||||
0x00,0x0b, // 0x44: packet type (0b = 0a+1)
|
||||
0x00,0x00,0x00,0x00,
|
||||
// d993195c (2010-04-28 07:27:15)
|
||||
0xd9,0x93,0x19,0x5c,0x60,0x04,0x20,0xe8, // FIXME: UID of OS paging file (?)
|
||||
// 7742b564 (1996-08-14 19:12:59)
|
||||
0x77,0x42,0xb5,0x64,0xf0,0x04,0x20,0xe8, // 7742B564.F00420E8 is UID of //
|
||||
0x77,0x42,0xb5,0x64,0xe0,0x04,0x20,0xe8 // 7742B564.E00420E8 is UID of / (resp. //samba)
|
||||
};
|
||||
|
||||
// get (dex) file parameters
|
||||
static UINT8 response_0718[] = {
|
||||
0x00,0x01, // 0x40:
|
||||
0x00,0x01, // 0x42:
|
||||
0x00,0x19, // 0x44: packet type (19 = 18+1)
|
||||
0x00,0x00,0x00,0x00, // 0x46:
|
||||
0x01,
|
||||
0x01, // 0x4b: systyp (1=dir, 0=file) i.e. is directory
|
||||
0x90,0x00,
|
||||
0x77,0x43,0x02,0x58,0xe0,0x04,0x20,0xe8, // 0x4e: source UID
|
||||
0x00,0x00, // 0x56
|
||||
0x00,0x00, // 0x58: file type (0x0321 = UASC file)
|
||||
0x00,0x00,0x00,0x00, // 0x5A:
|
||||
0x77,0x43,0x02,0x58,0xe8,0x04,0x20,0xe8, // 0x5E: source UID
|
||||
0x00,0x00,0x10,0x00, // 0x66: file size
|
||||
0x00,0x00,0x00,0x04, // 0x6A: n sectors (?)
|
||||
0xd9,0x8f,0xb5,0xef, // 0x6E:
|
||||
0x80,0x27,0x94,0x1e, // 0x72:
|
||||
0x77,0x42,0xb5,0x64,0xe0,0x04,0x20,0xe8, // source UID
|
||||
0x8d,0x15,0x00,0x02,
|
||||
0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00
|
||||
};
|
||||
|
||||
static UINT8 get_byte(const UINT8 *data) {
|
||||
return data[0];
|
||||
}
|
||||
|
||||
static void set_byte(UINT8 *data, const UINT8 value) {
|
||||
data[0] = value;
|
||||
}
|
||||
|
||||
static UINT16 get_word(const UINT8 *data) {
|
||||
return (data[0] << 8) | data[1];
|
||||
}
|
||||
|
||||
static void set_word(UINT8 *data, const UINT16 value) {
|
||||
data[0] = value >> 8;
|
||||
data[1] = value & 0xff;
|
||||
}
|
||||
|
||||
static UINT32 get_3byte(const UINT8 *data) {
|
||||
return (((data[0] << 8) | data[1]) << 8) | data[2];
|
||||
}
|
||||
|
||||
static void set_3byte(UINT8 *data, const UINT32 value) {
|
||||
data[0] = (value >> 16) & 0xff;
|
||||
data[1] = (value >> 8) & 0xff;
|
||||
data[2] = value & 0xff;
|
||||
}
|
||||
|
||||
static UINT32 get_long(const UINT8 *data) {
|
||||
return (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
|
||||
}
|
||||
|
||||
static void set_long(UINT8 *data, const UINT32 value) {
|
||||
data[0] = (value >> 24) & 0xff;
|
||||
data[1] = (value >> 16) & 0xff;
|
||||
data[2] = (value >> 8) & 0xff;
|
||||
data[3] = value & 0xff;
|
||||
}
|
||||
|
||||
static char *get_string(const UINT8 *data) {
|
||||
static char sb[256];
|
||||
int i;
|
||||
int stringLength = get_word(data);
|
||||
for (i = 0; i < stringLength && i < sizeof(sb) - 1; i++) {
|
||||
sb[i] = data[i + 2];
|
||||
}
|
||||
sb[stringLength] = 0;
|
||||
return sb;
|
||||
}
|
||||
|
||||
static char *get_file_name(const UINT8 *data) {
|
||||
char * s = get_string(data);
|
||||
int i = strlen(s);
|
||||
while (--i >= 0) {
|
||||
s[i] = tolower(s[i]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
static int get_file_size(const char *path) {
|
||||
int file_size = 0;
|
||||
emu_file file(OPEN_FLAG_READ | OPEN_FLAG_NO_PRELOAD);
|
||||
file_error filerr = file.open(path);
|
||||
if (filerr == FILERR_NONE)
|
||||
{
|
||||
file_size = file.size();
|
||||
file.close();
|
||||
}
|
||||
LOG1(("##### %s - file_size=%d",path, file_size));
|
||||
return file_size;
|
||||
}
|
||||
|
||||
static int is_directory(const char *path) {
|
||||
int is_directory = 0;
|
||||
osd_directory *curdir;
|
||||
if ((curdir = osd_opendir(path)) != NULL)
|
||||
{
|
||||
osd_closedir(curdir);
|
||||
is_directory = 1;
|
||||
}
|
||||
LOG1(("##### %s - is_directory=%d",path, is_directory));
|
||||
return is_directory;
|
||||
}
|
||||
|
||||
static int get_file_type(const char *path) {
|
||||
if (!is_directory(path)) {
|
||||
const char *suffix = path + strlen(path);
|
||||
while (suffix != path && *--suffix != '.') {
|
||||
}
|
||||
|
||||
if (strcmp(suffix, ".cmd") == 0 || strcmp(suffix, ".hlp") == 0) {
|
||||
return 0x0321; // UASC file
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_ethernet_header(UINT8 *data, UINT8 client_ethernet_address[6]) {
|
||||
memcpy(data + 0, client_ethernet_address, 6);
|
||||
set_3byte(data + 6, ETHERNET_APOLLO_PREFIX);
|
||||
set_3byte(data + 9, my_node_id);
|
||||
set_word(data + 12, ETHERNET_PACKET_TYPE_APOLLO);
|
||||
return ETHERNET_HEADER_SIZE;
|
||||
}
|
||||
|
||||
static int set_packet_header(UINT8 *packet_buffer, UINT32 dest_node_id,
|
||||
UINT32 source_node_id) {
|
||||
// --------- apollo header --------------
|
||||
set_word(packet_buffer, 0xffff);
|
||||
// set_word(packet_buffer + 2, data_size + PACKET_HEADER_SIZE);
|
||||
set_word(packet_buffer + 4, 0x00be);
|
||||
set_word(packet_buffer + 6, 0x0000);
|
||||
set_word(packet_buffer + 8, 0x0000); // Apollo network number
|
||||
set_3byte(packet_buffer + 10, ETHERNET_APOLLO_PREFIX);
|
||||
set_3byte(packet_buffer + 13, dest_node_id);
|
||||
set_word(packet_buffer + 16, 0x0000);
|
||||
set_word(packet_buffer + 18, 0x0000);
|
||||
set_word(packet_buffer + 20, 0x0000);
|
||||
set_3byte(packet_buffer + 22, ETHERNET_APOLLO_PREFIX);
|
||||
set_3byte(packet_buffer + 25, source_node_id);
|
||||
set_word(packet_buffer + 28, 0x0003);
|
||||
// --------- data header --------------
|
||||
set_long(packet_buffer + 30, dest_node_id);
|
||||
set_long(packet_buffer + 34, 0x24000000L);
|
||||
set_long(packet_buffer + 38, source_node_id);
|
||||
set_long(packet_buffer + 42, 0x01002400L);
|
||||
// set_word(packet_buffer + 46, data_size + 0x22);
|
||||
// set_word(packet_buffer + 48, data_size);
|
||||
set_word(packet_buffer + 50, 0x0000);
|
||||
set_word(packet_buffer + 52, 0x0000);
|
||||
// --------- data --------------
|
||||
set_word(packet_buffer + 54, 0x0401);
|
||||
set_word(packet_buffer + 56, 0x0003);
|
||||
set_word(packet_buffer + 58, 0x20e8);
|
||||
set_word(packet_buffer + 60, 0x616d);
|
||||
set_word(packet_buffer + 62, 0x0000);
|
||||
return PACKET_HEADER_SIZE;
|
||||
}
|
||||
|
||||
static int set_packet(UINT8 *packet_buffer, UINT8 *packet_data,
|
||||
int packet_data_size) {
|
||||
set_word(packet_buffer + 2, packet_data_size + PACKET_HEADER_SIZE);
|
||||
set_word(packet_buffer + 46, packet_data_size + 0x22);
|
||||
set_word(packet_buffer + 48, packet_data_size);
|
||||
|
||||
memcpy(packet_buffer + PACKET_HEADER_SIZE, packet_data, packet_data_size);
|
||||
|
||||
return packet_data_size;
|
||||
}
|
||||
|
||||
static int get_packet_size(UINT8 *packet_buffer) {
|
||||
return get_word(packet_buffer + 2);
|
||||
}
|
||||
|
||||
static int get_dir_data(const char *pathname, UINT8 *packet_buffer) {
|
||||
int nBytes, lineLength;
|
||||
char *data_buffer;
|
||||
osd_directory *curdir;
|
||||
const osd_directory_entry *dir;
|
||||
|
||||
char dir_path[1024];
|
||||
strcpy(dir_path, root_path);
|
||||
strcat (dir_path, pathname);
|
||||
|
||||
set_packet(packet_buffer, list_directory_header,
|
||||
sizeof(list_directory_header));
|
||||
data_buffer = (char *) (packet_buffer + get_packet_size(packet_buffer));
|
||||
|
||||
strcpy(data_buffer, "\n\r");
|
||||
strcat(data_buffer, pathname);
|
||||
strcat(data_buffer, "\n\r");
|
||||
|
||||
if ((curdir = osd_opendir(dir_path)) == NULL)
|
||||
{
|
||||
strcat(data_buffer, "Error: failed to open directory ");
|
||||
strcat(data_buffer, dir_path);
|
||||
strcat(data_buffer, "\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
osd_closedir(curdir);
|
||||
|
||||
// open a path to the netserver directory
|
||||
file_enumerator path(dir_path);
|
||||
|
||||
lineLength = 99;
|
||||
while ((dir = path.next()) != NULL)
|
||||
{
|
||||
LOG1(("##### %d %s", (int)strlen(dir->name), dir->name));
|
||||
|
||||
if (strcmp(dir->name, ".") != 0 && strcmp(dir->name, "..") != 0)
|
||||
{
|
||||
lineLength += 3 + strlen(dir->name);
|
||||
if (lineLength > 72) {
|
||||
strcat(data_buffer, "\n\r");
|
||||
lineLength = 3 + strlen(dir->name);
|
||||
}
|
||||
strcat(data_buffer, " ");
|
||||
strcat(data_buffer, dir->name);
|
||||
}
|
||||
}
|
||||
strcat(data_buffer, "\n\r");
|
||||
}
|
||||
|
||||
nBytes = strlen(data_buffer);
|
||||
nBytes = (nBytes + 1) & 0xfffffffe;
|
||||
|
||||
set_word(packet_buffer + 2, get_word(packet_buffer + 2) + nBytes);
|
||||
set_word(packet_buffer + 50, nBytes);
|
||||
|
||||
return nBytes + sizeof(list_directory_header);
|
||||
}
|
||||
|
||||
static int get_file_data(const char *pathname, UINT8 *packet_buffer,
|
||||
UINT16 first_sector, UINT16 last_sector) {
|
||||
UINT8 *packet_data = packet_buffer + PACKET_HEADER_SIZE;
|
||||
UINT8 *data_buffer;
|
||||
int nBytes;
|
||||
UINT32 fileSize = 0;
|
||||
file_error filerr;
|
||||
|
||||
if(current_file == NULL)
|
||||
{
|
||||
current_file = global_alloc(emu_file(root_path, OPEN_FLAG_READ));
|
||||
// skip leading '/'
|
||||
filerr = current_file->open( pathname+1);
|
||||
|
||||
if (filerr != FILERR_NONE)
|
||||
{
|
||||
global_free(current_file);
|
||||
current_file = NULL;
|
||||
}
|
||||
|
||||
fileSize = current_file == NULL ? 0 : current_file->size();
|
||||
current_sector = 0;
|
||||
|
||||
LOG1(("##### %s - %s filerr=%d fileSize=%d", root_path.cstr(), pathname, filerr, fileSize));
|
||||
} else {
|
||||
current_sector++;
|
||||
}
|
||||
current_last_sector = last_sector;
|
||||
|
||||
if (current_file == NULL)
|
||||
{
|
||||
set_packet(packet_buffer, not_found_data_header,
|
||||
sizeof(not_found_data_header));
|
||||
|
||||
set_word(packet_data + 0x0A, strlen(pathname));
|
||||
strncpy((char *) packet_data + 0x0C, pathname, 0x24);
|
||||
return sizeof(not_found_data_header);
|
||||
} else {
|
||||
set_packet(packet_buffer, receive_data_header,
|
||||
sizeof(receive_data_header));
|
||||
|
||||
data_buffer = (packet_buffer + get_packet_size(packet_buffer));
|
||||
|
||||
nBytes = current_file->read(data_buffer, 1024);
|
||||
|
||||
if (nBytes < 0) {
|
||||
nBytes = 0;
|
||||
}
|
||||
|
||||
// help in dex will fail, if size is odd (5.5.2010 - ost)
|
||||
nBytes = (nBytes + 1) & 0xfffffffe;
|
||||
|
||||
if (nBytes < 1024)
|
||||
{
|
||||
current_file->close();
|
||||
global_free(current_file);
|
||||
current_file = NULL;
|
||||
}
|
||||
else if (current_sector == 0) {
|
||||
// set header addresses from first sector read
|
||||
UINT32 low = get_long(data_buffer + 0);
|
||||
UINT32 start = get_long(data_buffer + 4);
|
||||
UINT32 high = low + fileSize - 1;
|
||||
|
||||
set_long(receive_data_header + 0x0A, high);
|
||||
set_long(receive_data_header + 0x0E, low);
|
||||
set_long(receive_data_header + 0x12, start);
|
||||
set_long(receive_data_header + 0x16, low);
|
||||
|
||||
set_packet(packet_buffer, receive_data_header,
|
||||
sizeof(receive_data_header));
|
||||
}
|
||||
|
||||
if (VERBOSE > 1) {
|
||||
LOG1(("##### %s: 3C505 current address = %0x first/last/current sector = %0x / %0x / %0x",
|
||||
pathname, get_long(receive_data_header + 0x16), first_sector, last_sector, current_sector));
|
||||
}
|
||||
|
||||
set_long(receive_data_header + 0x16, get_long(receive_data_header + 0x16) + nBytes);
|
||||
set_word(packet_data + 0x1A, nBytes < 1024 ? 0xffff : current_sector == last_sector ? 0x00ff : 0);
|
||||
|
||||
set_word(packet_buffer + 2, get_word(packet_buffer + 2) + nBytes);
|
||||
set_word(packet_buffer + 50, nBytes);
|
||||
|
||||
return nBytes + sizeof(receive_data_header);
|
||||
}
|
||||
}
|
||||
|
||||
static void log_data(const device_t *device, const char *type,
|
||||
const UINT8 *data, int data_length) {
|
||||
if (VERBOSE > 1) {
|
||||
int i;
|
||||
logerror("%s - %s: Net Server %s Data (length=%2x)", apollo_cpu_context(
|
||||
device->machine().firstcpu), device->tag(), type, data_length);
|
||||
for (i = 0; i < data_length; i++) {
|
||||
logerror(" %02x", data[i]);
|
||||
}
|
||||
logerror("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static UINT16 get_socket(const UINT8 rx_data_buffer[], int rx_data_length) {
|
||||
const UINT8 * packet_buffer = rx_data_buffer + ETHERNET_HEADER_SIZE;
|
||||
int packet_length = rx_data_length - ETHERNET_HEADER_SIZE;
|
||||
|
||||
UINT16 socket = packet_length < 0x11 ? 0xffff : get_word(packet_buffer + 0x10); // 0x10: dest socket
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
netman server
|
||||
***************************************************************************/
|
||||
|
||||
static int netman_server(const device_t *device,
|
||||
const UINT8 rx_data_buffer[], int rx_data_length, UINT8 tx_data_buffer[]) {
|
||||
UINT16 service;
|
||||
UINT16 node_type; // SAU7, SAU8 or SAU14
|
||||
char pathname[256];
|
||||
|
||||
int tx_data_length;
|
||||
|
||||
UINT8 *packet_buffer = tx_data_buffer + ETHERNET_HEADER_SIZE;
|
||||
|
||||
UINT32 client_node_id;
|
||||
UINT8 client_ethernet_address[6];
|
||||
|
||||
UINT16 last_sector;
|
||||
UINT16 first_sector;
|
||||
|
||||
client_node_id = get_3byte(rx_data_buffer + 9);
|
||||
memcpy(client_ethernet_address, rx_data_buffer + 6, 6);
|
||||
|
||||
log_data(device, "Rx", rx_data_buffer, rx_data_length);
|
||||
|
||||
// strip off the ethernet header;
|
||||
rx_data_buffer += ETHERNET_HEADER_SIZE;
|
||||
rx_data_length -= ETHERNET_HEADER_SIZE;
|
||||
|
||||
service = (rx_data_length > 0x45) ? get_word(rx_data_buffer + 0x44) : 0xffff;
|
||||
first_sector = (rx_data_length > 0x6b) ? get_word(rx_data_buffer + 0x6a) : 0;
|
||||
// FIXME: hack
|
||||
// last_sector = (rx_data_length > 0x6d) ? get_word(rx_data_buffer + 0x6c) : 0;
|
||||
last_sector = (rx_data_length > 0x6d) ? get_word(rx_data_buffer + 0x6c) : 0x0f;
|
||||
|
||||
set_ethernet_header(tx_data_buffer, client_ethernet_address);
|
||||
set_packet_header(packet_buffer, client_node_id, my_node_id);
|
||||
|
||||
node_type = service >> 8;
|
||||
|
||||
switch (service & 0xff) {
|
||||
case 6: // boot_$volun (find partner node)
|
||||
DLOG1(("Net Server service=%04x (boot_$volun)", service));
|
||||
set_packet(packet_buffer, response_0006, sizeof(response_0006));
|
||||
break;
|
||||
|
||||
case 8: // boot_$sysboot (get netboot)
|
||||
get_file_data(APOLLO_NETBOOT_PATH, packet_buffer, first_sector, last_sector);
|
||||
DLOG1(("Net Server service=%04x (boot_$sysboot - sector %x of %x-%x)", service, current_sector, first_sector, last_sector));
|
||||
break;
|
||||
case 0x0a: // boot_$get_uids (get UIDs for OS paging file, network root and the node entry directory)
|
||||
set_packet(packet_buffer, response_070a, sizeof(response_070a));
|
||||
DLOG1(("Net Server service=%04x (boot_$get_uids)", service));
|
||||
break;
|
||||
case 0x0c: // boot_$mult_ld (list directory for sau7, SAU8, SAU14)
|
||||
get_dir_data( node_type == 7 ? APOLLO_SAU7_PATH : node_type == 8 ? APOLLO_SAU8_PATH : APOLLO_SAU14_PATH, packet_buffer);
|
||||
DLOG1(("Net Server service=%04x (boot_$mult_ld)", service));
|
||||
break;
|
||||
case 0x12: // boot_$load (ex /sau7/self_test, domain_os, ...)
|
||||
strcpy(pathname, node_type == 7 ? APOLLO_SAU7_PATH : node_type == 8 ? APOLLO_SAU8_PATH : APOLLO_SAU14_PATH);
|
||||
strcat(pathname, "/");
|
||||
strcat(pathname, get_file_name(rx_data_buffer + 0x48));
|
||||
get_file_data(pathname, packet_buffer, first_sector, last_sector);
|
||||
DLOG1(("Net Server service=%04x (boot_$load %s - sector %x of %x-%x)", service, pathname, current_sector, first_sector, last_sector));
|
||||
break;
|
||||
case 0x18: // boot_$set_path (set current path and get attributes of current path)
|
||||
set_packet(packet_buffer, response_0718, sizeof(response_0718));
|
||||
|
||||
if (get_long(rx_data_buffer + 0x6e) == 0L && get_long(rx_data_buffer + 0x72) == 0L) {
|
||||
// reset path name to root dir
|
||||
strcpy(current_pathname, root_path);
|
||||
}
|
||||
|
||||
// FIXME: why is this necessary???
|
||||
if (is_directory(current_pathname)) {
|
||||
strcat(current_pathname, "/");
|
||||
strcat(current_pathname, get_file_name(rx_data_buffer + 0x48));
|
||||
}
|
||||
|
||||
// 0x4b: systyp (1=dir, 0=file)
|
||||
set_byte(packet_buffer + 0x4b, is_directory(current_pathname));
|
||||
set_word(packet_buffer + 0x58, get_file_type(current_pathname));
|
||||
set_long(packet_buffer + 0x66, get_file_size(current_pathname));
|
||||
|
||||
DLOG1(("Net Server service=%04x (boot_$set_path %s)", service, current_pathname + strlen(root_path)));
|
||||
break;
|
||||
case 0x1a: // boot_$load_file (?): load /sau7/cmd/startup.cmd, /sau7/cpu.dex, ...
|
||||
get_file_data(current_pathname + strlen(root_path), packet_buffer, first_sector, last_sector);
|
||||
DLOG1(("Net Server service=%04x (boot_$load_file %s - sector %x of %x-%x)", service, current_pathname + strlen(root_path), current_sector, first_sector, last_sector));
|
||||
break;
|
||||
default:
|
||||
DLOG(("Net Server - unexpected service %04x", service&0xff));
|
||||
return 0;
|
||||
}
|
||||
|
||||
set_word(packet_buffer + 0x44, (service & 0xff) + 1); // 0x44: response packet type
|
||||
|
||||
tx_data_length = ETHERNET_HEADER_SIZE + get_packet_size(packet_buffer);
|
||||
|
||||
log_data(device, "Tx", tx_data_buffer, tx_data_length);
|
||||
return tx_data_length;
|
||||
}
|
||||
|
||||
static int is_ethernet_broadcast_address(const UINT8 ethernet_header[]) {
|
||||
return get_3byte(ethernet_header + 0) == 0xffffff && //
|
||||
get_3byte(ethernet_header + 3) == 0xffffff;
|
||||
}
|
||||
|
||||
static int is_apollo_multicast_address(const UINT8 ethernet_header[]) {
|
||||
return get_3byte(ethernet_header + 0) == ETHERNET_APOLLO_DOMAIN_PREFIX && //
|
||||
(get_3byte(ethernet_header + 3) == 0L || get_3byte(ethernet_header + 3) == 1L);
|
||||
}
|
||||
|
||||
static int is_my_ethernet_address(const UINT8 mac_address[]) {
|
||||
return memcmp(mac_address, my_mac_address, 6) == 0;
|
||||
}
|
||||
|
||||
static int is_my_ip_address(const UINT8 ip_address[]) {
|
||||
return memcmp (ip_address, my_ip_address, 4) == 0;
|
||||
}
|
||||
|
||||
static int is_my_node_id(const UINT8 node_id[]) {
|
||||
return get_long(node_id) == my_node_id;
|
||||
}
|
||||
|
||||
static int ethernet_packet_is_for_me(const UINT8 ethernet_packet_header[],
|
||||
const int data_length) {
|
||||
return data_length >= ETHERNET_HEADER_SIZE && (
|
||||
is_ethernet_broadcast_address(ethernet_packet_header) ||
|
||||
is_apollo_multicast_address(ethernet_packet_header) ||
|
||||
is_my_ethernet_address(ethernet_packet_header));
|
||||
}
|
||||
|
||||
static int is_apollo_request(const UINT8 ethernet_header[],
|
||||
const int data_length) {
|
||||
return data_length >= 0x30 && //
|
||||
get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_APOLLO;
|
||||
}
|
||||
|
||||
static int is_apollo_arp_request(const UINT8 ethernet_header[], const int data_length) {
|
||||
return data_length >= 0x30 && //
|
||||
get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_ARP && //
|
||||
get_word(ethernet_header + 0x10) == ETHERNET_PACKET_TYPE_APOLLO && //
|
||||
is_apollo_multicast_address(ethernet_header) && //
|
||||
is_my_node_id(ethernet_header + 0x26);
|
||||
}
|
||||
|
||||
static int is_ip_arp_request(const UINT8 ethernet_header[], const int data_length) {
|
||||
return data_length >= 0x30 && //
|
||||
get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_ARP && //
|
||||
get_word(ethernet_header + 0x10) == ETHERNET_PACKET_TYPE_IP && //
|
||||
is_ethernet_broadcast_address(ethernet_header) && //
|
||||
is_my_ip_address (ethernet_header + 0x26);
|
||||
}
|
||||
|
||||
static int is_ip_echo_request(const UINT8 ethernet_header[], const int data_length) {
|
||||
return data_length >= 0x30 && //
|
||||
get_word(ethernet_header + 0x0c) == ETHERNET_PACKET_TYPE_IP && //
|
||||
get_byte(ethernet_header + 0x22) == ICMP_ECHO && //
|
||||
is_my_ethernet_address(ethernet_header);
|
||||
}
|
||||
|
||||
static UINT16 in_checksum(UINT8 *ptr, UINT32 nbytes)
|
||||
{
|
||||
UINT32 sum = 0;
|
||||
while (nbytes > 1)
|
||||
{
|
||||
// MSB first
|
||||
sum += (*ptr++) << 8;
|
||||
sum += *ptr++;
|
||||
nbytes -=2;
|
||||
}
|
||||
if (nbytes == 1)
|
||||
{
|
||||
sum += (*ptr++) << 8;
|
||||
}
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
sum += (sum >> 16);
|
||||
|
||||
return (~sum) & 0xffff;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
simple ARP Server emulation
|
||||
***************************************************************************/
|
||||
|
||||
static int arp_server(const device_t *device,
|
||||
const UINT8 rx_data[], int rx_data_length,
|
||||
UINT8 tx_data[]) {
|
||||
// static UINT8 arp_response[] = {
|
||||
// 0x08,0x00,0x1e,0x02,0x61,0x6d, // 0x00: Ethernet address of destination
|
||||
// 0x08,0x00,0x1e,0x04,0x20,0xe8, // 0x06: Ethernet address of sender
|
||||
// 0x08,0x06, // 0x0c: Protocol type
|
||||
// 0x00,0x01, // 0x0e: Hardware address space
|
||||
// 0x80,0x19, // 0x10: Protocol address space
|
||||
// 0x06, // 0x12: byte length of each hardware address
|
||||
// 0x04, // 0x13: byte length of each protocol address
|
||||
// 0x00,0x02, // 0x14: opcode (ares_op$REQUEST | ares_op$REPLY)
|
||||
// 0x08,0x00,0x1e,0x04,0x20,0xe8, // 0x16: Hardware address of sender of this packet
|
||||
// 0x00,0x04,0x20,0xe8, // 0x1c: Protocol address of sender of this packet
|
||||
// 0x08,0x00,0x1e,0x02,0x61,0x6d, // 0x20: Hardware address of target of this packet (if known)
|
||||
// 0x00,0x02,0x61,0x6d, // 0x26: Protocol address of target
|
||||
// ...
|
||||
// };
|
||||
|
||||
UINT16 tx_data_length = rx_data_length;
|
||||
memcpy(tx_data, rx_data, tx_data_length);
|
||||
|
||||
// 0x00: Ethernet address of destination
|
||||
memcpy(tx_data + 0x00, rx_data + 0x06, 6);
|
||||
// 0x06: Ethernet address of sender
|
||||
memcpy(tx_data + 0x06, my_mac_address, 6);
|
||||
// 0x14: opcode (ares_op$REQUEST | ares_op$REPLY)
|
||||
set_word(tx_data + 0x14, 2);
|
||||
// 0x16: Hardware address of sender
|
||||
memcpy(tx_data + 0x16, my_mac_address, 6);
|
||||
// 0x1c: Protocol address of sender
|
||||
memcpy(tx_data + 0x1c, rx_data + 0x26, 4);
|
||||
// 0x20: Hardware address of target (if known)
|
||||
memcpy(tx_data + 0x20, rx_data + 0x16, 6);
|
||||
// 0x26: Protocol address of target
|
||||
memcpy(tx_data + 0x26, rx_data + 0x1c, 4);
|
||||
|
||||
log_data(device, "ARP Rx", rx_data, rx_data_length);
|
||||
log_data(device, "ARP Tx", tx_data, tx_data_length);
|
||||
return tx_data_length;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
simple Echo (ping) Server emulation
|
||||
***************************************************************************/
|
||||
|
||||
static int echo_server(const device_t *device,
|
||||
const UINT8 rx_data[], int rx_data_length,
|
||||
UINT8 tx_data[]) {
|
||||
static const UINT32 ip_offset = sizeof(ethernet_header);
|
||||
static const UINT32 icmp_offset = ip_offset + sizeof(ip_header);
|
||||
|
||||
UINT16 tx_data_length = rx_data_length;
|
||||
memcpy(tx_data, rx_data, tx_data_length);
|
||||
|
||||
// 0x00: Ethernet address of destination
|
||||
memcpy(tx_data + 0x00, rx_data + 0x06, 6);
|
||||
// 0x06: Ethernet address of sender
|
||||
memcpy(tx_data + 0x06, rx_data + 0x00, 6);
|
||||
// 0x12: ip.id
|
||||
set_word(tx_data + 0x12, 0x0573);
|
||||
// 0x18: ip.checksum
|
||||
set_word(tx_data + 0x18, 0);
|
||||
set_word(tx_data + 0x18, in_checksum(tx_data + ip_offset, sizeof(ip_header)));
|
||||
|
||||
// 0x1a: Protocol address of sender
|
||||
memcpy(tx_data + 0x1a, rx_data + 0x1e, 4);
|
||||
// 0x1e: Protocol address of target
|
||||
memcpy(tx_data + 0x1e, rx_data + 0x1a, 4);
|
||||
// 0x22: icmp.type
|
||||
set_byte(tx_data + 0x22, ICMP_ECHOREPLY);
|
||||
// 0x24: icmp.cksump
|
||||
set_word(tx_data + 0x24, 0);
|
||||
set_word(tx_data + 0x24, in_checksum(tx_data + icmp_offset, tx_data_length-icmp_offset));
|
||||
|
||||
log_data(device, "Echo Rx", rx_data, rx_data_length);
|
||||
log_data(device, "Echo Tx", tx_data, tx_data_length);
|
||||
return tx_data_length;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
netserver
|
||||
***************************************************************************/
|
||||
|
||||
static int netserver(const device_t *device,
|
||||
const UINT8 rx_data[], int rx_data_length,
|
||||
UINT8 tx_data[]) {
|
||||
if (!ethernet_packet_is_for_me(rx_data, rx_data_length))
|
||||
return 0; // skip
|
||||
else if (is_apollo_request(rx_data, rx_data_length))
|
||||
{
|
||||
UINT16 socket = get_socket(rx_data, rx_data_length);
|
||||
|
||||
switch (socket) {
|
||||
case 1: // Paging socket
|
||||
break;
|
||||
case 2: // File socket
|
||||
// return file_server(device, rx_data, rx_data_length, tx_data);
|
||||
break;
|
||||
case 3: // NETMAN socket
|
||||
return netman_server(device, rx_data, rx_data_length, tx_data);
|
||||
case 4: // Information socket
|
||||
break;
|
||||
case 5: // Receives internet asknode "who" replies
|
||||
break;
|
||||
case 6: // File server overflow socket
|
||||
break;
|
||||
case 7: // Software diagnostic socket
|
||||
break;
|
||||
case 8: // routing information protocol (RIP) socket
|
||||
break;
|
||||
case 9: // Mailbox socket
|
||||
break;
|
||||
case 10: // NS Helper socket
|
||||
break;
|
||||
case 11: // TCP/IP
|
||||
break;
|
||||
case 12: // ?
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DLOG1(("Net Server - socket %d not yet supported", socket));
|
||||
return 0;
|
||||
} else if (is_apollo_arp_request(rx_data, rx_data_length)) {
|
||||
return arp_server(device, rx_data, rx_data_length, tx_data);
|
||||
} else if (is_ip_arp_request(rx_data, rx_data_length)) {
|
||||
return arp_server(device, rx_data, rx_data_length, tx_data);
|
||||
} else if (is_ip_echo_request(rx_data, rx_data_length)) {
|
||||
return echo_server(device, rx_data, rx_data_length, tx_data);
|
||||
} else {
|
||||
log_data(device, "unexpected Rx", rx_data, rx_data_length);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
receive_interrupt
|
||||
***************************************************************************/
|
||||
|
||||
static TIMER_CALLBACK(receive_interrupt) {
|
||||
device_t *device = (device_t *)ptr;
|
||||
|
||||
UINT8 tx_data_buffer[ETH_BUFFER_SIZE];
|
||||
|
||||
int tx_data_length = netserver(device, current_rx_data_buffer, current_rx_data_length, tx_data_buffer);
|
||||
|
||||
DLOG2(("Net Server rx/tx_data_length = %x/%x current_sector=%x current_last_sector=%x",
|
||||
current_rx_data_length, tx_data_length, current_sector, current_last_sector ));
|
||||
|
||||
if (tx_data_length > 0 && tx_callback != NULL) {
|
||||
// threecom3c505_receive(device, tx_data_buffer, tx_data_length);
|
||||
(*tx_callback)(device, tx_data_buffer, tx_data_length);
|
||||
}
|
||||
|
||||
if (current_file != NULL && current_sector < current_last_sector)
|
||||
{
|
||||
// more packets pending
|
||||
machine.scheduler().timer_set(attotime::from_msec(1), FUNC(receive_interrupt), 0, device);
|
||||
} else {
|
||||
current_rx_data_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
apollo_netserver_receive - receive and process an ethernet packet
|
||||
***************************************************************************/
|
||||
|
||||
int apollo_netserver_receive(device_t *device, const UINT8 rx_data_buffer[],
|
||||
int rx_data_length)
|
||||
{
|
||||
if (!ethernet_packet_is_for_me(rx_data_buffer, rx_data_length))
|
||||
{
|
||||
return 1; // skip packet
|
||||
}
|
||||
else if (current_rx_data_length > 0)
|
||||
{
|
||||
LOG1(("apollo_netserver_receive: busy - skipped data with length %02x",rx_data_length));
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(current_rx_data_buffer, rx_data_buffer, rx_data_length);
|
||||
current_rx_data_length = rx_data_length;
|
||||
|
||||
// delay response to multicast requests
|
||||
int ms = is_apollo_multicast_address(rx_data_buffer) ? 1000 : 1;
|
||||
device->machine().scheduler().timer_set(attotime::from_msec(ms), FUNC(receive_interrupt), 0, device);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
apollo_netserver_init - specify the transmitter call back function
|
||||
***************************************************************************/
|
||||
|
||||
void apollo_netserver_init(const char *root_path, apollo_netserver_transmit tx_data)
|
||||
{
|
||||
::root_path.cat(root_path);
|
||||
::root_path.cat(PATH_SEPARATOR);
|
||||
::root_path.cat(NETSERVER_ROOT_PATH);
|
||||
|
||||
::tx_callback = tx_data;
|
||||
|
||||
my_node_id = NETSERVER_NODE_ID;
|
||||
set_3byte(my_mac_address, ETHERNET_APOLLO_PREFIX);
|
||||
set_3byte(my_mac_address + 3, my_node_id);
|
||||
|
||||
current_rx_data_length = 0;
|
||||
}
|
@ -901,8 +901,6 @@ $(MESSOBJ)/apollo.a: \
|
||||
$(MESS_DRIVERS)/apollo.o \
|
||||
$(MESS_VIDEO)/apollo.o \
|
||||
$(MESS_MACHINE)/apollo_dbg.o \
|
||||
$(MESS_MACHINE)/apollo_eth.o \
|
||||
$(MESS_MACHINE)/apollo_net.o \
|
||||
$(MESS_MACHINE)/apollo_kbd.o \
|
||||
$(MESS_MACHINE)/3c505.o \
|
||||
$(MESS_MACHINE)/apollo.o \
|
||||
|
Loading…
Reference in New Issue
Block a user