Revision c6432634
b/hw/usb/hcd-ehci.c | ||
---|---|---|
438 | 438 |
return ehci_enabled(s) && (s->usbcmd & USBCMD_PSE); |
439 | 439 |
} |
440 | 440 |
|
441 |
static bool ehci_verify_qh(EHCIQueue *q, EHCIqh *qh) |
|
442 |
{ |
|
443 |
uint32_t devaddr = get_field(qh->epchar, QH_EPCHAR_DEVADDR); |
|
444 |
uint32_t endp = get_field(qh->epchar, QH_EPCHAR_EP); |
|
445 |
if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) || |
|
446 |
(endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) || |
|
447 |
(qh->current_qtd != q->qh.current_qtd) || |
|
448 |
(q->async && qh->next_qtd != q->qh.next_qtd) || |
|
449 |
(memcmp(&qh->altnext_qtd, &q->qh.altnext_qtd, |
|
450 |
7 * sizeof(uint32_t)) != 0) || |
|
451 |
(q->dev != NULL && q->dev->addr != devaddr)) { |
|
452 |
return false; |
|
453 |
} else { |
|
454 |
return true; |
|
455 |
} |
|
456 |
} |
|
457 |
|
|
458 |
static bool ehci_verify_qtd(EHCIPacket *p, EHCIqtd *qtd) |
|
459 |
{ |
|
460 |
if (p->qtdaddr != p->queue->qtdaddr || |
|
461 |
(p->queue->async && !NLPTR_TBIT(p->qtd.next) && |
|
462 |
(p->qtd.next != qtd->next)) || |
|
463 |
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd->altnext)) || |
|
464 |
p->qtd.bufptr[0] != qtd->bufptr[0]) { |
|
465 |
return false; |
|
466 |
} else { |
|
467 |
return true; |
|
468 |
} |
|
469 |
} |
|
470 |
|
|
441 | 471 |
/* Finish executing and writeback a packet outside of the regular |
442 | 472 |
fetchqh -> fetchqtd -> execute -> writeback cycle */ |
443 | 473 |
static void ehci_writeback_async_complete_packet(EHCIPacket *p) |
... | ... | |
1557 | 1587 |
|
1558 | 1588 |
static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) |
1559 | 1589 |
{ |
1590 |
uint32_t entry; |
|
1560 | 1591 |
EHCIPacket *p; |
1561 |
uint32_t entry, devaddr, endp; |
|
1562 | 1592 |
EHCIQueue *q; |
1563 | 1593 |
EHCIqh qh; |
1564 | 1594 |
|
... | ... | |
1588 | 1618 |
* The overlay area of the qh should never be changed by the guest, |
1589 | 1619 |
* except when idle, in which case the reset is a nop. |
1590 | 1620 |
*/ |
1591 |
devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR); |
|
1592 |
endp = get_field(qh.epchar, QH_EPCHAR_EP); |
|
1593 |
if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) || |
|
1594 |
(endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) || |
|
1595 |
(qh.current_qtd != q->qh.current_qtd) || |
|
1596 |
(q->async && qh.next_qtd != q->qh.next_qtd) || |
|
1597 |
(memcmp(&qh.altnext_qtd, &q->qh.altnext_qtd, |
|
1598 |
7 * sizeof(uint32_t)) != 0) || |
|
1599 |
(q->dev != NULL && q->dev->addr != devaddr)) { |
|
1621 |
if (!ehci_verify_qh(q, &qh)) { |
|
1600 | 1622 |
if (ehci_reset_queue(q) > 0) { |
1601 | 1623 |
ehci_trace_guest_bug(ehci, "guest updated active QH"); |
1602 | 1624 |
} |
... | ... | |
1610 | 1632 |
} |
1611 | 1633 |
|
1612 | 1634 |
if (q->dev == NULL) { |
1613 |
q->dev = ehci_find_device(q->ehci, devaddr); |
|
1635 |
q->dev = ehci_find_device(q->ehci, |
|
1636 |
get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)); |
|
1614 | 1637 |
} |
1615 | 1638 |
|
1616 | 1639 |
if (p && p->async == EHCI_ASYNC_FINISHED) { |
... | ... | |
1768 | 1791 |
|
1769 | 1792 |
p = QTAILQ_FIRST(&q->packets); |
1770 | 1793 |
if (p != NULL) { |
1771 |
if (p->qtdaddr != q->qtdaddr || |
|
1772 |
(q->async && !NLPTR_TBIT(p->qtd.next) && |
|
1773 |
(p->qtd.next != qtd.next)) || |
|
1774 |
(!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) || |
|
1775 |
p->qtd.bufptr[0] != qtd.bufptr[0]) { |
|
1794 |
if (!ehci_verify_qtd(p, &qtd)) { |
|
1776 | 1795 |
ehci_cancel_queue(q); |
1777 | 1796 |
ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD"); |
1778 | 1797 |
p = NULL; |
Also available in: Unified diff