From 3f461afeeb25194c359a6ba764f1966d0bbd0662 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 5 May 2023 00:28:08 +0600 Subject: [PATCH 1/9] usb: start hooking up USB interrupts to chipsets --- src/chipset/sis_5571.c | 37 ++++++++++++++++++++++++++++++++++++- src/include/86box/usb.h | 2 ++ src/usb.c | 3 +++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/chipset/sis_5571.c b/src/chipset/sis_5571.c index 0f77a1a07..aa8ea62f3 100644 --- a/src/chipset/sis_5571.c +++ b/src/chipset/sis_5571.c @@ -83,6 +83,8 @@ typedef struct sis_5571_t { smram_t *smram; usb_t *usb; + usb_params_t usb_params; + } sis_5571_t; static void @@ -638,6 +640,36 @@ pci_isa_bridge_read(int func, int addr, void *priv) } } +static void +sis_5571_usb_raise_interrupt(usb_t* usb, void* priv) +{ + sis_5571_t *dev = (sis_5571_t *) priv; + + if (dev->pci_conf_sb[0][0x68] & 0x80) { + /* TODO: Is the normal PCI interrupt inhibited when USB IRQ remapping is enabled? */ + switch (dev->pci_conf_sb[0][0x68] & 0x0F) { + case 0x00: + case 0x01: + case 0x02: + case 0x08: + case 0x0d: + break; + default: + picint(1 << dev->pci_conf_sb[0][0x68] & 0x0F); + break; + } + } else { + pci_set_irq(dev->sb_pci_slot, PCI_INTA); + } +} + +static uint8_t +sis_5571_usb_handle_smi(usb_t* usb, void* priv) +{ + /* Left unimplemented for now. */ + return 1; +} + static void sis_5571_reset(void *priv) { @@ -722,7 +754,10 @@ sis_5571_init(const device_t *info) dev->ide_drive[1] = device_add_inst(&sff8038i_device, 2); /* USB */ - dev->usb = device_add(&usb_device); + dev->usb_params.parent_priv = dev; + dev->usb_params.raise_interrupt = sis_5571_usb_raise_interrupt; + dev->usb_params.smi_handle = sis_5571_usb_handle_smi; + dev->usb = device_add_parameters(&usb_device, &dev->usb_params); sis_5571_reset(dev); diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index cf5938a3d..7860ada3b 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -28,6 +28,8 @@ typedef struct usb_t usb_t; typedef struct { void (*raise_interrupt)(usb_t*, void*); + /* Handle (but do not raise) SMI. Returns 1 if SMI can be raised, 0 otherwise. */ + uint8_t (*smi_handle)(usb_t*, void*); void* parent_priv; } usb_params_t; diff --git a/src/usb.c b/src/usb.c index 7dd8341c3..03fe8a9a6 100644 --- a/src/usb.c +++ b/src/usb.c @@ -80,6 +80,9 @@ static void usb_interrupt_ohci(usb_t* usb) { if (usb->ohci_mmio[OHCI_HcControl + 1] & 1) { + if (usb->usb_params && usb->usb_params->smi_handle && !usb->usb_params->smi_handle(usb, usb->usb_params->parent_priv)) + return; + smi_raise(); } else if (usb->usb_params != NULL) { From 4b0384e1b2e5f8fd451ff9b696058b770b00596f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 5 May 2023 01:20:32 +0600 Subject: [PATCH 2/9] usb: USB device configuration descriptor infrastructure --- src/include/86box/usb.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index 7860ada3b..10b27fd30 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -56,6 +56,18 @@ typedef struct uint8_t bLength; uint8_t bDescriptorType; } usb_desc_base_t; + +typedef struct +{ + usb_desc_base_t base; + + uint16_t wTotalLength; + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t bMaxPower; +} usb_desc_conf_t; #pragma pack(pop) /* USB endpoint device struct. Incomplete and unused. */ From af3bc0412c7d2d70f55f38357aaf9ba74129993d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 5 May 2023 22:09:08 +0600 Subject: [PATCH 3/9] usb: fix port reset logic --- src/usb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/usb.c b/src/usb.c index 03fe8a9a6..883e9b67a 100644 --- a/src/usb.c +++ b/src/usb.c @@ -215,6 +215,7 @@ ohci_port_reset_callback(void* priv) usb_t *dev = (usb_t *) priv; dev->ohci_mmio[OHCI_HcRhPortStatus1] &= ~0x10; + dev->ohci_mmio[OHCI_HcRhPortStatus1 + 2] |= 0x10; } void @@ -223,6 +224,7 @@ ohci_port_reset_callback_2(void* priv) usb_t *dev = (usb_t *) priv; dev->ohci_mmio[OHCI_HcRhPortStatus2] &= ~0x10; + dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] |= 0x10; } static void @@ -368,7 +370,6 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p) if (old & 0x01) { dev->ohci_mmio[addr] |= 0x10; timer_on_auto(&dev->ohci_port_reset_timer[(addr - OHCI_HcRhPortStatus1) / 4], 10000.); - dev->ohci_mmio[addr + 2] |= 0x10; } else dev->ohci_mmio[addr + 2] |= 0x01; } @@ -449,6 +450,7 @@ usb_reset(void *priv) dev->ohci_mmio[OHCI_HcRevision] = 0x10; dev->ohci_mmio[OHCI_HcRevision + 1] = 0x01; dev->ohci_mmio[OHCI_HcRhDescriptorA] = 0x02; + dev->ohci_mmio[OHCI_HcRhDescriptorA + 1] = 0x02; 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 331b579d44b0a4d720677ffa7c6aec339ae1075f Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 5 May 2023 22:19:04 +0600 Subject: [PATCH 4/9] usb: Make ports appear always powered on --- src/usb.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/usb.c b/src/usb.c index 883e9b67a..addc4b57e 100644 --- a/src/usb.c +++ b/src/usb.c @@ -186,6 +186,19 @@ ohci_mmio_read(uint32_t addr, void *p) ret = dev->ohci_mmio[addr]; + switch (addr) { + case 0x101: + ret = (ret & 0xfe) | (!!mem_a20_key); + break; + case OHCI_HcRhPortStatus1 + 1: + case OHCI_HcRhPortStatus2 + 1: + case OHCI_HcRhPortStatus3 + 1: + ret |= 0x1; + break; + default: + break; + } + if (addr == 0x101) ret = (ret & 0xfe) | (!!mem_a20_key); From b8fb1754d9021de270a377f965709c44f8676dee Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 5 May 2023 22:32:20 +0600 Subject: [PATCH 5/9] usb: OHCI HcInterruptDisable reads return HcInterruptEnable registers --- src/usb.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/usb.c b/src/usb.c index addc4b57e..19c17f865 100644 --- a/src/usb.c +++ b/src/usb.c @@ -195,6 +195,12 @@ ohci_mmio_read(uint32_t addr, void *p) case OHCI_HcRhPortStatus3 + 1: ret |= 0x1; break; + case OHCI_HcInterruptDisable: + case OHCI_HcInterruptDisable + 1: + case OHCI_HcInterruptDisable + 2: + case OHCI_HcInterruptDisable + 3: + ret = dev->ohci_mmio[OHCI_HcInterruptEnable + (addr - OHCI_HcInterruptDisable)]; + break; default: break; } @@ -433,6 +439,14 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p) case OHCI_HcRhPortStatus1 + 3: case OHCI_HcRhPortStatus2 + 3: return; + case OHCI_HcDoneHead: + case OHCI_HcBulkCurrentED: + case OHCI_HcBulkHeadED: + case OHCI_HcControlCurrentED: + case OHCI_HcControlHeadED: + case OHCI_HcPeriodCurrentED: + dev->ohci_mmio[addr] = (val & 0xf0); + return; } dev->ohci_mmio[addr] = val; From 1d0c18c3a9a85afd48da9547a483c559e3919f88 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 5 May 2023 22:46:18 +0600 Subject: [PATCH 6/9] usb: USB device attach/detach infrastructure --- src/include/86box/usb.h | 10 ++++++++++ src/usb.c | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/include/86box/usb.h b/src/include/86box/usb.h index 10b27fd30..ecb5c0f86 100644 --- a/src/include/86box/usb.h +++ b/src/include/86box/usb.h @@ -86,12 +86,22 @@ typedef struct 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; /* Functions. */ extern void uhci_update_io_mapping(usb_t *dev, uint8_t base_l, uint8_t base_h, int enable); extern void ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3, int enable); +/* Attach USB device to a port of a USB bus. Returns the port to which it got attached to. */ +extern uint8_t usb_attach_device(usb_t *dev, usb_device_t* device, uint8_t bus_type); +/* Detach USB device from a port. */ +extern void usb_detach_device(usb_t *dev, uint8_t port, uint8_t bus_type); #ifdef __cplusplus } diff --git a/src/usb.c b/src/usb.c index 19c17f865..d0703b5d7 100644 --- a/src/usb.c +++ b/src/usb.c @@ -464,6 +464,18 @@ ohci_update_mem_mapping(usb_t *dev, uint8_t base1, uint8_t base2, uint8_t base3, mem_mapping_set_addr(&dev->ohci_mmio_mapping, dev->ohci_mem_base, 0x1000); } +uint8_t +usb_attach_device(usb_t *dev, usb_device_t* device, uint8_t bus_type) +{ + return 255; +} + +void +usb_detach_device(usb_t *dev, uint8_t port, uint8_t bus_type) +{ + /* Unused. */ +} + static void usb_reset(void *priv) { From 6ec563984c73f239ea49a8eff2ff25c2bda41bfd Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 5 May 2023 23:26:41 +0600 Subject: [PATCH 7/9] usb: OHCI HcInterruptEnable bits --- src/usb.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/usb.c b/src/usb.c index d0703b5d7..090e35bd1 100644 --- a/src/usb.c +++ b/src/usb.c @@ -76,6 +76,18 @@ enum OHCI_HcRhPortStatus3 = 0x5C }; +/* OHCI HcInterruptEnable/Disable bits */ +enum +{ + OHCI_HcInterruptEnable_SO = 1 << 0, + OHCI_HcInterruptEnable_WDH = 1 << 1, + OHCI_HcInterruptEnable_SF = 1 << 2, + OHCI_HcInterruptEnable_RD = 1 << 3, + OHCI_HcInterruptEnable_UE = 1 << 4, + OHCI_HcInterruptEnable_HNO = 1 << 5, + OHCI_HcInterruptEnable_RHSC = 1 << 6, +}; + static void usb_interrupt_ohci(usb_t* usb) { From b987e7dacbc39744496835485c8b1e5c83521168 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 5 May 2023 23:50:50 +0600 Subject: [PATCH 8/9] usb: Partially implement HcInterruptEnable/Disable registers --- src/usb.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/usb.c b/src/usb.c index 090e35bd1..12385c808 100644 --- a/src/usb.c +++ b/src/usb.c @@ -292,6 +292,36 @@ ohci_mmio_write(uint32_t addr, uint8_t val, void *p) break; case OHCI_HcHCCA: return; + case OHCI_HcInterruptEnable: + dev->ohci_mmio[addr] = (val & 0x7f); + dev->ohci_mmio[OHCI_HcInterruptDisable] &= ~(val & 0x7f); + return; + case OHCI_HcInterruptEnable + 1: + case OHCI_HcInterruptEnable + 2: + return; + case OHCI_HcInterruptEnable + 3: + dev->ohci_mmio[addr] = (val & 0x40); + dev->ohci_mmio[addr] |= (val & 0x80); + if (val & 0x80) + dev->ohci_mmio[OHCI_HcInterruptDisable + 3] &= ~0x80; + if (val & 0x40) + dev->ohci_mmio[OHCI_HcInterruptDisable + 3] &= ~0x40; + return; + case OHCI_HcInterruptDisable: + dev->ohci_mmio[addr] = (val & 0x7f); + dev->ohci_mmio[OHCI_HcInterruptEnable] &= ~(val & 0x7f); + return; + case OHCI_HcInterruptDisable + 1: + case OHCI_HcInterruptDisable + 2: + return; + case OHCI_HcInterruptDisable + 3: + dev->ohci_mmio[addr] = (val & 0x40); + dev->ohci_mmio[addr] |= (val & 0x80); + if (val & 0x80) + dev->ohci_mmio[OHCI_HcInterruptEnable + 3] &= ~0x80; + if (val & 0x40) + dev->ohci_mmio[OHCI_HcInterruptEnable + 3] &= ~0x40; + return; case OHCI_HcInterruptStatus: dev->ohci_mmio[addr] &= ~(val & 0x7f); return; From 3ed7c4da7661620b5b1e312be835f1509aeb15e3 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Sat, 6 May 2023 00:08:21 +0600 Subject: [PATCH 9/9] usb: interrupt setting function (OHCI) --- src/usb.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/usb.c b/src/usb.c index 12385c808..0951412d6 100644 --- a/src/usb.c +++ b/src/usb.c @@ -258,6 +258,22 @@ ohci_port_reset_callback_2(void* priv) dev->ohci_mmio[OHCI_HcRhPortStatus2 + 2] |= 0x10; } +void +ohci_set_interrupt(usb_t* usb, uint8_t bit) +{ + if (!(usb->ohci_mmio[OHCI_HcInterruptEnable + 3] & 0x80)) + return; + + if (!(usb->ohci_mmio[OHCI_HcInterruptEnable] & bit)) + return; + + if (usb->ohci_mmio[OHCI_HcInterruptDisable] & bit) + return; + + usb->ohci_mmio[OHCI_HcInterruptStatus] |= bit; + usb_interrupt_ohci(usb); +} + static void ohci_mmio_write(uint32_t addr, uint8_t val, void *p) {