12
src/config.c
12
src/config.c
@@ -1214,6 +1214,11 @@ load_network(void)
|
||||
} else {
|
||||
strcpy(net_cards_conf[c].host_dev_name, "none");
|
||||
}
|
||||
|
||||
sprintf(temp, "net_%02i_link", c +1);
|
||||
net_cards_conf[c].link_state = config_get_int(cat, temp,
|
||||
(NET_LINK_10_HD|NET_LINK_10_FD|NET_LINK_100_HD|NET_LINK_100_FD|NET_LINK_1000_HD|NET_LINK_1000_FD));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2767,6 +2772,13 @@ save_network(void)
|
||||
/* config_set_string(cat, temp, "none"); */
|
||||
config_delete_var(cat, temp);
|
||||
}
|
||||
|
||||
sprintf(temp, "net_%02i_link", c + 1);
|
||||
if (net_cards_conf[c].link_state == (NET_LINK_10_HD|NET_LINK_10_FD|NET_LINK_100_HD|NET_LINK_100_FD|NET_LINK_1000_HD|NET_LINK_1000_FD)) {
|
||||
config_delete_var(cat, temp);
|
||||
} else {
|
||||
config_set_int(cat, temp, net_cards_conf[c].link_state);
|
||||
}
|
||||
}
|
||||
|
||||
delete_section_if_empty(cat);
|
||||
|
||||
@@ -21,7 +21,7 @@ typedef struct {
|
||||
dev_status_empty_active_t mo[MO_NUM];
|
||||
dev_status_empty_active_t cassette;
|
||||
dev_status_active_t hdd[HDD_BUS_USB];
|
||||
dev_status_active_t net;
|
||||
dev_status_empty_active_t net[NET_CARD_MAX];
|
||||
dev_status_empty_t cartridge[2];
|
||||
} machine_status_t;
|
||||
|
||||
|
||||
@@ -56,10 +56,26 @@
|
||||
#define NET_TYPE_PCAP 2 /* use the (Win)Pcap API */
|
||||
|
||||
#define NET_MAX_FRAME 1518
|
||||
#define NET_QUEUE_LEN 8
|
||||
/* Queue size must be a power of 2 */
|
||||
#define NET_QUEUE_LEN 16
|
||||
#define NET_QUEUE_LEN_MASK (NET_QUEUE_LEN - 1)
|
||||
#define NET_CARD_MAX 4
|
||||
#define NET_HOST_INTF_MAX 64
|
||||
|
||||
#define NET_PERIOD_10M 0.8
|
||||
#define NET_PERIOD_100M 0.08
|
||||
|
||||
enum {
|
||||
NET_LINK_DOWN = (1 << 1),
|
||||
NET_LINK_TEMP_DOWN = (1 << 2),
|
||||
NET_LINK_10_HD = (1 << 3),
|
||||
NET_LINK_10_FD = (1 << 4),
|
||||
NET_LINK_100_HD = (1 << 5),
|
||||
NET_LINK_100_FD = (1 << 6),
|
||||
NET_LINK_1000_HD = (1 << 7),
|
||||
NET_LINK_1000_FD = (1 << 8),
|
||||
};
|
||||
|
||||
/* Supported network cards. */
|
||||
enum {
|
||||
NONE = 0,
|
||||
@@ -79,25 +95,23 @@ typedef struct {
|
||||
int device_num;
|
||||
int net_type;
|
||||
char host_dev_name[128];
|
||||
uint32_t link_state;
|
||||
} netcard_conf_t;
|
||||
|
||||
extern netcard_conf_t net_cards_conf[NET_CARD_MAX];
|
||||
extern int net_card_current;
|
||||
|
||||
typedef int (*NETRXCB)(void *, uint8_t *, int);
|
||||
typedef int (*NETWAITCB)(void *);
|
||||
typedef int (*NETSETLINKSTATE)(void *);
|
||||
typedef int (*NETSETLINKSTATE)(void *, uint32_t link_state);
|
||||
|
||||
|
||||
typedef struct netpkt {
|
||||
uint8_t *data;
|
||||
int len;
|
||||
uint64_t tsc;
|
||||
} netpkt_t;
|
||||
|
||||
typedef struct {
|
||||
netpkt_t packets[NET_QUEUE_LEN];
|
||||
int size;
|
||||
int head;
|
||||
int tail;
|
||||
} netqueue_t;
|
||||
@@ -118,9 +132,7 @@ struct _netcard_t {
|
||||
const device_t *device;
|
||||
void *card_drv;
|
||||
struct netdrv_t host_drv;
|
||||
int (*poll)(void *);
|
||||
NETRXCB rx;
|
||||
NETWAITCB wait;
|
||||
NETSETLINKSTATE set_link_state;
|
||||
netqueue_t queues[3];
|
||||
netpkt_t queued_pkt;
|
||||
@@ -128,6 +140,10 @@ struct _netcard_t {
|
||||
mutex_t *rx_mutex;
|
||||
pc_timer_t timer;
|
||||
int card_num;
|
||||
double byte_period;
|
||||
uint32_t led_timer;
|
||||
uint32_t led_state;
|
||||
uint32_t link_state;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -148,7 +164,7 @@ extern netdev_t network_devs[NET_HOST_INTF_MAX];
|
||||
|
||||
/* Function prototypes. */
|
||||
extern void network_init(void);
|
||||
extern netcard_t *network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETLINKSTATE set_link_state);
|
||||
extern netcard_t *network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_link_state);
|
||||
extern void netcard_close(netcard_t *card);
|
||||
extern void network_close(void);
|
||||
extern void network_reset(void);
|
||||
@@ -157,6 +173,9 @@ extern void network_tx(netcard_t *card, uint8_t *, int);
|
||||
|
||||
extern int net_pcap_prepare(netdev_t *);
|
||||
|
||||
extern void network_connect(int id, int connect);
|
||||
extern int network_is_connected(int id);
|
||||
extern int network_dev_available(int);
|
||||
extern int network_dev_to_id(char *);
|
||||
extern int network_card_available(int);
|
||||
extern int network_card_has_config(int);
|
||||
@@ -165,7 +184,9 @@ extern int network_card_get_from_internal_name(char *);
|
||||
extern const device_t *network_card_getdevice(int);
|
||||
|
||||
extern int network_tx_pop(netcard_t *card, netpkt_t *out_pkt);
|
||||
extern int network_tx_popv(netcard_t *card, netpkt_t *pkt_vec, int vec_size);
|
||||
extern int network_rx_put(netcard_t *card, uint8_t *bufp, int len);
|
||||
extern int network_rx_put_pkt(netcard_t *card, netpkt_t *pkt);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <86box/zip.h>
|
||||
#include <86box/mo.h>
|
||||
#include <86box/hdd.h>
|
||||
#include <86box/thread.h>
|
||||
#include <86box/network.h>
|
||||
#include <86box/machine_status.h>
|
||||
|
||||
machine_status_t machine_status;
|
||||
@@ -48,5 +50,8 @@ machine_status_init() {
|
||||
machine_status.hdd[i].active = false;
|
||||
}
|
||||
|
||||
machine_status.net.active = false;
|
||||
for (size_t i = 0; i < NET_CARD_MAX; i++) {
|
||||
machine_status.net[i].active = false;
|
||||
machine_status.net[i].empty = !network_is_connected(i);
|
||||
}
|
||||
}
|
||||
@@ -619,7 +619,7 @@ threec503_nic_init(const device_t *info)
|
||||
dev->regs.gacfr = 0x09; /* Start with RAM mapping enabled. */
|
||||
|
||||
/* Attach ourselves to the network module. */
|
||||
dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL);
|
||||
dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL);
|
||||
|
||||
return(dev);
|
||||
}
|
||||
|
||||
@@ -228,7 +228,9 @@ dp8390_write_cr(dp8390_t *dev, uint32_t val)
|
||||
/* Send the packet to the system driver */
|
||||
dev->CR.tx_packet = 1;
|
||||
|
||||
network_tx(dev->card, &dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes);
|
||||
/* TODO: report TX error to the driver ? */
|
||||
if (!(dev->card->link_state & NET_LINK_DOWN))
|
||||
network_tx(dev->card, &dev->mem[(dev->tx_page_start * 256) - dev->mem_start], dev->tx_bytes);
|
||||
|
||||
/* some more debug */
|
||||
#ifdef ENABLE_DP8390_LOG
|
||||
@@ -291,6 +293,8 @@ dp8390_rx_common(void *priv, uint8_t *buf, int io_len)
|
||||
if ((dev->CR.stop != 0) || (dev->page_start == 0))
|
||||
return 0;
|
||||
|
||||
if (dev->card->link_state & NET_LINK_DOWN)
|
||||
return 0;
|
||||
/*
|
||||
* Add the pkt header + CRC to the length, and work
|
||||
* out how many 256-byte pages the frame would occupy.
|
||||
|
||||
@@ -1122,7 +1122,7 @@ nic_init(const device_t *info)
|
||||
nic_reset(dev);
|
||||
|
||||
/* Attach ourselves to the network module. */
|
||||
dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL);
|
||||
dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL);
|
||||
|
||||
nelog(1, "%s: %s attached IO=0x%X IRQ=%d\n", dev->name,
|
||||
dev->is_pci?"PCI":"ISA", dev->base_address, dev->base_irq);
|
||||
|
||||
@@ -72,6 +72,8 @@
|
||||
#include <86box/network.h>
|
||||
#include <86box/net_event.h>
|
||||
|
||||
#define PCAP_PKT_BATCH NET_QUEUE_LEN
|
||||
|
||||
enum {
|
||||
NET_EVENT_STOP = 0,
|
||||
NET_EVENT_TX,
|
||||
@@ -120,6 +122,17 @@ struct pcap_if {
|
||||
void *addresses;
|
||||
bpf_u_int32 flags;
|
||||
};
|
||||
|
||||
struct pcap_send_queue {
|
||||
u_int maxlen; /* Maximum size of the queue, in bytes. This
|
||||
variable contains the size of the buffer field. */
|
||||
u_int len; /* Current size of the queue, in bytes. */
|
||||
char *buffer; /* Buffer containing the packets to be sent. */
|
||||
};
|
||||
|
||||
typedef struct pcap_send_queue pcap_send_queue;
|
||||
|
||||
typedef void (*pcap_handler)(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes);
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
@@ -129,7 +142,11 @@ typedef struct {
|
||||
net_evt_t tx_event;
|
||||
net_evt_t stop_event;
|
||||
netpkt_t pkt;
|
||||
netpkt_t pktv[PCAP_PKT_BATCH];
|
||||
uint8_t mac_addr[6];
|
||||
#ifdef _WIN32
|
||||
struct pcap_send_queue *pcap_queue;
|
||||
#endif
|
||||
} net_pcap_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -154,11 +171,16 @@ static int (*f_pcap_setnonblock)(void*, int, char*);
|
||||
static int (*f_pcap_set_immediate_mode)(void *, int);
|
||||
static int (*f_pcap_set_promisc)(void *, int);
|
||||
static int (*f_pcap_set_snaplen)(void *, int);
|
||||
static int (*f_pcap_dispatch)(void *, int, pcap_handler callback, u_char *user);
|
||||
static void *(*f_pcap_create)(const char *, char*);
|
||||
static int (*f_pcap_activate)(void *);
|
||||
static void *(*f_pcap_geterr)(void *);
|
||||
#ifdef _WIN32
|
||||
static HANDLE (*f_pcap_getevent)(void *);
|
||||
static int (*f_pcap_sendqueue_queue)(void *, void *, void *);
|
||||
static u_int (*f_pcap_sendqueue_transmit)(void *, void *, int sync);
|
||||
static void *(*f_pcap_sendqueue_alloc)(u_int memsize);
|
||||
static void (*f_pcap_sendqueue_destroy)(void *);
|
||||
#else
|
||||
static int (*f_pcap_get_selectable_fd)(void *);
|
||||
#endif
|
||||
@@ -177,13 +199,18 @@ static dllimp_t pcap_imports[] = {
|
||||
{ "pcap_set_immediate_mode", &f_pcap_set_immediate_mode},
|
||||
{ "pcap_set_promisc", &f_pcap_set_promisc },
|
||||
{ "pcap_set_snaplen", &f_pcap_set_snaplen },
|
||||
{ "pcap_dispatch", &f_pcap_dispatch },
|
||||
{ "pcap_create", &f_pcap_create },
|
||||
{ "pcap_activate", &f_pcap_activate },
|
||||
{ "pcap_geterr", &f_pcap_geterr },
|
||||
#ifdef _WIN32
|
||||
{ "pcap_getevent", &f_pcap_getevent },
|
||||
{ "pcap_sendqueue_queue", &f_pcap_sendqueue_queue },
|
||||
{ "pcap_sendqueue_transmit", &f_pcap_sendqueue_transmit},
|
||||
{ "pcap_sendqueue_alloc", &f_pcap_sendqueue_alloc },
|
||||
{ "pcap_sendqueue_destroy", &f_pcap_sendqueue_destroy },
|
||||
#else
|
||||
{ "pcap_get_selectable_fd", &f_pcap_get_selectable_fd },
|
||||
{ "pcap_get_selectable_fd", &f_pcap_get_selectable_fd },
|
||||
#endif
|
||||
{ NULL, NULL },
|
||||
};
|
||||
@@ -208,15 +235,12 @@ pcap_log(const char *fmt, ...)
|
||||
|
||||
|
||||
static void
|
||||
net_pcap_read_packet(net_pcap_t *pcap)
|
||||
net_pcap_rx_handler(uint8_t *user, const struct pcap_pkthdr *h, const uint8_t *bytes)
|
||||
{
|
||||
struct pcap_pkthdr h;
|
||||
|
||||
uint8_t *data = (uint8_t *) f_pcap_next((void *) pcap->pcap, &h);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
network_rx_put(pcap->card, data, h.caplen);
|
||||
net_pcap_t *pcap = (net_pcap_t*)user;
|
||||
memcpy(pcap->pkt.data, bytes, h->caplen);
|
||||
pcap->pkt.len = h->caplen;
|
||||
network_rx_put_pkt(pcap->card, &pcap->pkt);
|
||||
}
|
||||
|
||||
/* Send a packet to the Pcap interface. */
|
||||
@@ -251,6 +275,7 @@ net_pcap_thread(void *priv)
|
||||
|
||||
bool run = true;
|
||||
|
||||
struct pcap_pkthdr h;
|
||||
while (run) {
|
||||
int ret = WaitForMultipleObjects(NET_EVENT_MAX, events, FALSE, INFINITE);
|
||||
|
||||
@@ -262,13 +287,17 @@ net_pcap_thread(void *priv)
|
||||
|
||||
case NET_EVENT_TX:
|
||||
net_event_clear(&pcap->tx_event);
|
||||
while (network_tx_pop(pcap->card, &pcap->pkt)) {
|
||||
net_pcap_in(pcap->pcap, pcap->pkt.data, pcap->pkt.len);
|
||||
int packets = network_tx_popv(pcap->card, pcap->pktv, PCAP_PKT_BATCH);
|
||||
for (int i = 0; i < packets; i++) {
|
||||
h.caplen = pcap->pktv[i].len;
|
||||
f_pcap_sendqueue_queue(pcap->pcap_queue, &h, pcap->pktv[i].data);
|
||||
}
|
||||
f_pcap_sendqueue_transmit(pcap->pcap, pcap->pcap_queue, 0);
|
||||
pcap->pcap_queue->len = 0;
|
||||
break;
|
||||
|
||||
case NET_EVENT_RX:
|
||||
net_pcap_read_packet(pcap);
|
||||
f_pcap_dispatch(pcap->pcap, PCAP_PKT_BATCH, net_pcap_rx_handler, (u_char *)pcap);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -305,13 +334,14 @@ net_pcap_thread(void *priv)
|
||||
if (pfd[NET_EVENT_TX].revents & POLLIN) {
|
||||
net_event_clear(&pcap->tx_event);
|
||||
|
||||
if (network_tx_pop(pcap->card, &pcap->pkt)) {
|
||||
net_pcap_in(pcap->pcap, pcap->pkt.data, pcap->pkt.len);
|
||||
int packets = network_tx_popv(pcap->card, pcap->pktv, PCAP_PKT_BATCH);
|
||||
for (int i = 0; i < packets; i++) {
|
||||
net_pcap_in(pcap->pcap, pcap->pktv[i].data, pcap->pktv[i].len);
|
||||
}
|
||||
}
|
||||
|
||||
if (pfd[NET_EVENT_RX].revents & POLLIN) {
|
||||
net_pcap_read_packet(pcap);
|
||||
f_pcap_dispatch(pcap->pcap, PCAP_PKT_BATCH, net_pcap_rx_handler, (u_char *)pcap);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -470,7 +500,15 @@ net_pcap_init(const netcard_t *card, const uint8_t *mac_addr, void *priv)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
pcap->pcap_queue = f_pcap_sendqueue_alloc(PCAP_PKT_BATCH * NET_MAX_FRAME);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < PCAP_PKT_BATCH; i++) {
|
||||
pcap->pktv[i].data = calloc(1, NET_MAX_FRAME);
|
||||
}
|
||||
pcap->pkt.data = calloc(1, NET_MAX_FRAME);
|
||||
|
||||
net_event_init(&pcap->tx_event);
|
||||
net_event_init(&pcap->stop_event);
|
||||
pcap->poll_tid = thread_create(net_pcap_thread, pcap);
|
||||
@@ -497,8 +535,14 @@ net_pcap_close(void *priv)
|
||||
thread_wait(pcap->poll_tid);
|
||||
pcap_log("PCAP: thread ended\n");
|
||||
|
||||
for (int i = 0; i < PCAP_PKT_BATCH; i++) {
|
||||
free(pcap->pktv[i].data);
|
||||
}
|
||||
free(pcap->pkt.data);
|
||||
|
||||
#ifdef _WIN32
|
||||
f_pcap_sendqueue_destroy((void*)pcap->pcap_queue);
|
||||
#endif
|
||||
/* OK, now shut down Pcap itself. */
|
||||
f_pcap_close((void*)pcap->pcap);
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <wchar.h>
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include <86box/86box.h>
|
||||
#include <86box/io.h>
|
||||
@@ -1253,6 +1254,10 @@ pcnetReceiveNoSync(void *priv, uint8_t *buf, int size)
|
||||
if (!pcnetIsLinkUp(dev))
|
||||
return 0;
|
||||
|
||||
dev->fMaybeOutOfSpace = !pcnetCanReceive(dev);
|
||||
if (dev->fMaybeOutOfSpace)
|
||||
return 0;
|
||||
|
||||
pcnetlog(1, "%s: pcnetReceiveNoSync: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", dev->name,
|
||||
buf[6], buf[7], buf[8], buf[9], buf[10], buf[11],
|
||||
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5],
|
||||
@@ -2025,11 +2030,15 @@ pcnet_bcr_writew(nic_t *dev, uint16_t rap, uint16_t val)
|
||||
case BCR_BSBC:
|
||||
case BCR_EECAS:
|
||||
case BCR_PLAT:
|
||||
case BCR_MIICAS:
|
||||
case BCR_MIIADDR:
|
||||
dev->aBCR[rap] = val;
|
||||
break;
|
||||
|
||||
case BCR_MIICAS:
|
||||
dev->netcard->byte_period = (dev->board == DEV_AM79C973 && (val & 0x28)) ? NET_PERIOD_100M : NET_PERIOD_10M;
|
||||
dev->aBCR[rap] = val;
|
||||
break;
|
||||
|
||||
case BCR_STVAL:
|
||||
val &= 0xffff;
|
||||
dev->aBCR[BCR_STVAL] = val;
|
||||
@@ -2091,12 +2100,13 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr)
|
||||
| 0x0008 /* Able to do auto-negotiation. */
|
||||
| 0x0004 /* Link up. */
|
||||
| 0x0001; /* Extended Capability, i.e. registers 4+ valid. */
|
||||
if (!dev->fLinkUp || dev->fLinkTempDown || isolate) {
|
||||
if (!pcnetIsLinkUp(dev) || isolate) {
|
||||
val &= ~(0x0020 | 0x0004);
|
||||
dev->cLinkDownReported++;
|
||||
}
|
||||
if (!autoneg) {
|
||||
/* Auto-negotiation disabled. */
|
||||
val &= ~(0x0020 | 0x0008);
|
||||
if (duplex)
|
||||
val &= ~0x2800; /* Full duplex forced. */
|
||||
else
|
||||
@@ -2127,7 +2137,7 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr)
|
||||
|
||||
case 5:
|
||||
/* Link partner ability register. */
|
||||
if (dev->fLinkUp && !dev->fLinkTempDown && !isolate) {
|
||||
if (pcnetIsLinkUp(dev) && !isolate) {
|
||||
val = 0x8000 /* Next page bit. */
|
||||
| 0x4000 /* Link partner acked us. */
|
||||
| 0x0400 /* Can do flow control. */
|
||||
@@ -2141,7 +2151,7 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr)
|
||||
|
||||
case 6:
|
||||
/* Auto negotiation expansion register. */
|
||||
if (dev->fLinkUp && !dev->fLinkTempDown && !isolate) {
|
||||
if (pcnetIsLinkUp(dev) && !isolate) {
|
||||
val = 0x0008 /* Link partner supports npage. */
|
||||
| 0x0004 /* Enable npage words. */
|
||||
| 0x0001; /* Can do N-way auto-negotiation. */
|
||||
@@ -2153,7 +2163,7 @@ pcnet_mii_readw(nic_t *dev, uint16_t miiaddr)
|
||||
|
||||
case 18:
|
||||
/* Diagnostic Register (FreeBSD pcn/ac101 driver reads this). */
|
||||
if (dev->fLinkUp && !dev->fLinkTempDown && !isolate) {
|
||||
if (pcnetIsLinkUp(dev) && !isolate) {
|
||||
val = 0x1000 /* Receive PLL locked. */
|
||||
| 0x0200; /* Signal detected. */
|
||||
|
||||
@@ -2191,7 +2201,7 @@ pcnet_bcr_readw(nic_t *dev, uint16_t rap)
|
||||
case BCR_LED2:
|
||||
case BCR_LED3:
|
||||
val = dev->aBCR[rap] & ~0x8000;
|
||||
if (dev->fLinkTempDown || !dev->fLinkUp) {
|
||||
if (!(pcnetIsLinkUp(dev))) {
|
||||
if (rap == 4)
|
||||
dev->cLinkDownReported++;
|
||||
val &= ~0x40;
|
||||
@@ -2842,40 +2852,28 @@ pcnetCanReceive(nic_t *dev)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
pcnetWaitReceiveAvail(void *priv)
|
||||
pcnetSetLinkState(void *priv, uint32_t link_state)
|
||||
{
|
||||
nic_t *dev = (nic_t *) priv;
|
||||
|
||||
dev->fMaybeOutOfSpace = !pcnetCanReceive(dev);
|
||||
|
||||
return dev->fMaybeOutOfSpace;
|
||||
}
|
||||
|
||||
static int
|
||||
pcnetSetLinkState(void *priv)
|
||||
{
|
||||
nic_t *dev = (nic_t *) priv;
|
||||
int fLinkUp;
|
||||
|
||||
if (dev->fLinkTempDown) {
|
||||
pcnetTempLinkDown(dev);
|
||||
return 1;
|
||||
if (link_state & NET_LINK_TEMP_DOWN) {
|
||||
pcnetTempLinkDown(dev);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fLinkUp = (dev->fLinkUp && !dev->fLinkTempDown);
|
||||
if (dev->fLinkUp != fLinkUp) {
|
||||
dev->fLinkUp = fLinkUp;
|
||||
if (fLinkUp) {
|
||||
dev->fLinkTempDown = 1;
|
||||
dev->cLinkDownReported = 0;
|
||||
dev->aCSR[0] |= 0x8000 | 0x2000; /* ERR | CERR (this is probably wrong) */
|
||||
timer_set_delay_u64(&dev->timer_restore, (dev->cMsLinkUpDelay * 1000) * TIMER_USEC);
|
||||
} else {
|
||||
dev->cLinkDownReported = 0;
|
||||
dev->aCSR[0] |= 0x8000 | 0x2000; /* ERR | CERR (this is probably wrong) */
|
||||
}
|
||||
bool link_up = !(link_state & NET_LINK_DOWN);
|
||||
if (dev->fLinkUp != link_up) {
|
||||
dev->fLinkUp = link_up;
|
||||
if (link_up) {
|
||||
dev->fLinkTempDown = 1;
|
||||
dev->cLinkDownReported = 0;
|
||||
dev->aCSR[0] |= 0x8000 | 0x2000;
|
||||
timer_set_delay_u64(&dev->timer_restore, (dev->cMsLinkUpDelay * 1000) * TIMER_USEC);
|
||||
} else {
|
||||
dev->cLinkDownReported = 0;
|
||||
dev->aCSR[0] |= 0x8000 | 0x2000;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -3054,7 +3052,8 @@ pcnet_init(const device_t *info)
|
||||
pcnetHardReset(dev);
|
||||
|
||||
/* Attach ourselves to the network module. */
|
||||
dev->netcard = network_attach(dev, dev->aPROM, pcnetReceiveNoSync, pcnetWaitReceiveAvail, pcnetSetLinkState);
|
||||
dev->netcard = network_attach(dev, dev->aPROM, pcnetReceiveNoSync, pcnetSetLinkState);
|
||||
dev->netcard->byte_period = (dev->board == DEV_AM79C973) ? NET_PERIOD_100M : NET_PERIOD_10M;
|
||||
|
||||
timer_add(&dev->timer, pcnetPollTimer, dev, 0);
|
||||
|
||||
|
||||
@@ -476,7 +476,7 @@ plip_net_init(const device_t *info)
|
||||
}
|
||||
|
||||
plip_log(1, " (attached to LPT)\n");
|
||||
instance->card = network_attach(instance, instance->mac, plip_rx, NULL, NULL);
|
||||
instance->card = network_attach(instance, instance->mac, plip_rx, NULL);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
#endif
|
||||
#include <86box/net_event.h>
|
||||
|
||||
#define SLIRP_PKT_BATCH NET_QUEUE_LEN
|
||||
|
||||
enum {
|
||||
NET_EVENT_STOP = 0,
|
||||
NET_EVENT_TX,
|
||||
@@ -60,6 +62,7 @@ typedef struct {
|
||||
net_evt_t tx_event;
|
||||
net_evt_t stop_event;
|
||||
netpkt_t pkt;
|
||||
netpkt_t pkt_tx_v[SLIRP_PKT_BATCH];
|
||||
#ifdef _WIN32
|
||||
HANDLE sock_event;
|
||||
#else
|
||||
@@ -153,22 +156,12 @@ ssize_t
|
||||
net_slirp_send_packet(const void *qp, size_t pkt_len, void *opaque)
|
||||
{
|
||||
net_slirp_t *slirp = (net_slirp_t *) opaque;
|
||||
uint8_t *mac = slirp->mac_addr;
|
||||
uint32_t mac_cmp32[2];
|
||||
uint16_t mac_cmp16[2];
|
||||
|
||||
slirp_log("SLiRP: received %d-byte packet\n", pkt_len);
|
||||
|
||||
/* Received MAC. */
|
||||
mac_cmp32[0] = *(uint32_t *) (((uint8_t *) qp) + 6);
|
||||
mac_cmp16[0] = *(uint16_t *) (((uint8_t *) qp) + 10);
|
||||
|
||||
/* Local MAC. */
|
||||
mac_cmp32[1] = *(uint32_t *) mac;
|
||||
mac_cmp16[1] = *(uint16_t *) (mac + 4);
|
||||
if ((mac_cmp32[0] != mac_cmp32[1]) || (mac_cmp16[0] != mac_cmp16[1])) {
|
||||
network_rx_put(slirp->card, (uint8_t *) qp, pkt_len);
|
||||
}
|
||||
memcpy(slirp->pkt.data, (uint8_t*) qp, pkt_len);
|
||||
slirp->pkt.len = pkt_len;
|
||||
network_rx_put_pkt(slirp->card, &slirp->pkt);
|
||||
|
||||
return pkt_len;
|
||||
}
|
||||
@@ -336,8 +329,9 @@ net_slirp_thread(void *priv)
|
||||
break;
|
||||
|
||||
case NET_EVENT_TX:
|
||||
while (network_tx_pop(slirp->card, &slirp->pkt)) {
|
||||
net_slirp_in(slirp, slirp->pkt.data, slirp->pkt.len);
|
||||
int packets = network_tx_popv(slirp->card, slirp->pkt_tx_v, SLIRP_PKT_BATCH);
|
||||
for (int i = 0; i < packets; i++) {
|
||||
net_slirp_in(slirp, slirp->pkt_tx_v[i].data, slirp->pkt_tx_v[i].len);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -381,11 +375,11 @@ net_slirp_thread(void *priv)
|
||||
if (slirp->pfd[NET_EVENT_TX].revents & POLLIN) {
|
||||
net_event_clear(&slirp->tx_event);
|
||||
|
||||
if (network_tx_pop(slirp->card, &slirp->pkt)) {
|
||||
net_slirp_in(slirp, slirp->pkt.data, slirp->pkt.len);
|
||||
int packets = network_tx_popv(slirp->card, slirp->pkt_tx_v, SLIRP_PKT_BATCH);
|
||||
for (int i = 0; i < packets; i++) {
|
||||
net_slirp_in(slirp, slirp->pkt_tx_v[i].data, slirp->pkt_tx_v[i].len);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
slirp_log("SLiRP: polling stopped.\n");
|
||||
@@ -453,6 +447,9 @@ net_slirp_init(const netcard_t *card, const uint8_t *mac_addr, void *priv)
|
||||
i++;
|
||||
}
|
||||
|
||||
for (int i = 0; i < SLIRP_PKT_BATCH; i++) {
|
||||
slirp->pkt_tx_v[i].data = calloc(1, NET_MAX_FRAME);
|
||||
}
|
||||
slirp->pkt.data = calloc(1, NET_MAX_FRAME);
|
||||
net_event_init(&slirp->tx_event);
|
||||
net_event_init(&slirp->stop_event);
|
||||
@@ -485,6 +482,9 @@ net_slirp_close(void *priv)
|
||||
net_event_close(&slirp->tx_event);
|
||||
net_event_close(&slirp->stop_event);
|
||||
slirp_cleanup(slirp->slirp);
|
||||
for (int i = 0; i < SLIRP_PKT_BATCH; i++) {
|
||||
free(slirp->pkt_tx_v[i].data);
|
||||
}
|
||||
free(slirp->pkt.data);
|
||||
free(slirp);
|
||||
slirp_card_num--;
|
||||
|
||||
@@ -788,7 +788,7 @@ wd_init(const device_t *info)
|
||||
mem_mapping_disable(&dev->ram_mapping);
|
||||
|
||||
/* Attach ourselves to the network module. */
|
||||
dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL, NULL);
|
||||
dev->dp8390->card = network_attach(dev->dp8390, dev->dp8390->physaddr, dp8390_rx, NULL);
|
||||
|
||||
if (!(dev->board_chip & WE_ID_BUS_MCA)) {
|
||||
wdlog("%s: attached IO=0x%X IRQ=%d, RAM addr=0x%06x\n", dev->name,
|
||||
|
||||
@@ -240,12 +240,11 @@ network_init(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
network_queue_init(netqueue_t *queue)
|
||||
{
|
||||
queue->size = NET_QUEUE_LEN;
|
||||
queue->head = queue->tail = 0;
|
||||
for (int i=0; i<queue->size; i++) {
|
||||
for (int i=0; i<NET_QUEUE_LEN; i++) {
|
||||
queue->packets[i].data = calloc(1, NET_MAX_FRAME);
|
||||
queue->packets[i].len = 0;
|
||||
}
|
||||
@@ -255,7 +254,7 @@ network_queue_init(netqueue_t *queue)
|
||||
static bool
|
||||
network_queue_full(netqueue_t *queue)
|
||||
{
|
||||
return ((queue->head + 1) % queue->size) == queue->tail;
|
||||
return ((queue->head + 1) & NET_QUEUE_LEN_MASK) == queue->tail;
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -264,30 +263,50 @@ network_queue_empty(netqueue_t *queue)
|
||||
return (queue->head == queue->tail);
|
||||
}
|
||||
|
||||
static inline void
|
||||
network_swap_packet(netpkt_t *pkt1, netpkt_t *pkt2)
|
||||
{
|
||||
netpkt_t tmp = *pkt2;
|
||||
*pkt2 = *pkt1;
|
||||
*pkt1 = tmp;
|
||||
}
|
||||
|
||||
int
|
||||
network_queue_put(netqueue_t *queue, uint8_t *data, int len)
|
||||
{
|
||||
if (len > NET_MAX_FRAME || network_queue_full(queue)) {
|
||||
if (len == 0 || len > NET_MAX_FRAME || network_queue_full(queue)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
netpkt_t *pkt = &queue->packets[queue->head];
|
||||
memcpy(pkt->data, data, len);
|
||||
pkt->len = len;
|
||||
queue->head = (queue->head + 1) % queue->size;
|
||||
queue->head = (queue->head + 1) & NET_QUEUE_LEN_MASK;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
network_queue_put_swap(netqueue_t *queue, netpkt_t *src_pkt)
|
||||
{
|
||||
if (src_pkt->len == 0 || src_pkt->len > NET_MAX_FRAME || network_queue_full(queue)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
netpkt_t *dst_pkt = &queue->packets[queue->head];
|
||||
network_swap_packet(src_pkt, dst_pkt);
|
||||
|
||||
queue->head = (queue->head + 1) & NET_QUEUE_LEN_MASK;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
network_queue_get(netqueue_t *queue, netpkt_t *dst_pkt) {
|
||||
network_queue_get_swap(netqueue_t *queue, netpkt_t *dst_pkt) {
|
||||
if (network_queue_empty(queue))
|
||||
return 0;
|
||||
|
||||
netpkt_t *pkt = &queue->packets[queue->tail];
|
||||
memcpy(dst_pkt->data, pkt->data, pkt->len);
|
||||
dst_pkt->len = pkt->len;
|
||||
queue->tail = (queue->tail + 1) % queue->size;
|
||||
|
||||
netpkt_t *src_pkt = &queue->packets[queue->tail];
|
||||
network_swap_packet(src_pkt, dst_pkt);
|
||||
queue->tail = (queue->tail + 1) & NET_QUEUE_LEN_MASK;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -303,23 +322,18 @@ network_queue_move(netqueue_t *dst_q, netqueue_t *src_q)
|
||||
|
||||
netpkt_t *src_pkt = &src_q->packets[src_q->tail];
|
||||
netpkt_t *dst_pkt = &dst_q->packets[dst_q->head];
|
||||
uint8_t *tmp_dat = dst_pkt->data;
|
||||
|
||||
dst_pkt->data = src_pkt->data;
|
||||
dst_pkt->len = src_pkt->len;
|
||||
dst_q->head = (dst_q->head + 1) % dst_q->size;
|
||||
network_swap_packet(src_pkt, dst_pkt);
|
||||
dst_q->head = (dst_q->head + 1) & NET_QUEUE_LEN_MASK;
|
||||
src_q->tail = (src_q->tail + 1) & NET_QUEUE_LEN_MASK;
|
||||
|
||||
src_pkt->data = tmp_dat;
|
||||
src_pkt->len = 0;
|
||||
src_q->tail = (src_q->tail + 1) % src_q->size;
|
||||
|
||||
return 1;
|
||||
return dst_pkt->len;
|
||||
}
|
||||
|
||||
static void
|
||||
void
|
||||
network_queue_clear(netqueue_t *queue)
|
||||
{
|
||||
for (int i=0; i<queue->size; i++) {
|
||||
for (int i=0; i<NET_QUEUE_LEN; i++) {
|
||||
free(queue->packets[i].data);
|
||||
queue->packets[i].len = 0;
|
||||
}
|
||||
@@ -331,42 +345,61 @@ static void
|
||||
network_rx_queue(void *priv)
|
||||
{
|
||||
netcard_t *card = (netcard_t *)priv;
|
||||
double timer_period;
|
||||
int ret = 0;
|
||||
|
||||
bool activity = false;
|
||||
|
||||
if (card->queued_pkt.len == 0) {
|
||||
thread_wait_mutex(card->rx_mutex);
|
||||
network_queue_get(&card->queues[NET_QUEUE_RX], &card->queued_pkt);
|
||||
thread_release_mutex(card->rx_mutex);
|
||||
uint32_t new_link_state = net_cards_conf[card->card_num].link_state;
|
||||
if (new_link_state != card->link_state) {
|
||||
if (card->set_link_state)
|
||||
card->set_link_state(card->card_drv, new_link_state);
|
||||
card->link_state = new_link_state;
|
||||
}
|
||||
|
||||
if (card->queued_pkt.len > 0) {
|
||||
uint32_t rx_bytes = 0;
|
||||
for (int i = 0; i < NET_QUEUE_LEN; i++) {
|
||||
if (card->queued_pkt.len == 0) {
|
||||
thread_wait_mutex(card->rx_mutex);
|
||||
int res = network_queue_get_swap(&card->queues[NET_QUEUE_RX], &card->queued_pkt);
|
||||
thread_release_mutex(card->rx_mutex);
|
||||
if (!res)
|
||||
break;
|
||||
}
|
||||
|
||||
network_dump_packet(&card->queued_pkt);
|
||||
ret = card->rx(card->card_drv, card->queued_pkt.data, card->queued_pkt.len);
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
activity = true;
|
||||
timer_period = 0.762939453125 * ((card->queued_pkt.len >= 128) ? ((double) card->queued_pkt.len) : 128.0);
|
||||
int res = card->rx(card->card_drv, card->queued_pkt.data, card->queued_pkt.len);
|
||||
if (!res)
|
||||
break;
|
||||
rx_bytes += card->queued_pkt.len;
|
||||
card->queued_pkt.len = 0;
|
||||
} else {
|
||||
timer_period = 0.762939453125 * 128.0;
|
||||
}
|
||||
timer_on_auto(&card->timer, timer_period);
|
||||
|
||||
/* Transmission. */
|
||||
uint32_t tx_bytes = 0;
|
||||
thread_wait_mutex(card->tx_mutex);
|
||||
ret = network_queue_move(&card->queues[NET_QUEUE_TX_HOST], &card->queues[NET_QUEUE_TX_VM]);
|
||||
for (int i = 0; i < NET_QUEUE_LEN; i++) {
|
||||
uint32_t bytes = network_queue_move(&card->queues[NET_QUEUE_TX_HOST], &card->queues[NET_QUEUE_TX_VM]);
|
||||
if (!bytes)
|
||||
break;
|
||||
tx_bytes += bytes;
|
||||
}
|
||||
thread_release_mutex(card->tx_mutex);
|
||||
if (ret) {
|
||||
if (tx_bytes) {
|
||||
/* Notify host that a packet is available in the TX queue */
|
||||
card->host_drv.notify_in(card->host_drv.priv);
|
||||
activity = true;
|
||||
}
|
||||
|
||||
ui_sb_update_icon(SB_NETWORK, activity);
|
||||
double timer_period = card->byte_period * (rx_bytes > tx_bytes ? rx_bytes : tx_bytes);
|
||||
if (timer_period < 200)
|
||||
timer_period = 200;
|
||||
|
||||
timer_on_auto(&card->timer, timer_period);
|
||||
|
||||
bool activity = rx_bytes || tx_bytes;
|
||||
bool led_on = card->led_timer & 0x80000000;
|
||||
if ((activity && !led_on) || (card->led_timer & 0x7fffffff) >= 150000) {
|
||||
ui_sb_update_icon(SB_NETWORK | card->card_num, activity);
|
||||
card->led_timer = 0 | (activity << 31);
|
||||
}
|
||||
|
||||
card->led_timer += timer_period;
|
||||
}
|
||||
|
||||
|
||||
@@ -378,17 +411,17 @@ network_rx_queue(void *priv)
|
||||
* modules.
|
||||
*/
|
||||
netcard_t *
|
||||
network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETLINKSTATE set_link_state)
|
||||
network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_link_state)
|
||||
{
|
||||
netcard_t *card = calloc(1, sizeof(netcard_t));
|
||||
card->queued_pkt.data = calloc(1, NET_MAX_FRAME);
|
||||
card->card_drv = card_drv;
|
||||
card->rx = rx;
|
||||
card->wait = wait;
|
||||
card->set_link_state = set_link_state;
|
||||
card->tx_mutex = thread_create_mutex();
|
||||
card->rx_mutex = thread_create_mutex();
|
||||
card->card_num = net_card_current;
|
||||
card->byte_period = NET_PERIOD_10M;
|
||||
|
||||
for (int i=0; i<3; i++) {
|
||||
network_queue_init(&card->queues[i]);
|
||||
@@ -420,7 +453,7 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETL
|
||||
}
|
||||
|
||||
timer_add(&card->timer, network_rx_queue, card, 0);
|
||||
timer_on_auto(&card->timer, 0.762939453125 * 2.0);
|
||||
timer_on_auto(&card->timer, 100);
|
||||
|
||||
return card;
|
||||
}
|
||||
@@ -475,8 +508,7 @@ network_reset(void)
|
||||
#endif
|
||||
|
||||
for (i = 0; i < NET_CARD_MAX; i++) {
|
||||
if (!net_cards_conf[i].device_num || net_cards_conf[i].net_type == NET_TYPE_NONE ||
|
||||
(net_cards_conf[i].net_type == NET_TYPE_PCAP && !strcmp(net_cards_conf[i].host_dev_name, "none"))) {
|
||||
if (!network_dev_available(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -498,12 +530,29 @@ int network_tx_pop(netcard_t *card, netpkt_t *out_pkt)
|
||||
int ret = 0;
|
||||
|
||||
thread_wait_mutex(card->tx_mutex);
|
||||
ret = network_queue_get(&card->queues[NET_QUEUE_TX_HOST], out_pkt);
|
||||
ret = network_queue_get_swap(&card->queues[NET_QUEUE_TX_HOST], out_pkt);
|
||||
thread_release_mutex(card->tx_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int network_tx_popv(netcard_t *card, netpkt_t *pkt_vec, int vec_size)
|
||||
{
|
||||
int pkt_count = 0;
|
||||
|
||||
netqueue_t *queue = &card->queues[NET_QUEUE_TX_HOST];
|
||||
thread_wait_mutex(card->tx_mutex);
|
||||
for (int i = 0; i < vec_size; i++) {
|
||||
if (!network_queue_get_swap(queue, pkt_vec))
|
||||
break;
|
||||
pkt_count++;
|
||||
pkt_vec++;
|
||||
}
|
||||
thread_release_mutex(card->tx_mutex);
|
||||
|
||||
return pkt_count;
|
||||
}
|
||||
|
||||
int network_rx_put(netcard_t *card, uint8_t *bufp, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -515,6 +564,39 @@ int network_rx_put(netcard_t *card, uint8_t *bufp, int len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int network_rx_put_pkt(netcard_t *card, netpkt_t *pkt)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
thread_wait_mutex(card->rx_mutex);
|
||||
ret = network_queue_put_swap(&card->queues[NET_QUEUE_RX], pkt);
|
||||
thread_release_mutex(card->rx_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
network_connect(int id, int connect)
|
||||
{
|
||||
if (id >= NET_CARD_MAX)
|
||||
return;
|
||||
|
||||
if (connect) {
|
||||
net_cards_conf[id].link_state &= ~NET_LINK_DOWN;
|
||||
} else {
|
||||
net_cards_conf[id].link_state |= NET_LINK_DOWN;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
network_is_connected(int id)
|
||||
{
|
||||
if (id >= NET_CARD_MAX)
|
||||
return 0;
|
||||
|
||||
return !(net_cards_conf[id].link_state & NET_LINK_DOWN);
|
||||
}
|
||||
|
||||
int
|
||||
network_dev_to_id(char *devname)
|
||||
{
|
||||
@@ -526,19 +608,29 @@ network_dev_to_id(char *devname)
|
||||
}
|
||||
}
|
||||
|
||||
/* If no match found, assume "none". */
|
||||
return(0);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
/* UI */
|
||||
int
|
||||
network_dev_available(int id)
|
||||
{
|
||||
int available = (net_cards_conf[id].device_num > 0) && (net_cards_conf[id].net_type != NET_TYPE_NONE);
|
||||
|
||||
if ((net_cards_conf[id].net_type == NET_TYPE_PCAP && (network_dev_to_id(net_cards_conf[id].host_dev_name) <= 0)))
|
||||
available = 0;
|
||||
|
||||
return available;
|
||||
}
|
||||
|
||||
int
|
||||
network_available(void)
|
||||
{
|
||||
int available = 0;
|
||||
|
||||
for (int i = 0; i < NET_CARD_MAX; i ++) {
|
||||
available |= (net_cards_conf[i].device_num > 0) && (net_cards_conf[i].net_type != NET_TYPE_NONE);
|
||||
available |= network_dev_available(i);
|
||||
}
|
||||
|
||||
return available;
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace {
|
||||
PixmapSetEmptyActive zip;
|
||||
PixmapSetEmptyActive mo;
|
||||
PixmapSetActive hd;
|
||||
PixmapSetActive net;
|
||||
PixmapSetEmptyActive net;
|
||||
QPixmap sound;
|
||||
};
|
||||
|
||||
@@ -220,7 +220,9 @@ struct MachineStatus::States {
|
||||
for (auto& h : hdds) {
|
||||
h.pixmaps = &pixmaps.hd;
|
||||
}
|
||||
net.pixmaps = &pixmaps.net;
|
||||
for (auto& n : net) {
|
||||
n.pixmaps = &pixmaps.net;
|
||||
}
|
||||
}
|
||||
|
||||
std::array<StateEmpty, 2> cartridge;
|
||||
@@ -230,7 +232,7 @@ struct MachineStatus::States {
|
||||
std::array<StateEmptyActive, ZIP_NUM> zip;
|
||||
std::array<StateEmptyActive, MO_NUM> mo;
|
||||
std::array<StateActive, HDD_BUS_USB> hdds;
|
||||
StateActive net;
|
||||
std::array<StateEmptyActive, NET_CARD_MAX> net;
|
||||
std::unique_ptr<ClickableLabel> sound;
|
||||
std::unique_ptr<QLabel> text;
|
||||
};
|
||||
@@ -320,6 +322,14 @@ void MachineStatus::iterateMO(const std::function<void (int)> &cb) {
|
||||
}
|
||||
}
|
||||
|
||||
void MachineStatus::iterateNIC(const std::function<void (int)> &cb) {
|
||||
for (int i = 0; i < NET_CARD_MAX; i++) {
|
||||
if (network_dev_available(i)) {
|
||||
cb(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int hdd_count(int bus) {
|
||||
int c = 0;
|
||||
int i;
|
||||
@@ -357,7 +367,10 @@ void MachineStatus::refreshIcons() {
|
||||
d->hdds[i].setActive(machine_status.hdd[i].active);
|
||||
}
|
||||
|
||||
d->net.setActive(machine_status.net.active);
|
||||
for (size_t i = 0; i < NET_CARD_MAX; i++) {
|
||||
d->net[i].setActive(machine_status.net[i].active);
|
||||
d->net[i].setEmpty(machine_status.net[i].empty);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
d->cartridge[i].setEmpty(machine_status.cartridge[i].empty);
|
||||
@@ -375,7 +388,6 @@ void MachineStatus::refresh(QStatusBar* sbar) {
|
||||
int c_xta = hdd_count(HDD_BUS_XTA);
|
||||
int c_ide = hdd_count(HDD_BUS_IDE);
|
||||
int c_scsi = hdd_count(HDD_BUS_SCSI);
|
||||
int do_net = network_available();
|
||||
|
||||
sbar->removeWidget(d->cassette.label.get());
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
@@ -396,7 +408,9 @@ void MachineStatus::refresh(QStatusBar* sbar) {
|
||||
for (size_t i = 0; i < HDD_BUS_USB; i++) {
|
||||
sbar->removeWidget(d->hdds[i].label.get());
|
||||
}
|
||||
sbar->removeWidget(d->net.label.get());
|
||||
for (size_t i = 0; i < NET_CARD_MAX; i++) {
|
||||
sbar->removeWidget(d->net[i].label.get());
|
||||
}
|
||||
sbar->removeWidget(d->sound.get());
|
||||
|
||||
if (cassette_enable) {
|
||||
@@ -503,6 +517,18 @@ void MachineStatus::refresh(QStatusBar* sbar) {
|
||||
sbar->addWidget(d->mo[i].label.get());
|
||||
});
|
||||
|
||||
iterateNIC([this, sbar](int i) {
|
||||
d->net[i].label = std::make_unique<ClickableLabel>();
|
||||
d->net[i].setEmpty(!network_is_connected(i));
|
||||
d->net[i].setActive(false);
|
||||
d->net[i].refresh();
|
||||
d->net[i].label->setToolTip(MediaMenu::ptr->netMenus[i]->title());
|
||||
connect((ClickableLabel*)d->net[i].label.get(), &ClickableLabel::clicked, [i](QPoint pos) {
|
||||
MediaMenu::ptr->netMenus[i]->popup(pos - QPoint(0, MediaMenu::ptr->netMenus[i]->sizeHint().height()));
|
||||
});
|
||||
sbar->addWidget(d->net[i].label.get());
|
||||
});
|
||||
|
||||
auto hdc_name = QString(hdc_get_internal_name(hdc_current));
|
||||
if ((has_mfm || hdc_name.left(5) == QStringLiteral("st506")) && c_mfm > 0) {
|
||||
d->hdds[HDD_BUS_MFM].label = std::make_unique<QLabel>();
|
||||
@@ -541,13 +567,6 @@ void MachineStatus::refresh(QStatusBar* sbar) {
|
||||
sbar->addWidget(d->hdds[HDD_BUS_SCSI].label.get());
|
||||
}
|
||||
|
||||
if (do_net) {
|
||||
d->net.label = std::make_unique<QLabel>();
|
||||
d->net.setActive(false);
|
||||
d->net.refresh();
|
||||
d->net.label->setToolTip(tr("Network"));
|
||||
sbar->addWidget(d->net.label.get());
|
||||
}
|
||||
d->sound = std::make_unique<ClickableLabel>();
|
||||
d->sound->setPixmap(d->pixmaps.sound);
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ public:
|
||||
static void iterateCDROM(const std::function<void(int i)>& cb);
|
||||
static void iterateZIP(const std::function<void(int i)>& cb);
|
||||
static void iterateMO(const std::function<void(int i)>& cb);
|
||||
static void iterateNIC(const std::function<void(int i)>& cb);
|
||||
|
||||
QString getMessage();
|
||||
public slots:
|
||||
|
||||
@@ -44,10 +44,14 @@ extern "C" {
|
||||
#include <86box/mo.h>
|
||||
#include <86box/sound.h>
|
||||
#include <86box/ui.h>
|
||||
#include <86box/thread.h>
|
||||
#include <86box/network.h>
|
||||
|
||||
};
|
||||
|
||||
#include "qt_newfloppydialog.hpp"
|
||||
#include "qt_util.hpp"
|
||||
#include "qt_deviceconfig.hpp"
|
||||
|
||||
std::shared_ptr<MediaMenu> MediaMenu::ptr;
|
||||
|
||||
@@ -156,6 +160,16 @@ void MediaMenu::refresh(QMenu *parentMenu) {
|
||||
moMenus[i] = menu;
|
||||
moUpdateMenu(i);
|
||||
});
|
||||
|
||||
netMenus.clear();
|
||||
MachineStatus::iterateNIC([this, parentMenu](int i) {
|
||||
auto *menu = parentMenu->addMenu("");
|
||||
netDisconnPos = menu->children().count();
|
||||
auto *action = menu->addAction(tr("&Connected"), [this, i] { network_is_connected(i) ? nicDisconnect(i) : nicConnect(i); });
|
||||
action->setCheckable(true);
|
||||
netMenus[i] = menu;
|
||||
nicUpdateMenu(i);
|
||||
});
|
||||
}
|
||||
|
||||
void MediaMenu::cassetteNewImage() {
|
||||
@@ -662,6 +676,44 @@ void MediaMenu::moUpdateMenu(int i) {
|
||||
menu->setTitle(QString::asprintf(tr("MO %i (%ls): %ls").toUtf8().constData(), i + 1, busName.toStdU16String().data(), name.isEmpty() ? tr("(empty)").toStdU16String().data() : name.toStdU16String().data()));
|
||||
}
|
||||
|
||||
void MediaMenu::nicConnect(int i) {
|
||||
network_connect(i, 1);
|
||||
ui_sb_update_icon_state(SB_NETWORK|i, 0);
|
||||
nicUpdateMenu(i);
|
||||
config_save();
|
||||
}
|
||||
|
||||
void MediaMenu::nicDisconnect(int i) {
|
||||
network_connect(i, 0);
|
||||
ui_sb_update_icon_state(SB_NETWORK|i, 1);
|
||||
nicUpdateMenu(i);
|
||||
config_save();
|
||||
}
|
||||
|
||||
void MediaMenu::nicUpdateMenu(int i) {
|
||||
if (!netMenus.contains(i))
|
||||
return;
|
||||
|
||||
QString netType = tr("None");
|
||||
switch (net_cards_conf[i].net_type) {
|
||||
case NET_TYPE_SLIRP:
|
||||
netType = "SLiRP";
|
||||
break;
|
||||
case NET_TYPE_PCAP:
|
||||
netType = "PCAP";
|
||||
break;
|
||||
}
|
||||
|
||||
QString devName = DeviceConfig::DeviceName(network_card_getdevice(net_cards_conf[i].device_num), network_card_get_internal_name(net_cards_conf[i].device_num), 1);
|
||||
|
||||
auto *menu = netMenus[i];
|
||||
auto childs = menu->children();
|
||||
auto *connectedAction = dynamic_cast<QAction*>(childs[netDisconnPos]);
|
||||
connectedAction->setChecked(network_is_connected(i));
|
||||
|
||||
menu->setTitle(QString::asprintf(tr("NIC %02i (%ls) %ls").toUtf8().constData(), i + 1, netType.toStdU16String().data(), devName.toStdU16String().data()));
|
||||
}
|
||||
|
||||
QString MediaMenu::getMediaOpenDirectory() {
|
||||
QString openDirectory;
|
||||
if (open_dir_usr_path > 0) {
|
||||
|
||||
@@ -56,6 +56,10 @@ public:
|
||||
void moEject(int i);
|
||||
void moReload(int i);
|
||||
void moUpdateMenu(int i);
|
||||
|
||||
void nicConnect(int i);
|
||||
void nicDisconnect(int i);
|
||||
void nicUpdateMenu(int i);
|
||||
private:
|
||||
QWidget* parentWidget = nullptr;
|
||||
|
||||
@@ -65,6 +69,7 @@ private:
|
||||
QMap<int, QMenu*> cdromMenus;
|
||||
QMap<int, QMenu*> zipMenus;
|
||||
QMap<int, QMenu*> moMenus;
|
||||
QMap<int, QMenu*> netMenus;
|
||||
|
||||
QString getMediaOpenDirectory();
|
||||
|
||||
@@ -89,5 +94,7 @@ private:
|
||||
int moEjectPos;
|
||||
int moReloadPos;
|
||||
|
||||
int netDisconnPos;
|
||||
|
||||
friend class MachineStatus;
|
||||
};
|
||||
|
||||
@@ -50,6 +50,8 @@ extern "C" {
|
||||
#include <86box/zip.h>
|
||||
#include <86box/mo.h>
|
||||
#include <86box/hdd.h>
|
||||
#include <86box/thread.h>
|
||||
#include <86box/network.h>
|
||||
#include <86box/machine_status.h>
|
||||
|
||||
void
|
||||
@@ -213,6 +215,7 @@ ui_sb_update_icon_state(int tag, int state) {
|
||||
case SB_HDD:
|
||||
break;
|
||||
case SB_NETWORK:
|
||||
machine_status.net[item].empty = state > 0 ? true : false;
|
||||
break;
|
||||
case SB_SOUND:
|
||||
break;
|
||||
@@ -246,7 +249,7 @@ ui_sb_update_icon(int tag, int active) {
|
||||
machine_status.hdd[item].active = active > 0 ? true : false;
|
||||
break;
|
||||
case SB_NETWORK:
|
||||
machine_status.net.active = active > 0 ? true : false;
|
||||
machine_status.net[item].active = active > 0 ? true : false;
|
||||
break;
|
||||
case SB_SOUND:
|
||||
break;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
<file>win/icons/mo_empty_active.ico</file>
|
||||
<file>win/icons/network.ico</file>
|
||||
<file>win/icons/network_active.ico</file>
|
||||
<file>win/icons/network_empty.ico</file>
|
||||
<file>win/icons/other_peripherals.ico</file>
|
||||
<file>win/icons/other_removable_devices.ico</file>
|
||||
<file>win/icons/ports.ico</file>
|
||||
|
||||
BIN
src/win/icons/network_empty.ico
Normal file
BIN
src/win/icons/network_empty.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
Reference in New Issue
Block a user