Merge pull request #1032 from richardg867/master
Implement PLIP network device
This commit is contained in:
@@ -170,8 +170,8 @@ pipc_reset_hard(void *priv)
|
|||||||
dev->ide_regs[0x34] = 0xc0;
|
dev->ide_regs[0x34] = 0xc0;
|
||||||
dev->ide_regs[0x3c] = 0x0e;
|
dev->ide_regs[0x3c] = 0x0e;
|
||||||
|
|
||||||
if (dev->local < VIA_PIPC_686A)
|
if (dev->local <= VIA_PIPC_586B)
|
||||||
dev->ide_regs[0x40] = 0x08;
|
dev->ide_regs[0x40] = 0x04;
|
||||||
dev->ide_regs[0x41] = 0x02;
|
dev->ide_regs[0x41] = 0x02;
|
||||||
dev->ide_regs[0x42] = 0x09;
|
dev->ide_regs[0x42] = 0x09;
|
||||||
dev->ide_regs[0x43] = (dev->local >= VIA_PIPC_686A) ? 0x0a : 0x3a;
|
dev->ide_regs[0x43] = (dev->local >= VIA_PIPC_686A) ? 0x0a : 0x3a;
|
||||||
@@ -513,17 +513,21 @@ pipc_write(int func, int addr, uint8_t val, void *priv)
|
|||||||
pci_set_irq_level(PCI_INTD, !(val & 1));
|
pci_set_irq_level(PCI_INTD, !(val & 1));
|
||||||
break;
|
break;
|
||||||
case 0x55:
|
case 0x55:
|
||||||
|
pipc_log("PIPC: PCI INT%c %d\n", (dev->local >= VIA_PIPC_596A) ? 'A' : 'D', val >> 4);
|
||||||
pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTA : PCI_INTD, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
|
pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTA : PCI_INTD, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
|
||||||
if (dev->local <= VIA_PIPC_586B)
|
if (dev->local <= VIA_PIPC_586B)
|
||||||
pci_set_mirq_routing(PCI_MIRQ0, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
|
pci_set_mirq_routing(PCI_MIRQ0, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
|
||||||
dev->pci_isa_regs[0x55] = val;
|
dev->pci_isa_regs[0x55] = val;
|
||||||
break;
|
break;
|
||||||
case 0x56:
|
case 0x56:
|
||||||
|
pipc_log("PIPC: PCI INT%c %d\n", (dev->local >= VIA_PIPC_596A) ? 'C' : 'A', val >> 4);
|
||||||
|
pipc_log("PIPC: PCI INTB %d\n", val & 0x0f);
|
||||||
pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTC : PCI_INTA, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
|
pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTC : PCI_INTA, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
|
||||||
pci_set_irq_routing(PCI_INTB, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
|
pci_set_irq_routing(PCI_INTB, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
|
||||||
dev->pci_isa_regs[0x56] = val;
|
dev->pci_isa_regs[0x56] = val;
|
||||||
break;
|
break;
|
||||||
case 0x57:
|
case 0x57:
|
||||||
|
pipc_log("PIPC: PCI INT%c %d\n", (dev->local >= VIA_PIPC_596A) ? 'D' : 'C', val >> 4);
|
||||||
pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTD : PCI_INTC, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
|
pci_set_irq_routing((dev->local >= VIA_PIPC_596A) ? PCI_INTD : PCI_INTC, (val & 0xf0) ? (val >> 4) : PCI_IRQ_DISABLED);
|
||||||
if (dev->local <= VIA_PIPC_586B)
|
if (dev->local <= VIA_PIPC_586B)
|
||||||
pci_set_mirq_routing(PCI_MIRQ1, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
|
pci_set_mirq_routing(PCI_MIRQ1, (val & 0x0f) ? (val & 0x0f) : PCI_IRQ_DISABLED);
|
||||||
@@ -656,10 +660,37 @@ pipc_write(int func, int addr, uint8_t val, void *priv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x40:
|
case 0x40:
|
||||||
dev->ide_regs[0x40] = val;
|
if (dev->local <= VIA_PIPC_586B) {
|
||||||
|
dev->ide_regs[0x40] = val & 0x03;
|
||||||
|
dev->ide_regs[0x40] |= 0x04;
|
||||||
|
} else
|
||||||
|
dev->ide_regs[0x40] = val & 0x0f;
|
||||||
pipc_ide_handlers(dev);
|
pipc_ide_handlers(dev);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 0x50: case 0x52:
|
||||||
|
if (dev->local <= VIA_PIPC_586B)
|
||||||
|
dev->ide_regs[addr] = val & 0xe3;
|
||||||
|
else if (dev->local <= VIA_PIPC_596B)
|
||||||
|
dev->ide_regs[addr] = val & 0xeb;
|
||||||
|
else if (dev->local <= VIA_PIPC_686A)
|
||||||
|
dev->ide_regs[addr] = val & 0xef;
|
||||||
|
else
|
||||||
|
dev->ide_regs[addr] = val & 0xf7;
|
||||||
|
break;
|
||||||
|
case 0x51: case 0x53:
|
||||||
|
if (dev->local <= VIA_PIPC_596B)
|
||||||
|
dev->ide_regs[addr] = val & 0xe3;
|
||||||
|
else if (dev->local <= VIA_PIPC_686A)
|
||||||
|
dev->ide_regs[addr] = val & 0xe7;
|
||||||
|
else
|
||||||
|
dev->ide_regs[addr] = val & 0xf7;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x61: case 0x69:
|
||||||
|
dev->ide_regs[addr] = val & 0x0f;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dev->ide_regs[addr] = val;
|
dev->ide_regs[addr] = val;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
#ifndef EMU_LPT_H
|
||||||
|
# define EMU_LPT_H
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -58,3 +61,5 @@ extern const lpt_device_t lpt_dac_device;
|
|||||||
extern const lpt_device_t lpt_dac_stereo_device;
|
extern const lpt_device_t lpt_dac_stereo_device;
|
||||||
|
|
||||||
extern const lpt_device_t dss_device;
|
extern const lpt_device_t dss_device;
|
||||||
|
|
||||||
|
#endif /*EMU_LPT_H*/
|
||||||
|
|||||||
24
src/include/86box/net_plip.h
Normal file
24
src/include/86box/net_plip.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||||
|
* running old operating systems and software designed for IBM
|
||||||
|
* PC systems and compatibles from 1981 through fairly recent
|
||||||
|
* system designs based on the PCI bus.
|
||||||
|
*
|
||||||
|
* This file is part of the 86Box distribution.
|
||||||
|
*
|
||||||
|
* Definitions for the PLIP parallel port network device.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Author: RichardG, <richardg867@gmail.com>
|
||||||
|
* Copyright 2020 RichardG.
|
||||||
|
*/
|
||||||
|
#ifndef NET_PLIP_H
|
||||||
|
# define NET_PLIP_H
|
||||||
|
# include <86box/device.h>
|
||||||
|
# include <86box/lpt.h>
|
||||||
|
|
||||||
|
extern const lpt_device_t lpt_plip_device;
|
||||||
|
extern const device_t plip_device;
|
||||||
|
|
||||||
|
#endif /*NET_PLIP_H*/
|
||||||
@@ -101,6 +101,7 @@ extern "C" {
|
|||||||
/* Global variables. */
|
/* Global variables. */
|
||||||
extern int nic_do_log; /* config */
|
extern int nic_do_log; /* config */
|
||||||
extern int network_ndev;
|
extern int network_ndev;
|
||||||
|
extern int network_rx_pause;
|
||||||
extern netdev_t network_devs[32];
|
extern netdev_t network_devs[32];
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <86box/pic.h>
|
#include <86box/pic.h>
|
||||||
#include <86box/sound.h>
|
#include <86box/sound.h>
|
||||||
#include <86box/prt_devs.h>
|
#include <86box/prt_devs.h>
|
||||||
|
#include <86box/net_plip.h>
|
||||||
|
|
||||||
|
|
||||||
lpt_port_t lpt_ports[3];
|
lpt_port_t lpt_ports[3];
|
||||||
@@ -30,6 +31,7 @@ static const struct
|
|||||||
{"Generic Text Printer", "text_prt", &lpt_prt_text_device},
|
{"Generic Text Printer", "text_prt", &lpt_prt_text_device},
|
||||||
{"Generic ESC/P Dot-Matrix", "dot_matrix", &lpt_prt_escp_device},
|
{"Generic ESC/P Dot-Matrix", "dot_matrix", &lpt_prt_escp_device},
|
||||||
{"Generic PostScript Printer", "postscript", &lpt_prt_ps_device},
|
{"Generic PostScript Printer", "postscript", &lpt_prt_ps_device},
|
||||||
|
{"PLIP Network", "plip", &lpt_plip_device},
|
||||||
{"", "", NULL}
|
{"", "", NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,8 +93,8 @@ lpt_devices_close(void)
|
|||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
dev = &lpt_ports[i];
|
dev = &lpt_ports[i];
|
||||||
|
|
||||||
if (dev->dt)
|
if (dev->dt)
|
||||||
dev->dt->close(dev->priv);
|
dev->dt->close(dev->priv);
|
||||||
|
|
||||||
dev->dt = NULL;
|
dev->dt = NULL;
|
||||||
}
|
}
|
||||||
@@ -140,7 +142,7 @@ lpt_read(uint16_t port, void *priv)
|
|||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
if (dev->dt && dev->dt->read_status)
|
if (dev->dt && dev->dt->read_status)
|
||||||
ret = dev->dt->read_status(dev->priv) | 0x0f;
|
ret = dev->dt->read_status(dev->priv) | 0x07;
|
||||||
else
|
else
|
||||||
ret = 0xdf;
|
ret = 0xdf;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -301,7 +301,7 @@ machine_at_apas3_init(const machine_t *model)
|
|||||||
device_add(&via_apro_device);
|
device_add(&via_apro_device);
|
||||||
device_add(&via_vt82c586b_device);
|
device_add(&via_vt82c586b_device);
|
||||||
device_add(&fdc37c669_device);
|
device_add(&fdc37c669_device);
|
||||||
device_add(&keyboard_ps2_pci_device);
|
device_add(&keyboard_ps2_ami_pci_device);
|
||||||
device_add(&sst_flash_39sf020_device);
|
device_add(&sst_flash_39sf020_device);
|
||||||
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
|
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ machine_at_ficva503a_init(const machine_t *model)
|
|||||||
|
|
||||||
pci_init(PCI_CONFIG_TYPE_1);
|
pci_init(PCI_CONFIG_TYPE_1);
|
||||||
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
|
pci_register_slot(0x00, PCI_CARD_NORTHBRIDGE, 0, 0, 0, 0);
|
||||||
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 0, 0, 3, 4);
|
pci_register_slot(0x07, PCI_CARD_SOUTHBRIDGE, 1, 2, 3, 4);
|
||||||
pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4);
|
pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4);
|
||||||
pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1);
|
pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1);
|
||||||
pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2);
|
pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2);
|
||||||
@@ -131,7 +131,7 @@ machine_at_ficva503a_init(const machine_t *model)
|
|||||||
|
|
||||||
device_add(&via_mvp3_device);
|
device_add(&via_mvp3_device);
|
||||||
device_add(&via_vt82c686a_device);
|
device_add(&via_vt82c686a_device);
|
||||||
device_add(&keyboard_ps2_pci_device);
|
device_add(&keyboard_ps2_ami_pci_device);
|
||||||
device_add(&via_vt82c686_sio_device);
|
device_add(&via_vt82c686_sio_device);
|
||||||
device_add(&sst_flash_39sf020_device);
|
device_add(&sst_flash_39sf020_device);
|
||||||
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
|
spd_register(SPD_TYPE_SDRAM, 0x7, 256);
|
||||||
|
|||||||
507
src/network/net_plip.c
Normal file
507
src/network/net_plip.c
Normal file
@@ -0,0 +1,507 @@
|
|||||||
|
/*
|
||||||
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||||
|
* running old operating systems and software designed for IBM
|
||||||
|
* PC systems and compatibles from 1981 through fairly recent
|
||||||
|
* system designs based on the PCI bus.
|
||||||
|
*
|
||||||
|
* This file is part of the 86Box distribution.
|
||||||
|
*
|
||||||
|
* Emulation of a PLIP parallel port network device.
|
||||||
|
*
|
||||||
|
* Tested against the Linux plip.c driver and the DOS plip.com
|
||||||
|
* packet driver. PLIP is not particularly fast, as it's a 4-bit
|
||||||
|
* half-duplex protocol operating over SPP.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Author: RichardG, <richardg867@gmail.com>
|
||||||
|
* Copyright 2020 RichardG.
|
||||||
|
*/
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <memory.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#define HAVE_STDARG_H
|
||||||
|
#include <86box/86box.h>
|
||||||
|
#include <86box/language.h>
|
||||||
|
#include <86box/lpt.h>
|
||||||
|
#include <86box/timer.h>
|
||||||
|
#include <86box/pit.h>
|
||||||
|
#include <86box/device.h>
|
||||||
|
#include <86box/network.h>
|
||||||
|
#include <86box/net_plip.h>
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PLIP_START = 0x00,
|
||||||
|
PLIP_TX_LEN_LSB_LOW = 0x10,
|
||||||
|
PLIP_TX_LEN_LSB_HIGH,
|
||||||
|
PLIP_TX_LEN_MSB_LOW,
|
||||||
|
PLIP_TX_LEN_MSB_HIGH,
|
||||||
|
PLIP_TX_DATA_LOW,
|
||||||
|
PLIP_TX_DATA_HIGH,
|
||||||
|
PLIP_TX_CHECKSUM_LOW,
|
||||||
|
PLIP_TX_CHECKSUM_HIGH,
|
||||||
|
PLIP_RX_LEN_LSB_LOW = 0x20,
|
||||||
|
PLIP_RX_LEN_LSB_HIGH,
|
||||||
|
PLIP_RX_LEN_MSB_LOW,
|
||||||
|
PLIP_RX_LEN_MSB_HIGH,
|
||||||
|
PLIP_RX_DATA_LOW,
|
||||||
|
PLIP_RX_DATA_HIGH,
|
||||||
|
PLIP_RX_CHECKSUM_LOW,
|
||||||
|
PLIP_RX_CHECKSUM_HIGH,
|
||||||
|
PLIP_END = 0x40
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t mac[6];
|
||||||
|
|
||||||
|
void *lpt;
|
||||||
|
pc_timer_t rx_timer;
|
||||||
|
pc_timer_t timeout_timer;
|
||||||
|
uint8_t status, ctrl;
|
||||||
|
|
||||||
|
uint8_t state, ack, tx_checksum, tx_checksum_calc, *tx_pkt;
|
||||||
|
uint16_t tx_len, tx_ptr;
|
||||||
|
|
||||||
|
uint8_t *rx_pkt, rx_checksum, rx_return_state;
|
||||||
|
uint16_t rx_len, rx_ptr;
|
||||||
|
} plip_t;
|
||||||
|
|
||||||
|
|
||||||
|
static void plip_receive_packet(plip_t *dev);
|
||||||
|
|
||||||
|
plip_t *instance;
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef ENABLE_PLIP_LOG
|
||||||
|
int plip_do_log = ENABLE_PLIP_LOG;
|
||||||
|
|
||||||
|
static void
|
||||||
|
plip_log(uint8_t lvl, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
if (plip_do_log >= lvl) {
|
||||||
|
va_start(ap, fmt);
|
||||||
|
pclog_ex(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define plip_log(lvl, fmt, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
timeout_timer(void *priv)
|
||||||
|
{
|
||||||
|
plip_t *dev = (plip_t *) priv;
|
||||||
|
|
||||||
|
plip_log(1, "PLIP: timeout at state %d status %02X\n", dev->state, dev->status);
|
||||||
|
|
||||||
|
/* Throw everything out the window. */
|
||||||
|
dev->state = PLIP_START;
|
||||||
|
dev->status = 0x80;
|
||||||
|
|
||||||
|
if (dev->tx_pkt) {
|
||||||
|
free(dev->tx_pkt);
|
||||||
|
dev->tx_pkt = NULL;
|
||||||
|
}
|
||||||
|
if (dev->rx_pkt) {
|
||||||
|
free(dev->rx_pkt);
|
||||||
|
dev->rx_pkt = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_disable(&dev->timeout_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
plip_write_data(uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
plip_t *dev = (plip_t *) priv;
|
||||||
|
|
||||||
|
plip_log(3, "PLIP: write_data(%02X)\n", val);
|
||||||
|
|
||||||
|
switch (dev->state) {
|
||||||
|
case PLIP_START:
|
||||||
|
if (val == 0x08) { /* D3/ACK wakes us up */
|
||||||
|
plip_log(2, "PLIP: ACK wakeup\n");
|
||||||
|
dev->state = PLIP_TX_LEN_LSB_LOW;
|
||||||
|
dev->status = 0x08;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case PLIP_TX_LEN_LSB_LOW:
|
||||||
|
if (!(val & 0x10))
|
||||||
|
return; /* D4/BUSY not high yet */
|
||||||
|
dev->tx_len = val & 0xf;
|
||||||
|
plip_log(2, "PLIP: tx_len = %04X (1/4)\n", dev->tx_len);
|
||||||
|
dev->state = PLIP_TX_LEN_LSB_HIGH;
|
||||||
|
dev->status &= ~0x88;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_TX_LEN_LSB_HIGH:
|
||||||
|
if (val & 0x10)
|
||||||
|
return; /* D4/BUSY not low yet */
|
||||||
|
dev->tx_len |= (val & 0xf) << 4;
|
||||||
|
plip_log(2, "PLIP: tx_len = %04X (2/4)\n", dev->tx_len);
|
||||||
|
dev->state = PLIP_TX_LEN_MSB_LOW;
|
||||||
|
dev->status |= 0x80;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_TX_LEN_MSB_LOW:
|
||||||
|
if (!(val & 0x10))
|
||||||
|
return; /* D4/BUSY not high yet */
|
||||||
|
dev->tx_len |= (val & 0xf) << 8;
|
||||||
|
plip_log(2, "PLIP: tx_len = %04X (3/4)\n", dev->tx_len);
|
||||||
|
dev->state = PLIP_TX_LEN_MSB_HIGH;
|
||||||
|
dev->status &= ~0x80;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_TX_LEN_MSB_HIGH:
|
||||||
|
if (val & 0x10)
|
||||||
|
return; /* D4/BUSY not low yet */
|
||||||
|
dev->tx_len |= (val & 0xf) << 12;
|
||||||
|
plip_log(2, "PLIP: tx_len = %04X (4/4)\n", dev->tx_len);
|
||||||
|
|
||||||
|
/* We have the length, allocate a packet. */
|
||||||
|
if (!(dev->tx_pkt = malloc(dev->tx_len))) /* unlikely */
|
||||||
|
fatal("PLIP: unable to allocate tx_pkt\n");
|
||||||
|
dev->tx_ptr = 0;
|
||||||
|
dev->tx_checksum_calc = 0;
|
||||||
|
|
||||||
|
dev->state = PLIP_TX_DATA_LOW;
|
||||||
|
dev->status |= 0x80;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_TX_DATA_LOW:
|
||||||
|
if (!(val & 0x10))
|
||||||
|
return; /* D4/BUSY not high yet */
|
||||||
|
dev->tx_pkt[dev->tx_ptr] = val & 0x0f;
|
||||||
|
plip_log(2, "PLIP: tx_pkt[%d] = %02X (1/2)\n", dev->tx_ptr, dev->tx_pkt[dev->tx_ptr]);
|
||||||
|
dev->state = PLIP_TX_DATA_HIGH;
|
||||||
|
dev->status &= ~0x80;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_TX_DATA_HIGH:
|
||||||
|
if (val & 0x10)
|
||||||
|
return; /* D4/BUSY not low yet */
|
||||||
|
dev->tx_pkt[dev->tx_ptr] |= (val & 0x0f) << 4;
|
||||||
|
plip_log(2, "PLIP: tx_pkt[%d] = %02X (2/2)\n", dev->tx_ptr, dev->tx_pkt[dev->tx_ptr]);
|
||||||
|
dev->tx_checksum_calc += dev->tx_pkt[dev->tx_ptr++];
|
||||||
|
|
||||||
|
/* Are we done yet? */
|
||||||
|
if (dev->tx_ptr < dev->tx_len) /* no, receive another byte */
|
||||||
|
dev->state = PLIP_TX_DATA_LOW;
|
||||||
|
else /* yes, move on to checksum */
|
||||||
|
dev->state = PLIP_TX_CHECKSUM_LOW;
|
||||||
|
dev->status |= 0x80;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_TX_CHECKSUM_LOW:
|
||||||
|
if (!(val & 0x10))
|
||||||
|
return; /* D4/BUSY not high yet */
|
||||||
|
dev->tx_checksum = val & 0x0f;
|
||||||
|
plip_log(2, "PLIP: tx_checksum = %02X (1/2)\n", dev->tx_checksum);
|
||||||
|
dev->state = PLIP_TX_CHECKSUM_HIGH;
|
||||||
|
dev->status &= ~0x80;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_TX_CHECKSUM_HIGH:
|
||||||
|
if (val & 0x10)
|
||||||
|
return; /* D4/BUSY not low yet */
|
||||||
|
dev->tx_checksum |= (val & 0x0f) << 4;
|
||||||
|
plip_log(2, "PLIP: tx_checksum = %02X (2/2)\n", dev->tx_checksum);
|
||||||
|
|
||||||
|
/* Verify checksum. */
|
||||||
|
if (dev->tx_checksum_calc == dev->tx_checksum) {
|
||||||
|
/* Make sure we know the other end's MAC address. */
|
||||||
|
memcpy(dev->mac, dev->tx_pkt + 6, 6);
|
||||||
|
|
||||||
|
/* Transmit packet. */
|
||||||
|
plip_log(2, "PLIP: transmitting %d-byte packet\n", dev->tx_len);
|
||||||
|
network_tx(dev->tx_pkt, dev->tx_len);
|
||||||
|
} else {
|
||||||
|
plip_log(1, "PLIP: checksum error: expected %02X, got %02X\n", dev->tx_checksum_calc, dev->tx_checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We're done with this packet. */
|
||||||
|
free(dev->tx_pkt);
|
||||||
|
dev->tx_pkt = NULL;
|
||||||
|
dev->tx_len = 0;
|
||||||
|
|
||||||
|
dev->state = PLIP_END;
|
||||||
|
dev->status |= 0x80;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_RX_LEN_LSB_LOW:
|
||||||
|
if (!(val & 0x01))
|
||||||
|
return; /* D3/ACK not high yet */
|
||||||
|
plip_log(2, "PLIP: rx_len = %04X (1/4)\n", dev->rx_len);
|
||||||
|
dev->status = (dev->rx_len & 0x0f) << 3;
|
||||||
|
dev->state = PLIP_RX_LEN_LSB_HIGH;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_RX_LEN_LSB_HIGH:
|
||||||
|
if (!(val & 0x10))
|
||||||
|
return; /* D4/BUSY not high yet */
|
||||||
|
plip_log(2, "PLIP: rx_len = %04X (2/4)\n", dev->rx_len);
|
||||||
|
dev->status = ((dev->rx_len >> 4) & 0x0f) << 3;
|
||||||
|
dev->status |= 0x80;
|
||||||
|
dev->state = PLIP_RX_LEN_MSB_LOW;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_RX_LEN_MSB_LOW:
|
||||||
|
if (val & 0x10)
|
||||||
|
return; /* D4/BUSY not low yet */
|
||||||
|
plip_log(2, "PLIP: rx_len = %04X (3/4)\n", dev->rx_len);
|
||||||
|
dev->status = ((dev->rx_len >> 8) & 0x0f) << 3;
|
||||||
|
dev->state = PLIP_RX_LEN_MSB_HIGH;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_RX_LEN_MSB_HIGH:
|
||||||
|
if (!(val & 0x10))
|
||||||
|
return; /* D4/BUSY not high yet */
|
||||||
|
plip_log(2, "PLIP: rx_len = %04X (4/4)\n", dev->rx_len);
|
||||||
|
dev->status = ((dev->rx_len >> 12) & 0x0f) << 3;
|
||||||
|
dev->status |= 0x80;
|
||||||
|
|
||||||
|
dev->rx_ptr = 0;
|
||||||
|
dev->rx_checksum = 0;
|
||||||
|
dev->state = PLIP_RX_DATA_LOW;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_RX_DATA_LOW:
|
||||||
|
if (val & 0x10)
|
||||||
|
return; /* D4/BUSY not low yet */
|
||||||
|
plip_log(2, "PLIP: rx_pkt[%d] = %02X (1/2)\n", dev->rx_ptr, dev->rx_pkt[dev->rx_ptr]);
|
||||||
|
dev->status = (dev->rx_pkt[dev->rx_ptr] & 0x0f) << 3;
|
||||||
|
dev->state = PLIP_RX_DATA_HIGH;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_RX_DATA_HIGH:
|
||||||
|
if (!(val & 0x10))
|
||||||
|
return; /* D4/BUSY not high yet */
|
||||||
|
plip_log(2, "PLIP: rx_pkt[%d] = %02X (2/2)\n", dev->rx_ptr, dev->rx_pkt[dev->rx_ptr]);
|
||||||
|
dev->status = ((dev->rx_pkt[dev->rx_ptr] >> 4) & 0x0f) << 3;
|
||||||
|
dev->status |= 0x80;
|
||||||
|
dev->rx_checksum += dev->rx_pkt[dev->rx_ptr++];
|
||||||
|
|
||||||
|
/* Are we done yet? */
|
||||||
|
if (dev->rx_ptr < dev->rx_len) /* no, send another byte */
|
||||||
|
dev->state = PLIP_RX_DATA_LOW;
|
||||||
|
else /* yes, move on to checksum */
|
||||||
|
dev->state = PLIP_RX_CHECKSUM_LOW;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_RX_CHECKSUM_LOW:
|
||||||
|
if (val & 0x10)
|
||||||
|
return; /* D4/BUSY not low yet */
|
||||||
|
plip_log(2, "PLIP: rx_checksum = %02X (1/2)\n", dev->rx_checksum);
|
||||||
|
dev->status = (dev->rx_checksum & 0x0f) << 3;
|
||||||
|
dev->state = PLIP_RX_CHECKSUM_HIGH;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_RX_CHECKSUM_HIGH:
|
||||||
|
if (!(val & 0x10))
|
||||||
|
return; /* D4/BUSY not high yet */
|
||||||
|
plip_log(2, "PLIP: rx_checksum = %02X (2/2)\n", dev->rx_checksum);
|
||||||
|
dev->status = ((dev->rx_checksum >> 4) & 0x0f) << 3;
|
||||||
|
dev->status |= 0x80;
|
||||||
|
|
||||||
|
/* We're done with this packet. */
|
||||||
|
free(dev->rx_pkt);
|
||||||
|
dev->rx_pkt = NULL;
|
||||||
|
dev->rx_len = 0;
|
||||||
|
|
||||||
|
dev->state = PLIP_END;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PLIP_END:
|
||||||
|
if (val == 0x00) { /* written after TX or RX is done */
|
||||||
|
plip_log(2, "PLIP: end\n");
|
||||||
|
dev->status = 0x80;
|
||||||
|
dev->state = PLIP_START;
|
||||||
|
|
||||||
|
timer_set_delay_u64(&dev->rx_timer, ISACONST); /* for DOS */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disengage timeout timer. */
|
||||||
|
timer_disable(&dev->timeout_timer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Engage timeout timer unless otherwise specified. */
|
||||||
|
timer_set_delay_u64(&dev->timeout_timer, 1000000 * TIMER_USEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
plip_write_ctrl(uint8_t val, void *priv)
|
||||||
|
{
|
||||||
|
plip_t *dev = (plip_t *) priv;
|
||||||
|
|
||||||
|
plip_log(3, "PLIP: write_ctrl(%02X)\n", val);
|
||||||
|
|
||||||
|
dev->ctrl = val;
|
||||||
|
|
||||||
|
if (val & 0x10) /* for Linux */
|
||||||
|
timer_set_delay_u64(&dev->rx_timer, ISACONST);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
|
plip_read_status(void *priv)
|
||||||
|
{
|
||||||
|
plip_t *dev = (plip_t *) priv;
|
||||||
|
|
||||||
|
plip_log(3, "PLIP: read_status() = %02X\n", dev->status);
|
||||||
|
|
||||||
|
return dev->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
plip_receive_packet(plip_t *dev)
|
||||||
|
{
|
||||||
|
/* At least the Linux driver supports being interrupted
|
||||||
|
in the PLIP_TX_LEN_LSB_LOW state, but let's be safe. */
|
||||||
|
if (dev->state > PLIP_START) {
|
||||||
|
plip_log(3, "PLIP: cannot receive, operation already in progress\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dev->rx_pkt || !dev->rx_len) { /* unpause RX queue if there's no packet to receive */
|
||||||
|
network_rx_pause = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(dev->ctrl & 0x10)) { /* checking this is essential to avoid collisions */
|
||||||
|
plip_log(3, "PLIP: cannot receive, interrupts are off\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plip_log(2, "PLIP: receiving %d-byte packet\n", dev->rx_len);
|
||||||
|
|
||||||
|
/* Set up to receive a packet. */
|
||||||
|
dev->status = 0xc7; /* DOS expects exactly 0xc7, while Linux masks the 7 off */
|
||||||
|
dev->state = PLIP_RX_LEN_LSB_LOW;
|
||||||
|
|
||||||
|
/* Engage timeout timer. */
|
||||||
|
timer_set_delay_u64(&dev->timeout_timer, 1000000 * TIMER_USEC);
|
||||||
|
|
||||||
|
/* Wake the other end up. */
|
||||||
|
lpt_irq(dev->lpt, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This timer defers a call to plip_receive_packet to
|
||||||
|
the next ISA clock, in order to avoid IRQ weirdness. */
|
||||||
|
static void
|
||||||
|
rx_timer(void *priv)
|
||||||
|
{
|
||||||
|
plip_t *dev = (plip_t *) priv;
|
||||||
|
|
||||||
|
plip_receive_packet(dev);
|
||||||
|
|
||||||
|
timer_disable(&dev->rx_timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
plip_rx(void *priv, uint8_t *buf, int io_len)
|
||||||
|
{
|
||||||
|
plip_t *dev = (plip_t *) priv;
|
||||||
|
|
||||||
|
plip_log(2, "PLIP: incoming %d-byte packet\n", io_len);
|
||||||
|
|
||||||
|
if (dev->rx_pkt) { /* shouldn't really happen with the RX queue paused */
|
||||||
|
plip_log(3, "PLIP: already have a packet to receive");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(dev->rx_pkt = malloc(io_len))) /* unlikely */
|
||||||
|
fatal("PLIP: unable to allocate rx_pkt\n");
|
||||||
|
|
||||||
|
network_rx_pause = 1; /* make sure we don't get any more packets while processing this one */
|
||||||
|
|
||||||
|
/* Copy this packet to our buffer. */
|
||||||
|
dev->rx_len = io_len;
|
||||||
|
memcpy(dev->rx_pkt, buf, dev->rx_len);
|
||||||
|
|
||||||
|
/* Dispatch this packet immediately if we're doing nothing. */
|
||||||
|
plip_receive_packet(dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void *
|
||||||
|
plip_lpt_init(void *lpt)
|
||||||
|
{
|
||||||
|
plip_t *dev = (plip_t *) malloc(sizeof(plip_t));
|
||||||
|
memset(dev, 0, sizeof(plip_t));
|
||||||
|
|
||||||
|
plip_log(1, "PLIP: lpt_init()\n");
|
||||||
|
|
||||||
|
dev->lpt = lpt;
|
||||||
|
memset(dev->mac, 0xfc, 6); /* static MAC used by Linux; just a placeholder */
|
||||||
|
|
||||||
|
dev->status = 0x80;
|
||||||
|
|
||||||
|
timer_add(&dev->rx_timer, rx_timer, dev, 0);
|
||||||
|
timer_add(&dev->timeout_timer, timeout_timer, dev, 0);
|
||||||
|
|
||||||
|
instance = dev;
|
||||||
|
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void *
|
||||||
|
plip_net_init(const device_t *info)
|
||||||
|
{
|
||||||
|
plip_log(1, "PLIP: net_init()");
|
||||||
|
|
||||||
|
if (!instance) {
|
||||||
|
plip_log(1, " (not attached to LPT)\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
plip_log(1, " (attached to LPT)\n");
|
||||||
|
network_attach(instance, instance->mac, plip_rx, NULL, NULL);
|
||||||
|
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
plip_close(void *priv)
|
||||||
|
{
|
||||||
|
free(priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const lpt_device_t lpt_plip_device = {
|
||||||
|
.name = "Parallel Line Internet Protocol (LPT)",
|
||||||
|
.init = plip_lpt_init,
|
||||||
|
.close = plip_close,
|
||||||
|
.write_data = plip_write_data,
|
||||||
|
.write_ctrl = plip_write_ctrl,
|
||||||
|
.read_data = NULL,
|
||||||
|
.read_status = plip_read_status,
|
||||||
|
.read_ctrl = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
const device_t plip_device =
|
||||||
|
{
|
||||||
|
"Parallel Line Internet Protocol (Network)",
|
||||||
|
0, 0,
|
||||||
|
plip_net_init, NULL,
|
||||||
|
NULL, NULL, NULL, NULL
|
||||||
|
};
|
||||||
@@ -36,8 +36,8 @@
|
|||||||
#include <86box/config.h>
|
#include <86box/config.h>
|
||||||
|
|
||||||
|
|
||||||
/* SLiRP can use poll() or select() for socket polling. While poll() is
|
/* SLiRP can use poll() or select() for socket polling.
|
||||||
better, it's slow and limited on Windows, so use select() there. */
|
poll() is best on *nix but slow and limited on Windows. */
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
# define SLIRP_USE_POLL 1
|
# define SLIRP_USE_POLL 1
|
||||||
#endif
|
#endif
|
||||||
@@ -93,7 +93,7 @@ slirp_log(const char *fmt, ...)
|
|||||||
static void
|
static void
|
||||||
net_slirp_guest_error(const char *msg, void *opaque)
|
net_slirp_guest_error(const char *msg, void *opaque)
|
||||||
{
|
{
|
||||||
slirp_log("SLiRP: guest_error: %s\n", msg);
|
slirp_log("SLiRP: guest_error(): %s\n", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -252,7 +252,7 @@ net_slirp_get_revents(int idx, void *opaque)
|
|||||||
static void
|
static void
|
||||||
slirp_tic(slirp_t *slirp)
|
slirp_tic(slirp_t *slirp)
|
||||||
{
|
{
|
||||||
int ret2;
|
int ret;
|
||||||
uint32_t tmo;
|
uint32_t tmo;
|
||||||
|
|
||||||
/* Let SLiRP create a list of all open sockets. */
|
/* Let SLiRP create a list of all open sockets. */
|
||||||
@@ -269,7 +269,7 @@ slirp_tic(slirp_t *slirp)
|
|||||||
|
|
||||||
/* Now wait for something to happen, or at most 'tmo' usec. */
|
/* Now wait for something to happen, or at most 'tmo' usec. */
|
||||||
#ifdef SLIRP_USE_POLL
|
#ifdef SLIRP_USE_POLL
|
||||||
ret2 = poll(slirp->pfd, slirp->pfd_len, tmo);
|
ret = poll(slirp->pfd, slirp->pfd_len, tmo);
|
||||||
#else
|
#else
|
||||||
if (tmo < 0)
|
if (tmo < 0)
|
||||||
tmo = 500;
|
tmo = 500;
|
||||||
@@ -278,11 +278,11 @@ slirp_tic(slirp_t *slirp)
|
|||||||
tv.tv_sec = 0;
|
tv.tv_sec = 0;
|
||||||
tv.tv_usec = tmo;
|
tv.tv_usec = tmo;
|
||||||
|
|
||||||
ret2 = select(slirp->nfds + 1, &slirp->rfds, &slirp->wfds, &slirp->xfds, &tv);
|
ret = select(slirp->nfds + 1, &slirp->rfds, &slirp->wfds, &slirp->xfds, &tv);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If something happened, let SLiRP handle it. */
|
/* If something happened, let SLiRP handle it. */
|
||||||
slirp_pollfds_poll(slirp->slirp, (ret2 <= 0), net_slirp_get_revents, slirp);
|
slirp_pollfds_poll(slirp->slirp, (ret <= 0), net_slirp_get_revents, slirp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -316,7 +316,7 @@ poll_thread(void *arg)
|
|||||||
struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
|
struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
|
||||||
struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
|
struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
|
||||||
struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */
|
struct in_addr bind = { .s_addr = htonl(0x00000000) }; /* 0.0.0.0 */
|
||||||
struct in6_addr ipv6dummy; /* contents don't matter; we're not doing IPv6 */
|
struct in6_addr ipv6dummy; /* contents don't matter; we're not using IPv6 */
|
||||||
|
|
||||||
/* Initialize SLiRP. */
|
/* Initialize SLiRP. */
|
||||||
slirp->slirp = slirp_init(0, 1, net, mask, host, 0, ipv6dummy, 0, ipv6dummy, NULL, NULL, NULL, NULL, dhcp, dns, ipv6dummy, NULL, NULL, &slirp_cb, arg);
|
slirp->slirp = slirp_init(0, 1, net, mask, host, 0, ipv6dummy, 0, ipv6dummy, NULL, NULL, NULL, NULL, dhcp, dns, ipv6dummy, NULL, NULL, &slirp_cb, arg);
|
||||||
@@ -326,23 +326,27 @@ poll_thread(void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Set up port forwarding. */
|
/* Set up port forwarding. */
|
||||||
int udp, from, to, i = 0;
|
int udp, external, internal, i = 0;
|
||||||
char *category = "SLiRP Port Forwarding";
|
char *category = "SLiRP Port Forwarding";
|
||||||
char key[16];
|
char key[20];
|
||||||
while (1) {
|
while (1) {
|
||||||
sprintf(key, "%d_udp", i);
|
sprintf(key, "%d_protocol", i);
|
||||||
udp = config_get_int(category, key, 0);
|
udp = strncmp(config_get_string(category, key, "tcp"), "udp", -1) == 0;
|
||||||
sprintf(key, "%d_from", i);
|
sprintf(key, "%d_external", i);
|
||||||
from = config_get_int(category, key, 0);
|
external = config_get_int(category, key, 0);
|
||||||
if (from < 1)
|
sprintf(key, "%d_internal", i);
|
||||||
|
internal = config_get_int(category, key, 0);
|
||||||
|
if ((external <= 0) && (internal <= 0))
|
||||||
break;
|
break;
|
||||||
sprintf(key, "%d_to", i);
|
else if (internal <= 0)
|
||||||
to = config_get_int(category, key, from);
|
internal = external;
|
||||||
|
else if (external <= 0)
|
||||||
|
external = internal;
|
||||||
|
|
||||||
if (slirp_add_hostfwd(slirp->slirp, udp, bind, from, dhcp, to) == 0)
|
if (slirp_add_hostfwd(slirp->slirp, udp, bind, external, dhcp, internal) == 0)
|
||||||
pclog("SLiRP: Forwarded %s port host:%d to guest:%d\n", udp ? "UDP" : "TCP", from, to);
|
pclog("SLiRP: Forwarded %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal);
|
||||||
else
|
else
|
||||||
pclog("SLiRP: Failed to forward %s port host:%d to guest:%d\n", udp ? "UDP" : "TCP", from, to);
|
pclog("SLiRP: Failed to forward %s port external:%d to internal:%d\n", udp ? "UDP" : "TCP", external, internal);
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#define HAVE_STDARG_H
|
#define HAVE_STDARG_H
|
||||||
#include <86box/86box.h>
|
#include <86box/86box.h>
|
||||||
#include <86box/device.h>
|
#include <86box/device.h>
|
||||||
@@ -64,6 +65,7 @@
|
|||||||
#include <86box/net_3c503.h>
|
#include <86box/net_3c503.h>
|
||||||
#include <86box/net_ne2000.h>
|
#include <86box/net_ne2000.h>
|
||||||
#include <86box/net_pcnet.h>
|
#include <86box/net_pcnet.h>
|
||||||
|
#include <86box/net_plip.h>
|
||||||
#include <86box/net_wd8003.h>
|
#include <86box/net_wd8003.h>
|
||||||
|
|
||||||
|
|
||||||
@@ -88,6 +90,8 @@ static netcard_t net_cards[] = {
|
|||||||
NULL },
|
NULL },
|
||||||
{ "[ISA] Western Digital WD8013EBT","wd8013ebt", &wd8013ebt_device,
|
{ "[ISA] Western Digital WD8013EBT","wd8013ebt", &wd8013ebt_device,
|
||||||
NULL },
|
NULL },
|
||||||
|
{ "[LPT] PLIP", "plip", &plip_device,
|
||||||
|
NULL },
|
||||||
{ "[MCA] NetWorth Ethernet/MC", "ethernextmc", ðernext_mc_device,
|
{ "[MCA] NetWorth Ethernet/MC", "ethernextmc", ðernext_mc_device,
|
||||||
NULL },
|
NULL },
|
||||||
{ "[MCA] Western Digital WD8003ET/A","wd8003eta", &wd8003eta_device,
|
{ "[MCA] Western Digital WD8003ET/A","wd8003eta", &wd8003eta_device,
|
||||||
@@ -113,6 +117,7 @@ int network_ndev;
|
|||||||
int network_card;
|
int network_card;
|
||||||
char network_host[522];
|
char network_host[522];
|
||||||
netdev_t network_devs[32];
|
netdev_t network_devs[32];
|
||||||
|
int network_rx_pause = 0;
|
||||||
#ifdef ENABLE_NIC_LOG
|
#ifdef ENABLE_NIC_LOG
|
||||||
int nic_do_log = ENABLE_NIC_LOG;
|
int nic_do_log = ENABLE_NIC_LOG;
|
||||||
#endif
|
#endif
|
||||||
@@ -140,6 +145,7 @@ static struct {
|
|||||||
|
|
||||||
#ifdef ENABLE_NETWORK_LOG
|
#ifdef ENABLE_NETWORK_LOG
|
||||||
int network_do_log = ENABLE_NETWORK_LOG;
|
int network_do_log = ENABLE_NETWORK_LOG;
|
||||||
|
FILE *network_dump = NULL;
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -153,8 +159,29 @@ network_log(const char *fmt, ...)
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
network_dump_packet(netpkt_t *pkt)
|
||||||
|
{
|
||||||
|
if (!network_dump)
|
||||||
|
return;
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, NULL);
|
||||||
|
struct {
|
||||||
|
uint32_t ts_sec, ts_usec, incl_len, orig_len;
|
||||||
|
} pcap_packet_hdr = {
|
||||||
|
tv.tv_sec, tv.tv_usec, pkt->len, pkt->len
|
||||||
|
};
|
||||||
|
|
||||||
|
fwrite(&pcap_packet_hdr, sizeof(pcap_packet_hdr), 1, network_dump);
|
||||||
|
fwrite(pkt->data, pkt->len, 1, network_dump);
|
||||||
|
fflush(network_dump);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
#define network_log(fmt, ...)
|
#define network_log(fmt, ...)
|
||||||
|
#define network_dump_packet(pkt)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -220,6 +247,25 @@ network_init(void)
|
|||||||
i = net_pcap_prepare(&network_devs[network_ndev]);
|
i = net_pcap_prepare(&network_devs[network_ndev]);
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
network_ndev += i;
|
network_ndev += i;
|
||||||
|
|
||||||
|
#ifdef ENABLE_NETWORK_LOG
|
||||||
|
/* Start packet dump. */
|
||||||
|
network_dump = fopen("network.pcap", "wb");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint32_t magic_number;
|
||||||
|
uint16_t version_major, version_minor;
|
||||||
|
int32_t thiszone;
|
||||||
|
uint32_t sigfigs, snaplen, network;
|
||||||
|
} pcap_hdr = {
|
||||||
|
0xa1b2c3d4,
|
||||||
|
2, 4,
|
||||||
|
0,
|
||||||
|
0, 65535, 1
|
||||||
|
};
|
||||||
|
fwrite(&pcap_hdr, sizeof(pcap_hdr), 1, network_dump);
|
||||||
|
fflush(network_dump);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -294,12 +340,18 @@ network_queue_clear(int tx)
|
|||||||
static void
|
static void
|
||||||
network_rx_queue(void *priv)
|
network_rx_queue(void *priv)
|
||||||
{
|
{
|
||||||
|
if (network_rx_pause) {
|
||||||
|
timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0 * 128.0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
netpkt_t *pkt = NULL;
|
netpkt_t *pkt = NULL;
|
||||||
|
|
||||||
network_busy(1);
|
network_busy(1);
|
||||||
|
|
||||||
network_queue_get(0, &pkt);
|
network_queue_get(0, &pkt);
|
||||||
if ((pkt != NULL) && (pkt->len > 0)) {
|
if ((pkt != NULL) && (pkt->len > 0)) {
|
||||||
|
network_dump_packet(pkt);
|
||||||
net_cards[network_card].rx(pkt->priv, pkt->data, pkt->len);
|
net_cards[network_card].rx(pkt->priv, pkt->data, pkt->len);
|
||||||
if (pkt->len >= 128)
|
if (pkt->len >= 128)
|
||||||
timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0 * ((double) pkt->len));
|
timer_on_auto(&network_rx_queue_timer, 0.762939453125 * 2.0 * ((double) pkt->len));
|
||||||
@@ -404,6 +456,7 @@ network_close(void)
|
|||||||
/* Here is where we clear the queues. */
|
/* Here is where we clear the queues. */
|
||||||
network_queue_clear(0);
|
network_queue_clear(0);
|
||||||
network_queue_clear(1);
|
network_queue_clear(1);
|
||||||
|
network_rx_pause = 0;
|
||||||
|
|
||||||
network_log("NETWORK: closed.\n");
|
network_log("NETWORK: closed.\n");
|
||||||
}
|
}
|
||||||
@@ -501,6 +554,7 @@ network_do_tx(void)
|
|||||||
|
|
||||||
network_queue_get(1, &pkt);
|
network_queue_get(1, &pkt);
|
||||||
if ((pkt != NULL) && (pkt->len > 0)) {
|
if ((pkt != NULL) && (pkt->len > 0)) {
|
||||||
|
network_dump_packet(pkt);
|
||||||
switch(network_type) {
|
switch(network_type) {
|
||||||
case NET_TYPE_PCAP:
|
case NET_TYPE_PCAP:
|
||||||
net_pcap_in(pkt->data, pkt->len);
|
net_pcap_in(pkt->data, pkt->len);
|
||||||
|
|||||||
@@ -744,7 +744,8 @@ NETOBJ := network.o \
|
|||||||
tcp_output.o tcp_subr.o tcp_timer.o udp.o util.o version.o \
|
tcp_output.o tcp_subr.o tcp_timer.o udp.o util.o version.o \
|
||||||
net_dp8390.o \
|
net_dp8390.o \
|
||||||
net_3c503.o net_ne2000.o \
|
net_3c503.o net_ne2000.o \
|
||||||
net_pcnet.o net_wd8003.o
|
net_pcnet.o net_wd8003.o \
|
||||||
|
net_plip.o
|
||||||
|
|
||||||
PRINTOBJ := png.o prt_cpmap.o \
|
PRINTOBJ := png.o prt_cpmap.o \
|
||||||
prt_escp.o prt_text.o prt_ps.o
|
prt_escp.o prt_text.o prt_ps.o
|
||||||
|
|||||||
Reference in New Issue
Block a user