From ae123f1f380e00f85215b99e289838a7ccf115a3 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 7 May 2023 16:55:15 +0600 Subject: [PATCH 01/25] usb: Implement HCCA reads and writes --- src/include/86box/usb.h | 4 ++-- src/usb.c | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index 6582f05e4..d8101c880 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -58,6 +58,7 @@ typedef struct usb_t } usb_t; #pragma pack(push, 1) + /* Base USB descriptor struct. */ typedef struct { @@ -76,6 +77,7 @@ typedef struct uint8_t bmAttributes; uint8_t bMaxPower; } usb_desc_conf_t; + #pragma pack(pop) typedef struct @@ -84,9 +86,7 @@ typedef struct uint16_t HccaFrameNumber; uint16_t HccaPad1; uint32_t HccaDoneHead; - uint32_t Reserved[29]; } usb_hcca_t; - /* USB endpoint device struct. Incomplete and unused. */ typedef struct { diff --git a/src/usb.c b/src/usb.c index 5b5e68bf2..0b3b5efe1 100644 --- a/src/usb.c +++ b/src/usb.c @@ -300,8 +300,13 @@ ohci_set_interrupt(usb_t *dev, uint8_t bit) void ohci_end_of_frame(usb_t* dev) { + usb_hcca_t hcca; /* TODO: Put endpoint and transfer descriptor processing here. */ + dma_bm_read(dev->ohci_mmio[OHCI_HcHCCA].l, (uint8_t*)&hcca, sizeof(usb_hcca_t), 4); + dev->ohci_mmio[OHCI_HcFmNumber].w[0]++; + + dma_bm_write(dev->ohci_mmio[OHCI_HcHCCA].l, (uint8_t*)&hcca, sizeof(usb_hcca_t), 4); } void From 708f00699b7c3dfee2086dd7d6e076ba2916a330 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 7 May 2023 17:29:06 +0600 Subject: [PATCH 02/25] usb: Transfer and endpoint descriptor structure --- src/include/86box/usb.h | 19 +++++++++++++++++++ src/usb.c | 1 - 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index d8101c880..bd94322ae 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -87,6 +87,25 @@ typedef struct uint16_t HccaPad1; uint32_t HccaDoneHead; } usb_hcca_t; + +/* Transfer descriptors */ +typedef struct +{ + uint32_t Control; + uint32_t CBP; + uint32_t NextTD; + uint32_t BE; +} usb_td_t; + +/* Endpoint descriptors */ +typedef struct +{ + uint32_t Control; + uint32_t TailP; + uint32_t HeadP; + uint32_t NextED; +} usb_ed_t; + /* USB endpoint device struct. Incomplete and unused. */ typedef struct { diff --git a/src/usb.c b/src/usb.c index 0b3b5efe1..3994f60c3 100644 --- a/src/usb.c +++ b/src/usb.c @@ -341,7 +341,6 @@ ohci_poll_interrupt_descriptors(void* priv) /* TODO: Actually poll the interrupt descriptors. */ - dev->ohci_interrupt_counter++; timer_on_auto(&dev->ohci_interrupt_desc_poll_timer, 1000.); } From 9ce81ac27561e96b771e56fccd477b582878aba6 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sun, 7 May 2023 23:07:03 +0600 Subject: [PATCH 03/25] usb: Start implementing Endpoint/Transfer descriptor parsing --- src/include/86box/usb.h | 29 +-------- src/usb.c | 141 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 128 insertions(+), 42 deletions(-) diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index bd94322ae..4c6fc289b 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -50,9 +50,8 @@ typedef struct usb_t uint32_t ohci_mem_base, irq_level; mem_mapping_t ohci_mmio_mapping; pc_timer_t ohci_frame_timer; - pc_timer_t ohci_interrupt_desc_poll_timer; pc_timer_t ohci_port_reset_timer[2]; - uint8_t ohci_interrupt_counter : 5; + uint8_t ohci_interrupt_counter : 3; usb_params_t* usb_params; } usb_t; @@ -80,32 +79,6 @@ typedef struct #pragma pack(pop) -typedef struct -{ - uint32_t HccaInterrruptTable[32]; - uint16_t HccaFrameNumber; - uint16_t HccaPad1; - uint32_t HccaDoneHead; -} usb_hcca_t; - -/* Transfer descriptors */ -typedef struct -{ - uint32_t Control; - uint32_t CBP; - uint32_t NextTD; - uint32_t BE; -} usb_td_t; - -/* Endpoint descriptors */ -typedef struct -{ - uint32_t Control; - uint32_t TailP; - uint32_t HeadP; - uint32_t NextED; -} usb_ed_t; - /* USB endpoint device struct. Incomplete and unused. */ typedef struct { diff --git a/src/usb.c b/src/usb.c index 3994f60c3..03b5f6546 100644 --- a/src/usb.c +++ b/src/usb.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #define HAVE_STDARG_H #include <86box/86box.h> @@ -117,6 +118,16 @@ enum OHCI_HcInterruptEnable_RHSC = 1 << 6, }; +/* OHCI HcControl bits */ +enum +{ + OHCI_HcControl_ControlBulkServiceRatio = 1 << 0, + OHCI_HcControl_PeriodicListEnable = 1 << 1, + OHCI_HcControl_IsochronousEnable = 1 << 2, + OHCI_HcControl_ControlListEnable = 1 << 3, + OHCI_HcControl_BulkListEnable = 1 << 4 +}; + static void usb_interrupt_ohci(usb_t *dev, uint32_t level) { @@ -216,6 +227,69 @@ uhci_update_io_mapping(usb_t *dev, uint8_t base_l, uint8_t base_h, int enable) io_sethandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, uhci_reg_writew, NULL, dev); } +typedef struct +{ + uint32_t HccaInterrruptTable[32]; + uint16_t HccaFrameNumber; + uint16_t HccaPad1; + uint32_t HccaDoneHead; +} usb_hcca_t; + +/* Transfer descriptors */ +typedef struct +{ + union + { + uint32_t Control; + struct + { + uint32_t Reserved : 18; + uint8_t bufferRounding : 1; + uint8_t Direction : 2; + uint8_t DelayInterrupt : 3; + uint8_t DataToggle : 2; + uint8_t ErrorCount : 2; + uint8_t ConditionCode : 4; + } flags; + }; + uint32_t CBP; + uint32_t NextTD; + uint32_t BE; +} usb_td_t; + +/* Endpoint descriptors */ +typedef struct +{ + union + { + uint32_t Control; + struct + { + uint8_t FunctionAddress : 7; + uint8_t EndpointNumber : 4; + uint8_t Direction : 2; + bool Speed : 1; + bool Skip : 1; + bool Format : 1; + uint16_t MaximumPacketSize : 11; + uint8_t Reserved : 5; + } flags; + }; + uint32_t TailP; + union + { + uint32_t HeadP; + struct + { + bool Halted : 1; + bool toggleCarry : 1; + } flags_2; + }; + uint32_t NextED; +} usb_ed_t; + +#define ENDPOINT_DESC_LIMIT 32 + static uint8_t ohci_mmio_read(uint32_t addr, void *p) { @@ -297,6 +371,14 @@ ohci_set_interrupt(usb_t *dev, uint8_t bit) ohci_update_irq(dev); } +uint8_t +ohci_service_endpoint_desc(usb_t* dev, uint32_t head) +{ + usb_ed_t endpoint_desc; + + return 0; +} + void ohci_end_of_frame(usb_t* dev) { @@ -304,7 +386,49 @@ ohci_end_of_frame(usb_t* dev) /* TODO: Put endpoint and transfer descriptor processing here. */ dma_bm_read(dev->ohci_mmio[OHCI_HcHCCA].l, (uint8_t*)&hcca, sizeof(usb_hcca_t), 4); + if (dev->ohci_mmio[OHCI_HcControl].l & OHCI_HcControl_PeriodicListEnable) { + ohci_service_endpoint_desc(dev, hcca.HccaInterrruptTable[dev->ohci_mmio[OHCI_HcFmNumber].l & 0x1f]); + } + + if ((dev->ohci_mmio[OHCI_HcControl].l & OHCI_HcControl_ControlListEnable) + && (dev->ohci_mmio[OHCI_HcCommandStatus].l & 0x2)) { + uint8_t result = ohci_service_endpoint_desc(dev, dev->ohci_mmio[OHCI_HcControlHeadED].l); + if (!result) { + dev->ohci_mmio[OHCI_HcControlHeadED].l = 0; + dev->ohci_mmio[OHCI_HcCommandStatus].l &= ~0x2; + } + } + + if ((dev->ohci_mmio[OHCI_HcControl].l & OHCI_HcControl_BulkListEnable) + && (dev->ohci_mmio[OHCI_HcCommandStatus].l & 0x4)) { + uint8_t result = ohci_service_endpoint_desc(dev, dev->ohci_mmio[OHCI_HcBulkHeadED].l); + if (!result) { + dev->ohci_mmio[OHCI_HcBulkHeadED].l = 0; + dev->ohci_mmio[OHCI_HcCommandStatus].l &= ~0x4; + } + } + + if (dev->ohci_interrupt_counter == 0 && !(dev->ohci_mmio[OHCI_HcInterruptStatus].l & OHCI_HcInterruptEnable_WDH)) { + if (dev->ohci_mmio[OHCI_HcDoneHead].l == 0) { + fatal("OHCI: HcDoneHead is still NULL!"); + } + + if (dev->ohci_mmio[OHCI_HcInterruptStatus].l & dev->ohci_mmio[OHCI_HcInterruptEnable].l) { + dev->ohci_mmio[OHCI_HcDoneHead].l |= 1; + } + + hcca.HccaDoneHead = dev->ohci_mmio[OHCI_HcDoneHead].l; + dev->ohci_mmio[OHCI_HcDoneHead].l = 0; + dev->ohci_interrupt_counter = 7; + ohci_set_interrupt(dev, OHCI_HcInterruptEnable_WDH); + } + + if (dev->ohci_interrupt_counter != 0 && dev->ohci_interrupt_counter != 7) { + dev->ohci_interrupt_counter--; + } + dev->ohci_mmio[OHCI_HcFmNumber].w[0]++; + hcca.HccaFrameNumber = dev->ohci_mmio[OHCI_HcFmNumber].w[0]; dma_bm_write(dev->ohci_mmio[OHCI_HcHCCA].l, (uint8_t*)&hcca, sizeof(usb_hcca_t), 4); } @@ -327,21 +451,11 @@ ohci_update_frame_counter(void* priv) dev->ohci_mmio[OHCI_HcFmRemaining].l &= ~(1 << 31); dev->ohci_mmio[OHCI_HcFmRemaining].l |= dev->ohci_mmio[OHCI_HcFmInterval].l & (1 << 31); ohci_start_of_frame(dev); - timer_on_auto(&dev->ohci_frame_timer, 1. / (12. * 1000. * 1000.)); + timer_on_auto(&dev->ohci_frame_timer, 1. / 12.); return; } - if (dev->ohci_mmio[OHCI_HcFmRemaining].w[0]) dev->ohci_mmio[OHCI_HcFmRemaining].w[0]--; - timer_on_auto(&dev->ohci_frame_timer, 1. / (12. * 1000. * 1000.)); -} - -void -ohci_poll_interrupt_descriptors(void* priv) -{ - usb_t *dev = (usb_t *) priv; - - /* TODO: Actually poll the interrupt descriptors. */ - - timer_on_auto(&dev->ohci_interrupt_desc_poll_timer, 1000.); + dev->ohci_mmio[OHCI_HcFmRemaining].w[0]--; + timer_on_auto(&dev->ohci_frame_timer, 1. / 12.); } void @@ -694,7 +808,6 @@ usb_init_ext(const device_t *info, void *params) timer_add(&dev->ohci_frame_timer, ohci_update_frame_counter, dev, 0); /* Unused for now, to be used for frame counting. */ timer_add(&dev->ohci_port_reset_timer[0], ohci_port_reset_callback, dev, 0); timer_add(&dev->ohci_port_reset_timer[1], ohci_port_reset_callback_2, dev, 0); - timer_add(&dev->ohci_interrupt_desc_poll_timer, ohci_poll_interrupt_descriptors, dev, 0); usb_reset(dev); From a6086c451e1bfc9d83d8582800ff71f049865ba5 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 8 May 2023 00:50:00 +0600 Subject: [PATCH 04/25] usb: Start finalizing work on OHCI --- src/include/86box/usb.h | 53 ++++++++++++++++------------- src/usb.c | 75 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 25 deletions(-) diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index 4c6fc289b..1f5413cd7 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -24,6 +24,33 @@ extern "C" { typedef struct usb_t usb_t; +/* USB endpoint device struct. Incomplete and unused. */ +typedef struct +{ + uint16_t vendor_id; + uint16_t device_id; + + /* Reads from endpoint. Non-zero value indicates error. */ + uint8_t (*device_in)(void* priv, uint8_t* data, uint32_t len); + /* Writes to endpoint. Non-zero value indicates error. */ + uint8_t (*device_out)(void* priv, uint8_t* data, uint32_t len); + /* Process setup packets. */ + uint8_t (*device_setup)(void* priv, uint8_t* data); + /* Device reset. */ + void (*device_reset)(void* priv); + /* Get address. */ + uint8_t (*device_get_address)(void* priv); + + void* priv; +} usb_device_t; + +enum usb_bus_types +{ + USB_BUS_OHCI = 0, + USB_BUS_UHCI, + USB_BUS_MAX +}; + /* USB device creation parameters struct */ typedef struct { @@ -52,6 +79,8 @@ typedef struct usb_t pc_timer_t ohci_frame_timer; pc_timer_t ohci_port_reset_timer[2]; uint8_t ohci_interrupt_counter : 3; + usb_device_t* ohci_devices[2]; + usb_device_t* uhci_devices[2]; usb_params_t* usb_params; } usb_t; @@ -79,30 +108,6 @@ typedef struct #pragma pack(pop) -/* USB endpoint device struct. Incomplete and unused. */ -typedef struct -{ - uint16_t vendor_id; - uint16_t device_id; - - /* Reads from endpoint. Non-zero value indicates error. */ - uint8_t (*device_in)(void* priv, uint8_t* data, uint32_t len); - /* Writes to endpoint. Non-zero value indicates error. */ - uint8_t (*device_out)(void* priv, uint8_t* data, uint32_t len); - /* Process setup packets. */ - uint8_t (*device_setup)(void* priv, uint8_t* data); - /* Device reset */ - void (*device_reset)(void* priv); - - void* priv; -} usb_device_t; - -enum usb_bus_types -{ - USB_BUS_OHCI = 0, - USB_BUS_UHCI = 1 -}; - /* Global variables. */ extern const device_t usb_device; diff --git a/src/usb.c b/src/usb.c index 03b5f6546..0b9a8255f 100644 --- a/src/usb.c +++ b/src/usb.c @@ -371,12 +371,85 @@ ohci_set_interrupt(usb_t *dev, uint8_t bit) ohci_update_irq(dev); } +/* Next two functions ported over from QEMU. */ +static int ohci_copy_td_input(usb_t* dev, usb_td_t *td, + uint8_t *buf, int len) +{ + uint32_t ptr, n; + + ptr = td->CBP; + n = 0x1000 - (ptr & 0xfff); + if (n > len) { + n = len; + } + dma_bm_write(ptr, buf, n, 1); + if (n == len) { + return 0; + } + ptr = td->BE & ~0xfffu; + buf += n; + dma_bm_write(ptr, buf, len - n, 1); + return 0; +} + +static int ohci_copy_td_output(usb_t* dev, usb_td_t *td, + uint8_t *buf, int len) +{ + uint32_t ptr, n; + + ptr = td->CBP; + n = 0x1000 - (ptr & 0xfff); + if (n > len) { + n = len; + } + dma_bm_read(ptr, buf, n, 1); + if (n == len) { + return 0; + } + ptr = td->BE & ~0xfffu; + buf += n; + dma_bm_read(ptr, buf, len - n, 1); + return 0; +} + +uint8_t +ohci_service_transfer_desc(usb_t* dev, usb_ed_t* endpoint_desc) +{ + +} + uint8_t ohci_service_endpoint_desc(usb_t* dev, uint32_t head) { usb_ed_t endpoint_desc; + uint8_t active = 0; + uint32_t next = 0; + uint32_t cur = 0; + uint32_t limit_counter = 0; + + if (head == 0) + return 0; - return 0; + for (cur = head; cur && limit_counter++ < ENDPOINT_DESC_LIMIT; cur = next) { + dma_bm_read(cur, (uint8_t*)&endpoint_desc, sizeof(usb_ed_t), 4); + + next = endpoint_desc.NextED & ~(0xFu); + + if (endpoint_desc.flags.Skip || endpoint_desc.flags_2.Halted) + continue; + + if (endpoint_desc.flags.Format) { + fatal("OHCI: Isochronous transfers not implemented!\n"); + } + + while ((endpoint_desc.HeadP & ~(0xFu)) != endpoint_desc.TailP) { + ohci_service_transfer_desc(dev, &endpoint_desc); + } + + dma_bm_write(cur, (uint8_t*)&endpoint_desc, sizeof(usb_ed_t), 4); + } + + return active; } void From 9c09d4260ed4bd88365a442977efc195d048e359 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 8 May 2023 16:51:16 +0600 Subject: [PATCH 05/25] usb: Finish work on OHCI --- src/include/86box/usb.h | 25 +++- src/usb.c | 260 ++++++++++++++++++++++++++++++++-------- 2 files changed, 229 insertions(+), 56 deletions(-) diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index 1f5413cd7..b9497b92e 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -24,18 +24,29 @@ extern "C" { typedef struct usb_t usb_t; +enum usb_pid +{ + USB_PID_OUT = 0xE1, + USB_PID_IN = 0x69, + USB_PID_SETUP = 0x2D +}; + +enum usb_errors +{ + USB_ERROR_NO_ERROR = 0, + USB_ERROR_NAK = 1, + USB_ERROR_OVERRUN = 2, + USB_ERROR_UNDERRUN = 3 +}; + /* USB endpoint device struct. Incomplete and unused. */ typedef struct { uint16_t vendor_id; uint16_t device_id; - /* Reads from endpoint. Non-zero value indicates error. */ - uint8_t (*device_in)(void* priv, uint8_t* data, uint32_t len); - /* Writes to endpoint. Non-zero value indicates error. */ - uint8_t (*device_out)(void* priv, uint8_t* data, uint32_t len); - /* Process setup packets. */ - uint8_t (*device_setup)(void* priv, uint8_t* data); + /* General-purpose function for I/O. Non-zero value indicates error. */ + uint8_t (*device_process)(void* priv, uint8_t* data, uint32_t *len, uint8_t pid_token, uint8_t endpoint, uint8_t underrun_not_allowed); /* Device reset. */ void (*device_reset)(void* priv); /* Get address. */ @@ -81,6 +92,8 @@ typedef struct usb_t uint8_t ohci_interrupt_counter : 3; usb_device_t* ohci_devices[2]; usb_device_t* uhci_devices[2]; + uint8_t ohci_usb_buf[4096]; + uint8_t ohci_initial_start; usb_params_t* usb_params; } usb_t; diff --git a/src/usb.c b/src/usb.c index 0b9a8255f..f6262e11f 100644 --- a/src/usb.c +++ b/src/usb.c @@ -22,6 +22,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> @@ -238,20 +239,7 @@ typedef struct /* Transfer descriptors */ typedef struct { - union - { - uint32_t Control; - struct - { - uint32_t Reserved : 18; - uint8_t bufferRounding : 1; - uint8_t Direction : 2; - uint8_t DelayInterrupt : 3; - uint8_t DataToggle : 2; - uint8_t ErrorCount : 2; - uint8_t ConditionCode : 4; - } flags; - }; + uint32_t Control; uint32_t CBP; uint32_t NextTD; uint32_t BE; @@ -260,31 +248,9 @@ typedef struct /* Endpoint descriptors */ typedef struct { - union - { - uint32_t Control; - struct - { - uint8_t FunctionAddress : 7; - uint8_t EndpointNumber : 4; - uint8_t Direction : 2; - bool Speed : 1; - bool Skip : 1; - bool Format : 1; - uint16_t MaximumPacketSize : 11; - uint8_t Reserved : 5; - } flags; - }; + uint32_t Control; uint32_t TailP; - union - { - uint32_t HeadP; - struct - { - bool Halted : 1; - bool toggleCarry : 1; - } flags_2; - }; + uint32_t HeadP; uint32_t NextED; } usb_ed_t; @@ -368,6 +334,8 @@ ohci_set_interrupt(usb_t *dev, uint8_t bit) dev->ohci_mmio[OHCI_HcInterruptStatus].b[0] |= bit; + /* TODO: Does setting UnrecoverableError also assert PERR# on any emulated USB chipsets? */ + ohci_update_irq(dev); } @@ -412,10 +380,136 @@ static int ohci_copy_td_output(usb_t* dev, usb_td_t *td, return 0; } +#define OHCI_TD_DIR(val) ((val >> 19) & 3) +#define OHCI_ED_DIR(val) ((val >> 11) & 3) + uint8_t ohci_service_transfer_desc(usb_t* dev, usb_ed_t* endpoint_desc) { + uint32_t td_addr = endpoint_desc->HeadP & ~(0xf); + usb_td_t td; + uint8_t dir, pid_token; + uint32_t len = 0, pktlen = 0; + uint32_t actual_length = 0; + uint32_t i = 0; + uint8_t device_result = 0; + usb_device_t* target = NULL; + dma_bm_read(td_addr, (uint8_t*)&td, sizeof(usb_td_t), 4); + + switch (dir = OHCI_ED_DIR(endpoint_desc->Control)) { + case 1: + case 2: + break; + default: + dir = OHCI_TD_DIR(td.Control); + break; + } + + switch (dir) { + case 0: /* Setup */ + pid_token = USB_PID_SETUP; + break; + case 1: /* OUT */ + pid_token = USB_PID_OUT; + break; + case 2: /* IN */ + pid_token = USB_PID_IN; + break; + } + + if (td.CBP && td.BE) { + if ((td.CBP & 0xfffff000) != (td.BE & 0xfffff000)) { + len = (td.BE & 0xfff) + 0x1001 - (td.CBP & 0xfff); + } else { + if (td.CBP > td.BE) { + ohci_set_interrupt(dev, OHCI_HcInterruptEnable_UE); + return 1; + } + + len = (td.BE - td.CBP) + 1; + } + if (len > sizeof(dev->ohci_usb_buf)) { + len = sizeof(dev->ohci_usb_buf); + } + + pktlen = len; + if (len && pid_token != USB_PID_IN) { + pktlen = (endpoint_desc->Control >> 16) & 0xFFF; + if (pktlen > len) { + pktlen = len; + } + ohci_copy_td_output(dev, &td, dev->ohci_usb_buf, pktlen); + } + } + + for (i = 0; i < 2; i++) { + if (!dev->ohci_devices[i]) + continue; + + assert(dev->ohci_devices[i]->device_get_address != NULL); + + if (dev->ohci_devices[i]->device_get_address(dev->ohci_devices[i]->priv) != (endpoint_desc->Control & 0x7f)) + continue; + + target = dev->ohci_devices[i]; + break; + } + + if (!target) + return 1; + + device_result = target->device_process(target->priv, dev->ohci_usb_buf, &actual_length, pid_token, (endpoint_desc->Control & 0x780) >> 7, !(endpoint_desc->Control & (1 << 18))); + + if ((actual_length == pktlen) || (pid_token == USB_PID_IN && (endpoint_desc->Control & (1 << 18)) && device_result == USB_ERROR_NO_ERROR)) { + if (len == actual_length) { + td.CBP = 0; + } else { + if ((td.CBP & 0xfff) + actual_length > 0xfff) { + td.CBP = (td.BE & ~0xfff) + ((td.CBP + actual_length) & 0xfff); + } else { + td.CBP += actual_length; + } + } + + td.Control |= (1 << 25); /* dataToggle[1] */ + td.Control ^= (1 << 24); /* dataToggle[0] */ + td.Control &= ~0xFC000000; /* Set both ErrorCount and ConditionCode to 0. */ + + if (pid_token != USB_PID_IN && len != actual_length) { + goto exit_no_retire; + } + + endpoint_desc->HeadP &= ~0x2; + if (td.Control & (1 << 24)) { + endpoint_desc->HeadP |= 0x2; + } + } else { + if (actual_length != 0xFFFFFFFF && actual_length >= 0) { + td.Control &= ~0xF0000000; + td.Control |= 0x90000000; + } else { + switch (device_result) { + case USB_ERROR_NAK: + return 1; + } + dev->ohci_interrupt_counter = 0; + } + + endpoint_desc->HeadP |= 0x1; + } + + endpoint_desc->HeadP &= 0xf; + endpoint_desc->HeadP |= td.NextTD & ~0xf; + td.NextTD = dev->ohci_mmio[OHCI_HcDoneHead].l; + dev->ohci_mmio[OHCI_HcDoneHead].l = td_addr; + i = (td.Control >> 21) & 7; + if (i < dev->ohci_interrupt_counter) { + dev->ohci_interrupt_counter = i; + } +exit_no_retire: + dma_bm_write(td_addr, (uint8_t*)&td, sizeof(usb_td_t), 4); + return !(td.Control & 0xF0000000); } uint8_t @@ -435,13 +529,15 @@ ohci_service_endpoint_desc(usb_t* dev, uint32_t head) next = endpoint_desc.NextED & ~(0xFu); - if (endpoint_desc.flags.Skip || endpoint_desc.flags_2.Halted) + if ((endpoint_desc.Control & (1 << 13)) || (endpoint_desc.HeadP & (1 << 0))) continue; - if (endpoint_desc.flags.Format) { + if (endpoint_desc.Control & 0x8000) { fatal("OHCI: Isochronous transfers not implemented!\n"); } + active = 1; + while ((endpoint_desc.HeadP & ~(0xFu)) != endpoint_desc.TailP) { ohci_service_transfer_desc(dev, &endpoint_desc); } @@ -549,6 +645,23 @@ ohci_port_reset_callback_2(void* priv) dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] |= 0x10; } +static void +ohci_soft_reset(usb_t* dev) +{ + uint32_t old_HcControl = (dev->ohci_mmio[OHCI_HcControl].l & 0x100) | 0xc0; + memset(dev->ohci_mmio, 0x00, 4096); + dev->ohci_mmio[OHCI_HcRevision].b[0] = 0x10; + dev->ohci_mmio[OHCI_HcRevision].b[1] = 0x01; + dev->ohci_mmio[OHCI_HcRhDescriptorA].b[0] = 0x02; + dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] = 0x02; + dev->ohci_mmio[OHCI_HcFmInterval].l = 0x27782edf; /* FrameInterval = 11999, FSLargestDataPacket = 10104 */ + dev->ohci_mmio[OHCI_HcLSThreshold].l = 0x628; + dev->ohci_mmio[OHCI_HcInterruptEnable].l |= (1 << 31); + dev->ohci_mmio[OHCI_HcControl].l = old_HcControl; + dev->ohci_interrupt_counter = 7; + ohci_update_irq(dev); +} + static void ohci_mmio_write(uint32_t addr, uint8_t val, void *p) { @@ -563,9 +676,19 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p) switch (addr) { case OHCI_aHcControl: + old = dev->ohci_mmio[OHCI_HcControl].b[0]; if ((val & 0xc0) == 0x00) { /* UsbReset */ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] = dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] = 0x16; + for (int i = 0; i < 2; i++) { + if (dev->ohci_devices[i]) { + dev->ohci_devices[i]->device_reset(dev->ohci_devices[i]->priv); + } + } + } else if ((val & 0xc0) == 0x80 && (old & 0xc0) != (val & 0xc0)) { + dev->ohci_mmio[OHCI_HcFmRemaining].l = 0; + dev->ohci_initial_start = 1; + timer_on_auto(&dev->ohci_frame_timer, 1000.); } break; case OHCI_aHcCommandStatus: @@ -578,10 +701,7 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p) /* bit HostControllerReset must be cleared for the controller to be seen as initialized */ if (val & 0x01) { - memset(dev->ohci_mmio, 0x00, 4096); - dev->ohci_mmio[OHCI_HcRevision].b[0] = 0x10; - dev->ohci_mmio[OHCI_HcRevision].b[1] = 0x01; - dev->ohci_mmio[OHCI_HcRhDescriptorA].b[0] = 0x02; + ohci_soft_reset(dev); val &= ~0x01; } break; @@ -722,6 +842,8 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p) if (old & 0x01) { dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x10; timer_on_auto(&dev->ohci_port_reset_timer[(addr - OHCI_aHcRhPortStatus1) / 4], 10000.); + if (dev->ohci_devices[(addr - OHCI_aHcRhPortStatus1) >> 2]) + dev->ohci_devices[(addr - OHCI_aHcRhPortStatus1) >> 2]->device_reset(dev->ohci_devices[(addr - OHCI_aHcRhPortStatus1) >> 2]->priv); } else dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x01; } @@ -817,13 +939,54 @@ ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3, uint8_t usb_attach_device(usb_t *dev, usb_device_t* device, uint8_t bus_type) { + switch (bus_type) { + case USB_BUS_OHCI: + { + for (int i = 0; i < 2; i++) { + if (!dev->ohci_devices[i]) { + dev->ohci_devices[i] = device; + dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[0] |= 0x1; + dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[2] |= 0x1; + if ((dev->ohci_mmio[OHCI_HcControl].b[0] & 0xc0) == 0xc0) { + ohci_set_interrupt(dev, OHCI_HcInterruptEnable_RD); + } + ohci_set_interrupt(dev, OHCI_HcInterruptEnable_RHSC); + return i; + } + } + } + break; + } return 255; } void usb_detach_device(usb_t *dev, uint8_t port, uint8_t bus_type) { - /* Unused. */ + switch (bus_type) { + case USB_BUS_OHCI: + { + for (int i = 0; i < 2; i++) { + if (dev->ohci_devices[i]) { + uint32_t old = dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].l; + dev->ohci_devices[i] = NULL; + if (dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[0] & 0x1) { + dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[0] &= ~0x1; + dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[2] |= 0x1; + } + if (dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[0] & 0x2) { + dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[0] &= ~0x2; + dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[2] |= 0x2; + } + if (old != dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].l) + ohci_set_interrupt(dev, OHCI_HcInterruptEnable_RHSC); + return; + } + } + } + break; + } + return; } static void @@ -835,11 +998,8 @@ usb_reset(void *priv) dev->uhci_io[0x0c] = 0x40; dev->uhci_io[0x10] = dev->uhci_io[0x12] = 0x80; - memset(dev->ohci_mmio, 0x00, sizeof(dev->ohci_mmio)); - dev->ohci_mmio[OHCI_HcRevision].b[0] = 0x10; - dev->ohci_mmio[OHCI_HcRevision].b[1] = 0x01; - dev->ohci_mmio[OHCI_HcRhDescriptorA].b[0] = 0x02; - dev->ohci_mmio[OHCI_HcRhDescriptorA].b[1] = 0x02; + ohci_soft_reset(dev); + dev->ohci_mmio[OHCI_HcControl].l = 0x00; io_removehandler(dev->uhci_io_base, 0x20, uhci_reg_read, NULL, NULL, uhci_reg_write, uhci_reg_writew, NULL, dev); dev->uhci_enable = 0; From 2fac3e5dc59b26e0e5e43c25be7bd56e52e93d95 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 8 May 2023 17:13:34 +0600 Subject: [PATCH 06/25] usb: don't process EOF on very first SOF --- src/usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/usb.c b/src/usb.c index f6262e11f..1dd6aa02c 100644 --- a/src/usb.c +++ b/src/usb.c @@ -552,7 +552,8 @@ void ohci_end_of_frame(usb_t* dev) { usb_hcca_t hcca; - /* TODO: Put endpoint and transfer descriptor processing here. */ + if (dev->ohci_initial_start) + return; dma_bm_read(dev->ohci_mmio[OHCI_HcHCCA].l, (uint8_t*)&hcca, sizeof(usb_hcca_t), 4); if (dev->ohci_mmio[OHCI_HcControl].l & OHCI_HcControl_PeriodicListEnable) { @@ -605,6 +606,7 @@ ohci_end_of_frame(usb_t* dev) void ohci_start_of_frame(usb_t* dev) { + dev->ohci_initial_start = 0; ohci_set_interrupt(dev, OHCI_HcInterruptEnable_SO); } From 50b0fe499086fa36b85ecc214fa5332a7c109945 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 8 May 2023 22:30:28 +0600 Subject: [PATCH 07/25] usb: Add ability to attach and detach devices for real --- src/include/86box/usb.h | 1 + src/usb.c | 50 +++++++++++++++++++++++++---------------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index b9497b92e..4dbec55c3 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -123,6 +123,7 @@ typedef struct /* Global variables. */ extern const device_t usb_device; +extern usb_t* usb_device_inst; /* Functions. */ extern void uhci_update_io_mapping(usb_t *dev, uint8_t base_l, uint8_t base_h, int enable); diff --git a/src/usb.c b/src/usb.c index 1dd6aa02c..2ef5bb895 100644 --- a/src/usb.c +++ b/src/usb.c @@ -129,6 +129,8 @@ enum OHCI_HcControl_BulkListEnable = 1 << 4 }; +usb_t* usb_device_inst = NULL; + static void usb_interrupt_ohci(usb_t *dev, uint32_t level) { @@ -851,8 +853,12 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p) } if (val & 0x08) dev->ohci_mmio[addr >> 2].b[addr & 3] &= ~0x04; - if (val & 0x04) - dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x04; + if (val & 0x04) { + if (old & 0x01) + dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x04; + else + dev->ohci_mmio[(addr + 2) >> 2].b[(addr + 2) & 3] |= 0x01; + } if (val & 0x02) { if (old & 0x01) dev->ohci_mmio[addr >> 2].b[addr & 3] |= 0x02; @@ -946,13 +952,16 @@ usb_attach_device(usb_t *dev, usb_device_t* device, uint8_t bus_type) { for (int i = 0; i < 2; i++) { if (!dev->ohci_devices[i]) { + uint32_t old = dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].l; dev->ohci_devices[i] = device; dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[0] |= 0x1; - dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[2] |= 0x1; if ((dev->ohci_mmio[OHCI_HcControl].b[0] & 0xc0) == 0xc0) { ohci_set_interrupt(dev, OHCI_HcInterruptEnable_RD); } - ohci_set_interrupt(dev, OHCI_HcInterruptEnable_RHSC); + if (old != dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].l) { + dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[2] |= 0x1; + ohci_set_interrupt(dev, OHCI_HcInterruptEnable_RHSC); + } return i; } } @@ -968,23 +977,24 @@ usb_detach_device(usb_t *dev, uint8_t port, uint8_t bus_type) switch (bus_type) { case USB_BUS_OHCI: { - for (int i = 0; i < 2; i++) { - if (dev->ohci_devices[i]) { - uint32_t old = dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].l; - dev->ohci_devices[i] = NULL; - if (dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[0] & 0x1) { - dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[0] &= ~0x1; - dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[2] |= 0x1; - } - if (dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[0] & 0x2) { - dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[0] &= ~0x2; - dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].b[2] |= 0x2; - } - if (old != dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * i)].l) - ohci_set_interrupt(dev, OHCI_HcInterruptEnable_RHSC); - return; + if (port > 2) + return; + if (dev->ohci_devices[port]) { + uint32_t old = dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * port)].l; + dev->ohci_devices[port] = NULL; + if (dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * port)].b[0] & 0x1) { + dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * port)].b[0] &= ~0x1; + dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * port)].b[2] |= 0x1; } + if (dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * port)].b[0] & 0x2) { + dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * port)].b[0] &= ~0x2; + dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * port)].b[2] |= 0x2; + } + if (old != dev->ohci_mmio[OHCI_HcRhPortStatus1 + (4 * port)].l) + ohci_set_interrupt(dev, OHCI_HcInterruptEnable_RHSC); + return; } + } break; } @@ -1046,6 +1056,8 @@ usb_init_ext(const device_t *info, void *params) usb_reset(dev); + usb_device_inst = dev; + return dev; } From efedd983eb89496b1ddcae6fb83227ee804014bc Mon Sep 17 00:00:00 2001 From: cold-brewed Date: Mon, 8 May 2023 13:05:01 -0400 Subject: [PATCH 08/25] network: Add null network driver and make it the default mode --- src/include/86box/network.h | 6 +- src/network/CMakeLists.txt | 2 +- src/network/net_null.c | 224 ++++++++++++++++++++++++++++++++++ src/network/network.c | 48 ++++++-- src/qt/qt_mediamenu.cpp | 2 +- src/qt/qt_settingsnetwork.cpp | 9 +- src/win/languages/dialogs.rc | 8 +- src/win/win_settings.c | 2 +- 8 files changed, 277 insertions(+), 24 deletions(-) create mode 100644 src/network/net_null.c diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 4f514d1ac..a49193de0 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -48,7 +48,7 @@ #include /* Network provider types. */ -#define NET_TYPE_NONE 0 /* networking disabled */ +#define NET_TYPE_NONE 0 /* use the null network driver */ #define NET_TYPE_SLIRP 1 /* use the SLiRP port forwarder */ #define NET_TYPE_PCAP 2 /* use the (Win)Pcap API */ #define NET_TYPE_VDE 3 /* use the VDE plug API */ @@ -57,6 +57,7 @@ /* Queue size must be a power of 2 */ #define NET_QUEUE_LEN 16 #define NET_QUEUE_LEN_MASK (NET_QUEUE_LEN - 1) +#define NET_QUEUE_COUNT 3 #define NET_CARD_MAX 4 #define NET_HOST_INTF_MAX 64 @@ -125,6 +126,7 @@ typedef struct netdrv_t { extern const netdrv_t net_pcap_drv; extern const netdrv_t net_slirp_drv; extern const netdrv_t net_vde_drv; +extern const netdrv_t net_null_drv; struct _netcard_t { const device_t *device; @@ -132,7 +134,7 @@ struct _netcard_t { struct netdrv_t host_drv; NETRXCB rx; NETSETLINKSTATE set_link_state; - netqueue_t queues[3]; + netqueue_t queues[NET_QUEUE_COUNT]; netpkt_t queued_pkt; mutex_t *tx_mutex; mutex_t *rx_mutex; diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt index c6178a790..94e066a19 100644 --- a/src/network/CMakeLists.txt +++ b/src/network/CMakeLists.txt @@ -14,7 +14,7 @@ # set(net_sources) list(APPEND net_sources network.c net_pcap.c net_slirp.c net_dp8390.c net_3c501.c - net_3c503.c net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c net_event.c) + net_3c503.c net_ne2000.c net_pcnet.c net_wd8003.c net_plip.c net_event.c net_null.c) option(SLIRP_EXTERNAL "Link against the system-provided libslirp library" OFF) mark_as_advanced(SLIRP_EXTERNAL) diff --git a/src/network/net_null.c b/src/network/net_null.c new file mode 100644 index 000000000..e69b4acb6 --- /dev/null +++ b/src/network/net_null.c @@ -0,0 +1,224 @@ +/* +* 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. +* +* Null network driver +* +* +* +* Authors: cold-brewed +* +* Copyright 2023 The 86Box development team +*/ + +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include +# include +#else +# include +#endif + +#define HAVE_STDARG_H +#include <86box/86box.h> +#include <86box/device.h> +#include <86box/thread.h> +#include <86box/timer.h> +#include <86box/network.h> +#include <86box/net_event.h> + +enum { + NET_EVENT_STOP = 0, + NET_EVENT_TX, + NET_EVENT_RX, + NET_EVENT_MAX +}; + +/* Special define for the windows portion. Because we are not interested + * in NET_EVENT_RX for the null driver, we only need to poll up to + * NET_EVENT_TX. NET_EVENT_RX gives us a different NET_EVENT_MAX + * excluding NET_EVENT_RX. */ +#define NET_EVENT_TX_MAX NET_EVENT_RX + +#define NULL_PKT_BATCH NET_QUEUE_LEN + +typedef struct { + uint8_t mac_addr[6]; + netcard_t *card; + thread_t *poll_tid; + net_evt_t tx_event; + net_evt_t stop_event; + netpkt_t pkt; + netpkt_t pktv[NULL_PKT_BATCH]; +} net_null_t; + +#ifdef ENABLE_NET_NULL_LOG +int net_null_do_log = ENABLE_NET_NULL_LOG; + +static void +net_null_log(const char *fmt, ...) +{ + va_list ap; + + if (net_null_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define net_null_log(fmt, ...) +#endif + +#ifdef _WIN32 +static void +net_null_thread(void *priv) +{ + net_null_t *net_null = (net_null_t *) priv; + + net_null_log("Null Network: polling started.\n"); + + HANDLE events[NET_EVENT_TX_MAX]; + events[NET_EVENT_STOP] = net_event_get_handle(&net_null->stop_event); + events[NET_EVENT_TX] = net_event_get_handle(&net_null->tx_event); + + bool run = true; + + while (run) { + int ret = WaitForMultipleObjects(NET_EVENT_TX_MAX, events, FALSE, INFINITE); + + switch (ret - WAIT_OBJECT_0) { + case NET_EVENT_STOP: + net_event_clear(&net_null->stop_event); + run = false; + break; + + case NET_EVENT_TX: + net_event_clear(&net_null->tx_event); + int packets = network_tx_popv(net_null->card, net_null->pktv, NULL_PKT_BATCH); + for (int i = 0; i < packets; i++) { + net_null_log("Null Network: Ignoring TX packet (%d bytes)\n", net_null->pktv[i].len); + } + break; + + default: + net_null_log("Null Network: Unknown event.\n"); + break; + } + } + + net_null_log("Null Network: polling stopped.\n"); +} +#else +static void +net_null_thread(void *priv) +{ + net_null_t *net_null = (net_null_t *) priv; + + net_null_log("Null Network: polling started.\n"); + + struct pollfd pfd[NET_EVENT_MAX]; + pfd[NET_EVENT_STOP].fd = net_event_get_fd(&net_null->stop_event); + pfd[NET_EVENT_STOP].events = POLLIN | POLLPRI; + + pfd[NET_EVENT_TX].fd = net_event_get_fd(&net_null->tx_event); + pfd[NET_EVENT_TX].events = POLLIN | POLLPRI; + + while (1) { + poll(pfd, NET_EVENT_MAX, -1); + + if (pfd[NET_EVENT_STOP].revents & POLLIN) { + net_event_clear(&net_null->stop_event); + break; + } + + if (pfd[NET_EVENT_TX].revents & POLLIN) { + net_event_clear(&net_null->tx_event); + + int packets = network_tx_popv(net_null->card, net_null->pktv, NULL_PKT_BATCH); + for (int i = 0; i < packets; i++) { + net_null_log("Null Network: Ignoring TX packet (%d bytes)\n", net_null->pktv[i].len); + } + } + } + + net_null_log("Null Network: polling stopped.\n"); +} +#endif + +void * +net_null_init(const netcard_t *card, const uint8_t *mac_addr, void *priv) +{ + net_null_log("Null Network: Init\n"); + + net_null_t *net_null = calloc(1, sizeof(net_null_t)); + net_null->card = (netcard_t *) card; + memcpy(net_null->mac_addr, mac_addr, sizeof(net_null->mac_addr)); + + for (int i = 0; i < NULL_PKT_BATCH; i++) { + net_null->pktv[i].data = calloc(1, NET_MAX_FRAME); + } + net_null->pkt.data = calloc(1, NET_MAX_FRAME); + + net_event_init(&net_null->tx_event); + net_event_init(&net_null->stop_event); + net_null->poll_tid = thread_create(net_null_thread, net_null); + + return net_null; +} + + + +void +net_null_in_available(void *priv) +{ + net_null_t *net_null = (net_null_t *) priv; + net_event_set(&net_null->tx_event); +} + +void +net_null_close(void *priv) +{ + if (!priv) + return; + + net_null_t *net_null = (net_null_t *) priv; + + net_null_log("Null Network: closing.\n"); + + /* Tell the thread to terminate. */ + net_event_set(&net_null->stop_event); + + /* Wait for the thread to finish. */ + net_null_log("Null Network: waiting for thread to end...\n"); + thread_wait(net_null->poll_tid); + net_null_log("Null Network: thread ended\n"); + + for (int i = 0; i < NULL_PKT_BATCH; i++) { + free(net_null->pktv[i].data); + } + free(net_null->pkt.data); + + net_event_close(&net_null->tx_event); + net_event_close(&net_null->stop_event); + + free(net_null); +} + +const netdrv_t net_null_drv = { + &net_null_in_available, + &net_null_init, + &net_null_close, + NULL +}; \ No newline at end of file diff --git a/src/network/network.c b/src/network/network.c index ce81fcc93..a4f1369ed 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -442,13 +442,12 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_lin card->card_num = net_card_current; card->byte_period = NET_PERIOD_10M; - for (int i = 0; i < 3; i++) { + for (int i = 0; i < NET_QUEUE_COUNT; i++) { network_queue_init(&card->queues[i]); } switch (net_cards_conf[net_card_current].net_type) { case NET_TYPE_SLIRP: - default: card->host_drv = net_slirp_drv; card->host_drv.priv = card->host_drv.init(card, mac, NULL); break; @@ -463,18 +462,45 @@ network_attach(void *card_drv, uint8_t *mac, NETRXCB rx, NETSETLINKSTATE set_lin card->host_drv.priv = card->host_drv.init(card, mac, net_cards_conf[net_card_current].host_dev_name); break; #endif + default: + card->host_drv.priv = NULL; + break; } + // Use null driver on: + // * No specific driver selected (card->host_drv.priv is set to null above) + // * Failure to init a specific driver (in which case card->host_drv.priv is null) if (!card->host_drv.priv) { - thread_close_mutex(card->tx_mutex); - thread_close_mutex(card->rx_mutex); - for (int i = 0; i < 3; i++) { - network_queue_clear(&card->queues[i]); + + if(net_cards_conf[net_card_current].net_type != NET_TYPE_NONE) { + // We're here because of a failure + // Placeholder to display a msgbox about falling back to null + ui_msgbox(MBX_ERROR | MBX_ANSI, "Network driver initialization failed. Falling back to NULL driver."); + } + + // Init null driver + card->host_drv = net_null_drv; + card->host_drv.priv = card->host_drv.init(card, mac, NULL); + // Set link state to disconnected by default + network_connect(card->card_num, 0); + ui_sb_update_icon_state(SB_NETWORK | card->card_num, 1); + + // If null fails, something is very wrong + // Clean up and fatal + if(!card->host_drv.priv) { + thread_close_mutex(card->tx_mutex); + thread_close_mutex(card->rx_mutex); + for (int i = 0; i < NET_QUEUE_COUNT; i++) { + network_queue_clear(&card->queues[i]); + } + + free(card->queued_pkt.data); + free(card); + // Placeholder - insert the error message + fatal("Error initializing the network device: Null driver initialization failed"); + return NULL; } - free(card->queued_pkt.data); - free(card); - return NULL; } timer_add(&card->timer, network_rx_queue, card, 0); @@ -491,7 +517,7 @@ netcard_close(netcard_t *card) thread_close_mutex(card->tx_mutex); thread_close_mutex(card->rx_mutex); - for (int i = 0; i < 3; i++) { + for (int i = 0; i < NET_QUEUE_COUNT; i++) { network_queue_clear(&card->queues[i]); } @@ -641,7 +667,7 @@ network_dev_to_id(char *devname) int network_dev_available(int id) { - int available = (net_cards_conf[id].device_num > 0) && (net_cards_conf[id].net_type != NET_TYPE_NONE); + int available = (net_cards_conf[id].device_num > 0); if ((net_cards_conf[id].net_type == NET_TYPE_PCAP && (network_dev_to_id(net_cards_conf[id].host_dev_name) <= 0))) available = 0; diff --git a/src/qt/qt_mediamenu.cpp b/src/qt/qt_mediamenu.cpp index 841cd3053..26169b0d0 100644 --- a/src/qt/qt_mediamenu.cpp +++ b/src/qt/qt_mediamenu.cpp @@ -849,7 +849,7 @@ MediaMenu::nicUpdateMenu(int i) if (!netMenus.contains(i)) return; - QString netType = tr("None"); + QString netType = tr("Null Driver"); switch (net_cards_conf[i].net_type) { case NET_TYPE_SLIRP: netType = "SLiRP"; diff --git a/src/qt/qt_settingsnetwork.cpp b/src/qt/qt_settingsnetwork.cpp index ceb4810bc..acc7ebfc4 100644 --- a/src/qt/qt_settingsnetwork.cpp +++ b/src/qt/qt_settingsnetwork.cpp @@ -40,9 +40,10 @@ SettingsNetwork::enableElements(Ui::SettingsNetwork *ui) auto *socket_line = findChild(QString("socketVDENIC%1").arg(i + 1)); int netType = net_type_cbox->currentData().toInt(); - bool adaptersEnabled = netType == NET_TYPE_SLIRP - || NET_TYPE_VDE - || (netType == NET_TYPE_PCAP && intf_cbox->currentData().toInt() > 0); + bool adaptersEnabled = netType == NET_TYPE_NONE + || netType == NET_TYPE_SLIRP + || netType == NET_TYPE_VDE + || (netType == NET_TYPE_PCAP && intf_cbox->currentData().toInt() > 0); intf_cbox->setEnabled(net_type_cbox->currentData().toInt() == NET_TYPE_PCAP); nic_cbox->setEnabled(adaptersEnabled); @@ -133,7 +134,7 @@ SettingsNetwork::onCurrentMachineChanged(int machineId) cbox = findChild(QString("comboBoxNet%1").arg(i + 1)); model = cbox->model(); removeRows = model->rowCount(); - Models::AddEntry(model, tr("None"), NET_TYPE_NONE); + Models::AddEntry(model, tr("Null Driver"), NET_TYPE_NONE); Models::AddEntry(model, "SLiRP", NET_TYPE_SLIRP); if (network_ndev > 1) { diff --git a/src/win/languages/dialogs.rc b/src/win/languages/dialogs.rc index 3286ee2be..876fd8939 100644 --- a/src/win/languages/dialogs.rc +++ b/src/win/languages/dialogs.rc @@ -408,7 +408,7 @@ BEGIN CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 2) + 20, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT COMBOBOX IDC_COMBO_NET1_TYPE, - CFG_HMARGIN, 28, 32, CFG_COMBO_HEIGHT, + CFG_HMARGIN, 28, 48, CFG_COMBO_HEIGHT, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_COMBO_PCAP1, @@ -422,7 +422,7 @@ BEGIN CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 3) + 50, 27, CFG_BTN_WIDTH, CFG_BTN_HEIGHT COMBOBOX IDC_COMBO_NET2_TYPE, - CFG_HMARGIN, 49, 32, CFG_COMBO_HEIGHT, + CFG_HMARGIN, 49, 48, CFG_COMBO_HEIGHT, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_COMBO_PCAP2, @@ -436,7 +436,7 @@ BEGIN CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 3) + 50, 48, CFG_BTN_WIDTH, CFG_BTN_HEIGHT COMBOBOX IDC_COMBO_NET3_TYPE, - CFG_HMARGIN, 70, 32, CFG_COMBO_HEIGHT, + CFG_HMARGIN, 70, 48, CFG_COMBO_HEIGHT, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_COMBO_PCAP3, @@ -450,7 +450,7 @@ BEGIN CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 3) + 50, 69, CFG_BTN_WIDTH, CFG_BTN_HEIGHT COMBOBOX IDC_COMBO_NET4_TYPE, - CFG_HMARGIN, 91, 32, CFG_COMBO_HEIGHT, + CFG_HMARGIN, 91, 48, CFG_COMBO_HEIGHT, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_COMBO_PCAP4, diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 333888a65..2936f6639 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -2062,7 +2062,7 @@ win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) lptsTemp = (LPTSTR) malloc(512 * sizeof(WCHAR)); for (uint8_t i = 0; i < NET_CARD_MAX; i++) { - settings_add_string(hdlg, IDC_COMBO_NET1_TYPE + i, (LPARAM) L"None"); + settings_add_string(hdlg, IDC_COMBO_NET1_TYPE + i, (LPARAM) L"Null Driver"); settings_add_string(hdlg, IDC_COMBO_NET1_TYPE + i, (LPARAM) L"SLiRP"); settings_add_string(hdlg, IDC_COMBO_NET1_TYPE + i, (LPARAM) L"PCap"); settings_set_cur_sel(hdlg, IDC_COMBO_NET1_TYPE + i, temp_net_type[i]); From 41ca38341c31d2a4ad433f5f92e9093b9ac2184a Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Mon, 8 May 2023 23:27:52 +0600 Subject: [PATCH 09/25] usb: Structure definitions for USB device descriptors --- src/include/86box/usb.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index 4dbec55c3..d94d8a137 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -107,6 +107,34 @@ typedef struct uint8_t bDescriptorType; } usb_desc_base_t; +typedef struct +{ + usb_desc_base_t base; + + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} usb_desc_interface_t; + +typedef struct +{ + usb_desc_base_t base; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint8_t wMaxPacketSize; + uint8_t bInterval; +} usb_desc_endpoint_t; + +typedef struct +{ + usb_desc_base_t base; + uint16_t bString[]; +} usb_desc_string_t; + typedef struct { usb_desc_base_t base; @@ -117,6 +145,8 @@ typedef struct uint8_t iConfiguration; uint8_t bmAttributes; uint8_t bMaxPower; + + usb_desc_interface_t interface_descs[]; } usb_desc_conf_t; #pragma pack(pop) From b86622c725b69881cb13b4a62b70842f29520696 Mon Sep 17 00:00:00 2001 From: cold-brewed Date: Mon, 8 May 2023 13:40:35 -0400 Subject: [PATCH 10/25] network: Add null network driver to win32 makefile --- src/win/Makefile.mingw | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 0aa08d267..4b60cb930 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -669,7 +669,8 @@ NETOBJ := network.o \ net_dp8390.o net_3c501.o \ net_3c503.o net_ne2000.o \ net_pcnet.o net_wd8003.o \ - net_plip.o net_event.o + net_plip.o net_event.o \ + net_null.o PRINTOBJ := png.o prt_cpmap.o \ prt_escp.o prt_text.o prt_ps.o From 8f7752e63cb52d4af2bda4eaa7e7be870682670e Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Tue, 9 May 2023 00:14:15 +0600 Subject: [PATCH 11/25] usb: Add a bit of logging --- src/usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/usb.c b/src/usb.c index 2ef5bb895..894e0a864 100644 --- a/src/usb.c +++ b/src/usb.c @@ -681,6 +681,9 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p) switch (addr) { case OHCI_aHcControl: old = dev->ohci_mmio[OHCI_HcControl].b[0]; +#ifdef ENABLE_USB_LOG + usb_log("OHCI: OHCI state 0x%X\n", (val & 0xc0)); +#endif if ((val & 0xc0) == 0x00) { /* UsbReset */ dev->ohci_mmio[OHCI_HcRhPortStatus1].b[2] = dev->ohci_mmio[OHCI_HcRhPortStatus2].b[2] = 0x16; From 4704e4e84755e1e1c0e10650b11616b4497b4e24 Mon Sep 17 00:00:00 2001 From: cold-brewed Date: Tue, 9 May 2023 10:53:06 -0400 Subject: [PATCH 12/25] vde: Don't fatal() in network driver --- src/network/net_vde.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/net_vde.c b/src/network/net_vde.c index 904b2789a..9bed78a9e 100644 --- a/src/network/net_vde.c +++ b/src/network/net_vde.c @@ -280,7 +280,7 @@ void *net_vde_init(const netcard_t *card, const uint8_t *mac_addr, void *priv) { // TODO: Once there is a solution for the mentioned crash, this should be removed // and/or replaced by proper error handling code. //- - fatal("Could not open the specified VDE socket (%s). Please fix your networking configuration.", socket_name); + // fatal("Could not open the specified VDE socket (%s). Please fix your networking configuration.", socket_name); // It makes no sense to issue this warning since the program will crash anyway... // ui_msgbox_header(MBX_WARNING, (wchar_t *) IDS_2167, (wchar_t *) IDS_2168); return NULL; From 0ab0caf5b16c324409f0a736afc8350ea2bad9f4 Mon Sep 17 00:00:00 2001 From: cold-brewed Date: Tue, 9 May 2023 13:11:00 -0400 Subject: [PATCH 13/25] vde: Properly initialize a variable and fix bit width --- src/include/86box/network.h | 6 +++--- src/network/network.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 4f514d1ac..ccd6f2f70 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -150,9 +150,9 @@ typedef struct { } netdev_t; typedef struct { - int has_slirp: 1; - int has_pcap: 1; - int has_vde: 1; + int has_slirp; + int has_pcap; + int has_vde; } network_devmap_t; diff --git a/src/network/network.c b/src/network/network.c index ce81fcc93..38f86f586 100644 --- a/src/network/network.c +++ b/src/network/network.c @@ -123,7 +123,7 @@ netcard_conf_t net_cards_conf[NET_CARD_MAX]; uint16_t net_card_current = 0; /* Global variables. */ -network_devmap_t network_devmap; +network_devmap_t network_devmap = {0}; int network_ndev; netdev_t network_devs[NET_HOST_INTF_MAX]; From d0845ccadeb360203693b13138c905446d273ee5 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 10 May 2023 17:09:13 +0600 Subject: [PATCH 14/25] usb: Infrastructure changes Make OHCI OwnershipChange work properly --- src/chipset/ali1543.c | 1 + src/chipset/ali6117.c | 1 - src/chipset/intel_piix.c | 1 + src/chipset/sis_5571.c | 1 + src/chipset/stpc.c | 1 + src/chipset/via_pipc.c | 1 + src/include/86box/usb.h | 96 ++++++++++++++++++++++++++++------------ src/usb.c | 4 +- 8 files changed, 76 insertions(+), 30 deletions(-) diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index 2e2f74305..26673edec 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -20,6 +20,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/timer.h> diff --git a/src/chipset/ali6117.c b/src/chipset/ali6117.c index 98451067a..796ca880f 100644 --- a/src/chipset/ali6117.c +++ b/src/chipset/ali6117.c @@ -30,7 +30,6 @@ #include <86box/pit.h> #include <86box/device.h> #include <86box/port_92.h> -#include <86box/usb.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/chipset.h> diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index 470978611..f550d9503 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -23,6 +23,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" diff --git a/src/chipset/sis_5571.c b/src/chipset/sis_5571.c index c158e2d63..a20f5fadd 100644 --- a/src/chipset/sis_5571.c +++ b/src/chipset/sis_5571.c @@ -20,6 +20,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c index 2e4b045f2..822f462ad 100644 --- a/src/chipset/stpc.c +++ b/src/chipset/stpc.c @@ -20,6 +20,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/mem.h> diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index c2abc4465..067b733a2 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -26,6 +26,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index d94d8a137..455282f71 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -23,6 +23,7 @@ extern "C" { #endif typedef struct usb_t usb_t; +typedef struct usb_device_t usb_device_t; enum usb_pid { @@ -39,22 +40,6 @@ enum usb_errors USB_ERROR_UNDERRUN = 3 }; -/* USB endpoint device struct. Incomplete and unused. */ -typedef struct -{ - uint16_t vendor_id; - uint16_t device_id; - - /* General-purpose function for I/O. Non-zero value indicates error. */ - uint8_t (*device_process)(void* priv, uint8_t* data, uint32_t *len, uint8_t pid_token, uint8_t endpoint, uint8_t underrun_not_allowed); - /* Device reset. */ - void (*device_reset)(void* priv); - /* Get address. */ - uint8_t (*device_get_address)(void* priv); - - void* priv; -} usb_device_t; - enum usb_bus_types { USB_BUS_OHCI = 0, @@ -107,6 +92,35 @@ typedef struct uint8_t bDescriptorType; } usb_desc_base_t; +typedef struct +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} usb_desc_setup_t; + +typedef struct +{ + usb_desc_base_t base; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} usb_desc_endpoint_t; + +typedef struct +{ + usb_desc_base_t base; + + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bDescriptorType; + uint16_t wDescriptorLength; +} usb_desc_hid_t; + typedef struct { usb_desc_base_t base; @@ -123,16 +137,7 @@ typedef struct typedef struct { usb_desc_base_t base; - uint8_t bEndpointAddress; - uint8_t bmAttributes; - uint8_t wMaxPacketSize; - uint8_t bInterval; -} usb_desc_endpoint_t; - -typedef struct -{ - usb_desc_base_t base; - uint16_t bString[]; + char16_t bString[]; } usb_desc_string_t; typedef struct @@ -145,12 +150,47 @@ typedef struct uint8_t iConfiguration; uint8_t bmAttributes; uint8_t bMaxPower; - - usb_desc_interface_t interface_descs[]; } usb_desc_conf_t; +typedef struct +{ + usb_desc_base_t base; + + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} usb_desc_device_t; + #pragma pack(pop) +/* USB endpoint device struct. Incomplete and unused. */ +typedef struct usb_device_t +{ + usb_desc_device_t device_desc; + struct { + usb_desc_conf_t conf_desc; + usb_desc_base_t* other_descs[16]; + } conf_desc_items; + + /* General-purpose function for I/O. Non-zero value indicates error. */ + uint8_t (*device_process)(void* priv, uint8_t* data, uint32_t *len, uint8_t pid_token, uint8_t endpoint, uint8_t underrun_not_allowed); + /* Device reset. */ + void (*device_reset)(void* priv); + /* Get address. */ + uint8_t (*device_get_address)(void* priv); + + void* priv; +} usb_device_t; + /* Global variables. */ extern const device_t usb_device; extern usb_t* usb_device_inst; diff --git a/src/usb.c b/src/usb.c index 894e0a864..5d661bd72 100644 --- a/src/usb.c +++ b/src/usb.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #define HAVE_STDARG_H #include <86box/86box.h> @@ -702,8 +703,9 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p) /* bit OwnershipChangeRequest triggers an ownership change (SMM <-> OS) */ if (val & 0x08) { dev->ohci_mmio[OHCI_HcInterruptStatus].b[3] = 0x40; - if ((dev->ohci_mmio[OHCI_HcInterruptEnable].b[3] & 0xc0) == 0xc0) + if ((dev->ohci_mmio[OHCI_HcInterruptEnable].b[3] & 0x40) == 0x40) { smi_raise(); + } } /* bit HostControllerReset must be cleared for the controller to be seen as initialized */ From 98ebfce4601df14b68634a4cce1a01eb7204bf51 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 10 May 2023 17:19:35 +0600 Subject: [PATCH 15/25] usb: Revert usage of uchar.h --- src/chipset/ali1543.c | 1 - src/chipset/intel_piix.c | 1 - src/chipset/sis_5571.c | 1 - src/chipset/stpc.c | 1 - src/chipset/via_pipc.c | 1 - src/include/86box/usb.h | 14 +++++++++++++- src/usb.c | 1 - 7 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/chipset/ali1543.c b/src/chipset/ali1543.c index 26673edec..2e2f74305 100644 --- a/src/chipset/ali1543.c +++ b/src/chipset/ali1543.c @@ -20,7 +20,6 @@ #include #include #include -#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/timer.h> diff --git a/src/chipset/intel_piix.c b/src/chipset/intel_piix.c index f550d9503..470978611 100644 --- a/src/chipset/intel_piix.c +++ b/src/chipset/intel_piix.c @@ -23,7 +23,6 @@ #include #include #include -#include #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" diff --git a/src/chipset/sis_5571.c b/src/chipset/sis_5571.c index a20f5fadd..c158e2d63 100644 --- a/src/chipset/sis_5571.c +++ b/src/chipset/sis_5571.c @@ -20,7 +20,6 @@ #include #include #include -#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> diff --git a/src/chipset/stpc.c b/src/chipset/stpc.c index 822f462ad..2e4b045f2 100644 --- a/src/chipset/stpc.c +++ b/src/chipset/stpc.c @@ -20,7 +20,6 @@ #include #include #include -#include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/mem.h> diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 067b733a2..c2abc4465 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -26,7 +26,6 @@ #include #include #include -#include #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index 455282f71..d0801b99c 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -92,6 +92,18 @@ typedef struct uint8_t bDescriptorType; } usb_desc_base_t; +enum usb_desc_setup_req_types +{ + USB_SETUP_TYPE_DEVICE = 0x0, + USB_SETUP_TYPE_INTERFACE = 0x1, + USB_SETUP_TYPE_ENDPOING = 0x2, + USB_SETUP_TYPE_OTHER = 0x3, +}; + +#define USB_SETUP_TYPE_MAX 0x1F + +#define USB_SETUP_DEV_TO_HOST 0x80 + typedef struct { uint8_t bmRequestType; @@ -137,7 +149,7 @@ typedef struct typedef struct { usb_desc_base_t base; - char16_t bString[]; + uint16_t bString[]; } usb_desc_string_t; typedef struct diff --git a/src/usb.c b/src/usb.c index 5d661bd72..fce5fe0b0 100644 --- a/src/usb.c +++ b/src/usb.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #define HAVE_STDARG_H #include <86box/86box.h> From 889392539666e87292cf2cf647c5c4559bbeabd7 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Wed, 10 May 2023 17:28:40 +0600 Subject: [PATCH 16/25] usb: Return early on invalid directions --- src/usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/usb.c b/src/usb.c index fce5fe0b0..85c2a6fc8 100644 --- a/src/usb.c +++ b/src/usb.c @@ -390,7 +390,7 @@ ohci_service_transfer_desc(usb_t* dev, usb_ed_t* endpoint_desc) { uint32_t td_addr = endpoint_desc->HeadP & ~(0xf); usb_td_t td; - uint8_t dir, pid_token; + uint8_t dir, pid_token = 255; uint32_t len = 0, pktlen = 0; uint32_t actual_length = 0; uint32_t i = 0; @@ -418,6 +418,8 @@ ohci_service_transfer_desc(usb_t* dev, usb_ed_t* endpoint_desc) case 2: /* IN */ pid_token = USB_PID_IN; break; + default: + return 1; } if (td.CBP && td.BE) { From 30ee26886986b543581c510329b901ab264db7cb Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 12 May 2023 01:44:54 -0400 Subject: [PATCH 17/25] LLVM doesn't support multiplication in rc macros --- src/win/languages/dialogs.rc | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/win/languages/dialogs.rc b/src/win/languages/dialogs.rc index 876fd8939..eb542a971 100644 --- a/src/win/languages/dialogs.rc +++ b/src/win/languages/dialogs.rc @@ -3,6 +3,8 @@ #define CFG_BTN_WIDTH 46 #define CFG_BTN_HEIGHT 14 #define CFG_PANE_LTEXT_PRI_WIDTH 85 +#define CFG_PANE_LTEXT_PRI_WIDTH_2 170 +#define CFG_PANE_LTEXT_PRI_WIDTH_3 255 #define CFG_PANE_LTEXT_HEIGHT 10 #define CFG_COMBO_BTN_WIDTH 212 #define CFG_COMBO_NOBTN_WIDTH CFG_COMBO_BTN_WIDTH + CFG_BTN_WIDTH + 8 @@ -405,7 +407,7 @@ BEGIN LTEXT STR_PCAP, IDT_PCAP, CFG_HMARGIN + CFG_PANE_LTEXT_PRI_WIDTH - 10, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT LTEXT STR_NET, IDT_NET, - CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 2) + 20, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT + CFG_HMARGIN + CFG_PANE_LTEXT_PRI_WIDTH_2 + 20, CFG_VMARGIN, CFG_PANE_LTEXT_PRI_WIDTH, CFG_PANE_LTEXT_HEIGHT COMBOBOX IDC_COMBO_NET1_TYPE, CFG_HMARGIN, 28, 48, CFG_COMBO_HEIGHT, @@ -416,10 +418,10 @@ BEGIN CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_COMBO_NET1, - CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 2) + 20, 28, 110, CFG_COMBO_HEIGHT, + CFG_HMARGIN + CFG_PANE_LTEXT_PRI_WIDTH_2 + 20, 28, 110, CFG_COMBO_HEIGHT, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_NET1, - CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 3) + 50, 27, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + CFG_HMARGIN + CFG_PANE_LTEXT_PRI_WIDTH_3 + 50, 27, CFG_BTN_WIDTH, CFG_BTN_HEIGHT COMBOBOX IDC_COMBO_NET2_TYPE, CFG_HMARGIN, 49, 48, CFG_COMBO_HEIGHT, @@ -430,10 +432,10 @@ BEGIN CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_COMBO_NET2, - CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 2) + 20, 49, 110, CFG_COMBO_HEIGHT, + CFG_HMARGIN + CFG_PANE_LTEXT_PRI_WIDTH_2 + 20, 49, 110, CFG_COMBO_HEIGHT, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_NET2, - CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 3) + 50, 48, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + CFG_HMARGIN + CFG_PANE_LTEXT_PRI_WIDTH_3 + 50, 48, CFG_BTN_WIDTH, CFG_BTN_HEIGHT COMBOBOX IDC_COMBO_NET3_TYPE, CFG_HMARGIN, 70, 48, CFG_COMBO_HEIGHT, @@ -444,10 +446,10 @@ BEGIN CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_COMBO_NET3, - CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 2) + 20, 70, 110, CFG_COMBO_HEIGHT, + CFG_HMARGIN + CFG_PANE_LTEXT_PRI_WIDTH_2 + 20, 70, 110, CFG_COMBO_HEIGHT, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_NET3, - CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 3) + 50, 69, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + CFG_HMARGIN + CFG_PANE_LTEXT_PRI_WIDTH_3 + 50, 69, CFG_BTN_WIDTH, CFG_BTN_HEIGHT COMBOBOX IDC_COMBO_NET4_TYPE, CFG_HMARGIN, 91, 48, CFG_COMBO_HEIGHT, @@ -458,10 +460,10 @@ BEGIN CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_COMBO_NET4, - CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 2) + 20, 91, 110, CFG_COMBO_HEIGHT, + CFG_HMARGIN + CFG_PANE_LTEXT_PRI_WIDTH_2 + 20, 91, 110, CFG_COMBO_HEIGHT, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON STR_CONFIGURE, IDC_CONFIGURE_NET4, - CFG_HMARGIN + (CFG_PANE_LTEXT_PRI_WIDTH * 3) + 50, 90, CFG_BTN_WIDTH, CFG_BTN_HEIGHT + CFG_HMARGIN + CFG_PANE_LTEXT_PRI_WIDTH_3 + 50, 90, CFG_BTN_WIDTH, CFG_BTN_HEIGHT END From e524b75352862375e34745cf1226b0456f088800 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 12 May 2023 00:41:45 -0400 Subject: [PATCH 18/25] Add support for sonarcloud --- .github/workflows/cmake.yml | 82 +++++++++++++++++++++++++++++++++---- sonar-project.properties | 12 ++++++ 2 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 sonar-project.properties diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 9041ca0fc..ab9cf96c7 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -30,6 +30,9 @@ jobs: runs-on: windows-2022 + env: + BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed + defaults: run: shell: msys2 {0} @@ -106,6 +109,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Install sonar-scanner and build-wrapper + uses: SonarSource/sonarcloud-github-c-cpp@v1 - name: Configure CMake run: >- @@ -117,7 +125,15 @@ jobs: -D STATIC_BUILD=${{ matrix.ui.static }} - name: Build - run: cmake --build build + run: | + build-wrapper-win-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build + + - name: Run sonar-scanner + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" - name: Generate package run: cmake --install build @@ -134,6 +150,7 @@ jobs: runs-on: windows-2022 env: + BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed VCPKG_BINARY_SOURCES: 'clear;nuget,GitHub,readwrite' strategy: @@ -209,6 +226,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Install sonar-scanner and build-wrapper + uses: SonarSource/sonarcloud-github-c-cpp@v1 - name: Configure CMake run: > @@ -229,13 +251,23 @@ jobs: - name: Reconfigure CMake if: matrix.ui.qt == 'on' - run: cmake clean build + run: | + cmake clean build - name: Build - run: cmake --build build + run: | + build-wrapper-win-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build + + - name: Run sonar-scanner + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" - name: Generate package - run: cmake --install build + run: | + cmake --install build - name: Upload artifact uses: actions/upload-artifact@v3 @@ -248,6 +280,9 @@ jobs: runs-on: ubuntu-22.04 + env: + BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed + strategy: fail-fast: true matrix: @@ -295,6 +330,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Install sonar-scanner and build-wrapper + uses: SonarSource/sonarcloud-github-c-cpp@v1 - name: Configure CMake run: >- @@ -305,10 +345,19 @@ jobs: -D QT=${{ matrix.ui.qt }} - name: Build - run: cmake --build build + run: | + build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build + + - name: Run sonar-scanner + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" - name: Generate package - run: cmake --install build + run: | + cmake --install build - name: Upload artifact uses: actions/upload-artifact@v3 @@ -321,6 +370,9 @@ jobs: runs-on: macos-11 + env: + BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed + strategy: fail-fast: true matrix: @@ -362,6 +414,11 @@ jobs: - name: Checkout repository uses: actions/checkout@v3 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + + - name: Install sonar-scanner and build-wrapper + uses: SonarSource/sonarcloud-github-c-cpp@v1 - name: Configure CMake run: >- @@ -375,10 +432,19 @@ jobs: -D OpenAL_ROOT=$(brew --prefix openal-soft) - name: Build - run: cmake --build build + run: | + build-wrapper-macosx-x86 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build + + - name: Run sonar-scanner + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: | + sonar-scanner --define sonar.cfamily.build-wrapper-output="${{ env.BUILD_WRAPPER_OUT_DIR }}" - name: Generate package - run: cmake --install build + run: | + cmake --install build - name: Upload artifact uses: actions/upload-artifact@v3 diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 000000000..9011c9954 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,12 @@ +sonar.projectKey=86Box_86Box +sonar.organization=86Box + +# This is the name and version displayed in the SonarCloud UI. +#sonar.projectName=86Box +#sonar.projectVersion=1.0 + +# Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. +#sonar.sources=. + +# Encoding of the source code. Default is default system encoding +#sonar.sourceEncoding=UTF-8 From aa9e88587628234c79aaf58de9094975fad4fed8 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 12 May 2023 01:02:03 -0400 Subject: [PATCH 19/25] Temporary till I figure out the problem with msys2 --- .github/workflows/cmake.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index ab9cf96c7..80abcf79b 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -126,9 +126,10 @@ jobs: - name: Build run: | - build-wrapper-win-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build + cmake --build build - name: Run sonar-scanner + if: 0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 7200fc1b4e7725d3531e2210c2225306d3238d95 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 12 May 2023 02:29:29 -0400 Subject: [PATCH 20/25] Disable running sonarcloud for now --- .github/workflows/cmake.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 80abcf79b..df09442e9 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -260,6 +260,7 @@ jobs: build-wrapper-win-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - name: Run sonar-scanner + if: 0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -350,6 +351,7 @@ jobs: build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - name: Run sonar-scanner + if: 0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -437,6 +439,7 @@ jobs: build-wrapper-macosx-x86 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - name: Run sonar-scanner + if: 0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From cde2f87213ee40a07c72c7c36c7a916737a20880 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 12 May 2023 02:33:34 -0400 Subject: [PATCH 21/25] Disable LLVM builds till we can fix them properly --- .github/workflows/cmake.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index df09442e9..3d8e477dd 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -147,6 +147,7 @@ jobs: llvm-windows: name: "Windows vcpkg/LLVM (${{ matrix.ui.name }}, ${{ matrix.build.name }}, ${{ matrix.dynarec.name }}, ${{ matrix.target.name }})" + if: 0 runs-on: windows-2022 From 248741ddbcbe1b1927e3c8af430390fae8e5aa9c Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 12 May 2023 02:39:45 -0400 Subject: [PATCH 22/25] Consistancy for GHA scripts --- .github/workflows/codeql.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 107755af6..69c877776 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -129,8 +129,8 @@ jobs: -D STATIC_BUILD=${{ matrix.ui.static }} - name: Build - run: cmake --build build - + run: | + cmake --build build - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 @@ -212,7 +212,8 @@ jobs: -D QT=${{ matrix.ui.qt }} - name: Build - run: cmake --build build + run: | + cmake --build build - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 @@ -290,7 +291,8 @@ jobs: -D OpenAL_ROOT=$(brew --prefix openal-soft) - name: Build - run: cmake --build build + run: | + cmake --build build - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 From 9289910f353c39bb4a1f685a9f6b9d18af5aab69 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 14 May 2023 10:38:47 -0400 Subject: [PATCH 23/25] Enable sonarcloud --- .github/workflows/cmake.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 3d8e477dd..49ea8c890 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -261,7 +261,7 @@ jobs: build-wrapper-win-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - name: Run sonar-scanner - if: 0 +# if: 0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -352,7 +352,7 @@ jobs: build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - name: Run sonar-scanner - if: 0 +# if: 0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} @@ -440,7 +440,7 @@ jobs: build-wrapper-macosx-x86 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build - name: Run sonar-scanner - if: 0 +# if: 0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} From 13b67fcc3544f385b3d0d8b71df7ffb546fe2175 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Sun, 14 May 2023 10:47:30 -0400 Subject: [PATCH 24/25] Fix sonar organization --- sonar-project.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonar-project.properties b/sonar-project.properties index 9011c9954..781fad035 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,5 +1,5 @@ sonar.projectKey=86Box_86Box -sonar.organization=86Box +sonar.organization=86box # This is the name and version displayed in the SonarCloud UI. #sonar.projectName=86Box From 4e994e1aef14f6cf085a68d4df6502280269e809 Mon Sep 17 00:00:00 2001 From: Jasmine Iwanek Date: Fri, 12 May 2023 20:49:02 -0400 Subject: [PATCH 25/25] Fix PCjr memory steps --- src/machine/machine_table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index f089fe93e..bb91e6977 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -303,7 +303,7 @@ const machine_t machines[] = { .ram = { .min = 128, .max = 640, - .step = 128 + .step = 64 }, .nvrmask = 0, .kbc_device = NULL, /* TODO: No specific kbd_device yet */