diff options
author | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2006-05-22 17:17:06 +0000 |
---|---|---|
committer | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2006-05-22 17:17:06 +0000 |
commit | 6106487019177fa2bf61fa1beab11b3b113ad858 (patch) | |
tree | d07e6346c185ebb12d8880ac6416db414f1f2efe /hw/usb-ohci.c | |
parent | 6cb7ee859a1b28aae8eab7f88908c9c9262b8a5c (diff) |
Fix USB root hub hotplugging.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1931 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/usb-ohci.c')
-rw-r--r-- | hw/usb-ohci.c | 53 |
1 files changed, 29 insertions, 24 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) { |