From 9c65d20621d360bd5bc6331507c9269c1087293b Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sat, 27 Aug 2022 16:52:33 +0200 Subject: [PATCH 1/4] network: improve throughput by batch processing packets --- src/include/86box/network.h | 8 ++- src/network/net_pcap.c | 74 +++++++++++++++---- src/network/net_slirp.c | 36 +++++----- src/network/network.c | 140 ++++++++++++++++++++++++------------ 4 files changed, 176 insertions(+), 82 deletions(-) diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 2fe0553f8..54181ae8e 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -56,7 +56,9 @@ #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 @@ -92,12 +94,10 @@ typedef int (*NETSETLINKSTATE)(void *); 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; @@ -165,7 +165,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 diff --git a/src/network/net_pcap.c b/src/network/net_pcap.c index 0baa16186..9aa486316 100644 --- a/src/network/net_pcap.c +++ b/src/network/net_pcap.c @@ -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); diff --git a/src/network/net_slirp.c b/src/network/net_slirp.c index 7535a0609..46b913416 100644 --- a/src/network/net_slirp.c +++ b/src/network/net_slirp.c @@ -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--; diff --git a/src/network/network.c b/src/network/network.c index a406140c4..a01eb938e 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -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; isize; i++) { + for (int i=0; ipackets[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; isize; i++) { + for (int i=0; ipackets[i].data); queue->packets[i].len = 0; } @@ -331,41 +345,47 @@ static void network_rx_queue(void *priv) { netcard_t *card = (netcard_t *)priv; - double timer_period; - int ret = 0; - bool activity = false; + 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; + } - 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); - } - - if (card->queued_pkt.len > 0) { 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; } + double timer_period = 0.762939453125 * (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; ui_sb_update_icon(SB_NETWORK, activity); } @@ -498,12 +518,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 +552,17 @@ 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; +} + int network_dev_to_id(char *devname) { From c0b6c55926c4526f267fc742714a8e67d691d1ee Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sat, 27 Aug 2022 17:08:50 +0200 Subject: [PATCH 2/4] network: support > 10Mbps throughput --- src/include/86box/network.h | 4 ++++ src/network/net_pcnet.c | 7 ++++++- src/network/network.c | 5 +++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 54181ae8e..4f9e6b70e 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -62,6 +62,9 @@ #define NET_CARD_MAX 4 #define NET_HOST_INTF_MAX 64 +#define NET_PERIOD_10M 0.8 +#define NET_PERIOD_100M 0.08 + /* Supported network cards. */ enum { NONE = 0, @@ -128,6 +131,7 @@ struct _netcard_t { mutex_t *rx_mutex; pc_timer_t timer; int card_num; + double byte_period; }; typedef struct { diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index 25ced4679..2b2b22540 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -2025,11 +2025,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; @@ -3055,6 +3059,7 @@ pcnet_init(const device_t *info) /* Attach ourselves to the network module. */ dev->netcard = network_attach(dev, dev->aPROM, pcnetReceiveNoSync, pcnetWaitReceiveAvail, pcnetSetLinkState); + dev->netcard->byte_period = (dev->board == DEV_AM79C973) ? NET_PERIOD_100M : NET_PERIOD_10M; timer_add(&dev->timer, pcnetPollTimer, dev, 0); diff --git a/src/network/network.c b/src/network/network.c index a01eb938e..a8106afeb 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -379,7 +379,7 @@ network_rx_queue(void *priv) card->host_drv.notify_in(card->host_drv.priv); } - double timer_period = 0.762939453125 * (rx_bytes > tx_bytes ? rx_bytes : tx_bytes); + double timer_period = card->byte_period * (rx_bytes > tx_bytes ? rx_bytes : tx_bytes); if (timer_period < 200) timer_period = 200; @@ -409,6 +409,7 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETWAITCB wait, NETSETL 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]); @@ -440,7 +441,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; } From ea21790fc9a3dec558c17a01e54cb5c98ce3f35c Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sat, 27 Aug 2022 19:08:28 +0200 Subject: [PATCH 3/4] network: allow to set a NIC's link from the status bar --- src/config.c | 12 ++++++ src/include/86box/machine_status.h | 2 +- src/include/86box/network.h | 25 +++++++++--- src/machine_status.c | 6 ++- src/network/net_3c503.c | 2 +- src/network/net_dp8390.c | 6 ++- src/network/net_ne2000.c | 2 +- src/network/net_pcnet.c | 62 ++++++++++++++---------------- src/network/net_plip.c | 2 +- src/network/net_wd8003.c | 2 +- src/network/network.c | 59 ++++++++++++++++++++++++---- src/qt/qt_machinestatus.cpp | 41 ++++++++++++++------ src/qt/qt_machinestatus.hpp | 1 + src/qt/qt_mediamenu.cpp | 38 ++++++++++++++++++ src/qt/qt_mediamenu.hpp | 5 +++ src/qt/qt_ui.cpp | 4 +- 16 files changed, 202 insertions(+), 67 deletions(-) diff --git a/src/config.c b/src/config.c index b0c73e0d0..0c6c0e28b 100644 --- a/src/config.c +++ b/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); diff --git a/src/include/86box/machine_status.h b/src/include/86box/machine_status.h index 2afed078e..6baafeeb0 100644 --- a/src/include/86box/machine_status.h +++ b/src/include/86box/machine_status.h @@ -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_active_t net[NET_CARD_MAX]; dev_status_empty_t cartridge[2]; } machine_status_t; diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 4f9e6b70e..f294bf500 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -65,6 +65,17 @@ #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, @@ -84,14 +95,14 @@ 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 { @@ -121,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; @@ -132,6 +141,9 @@ struct _netcard_t { pc_timer_t timer; int card_num; double byte_period; + uint32_t led_timer; + uint32_t led_state; + uint32_t link_state; }; typedef struct { @@ -152,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); @@ -161,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); diff --git a/src/machine_status.c b/src/machine_status.c index 258c16821..3031c9ad3 100644 --- a/src/machine_status.c +++ b/src/machine_status.c @@ -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,7 @@ 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; + } } \ No newline at end of file diff --git a/src/network/net_3c503.c b/src/network/net_3c503.c index d54a00593..2e5c97519 100644 --- a/src/network/net_3c503.c +++ b/src/network/net_3c503.c @@ -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); } diff --git a/src/network/net_dp8390.c b/src/network/net_dp8390.c index c9908f883..ad4345ae6 100644 --- a/src/network/net_dp8390.c +++ b/src/network/net_dp8390.c @@ -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. diff --git a/src/network/net_ne2000.c b/src/network/net_ne2000.c index 960f7cdbf..c7f1a0ccb 100644 --- a/src/network/net_ne2000.c +++ b/src/network/net_ne2000.c @@ -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); diff --git a/src/network/net_pcnet.c b/src/network/net_pcnet.c index 2b2b22540..340b056d3 100644 --- a/src/network/net_pcnet.c +++ b/src/network/net_pcnet.c @@ -29,6 +29,7 @@ #include #include #include +#include #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], @@ -2095,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 @@ -2131,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. */ @@ -2145,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. */ @@ -2157,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. */ @@ -2195,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; @@ -2846,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; @@ -3058,7 +3052,7 @@ 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); diff --git a/src/network/net_plip.c b/src/network/net_plip.c index cf1a0f9c3..9372e8022 100644 --- a/src/network/net_plip.c +++ b/src/network/net_plip.c @@ -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; } diff --git a/src/network/net_wd8003.c b/src/network/net_wd8003.c index be52a11aa..d53f570f0 100644 --- a/src/network/net_wd8003.c +++ b/src/network/net_wd8003.c @@ -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, diff --git a/src/network/network.c b/src/network/network.c index a8106afeb..7c6ab0826 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -346,6 +346,13 @@ network_rx_queue(void *priv) { netcard_t *card = (netcard_t *)priv; + 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; + } + uint32_t rx_bytes = 0; for (int i = 0; i < NET_QUEUE_LEN; i++) { if (card->queued_pkt.len == 0) { @@ -386,7 +393,13 @@ network_rx_queue(void *priv) timer_on_auto(&card->timer, timer_period); bool activity = rx_bytes || tx_bytes; - ui_sb_update_icon(SB_NETWORK, activity); + 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; } @@ -398,13 +411,12 @@ 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(); @@ -496,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; } @@ -564,6 +575,28 @@ int network_rx_put_pkt(netcard_t *card, netpkt_t *pkt) 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) { @@ -575,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; diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index a6ea65fd3..c04d6ee5c 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -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 cartridge; @@ -230,7 +232,7 @@ struct MachineStatus::States { std::array zip; std::array mo; std::array hdds; - StateActive net; + std::array net; std::unique_ptr sound; std::unique_ptr text; }; @@ -320,6 +322,14 @@ void MachineStatus::iterateMO(const std::function &cb) { } } +void MachineStatus::iterateNIC(const std::function &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,9 @@ 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); + } for (int i = 0; i < 2; ++i) { d->cartridge[i].setEmpty(machine_status.cartridge[i].empty); @@ -375,7 +387,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 +407,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 +516,17 @@ void MachineStatus::refresh(QStatusBar* sbar) { sbar->addWidget(d->mo[i].label.get()); }); + iterateNIC([this, sbar](int i) { + d->net[i].label = std::make_unique(); + 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(); @@ -541,13 +565,6 @@ void MachineStatus::refresh(QStatusBar* sbar) { sbar->addWidget(d->hdds[HDD_BUS_SCSI].label.get()); } - if (do_net) { - d->net.label = std::make_unique(); - d->net.setActive(false); - d->net.refresh(); - d->net.label->setToolTip(tr("Network")); - sbar->addWidget(d->net.label.get()); - } d->sound = std::make_unique(); d->sound->setPixmap(d->pixmaps.sound); diff --git a/src/qt/qt_machinestatus.hpp b/src/qt/qt_machinestatus.hpp index 8c31dd238..8d085f93a 100644 --- a/src/qt/qt_machinestatus.hpp +++ b/src/qt/qt_machinestatus.hpp @@ -66,6 +66,7 @@ public: static void iterateCDROM(const std::function& cb); static void iterateZIP(const std::function& cb); static void iterateMO(const std::function& cb); + static void iterateNIC(const std::function& cb); QString getMessage(); public slots: diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index a4fcb5113..90cd80257 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -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::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("&Disconnected"), [i] { network_connect(i, !network_is_connected(i)); config_save(); }); + action->setCheckable(true); + netMenus[i] = menu; + nicUpdateMenu(i); + }); } void MediaMenu::cassetteNewImage() { @@ -662,6 +676,30 @@ 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::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(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) { diff --git a/src/qt/qt_mediamenu.hpp b/src/qt/qt_mediamenu.hpp index 9b08d3ee3..a5c50a472 100644 --- a/src/qt/qt_mediamenu.hpp +++ b/src/qt/qt_mediamenu.hpp @@ -56,6 +56,8 @@ public: void moEject(int i); void moReload(int i); void moUpdateMenu(int i); + + void nicUpdateMenu(int i); private: QWidget* parentWidget = nullptr; @@ -65,6 +67,7 @@ private: QMap cdromMenus; QMap zipMenus; QMap moMenus; + QMap netMenus; QString getMediaOpenDirectory(); @@ -89,5 +92,7 @@ private: int moEjectPos; int moReloadPos; + int netDisconnPos; + friend class MachineStatus; }; diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index 7400a4f7a..65a8cec44 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -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 @@ -246,7 +248,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; From d3dde1737a6a8f11dbf83beacde9aeeefd710682 Mon Sep 17 00:00:00 2001 From: Adrien Moulin Date: Sun, 28 Aug 2022 13:56:24 +0200 Subject: [PATCH 4/4] network: add a new status bar icon for the network disconnected state --- src/include/86box/machine_status.h | 2 +- src/machine_status.c | 1 + src/qt/qt_machinestatus.cpp | 6 ++++-- src/qt/qt_mediamenu.cpp | 18 ++++++++++++++++-- src/qt/qt_mediamenu.hpp | 2 ++ src/qt/qt_ui.cpp | 1 + src/qt_resources.qrc | 1 + src/win/icons/network_empty.ico | Bin 0 -> 6950 bytes 8 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 src/win/icons/network_empty.ico diff --git a/src/include/86box/machine_status.h b/src/include/86box/machine_status.h index 6baafeeb0..31cefdfd4 100644 --- a/src/include/86box/machine_status.h +++ b/src/include/86box/machine_status.h @@ -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[NET_CARD_MAX]; + dev_status_empty_active_t net[NET_CARD_MAX]; dev_status_empty_t cartridge[2]; } machine_status_t; diff --git a/src/machine_status.c b/src/machine_status.c index 3031c9ad3..1429d9295 100644 --- a/src/machine_status.c +++ b/src/machine_status.c @@ -52,5 +52,6 @@ machine_status_init() { 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); } } \ No newline at end of file diff --git a/src/qt/qt_machinestatus.cpp b/src/qt/qt_machinestatus.cpp index c04d6ee5c..9e93e882b 100644 --- a/src/qt/qt_machinestatus.cpp +++ b/src/qt/qt_machinestatus.cpp @@ -88,7 +88,7 @@ namespace { PixmapSetEmptyActive zip; PixmapSetEmptyActive mo; PixmapSetActive hd; - PixmapSetActive net; + PixmapSetEmptyActive net; QPixmap sound; }; @@ -232,7 +232,7 @@ struct MachineStatus::States { std::array zip; std::array mo; std::array hdds; - std::array net; + std::array net; std::unique_ptr sound; std::unique_ptr text; }; @@ -369,6 +369,7 @@ void MachineStatus::refreshIcons() { 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) { @@ -518,6 +519,7 @@ void MachineStatus::refresh(QStatusBar* sbar) { iterateNIC([this, sbar](int i) { d->net[i].label = std::make_unique(); + 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()); diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index 90cd80257..0050da900 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -165,7 +165,7 @@ void MediaMenu::refresh(QMenu *parentMenu) { MachineStatus::iterateNIC([this, parentMenu](int i) { auto *menu = parentMenu->addMenu(""); netDisconnPos = menu->children().count(); - auto *action = menu->addAction(tr("&Disconnected"), [i] { network_connect(i, !network_is_connected(i)); config_save(); }); + auto *action = menu->addAction(tr("&Connected"), [this, i] { network_is_connected(i) ? nicDisconnect(i) : nicConnect(i); }); action->setCheckable(true); netMenus[i] = menu; nicUpdateMenu(i); @@ -676,6 +676,20 @@ 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; @@ -695,7 +709,7 @@ void MediaMenu::nicUpdateMenu(int i) { auto *menu = netMenus[i]; auto childs = menu->children(); auto *connectedAction = dynamic_cast(childs[netDisconnPos]); - connectedAction->setChecked(!network_is_connected(i)); + 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())); } diff --git a/src/qt/qt_mediamenu.hpp b/src/qt/qt_mediamenu.hpp index a5c50a472..de892d73c 100644 --- a/src/qt/qt_mediamenu.hpp +++ b/src/qt/qt_mediamenu.hpp @@ -57,6 +57,8 @@ public: void moReload(int i); void moUpdateMenu(int i); + void nicConnect(int i); + void nicDisconnect(int i); void nicUpdateMenu(int i); private: QWidget* parentWidget = nullptr; diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index 65a8cec44..febf4cba7 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -215,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; diff --git a/src/qt_resources.qrc b/src/qt_resources.qrc index fec56ad71..67f9cadac 100644 --- a/src/qt_resources.qrc +++ b/src/qt_resources.qrc @@ -33,6 +33,7 @@ win/icons/mo_empty_active.ico win/icons/network.ico win/icons/network_active.ico + win/icons/network_empty.ico win/icons/other_peripherals.ico win/icons/other_removable_devices.ico win/icons/ports.ico diff --git a/src/win/icons/network_empty.ico b/src/win/icons/network_empty.ico new file mode 100644 index 0000000000000000000000000000000000000000..4a1a102846ea018ba6d899b5352dd9fbdcfce858 GIT binary patch literal 6950 zcmZQzU}Run5D);-91Iz(3=D1z3=AS75IzSR1H(F21_lWU2>%2d1H(3M1_lKM2!90! z14Eq<1A_(w1A_nq1A_tsM4SN+5D*Yx5EK+-@bU3s$jZuMsH>}EsIRYQXlQ6)Xl`z1 z*tTsO!~XsI84escz;N~IRfhln|Kl-jRBAK?Mnhoega9L|Q$d9fNQi}j86?5Vz{9}E zz|H{Tf(1au2|EK112Y3N0}Dh20|PTufE^?YQqIG`0@lL7#=yn^Q4TVJoq>UufdMK2 zGJ}DQftP_7ECA+0^n*+Qna<9@z{bGMz{SALzz&8CApIN+91Pqbn?ab3fsuiefrEhw z!~tPm21W)(WO*^ zPhU_^uf z69Wi>y~+tL%Rt2|NC;f6F@XyfHUFn85;|0uRIomu{fK7^V(Xjx&G+ z7#Ki>CJ2Mf1X}|V1{Iqi0VWU!WFs@!3XpXmVFpgHN`xg~b({aofBnF)desJo(9i&eRZ#lfss#+!!Tbd%;vo5}p&uAlt^dGqH6D|G zwf_USy)D7Oz+gZ`dmC3hFxs|;#Na478UiCa1VDv3xL^f^0;rG%(V!v>R4PLym>Af> zoL%nkpmg^*!Jz)N5_cZF*V8<4S~@RKnej+ zISehckwl?PQ0WIMyWzDJNE}x6fr>~_odT*SK-~#&#RsZ)AXOkpFGvc6nHZo7K!q)sP)jA6e0m5!TMolfGhw-6-*Kw$sk7|W6^gsACNZ z1(*z&1{nz&!(@SmB-~!GEHr>X4F*ul0F)BY6oB-Dq(LnTP&A`SLjoA20Hhz}NHhf? z{Sd1_Eex#g2PpwzklR5Rq8v^lJP2Z;84pqgvK4``C;%Cbz#uJf{Qv*e`v3n|?f+UI z8vkn5s`a6vq2aGqty=x}YiQ`NSF2Vb)2mjkS```^8j3`(2B}}QYSsFyp`r1sR;}89 gH8iw-)vERXuZG6|$3?$dwf_It(D?tqR_*@}0J&!nAOHXW literal 0 HcmV?d00001