static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
                          UHCI_TD *td, uint32_t td_addr, uint32_t *int_mask)
{
    int len = 0, max_len;
    bool spd;
    bool queuing = (q != NULL);
    uint8_t pid = td->token & 0xff;
    UHCIAsync *async = uhci_async_find_td(s, td_addr);
    if (async) {
        if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) {
            assert(q == NULL || q == async->queue);
            q = async->queue;
        } else {
            uhci_queue_free(async->queue, "guest re-used pending td");
            async = NULL;
    if (q == NULL) {
        q = uhci_queue_find(s, td);
        if (q && !uhci_queue_verify(q, qh_addr, td, td_addr, queuing)) {
            uhci_queue_free(q, "guest re-used qh");
            q = NULL;
    if (q) {
        q->valid = 32;
    /* Is active ? */
    if (!(td->ctrl & TD_CTRL_ACTIVE)) {
        if (async) {
            /* Guest marked a pending td non-active, cancel the queue */
            uhci_queue_free(async->queue, "pending td non-active");
        /*
         * ehci11d spec page 22: "Even if the Active bit in the TD is already
         * cleared when the TD is fetched ... an IOC interrupt is generated"
         */
        if (td->ctrl & TD_CTRL_IOC) {
                *int_mask |= 0x01;
        return TD_RESULT_NEXT_QH;
    if (async) {
        if (queuing) {
            /* we are busy filling the queue, we are not prepared
               to consume completed packages then, just leave them
               in async state */
            return TD_RESULT_ASYNC_CONT;
        if (!async->done) {
            UHCI_TD last_td;
            UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs, asyncs_head);
            /*
             * While we are waiting for the current td to complete, the guest
             * may have added more tds to the queue. Note we re-read the td
             * rather then caching it, as we want to see guest made changes!
             */
            uhci_read_td(s, &last_td, last->td_addr);
            uhci_queue_fill(async->queue, &last_td);
            return TD_RESULT_ASYNC_CONT;
        uhci_async_unlink(async);
        goto done;
    /* Allocate new packet */
    if (q == NULL) {
        USBDevice *dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
        USBEndpoint *ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
        q = uhci_queue_new(s, qh_addr, td, ep);
    async = uhci_async_alloc(q, td_addr);
    max_len = ((td->token >> 21) + 1) & 0x7ff;
    spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
    usb_packet_setup(&async->packet, pid, q->ep, td_addr, spd,
                     (td->ctrl & TD_CTRL_IOC) != 0);
    qemu_sglist_add(&async->sgl, td->buffer, max_len);
    usb_packet_map(&async->packet, &async->sgl);
    switch(pid) {
    case USB_TOKEN_OUT:
    case USB_TOKEN_SETUP:
        len = usb_handle_packet(q->ep->dev, &async->packet);
        if (len >= 0)
            len = max_len;
        break;
    case USB_TOKEN_IN:
        len = usb_handle_packet(q->ep->dev, &async->packet);
        break;
    default:
        /* invalid pid : frame interrupted */
        usb_packet_unmap(&async->packet, &async->sgl);
        uhci_async_free(async);
        s->status |= UHCI_STS_HCPERR;
        uhci_update_irq(s);
        return TD_RESULT_STOP_FRAME;
    if (len == USB_RET_ASYNC) {
        uhci_async_link(async);
        if (!queuing) {
            uhci_queue_fill(q, td);
        return TD_RESULT_ASYNC_START;
    async->packet.result = len;
done:
    len = uhci_complete_td(s, td, async, int_mask);
    usb_packet_unmap(&async->packet, &async->sgl);
    uhci_async_free(async);
    return len;
static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr,
                          UHCI_TD *td, uint32_t td_addr, uint32_t *int_mask)
{
    int len = 0, max_len;
    bool spd;
    bool queuing = (q != NULL);
    uint8_t pid = td->token & 0xff;
    UHCIAsync *async = uhci_async_find_td(s, td_addr);
    if (async) {
        if (uhci_queue_verify(async->queue, qh_addr, td, td_addr, queuing)) {
            assert(q == NULL || q == async->queue);
            q = async->queue;
        } else {
            uhci_queue_free(async->queue, "guest re-used pending td");
            async = NULL;
    if (q == NULL) {
        q = uhci_queue_find(s, td);
        if (q && !uhci_queue_verify(q, qh_addr, td, td_addr, queuing)) {
            uhci_queue_free(q, "guest re-used qh");
            q = NULL;
    if (q) {
        q->valid = 32;
    
    if (!(td->ctrl & TD_CTRL_ACTIVE)) {
        if (async) {
            
            uhci_queue_free(async->queue, "pending td non-active");
        



        if (td->ctrl & TD_CTRL_IOC) {
                *int_mask |= 0x01;
        return TD_RESULT_NEXT_QH;
    if (async) {
        if (queuing) {
            


            return TD_RESULT_ASYNC_CONT;
        if (!async->done) {
            UHCI_TD last_td;
            UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs, asyncs_head);
            




            uhci_read_td(s, &last_td, last->td_addr);
            uhci_queue_fill(async->queue, &last_td);
            return TD_RESULT_ASYNC_CONT;
        uhci_async_unlink(async);
        goto done;
    
    if (q == NULL) {
        USBDevice *dev = uhci_find_device(s, (td->token >> 8) & 0x7f);
        USBEndpoint *ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf);
        q = uhci_queue_new(s, qh_addr, td, ep);
    async = uhci_async_alloc(q, td_addr);
    max_len = ((td->token >> 21) + 1) & 0x7ff;
    spd = (pid == USB_TOKEN_IN && (td->ctrl & TD_CTRL_SPD) != 0);
    usb_packet_setup(&async->packet, pid, q->ep, td_addr, spd,
                     (td->ctrl & TD_CTRL_IOC) != 0);
    qemu_sglist_add(&async->sgl, td->buffer, max_len);
    usb_packet_map(&async->packet, &async->sgl);
    switch(pid) {
    case USB_TOKEN_OUT:
    case USB_TOKEN_SETUP:
        len = usb_handle_packet(q->ep->dev, &async->packet);
        if (len >= 0)
            len = max_len;
        break;
    case USB_TOKEN_IN:
        len = usb_handle_packet(q->ep->dev, &async->packet);
        break;
    default:
        
        usb_packet_unmap(&async->packet, &async->sgl);
        uhci_async_free(async);
        s->status |= UHCI_STS_HCPERR;
        uhci_update_irq(s);
        return TD_RESULT_STOP_FRAME;
    if (len == USB_RET_ASYNC) {
        uhci_async_link(async);
        if (!queuing) {
            uhci_queue_fill(q, td);
        return TD_RESULT_ASYNC_START;
    async->packet.result = len;
done:
    len = uhci_complete_td(s, td, async, int_mask);
    usb_packet_unmap(&async->packet, &async->sgl);
    uhci_async_free(async);
    return len;
static int FUNC_0(UHCIState *VAR_0, UHCIQueue *VAR_1, uint32_t VAR_2,
                          UHCI_TD *VAR_3, uint32_t VAR_4, uint32_t *VAR_5)
{
    int VAR_6 = 0, VAR_7;
    bool spd;
    bool queuing = (VAR_1 != NULL);
    uint8_t pid = VAR_3->token & 0xff;
    UHCIAsync *async = uhci_async_find_td(VAR_0, VAR_4);
    if (async) {
        if (uhci_queue_verify(async->queue, VAR_2, VAR_3, VAR_4, queuing)) {
            assert(VAR_1 == NULL || VAR_1 == async->queue);
            VAR_1 = async->queue;
        } else {
            uhci_queue_free(async->queue, "guest re-used pending VAR_3");
            async = NULL;
    if (VAR_1 == NULL) {
        VAR_1 = uhci_queue_find(VAR_0, VAR_3);
        if (VAR_1 && !uhci_queue_verify(VAR_1, VAR_2, VAR_3, VAR_4, queuing)) {
            uhci_queue_free(VAR_1, "guest re-used qh");
            VAR_1 = NULL;
    if (VAR_1) {
        VAR_1->valid = 32;
    
    if (!(VAR_3->ctrl & TD_CTRL_ACTIVE)) {
        if (async) {
            
            uhci_queue_free(async->queue, "pending VAR_3 non-active");
        



        if (VAR_3->ctrl & TD_CTRL_IOC) {
                *VAR_5 |= 0x01;
        return TD_RESULT_NEXT_QH;
    if (async) {
        if (queuing) {
            


            return TD_RESULT_ASYNC_CONT;
        if (!async->done) {
            UHCI_TD last_td;
            UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs, asyncs_head);
            




            uhci_read_td(VAR_0, &last_td, last->VAR_4);
            uhci_queue_fill(async->queue, &last_td);
            return TD_RESULT_ASYNC_CONT;
        uhci_async_unlink(async);
        goto done;
    
    if (VAR_1 == NULL) {
        USBDevice *dev = uhci_find_device(VAR_0, (VAR_3->token >> 8) & 0x7f);
        USBEndpoint *ep = usb_ep_get(dev, pid, (VAR_3->token >> 15) & 0xf);
        VAR_1 = uhci_queue_new(VAR_0, VAR_2, VAR_3, ep);
    async = uhci_async_alloc(VAR_1, VAR_4);
    VAR_7 = ((VAR_3->token >> 21) + 1) & 0x7ff;
    spd = (pid == USB_TOKEN_IN && (VAR_3->ctrl & TD_CTRL_SPD) != 0);
    usb_packet_setup(&async->packet, pid, VAR_1->ep, VAR_4, spd,
                     (VAR_3->ctrl & TD_CTRL_IOC) != 0);
    qemu_sglist_add(&async->sgl, VAR_3->buffer, VAR_7);
    usb_packet_map(&async->packet, &async->sgl);
    switch(pid) {
    case USB_TOKEN_OUT:
    case USB_TOKEN_SETUP:
        VAR_6 = usb_handle_packet(VAR_1->ep->dev, &async->packet);
        if (VAR_6 >= 0)
            VAR_6 = VAR_7;
        break;
    case USB_TOKEN_IN:
        VAR_6 = usb_handle_packet(VAR_1->ep->dev, &async->packet);
        break;
    default:
        
        usb_packet_unmap(&async->packet, &async->sgl);
        uhci_async_free(async);
        VAR_0->status |= UHCI_STS_HCPERR;
        uhci_update_irq(VAR_0);
        return TD_RESULT_STOP_FRAME;
    if (VAR_6 == USB_RET_ASYNC) {
        uhci_async_link(async);
        if (!queuing) {
            uhci_queue_fill(VAR_1, VAR_3);
        return TD_RESULT_ASYNC_START;
    async->packet.result = VAR_6;
done:
    VAR_6 = uhci_complete_td(VAR_0, VAR_3, async, VAR_5);
    usb_packet_unmap(&async->packet, &async->sgl);
    uhci_async_free(async);
    return VAR_6;
static int FUNC_0(UHCIState *VAR_0, UHCIQueue *VAR_1, uint32_t VAR_2,
UHCI_TD *VAR_3, uint32_t VAR_4, uint32_t *VAR_5)
{ int VAR_6 = 0, VAR_7; bool spd; bool queuing = (VAR_1 != NULL); uint8_t pid = VAR_3->token & 0xff; UHCIAsync *async = uhci_async_find_td(VAR_0, VAR_4); if (async) { if (uhci_queue_verify(async->queue, VAR_2, VAR_3, VAR_4, queuing)) { assert(VAR_1 == NULL || VAR_1 == async->queue); VAR_1 = async->queue; } else { uhci_queue_free(async->queue, "guest re-used pending VAR_3"); async = NULL; if (VAR_1 == NULL) { VAR_1 = uhci_queue_find(VAR_0, VAR_3); if (VAR_1 && !uhci_queue_verify(VAR_1, VAR_2, VAR_3, VAR_4, queuing)) { uhci_queue_free(VAR_1, "guest re-used qh"); VAR_1 = NULL; if (VAR_1) { VAR_1->valid = 32; if (!(VAR_3->ctrl & TD_CTRL_ACTIVE)) { if (async) { uhci_queue_free(async->queue, "pending VAR_3 non-active"); if (VAR_3->ctrl & TD_CTRL_IOC) { *VAR_5 |= 0x01; return TD_RESULT_NEXT_QH; if (async) { if (queuing) { return TD_RESULT_ASYNC_CONT; if (!async->done) { UHCI_TD last_td; UHCIAsync *last = QTAILQ_LAST(&async->queue->asyncs, asyncs_head); uhci_read_td(VAR_0, &last_td, last->VAR_4); uhci_queue_fill(async->queue, &last_td); return TD_RESULT_ASYNC_CONT; uhci_async_unlink(async); goto done; if (VAR_1 == NULL) { USBDevice *dev = uhci_find_device(VAR_0, (VAR_3->token >> 8) & 0x7f); USBEndpoint *ep = usb_ep_get(dev, pid, (VAR_3->token >> 15) & 0xf); VAR_1 = uhci_queue_new(VAR_0, VAR_2, VAR_3, ep); async = uhci_async_alloc(VAR_1, VAR_4); VAR_7 = ((VAR_3->token >> 21) + 1) & 0x7ff; spd = (pid == USB_TOKEN_IN && (VAR_3->ctrl & TD_CTRL_SPD) != 0); usb_packet_setup(&async->packet, pid, VAR_1->ep, VAR_4, spd,
(VAR_3->ctrl & TD_CTRL_IOC) != 0); qemu_sglist_add(&async->sgl, VAR_3->buffer, VAR_7); usb_packet_map(&async->packet, &async->sgl); switch(pid) { case USB_TOKEN_OUT:
case USB_TOKEN_SETUP:
VAR_6 = usb_handle_packet(VAR_1->ep->dev, &async->packet); if (VAR_6 >= 0)
VAR_6 = VAR_7; break; case USB_TOKEN_IN:
VAR_6 = usb_handle_packet(VAR_1->ep->dev, &async->packet); break; default:
usb_packet_unmap(&async->packet, &async->sgl); uhci_async_free(async); VAR_0->status |= UHCI_STS_HCPERR; uhci_update_irq(VAR_0); return TD_RESULT_STOP_FRAME; if (VAR_6 == USB_RET_ASYNC) { uhci_async_link(async); if (!queuing) { uhci_queue_fill(VAR_1, VAR_3); return TD_RESULT_ASYNC_START; async->packet.result = VAR_6; done:
VAR_6 = uhci_complete_td(VAR_0, VAR_3, async, VAR_5); usb_packet_unmap(&async->packet, &async->sgl); uhci_async_free(async); return VAR_6;