Commit 6106487019177fa2bf61fa1beab11b3b113ad858
1 parent
6cb7ee85
Fix USB root hub hotplugging.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1931 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
34 additions
and
29 deletions
hw/usb-ohci.c
| @@ -248,19 +248,39 @@ struct ohci_td { | @@ -248,19 +248,39 @@ struct ohci_td { | ||
| 248 | #define OHCI_CC_BUFFEROVERRUN 0xc | 248 | #define OHCI_CC_BUFFEROVERRUN 0xc |
| 249 | #define OHCI_CC_BUFFERUNDERRUN 0xd | 249 | #define OHCI_CC_BUFFERUNDERRUN 0xd |
| 250 | 250 | ||
| 251 | +/* Update IRQ levels */ | ||
| 252 | +static inline void ohci_intr_update(OHCIState *ohci) | ||
| 253 | +{ | ||
| 254 | + int level = 0; | ||
| 255 | + | ||
| 256 | + if ((ohci->intr & OHCI_INTR_MIE) && | ||
| 257 | + (ohci->intr_status & ohci->intr)) | ||
| 258 | + level = 1; | ||
| 259 | + | ||
| 260 | + pci_set_irq(&ohci->pci_dev, 0, level); | ||
| 261 | +} | ||
| 262 | + | ||
| 263 | +/* Set an interrupt */ | ||
| 264 | +static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) | ||
| 265 | +{ | ||
| 266 | + ohci->intr_status |= intr; | ||
| 267 | + ohci_intr_update(ohci); | ||
| 268 | +} | ||
| 269 | + | ||
| 270 | +/* Attach or detach a device on a root hub port. */ | ||
| 251 | static void ohci_attach(USBPort *port1, USBDevice *dev) | 271 | static void ohci_attach(USBPort *port1, USBDevice *dev) |
| 252 | { | 272 | { |
| 253 | OHCIState *s = port1->opaque; | 273 | OHCIState *s = port1->opaque; |
| 254 | OHCIPort *port = &s->rhport[port1->index]; | 274 | OHCIPort *port = &s->rhport[port1->index]; |
| 275 | + uint32_t old_state = port->ctrl; | ||
| 255 | 276 | ||
| 256 | if (dev) { | 277 | if (dev) { |
| 257 | if (port->port.dev) { | 278 | if (port->port.dev) { |
| 258 | usb_attach(port1, NULL); | 279 | usb_attach(port1, NULL); |
| 259 | } | 280 | } |
| 260 | /* set connect status */ | 281 | /* set connect status */ |
| 261 | - if (!(port->ctrl & OHCI_PORT_CCS)) { | ||
| 262 | - port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; | ||
| 263 | - } | 282 | + port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; |
| 283 | + | ||
| 264 | /* update speed */ | 284 | /* update speed */ |
| 265 | if (dev->speed == USB_SPEED_LOW) | 285 | if (dev->speed == USB_SPEED_LOW) |
| 266 | port->ctrl |= OHCI_PORT_LSDA; | 286 | port->ctrl |= OHCI_PORT_LSDA; |
| @@ -273,8 +293,9 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) | @@ -273,8 +293,9 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) | ||
| 273 | dprintf("usb-ohci: Attached port %d\n", port1->index); | 293 | dprintf("usb-ohci: Attached port %d\n", port1->index); |
| 274 | } else { | 294 | } else { |
| 275 | /* set connect status */ | 295 | /* set connect status */ |
| 276 | - if (!(port->ctrl & OHCI_PORT_CCS)) { | ||
| 277 | - port->ctrl |= OHCI_PORT_CCS | OHCI_PORT_CSC; | 296 | + if (port->ctrl & OHCI_PORT_CCS) { |
| 297 | + port->ctrl &= ~OHCI_PORT_CCS; | ||
| 298 | + port->ctrl |= OHCI_PORT_CSC; | ||
| 278 | } | 299 | } |
| 279 | /* disable port */ | 300 | /* disable port */ |
| 280 | if (port->ctrl & OHCI_PORT_PES) { | 301 | if (port->ctrl & OHCI_PORT_PES) { |
| @@ -290,6 +311,9 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) | @@ -290,6 +311,9 @@ static void ohci_attach(USBPort *port1, USBDevice *dev) | ||
| 290 | port->port.dev = NULL; | 311 | port->port.dev = NULL; |
| 291 | dprintf("usb-ohci: Detached port %d\n", port1->index); | 312 | dprintf("usb-ohci: Detached port %d\n", port1->index); |
| 292 | } | 313 | } |
| 314 | + | ||
| 315 | + if (old_state != port->ctrl) | ||
| 316 | + ohci_set_interrupt(s, OHCI_INTR_RHSC); | ||
| 293 | } | 317 | } |
| 294 | 318 | ||
| 295 | /* Reset the controller */ | 319 | /* Reset the controller */ |
| @@ -335,25 +359,6 @@ static void ohci_reset(OHCIState *ohci) | @@ -335,25 +359,6 @@ static void ohci_reset(OHCIState *ohci) | ||
| 335 | dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); | 359 | dprintf("usb-ohci: Reset %s\n", ohci->pci_dev.name); |
| 336 | } | 360 | } |
| 337 | 361 | ||
| 338 | -/* Update IRQ levels */ | ||
| 339 | -static inline void ohci_intr_update(OHCIState *ohci) | ||
| 340 | -{ | ||
| 341 | - int level = 0; | ||
| 342 | - | ||
| 343 | - if ((ohci->intr & OHCI_INTR_MIE) && | ||
| 344 | - (ohci->intr_status & ohci->intr)) | ||
| 345 | - level = 1; | ||
| 346 | - | ||
| 347 | - pci_set_irq(&ohci->pci_dev, 0, level); | ||
| 348 | -} | ||
| 349 | - | ||
| 350 | -/* Set an interrupt */ | ||
| 351 | -static inline void ohci_set_interrupt(OHCIState *ohci, uint32_t intr) | ||
| 352 | -{ | ||
| 353 | - ohci->intr_status |= intr; | ||
| 354 | - ohci_intr_update(ohci); | ||
| 355 | -} | ||
| 356 | - | ||
| 357 | /* Get an array of dwords from main memory */ | 362 | /* Get an array of dwords from main memory */ |
| 358 | static inline int get_dwords(uint32_t addr, uint32_t *buf, int num) | 363 | static inline int get_dwords(uint32_t addr, uint32_t *buf, int num) |
| 359 | { | 364 | { |
hw/usb-uhci.c
| @@ -327,9 +327,8 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) | @@ -327,9 +327,8 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) | ||
| 327 | usb_attach(port1, NULL); | 327 | usb_attach(port1, NULL); |
| 328 | } | 328 | } |
| 329 | /* set connect status */ | 329 | /* set connect status */ |
| 330 | - if (!(port->ctrl & UHCI_PORT_CCS)) { | ||
| 331 | - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; | ||
| 332 | - } | 330 | + port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; |
| 331 | + | ||
| 333 | /* update speed */ | 332 | /* update speed */ |
| 334 | if (dev->speed == USB_SPEED_LOW) | 333 | if (dev->speed == USB_SPEED_LOW) |
| 335 | port->ctrl |= UHCI_PORT_LSDA; | 334 | port->ctrl |= UHCI_PORT_LSDA; |
| @@ -341,8 +340,9 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) | @@ -341,8 +340,9 @@ static void uhci_attach(USBPort *port1, USBDevice *dev) | ||
| 341 | USB_MSG_ATTACH, 0, 0, NULL, 0); | 340 | USB_MSG_ATTACH, 0, 0, NULL, 0); |
| 342 | } else { | 341 | } else { |
| 343 | /* set connect status */ | 342 | /* set connect status */ |
| 344 | - if (!(port->ctrl & UHCI_PORT_CCS)) { | ||
| 345 | - port->ctrl |= UHCI_PORT_CCS | UHCI_PORT_CSC; | 343 | + if (port->ctrl & UHCI_PORT_CCS) { |
| 344 | + port->ctrl &= ~UHCI_PORT_CCS; | ||
| 345 | + port->ctrl |= UHCI_PORT_CSC; | ||
| 346 | } | 346 | } |
| 347 | /* disable port */ | 347 | /* disable port */ |
| 348 | if (port->ctrl & UHCI_PORT_EN) { | 348 | if (port->ctrl & UHCI_PORT_EN) { |