From 6106487019177fa2bf61fa1beab11b3b113ad858 Mon Sep 17 00:00:00 2001 From: pbrook Date: Mon, 22 May 2006 17:17:06 +0000 Subject: [PATCH] Fix USB root hub hotplugging. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1931 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/usb-ohci.c | 53 ++++++++++++++++++++++++++++----------------------- hw/usb-uhci.c | 10 +++++----- 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c index 73d262036a..0cc27232d8 100644 --- a/hw/usb-ohci.c +++ b/hw/usb-ohci.c @@ -248,19 +248,39 @@ struct ohci_td { #define OHCI_CC_BUFFEROVERRUN 0xc #define OHCI_CC_BUFFERUNDERRUN 0xd +/* Update IRQ levels */ +static inline void ohci_intr_update(OHCIState *ohci) +{ + int level = 0; + + if ((ohci->intr & OHCI_INTR_MIE) && + (ohci->intr_status & ohci->intr)) + level = 1; + + pci_set_irq(&ohci->pci_dev, 0, level); +} + +/* Set an interrupt */ +static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) +{ + ohci->intr_status |= intr; + ohci_intr_update(ohci); +} + +/* Attach or detach a device on a root hub port. */ static void ohci_attach(USBPort *port1, USBDevice *dev) { OHCIState *s = port1->opaque; OHCIPort *port = &s->rhport[port1->index]; + uint32_t old_state = port->ctrl; if (dev) { if (port->port.dev) { usb_attach(port1, NULL); } /* set connect status */ - if (!(port->ctrl & OHCI_PORT_CCS)) { - port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; - } + port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; + /* update speed */ if (dev->speed == USB_SPEED_LOW) port->ctrl |= OHCI_PORT_LSDA; @@ -273,8 +293,9 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) dprintf("usb-ohci: Attached port %d\n", port1->index); } else { /* set connect status */ - if (!(port->ctrl & OHCI_PORT_CCS)) { - port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; + if (port->ctrl & OHCI_PORT_CCS) { + port->ctrl &= ~OHCI_PORT_CCS; + port->ctrl |= OHCI_PORT_CSC; } /* disable port */ if (port->ctrl & OHCI_PORT_PES) { @@ -290,6 +311,9 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) port->port.dev = NULL; dprintf("usb-ohci: Detached port %d\n", port1->index); } + + if (old_state != port->ctrl) + ohci_set_interrupt(s, OHCI_INTR_RHSC); } /* Reset the controller */ @@ -335,25 +359,6 @@ static void ohci_reset(OHCIState *ohci) dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); } -/* Update IRQ levels */ -static inline void ohci_intr_update(OHCIState *ohci) -{ - int level = 0; - - if ((ohci->intr & OHCI_INTR_MIE) && - (ohci->intr_status & ohci->intr)) - level = 1; - - pci_set_irq(&ohci->pci_dev, 0, level); -} - -/* Set an interrupt */ -static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) -{ - ohci->intr_status |= intr; - ohci_intr_update(ohci); -} - /* Get an array of dwords from main memory */ static inline int get_dwords(uint32_t addr, uint32_t *buf, int num) { diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c index d3358febc9..1a6e0130f9 100644 --- a/hw/usb-uhci.c +++ b/hw/usb-uhci.c @@ -327,9 +327,8 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) usb_attach(port1, NULL); } /* set connect status */ - if (!(port->ctrl & UHCI_PORT_CCS)) { - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; - } + port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; + /* update speed */ if (dev->speed == USB_SPEED_LOW) port->ctrl |= UHCI_PORT_LSDA; @@ -341,8 +340,9 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) USB_MSG_ATTACH, 0, 0, NULL, 0); } else { /* set connect status */ - if (!(port->ctrl & UHCI_PORT_CCS)) { - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; + if (port->ctrl & UHCI_PORT_CCS) { + port->ctrl &= ~UHCI_PORT_CCS; + port->ctrl |= UHCI_PORT_CSC; } /* disable port */ if (port->ctrl & UHCI_PORT_EN) {