aboutsummaryrefslogtreecommitdiff
path: root/hw/usb-ohci.c
diff options
context:
space:
mode:
authorpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2006-05-22 17:17:06 +0000
committerpbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>2006-05-22 17:17:06 +0000
commit6106487019177fa2bf61fa1beab11b3b113ad858 (patch)
treed07e6346c185ebb12d8880ac6416db414f1f2efe /hw/usb-ohci.c
parent6cb7ee859a1b28aae8eab7f88908c9c9262b8a5c (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.c53
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)
{