static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask)

{

    int len = 0, max_len, err, ret;

    uint8_t pid;



    max_len = ((td->token >> 21) + 1) & 0x7ff;

    pid = td->token & 0xff;



    ret = async->packet.result;



    if (td->ctrl & TD_CTRL_IOS)

        td->ctrl &= ~TD_CTRL_ACTIVE;



    if (ret < 0)

        goto out;



    len = async->packet.result;

    td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);



    /* The NAK bit may have been set by a previous frame, so clear it

       here.  The docs are somewhat unclear, but win2k relies on this

       behavior.  */

    td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);

    if (td->ctrl & TD_CTRL_IOC)

        *int_mask |= 0x01;



    if (pid == USB_TOKEN_IN) {

        if (len > max_len) {

            ret = USB_RET_BABBLE;

            goto out;

        }



        if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {

            *int_mask |= 0x02;

            /* short packet: do not update QH */

            trace_usb_uhci_packet_complete_shortxfer(async->queue->token,

                                                    async->td);

            return TD_RESULT_NEXT_QH;

        }

    }



    /* success */

    trace_usb_uhci_packet_complete_success(async->queue->token, async->td);

    return TD_RESULT_COMPLETE;



out:

    /*

     * We should not do any further processing on a queue with errors!

     * This is esp. important for bulk endpoints with pipelining enabled

     * (redirection to a real USB device), where we must cancel all the

     * transfers after this one so that:

     * 1) If they've completed already, they are not processed further

     *    causing more stalls, originating from the same failed transfer

     * 2) If still in flight, they are cancelled before the guest does

     *    a clear stall, otherwise the guest and device can loose sync!

     */

    while (!QTAILQ_EMPTY(&async->queue->asyncs)) {

        UHCIAsync *as = QTAILQ_FIRST(&async->queue->asyncs);

        uhci_async_unlink(as);

        uhci_async_cancel(as);

    }



    switch(ret) {

    case USB_RET_STALL:

        td->ctrl |= TD_CTRL_STALL;

        td->ctrl &= ~TD_CTRL_ACTIVE;

        s->status |= UHCI_STS_USBERR;

        if (td->ctrl & TD_CTRL_IOC) {

            *int_mask |= 0x01;

        }

        uhci_update_irq(s);

        trace_usb_uhci_packet_complete_stall(async->queue->token, async->td);

        return TD_RESULT_NEXT_QH;



    case USB_RET_BABBLE:

        td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;

        td->ctrl &= ~TD_CTRL_ACTIVE;

        s->status |= UHCI_STS_USBERR;

        if (td->ctrl & TD_CTRL_IOC) {

            *int_mask |= 0x01;

        }

        uhci_update_irq(s);

        /* frame interrupted */

        trace_usb_uhci_packet_complete_babble(async->queue->token, async->td);

        return TD_RESULT_STOP_FRAME;



    case USB_RET_NAK:

        td->ctrl |= TD_CTRL_NAK;

        if (pid == USB_TOKEN_SETUP)

            break;

        return TD_RESULT_NEXT_QH;



    case USB_RET_IOERROR:

    case USB_RET_NODEV:

    default:

	break;

    }



    /* Retry the TD if error count is not zero */



    td->ctrl |= TD_CTRL_TIMEOUT;

    err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;

    if (err != 0) {

        err--;

        if (err == 0) {

            td->ctrl &= ~TD_CTRL_ACTIVE;

            s->status |= UHCI_STS_USBERR;

            if (td->ctrl & TD_CTRL_IOC)

                *int_mask |= 0x01;

            uhci_update_irq(s);

            trace_usb_uhci_packet_complete_error(async->queue->token,

                                                 async->td);

        }

    }

    td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |

        (err << TD_CTRL_ERROR_SHIFT);

    return TD_RESULT_NEXT_QH;

}

static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_t *int_mask)

{

    int len = 0, max_len, err, ret;

    uint8_t pid;



    max_len = ((td->token >> 21) + 1) & 0x7ff;

    pid = td->token & 0xff;



    ret = async->packet.result;



    if (td->ctrl & TD_CTRL_IOS)

        td->ctrl &= ~TD_CTRL_ACTIVE;



    if (ret < 0)

        goto out;



    len = async->packet.result;

    td->ctrl = (td->ctrl & ~0x7ff) | ((len - 1) & 0x7ff);



    





    td->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);

    if (td->ctrl & TD_CTRL_IOC)

        *int_mask |= 0x01;



    if (pid == USB_TOKEN_IN) {

        if (len > max_len) {

            ret = USB_RET_BABBLE;

            goto out;

        }



        if ((td->ctrl & TD_CTRL_SPD) && len < max_len) {

            *int_mask |= 0x02;

            

            trace_usb_uhci_packet_complete_shortxfer(async->queue->token,

                                                    async->td);

            return TD_RESULT_NEXT_QH;

        }

    }



    

    trace_usb_uhci_packet_complete_success(async->queue->token, async->td);

    return TD_RESULT_COMPLETE;



out:

    



















    while (!QTAILQ_EMPTY(&async->queue->asyncs)) {

        UHCIAsync *as = QTAILQ_FIRST(&async->queue->asyncs);

        uhci_async_unlink(as);

        uhci_async_cancel(as);

    }



    switch(ret) {

    case USB_RET_STALL:

        td->ctrl |= TD_CTRL_STALL;

        td->ctrl &= ~TD_CTRL_ACTIVE;

        s->status |= UHCI_STS_USBERR;

        if (td->ctrl & TD_CTRL_IOC) {

            *int_mask |= 0x01;

        }

        uhci_update_irq(s);

        trace_usb_uhci_packet_complete_stall(async->queue->token, async->td);

        return TD_RESULT_NEXT_QH;



    case USB_RET_BABBLE:

        td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;

        td->ctrl &= ~TD_CTRL_ACTIVE;

        s->status |= UHCI_STS_USBERR;

        if (td->ctrl & TD_CTRL_IOC) {

            *int_mask |= 0x01;

        }

        uhci_update_irq(s);

        

        trace_usb_uhci_packet_complete_babble(async->queue->token, async->td);

        return TD_RESULT_STOP_FRAME;



    case USB_RET_NAK:

        td->ctrl |= TD_CTRL_NAK;

        if (pid == USB_TOKEN_SETUP)

            break;

        return TD_RESULT_NEXT_QH;



    case USB_RET_IOERROR:

    case USB_RET_NODEV:

    default:

	break;

    }



    



    td->ctrl |= TD_CTRL_TIMEOUT;

    err = (td->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;

    if (err != 0) {

        err--;

        if (err == 0) {

            td->ctrl &= ~TD_CTRL_ACTIVE;

            s->status |= UHCI_STS_USBERR;

            if (td->ctrl & TD_CTRL_IOC)

                *int_mask |= 0x01;

            uhci_update_irq(s);

            trace_usb_uhci_packet_complete_error(async->queue->token,

                                                 async->td);

        }

    }

    td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |

        (err << TD_CTRL_ERROR_SHIFT);

    return TD_RESULT_NEXT_QH;

}

static int FUNC_0(UHCIState *VAR_0, UHCI_TD *VAR_1, UHCIAsync *VAR_2, uint32_t *VAR_3)

{

    int VAR_4 = 0, VAR_5, VAR_6, VAR_7;

    uint8_t pid;



    VAR_5 = ((VAR_1->token >> 21) + 1) & 0x7ff;

    pid = VAR_1->token & 0xff;



    VAR_7 = VAR_2->packet.result;



    if (VAR_1->ctrl & TD_CTRL_IOS)

        VAR_1->ctrl &= ~TD_CTRL_ACTIVE;



    if (VAR_7 < 0)

        goto out;



    VAR_4 = VAR_2->packet.result;

    VAR_1->ctrl = (VAR_1->ctrl & ~0x7ff) | ((VAR_4 - 1) & 0x7ff);



    





    VAR_1->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK);

    if (VAR_1->ctrl & TD_CTRL_IOC)

        *VAR_3 |= 0x01;



    if (pid == USB_TOKEN_IN) {

        if (VAR_4 > VAR_5) {

            VAR_7 = USB_RET_BABBLE;

            goto out;

        }



        if ((VAR_1->ctrl & TD_CTRL_SPD) && VAR_4 < VAR_5) {

            *VAR_3 |= 0x02;

            

            trace_usb_uhci_packet_complete_shortxfer(VAR_2->queue->token,

                                                    VAR_2->VAR_1);

            return TD_RESULT_NEXT_QH;

        }

    }



    

    trace_usb_uhci_packet_complete_success(VAR_2->queue->token, VAR_2->VAR_1);

    return TD_RESULT_COMPLETE;



out:

    



















    while (!QTAILQ_EMPTY(&VAR_2->queue->asyncs)) {

        UHCIAsync *as = QTAILQ_FIRST(&VAR_2->queue->asyncs);

        uhci_async_unlink(as);

        uhci_async_cancel(as);

    }



    switch(VAR_7) {

    case USB_RET_STALL:

        VAR_1->ctrl |= TD_CTRL_STALL;

        VAR_1->ctrl &= ~TD_CTRL_ACTIVE;

        VAR_0->status |= UHCI_STS_USBERR;

        if (VAR_1->ctrl & TD_CTRL_IOC) {

            *VAR_3 |= 0x01;

        }

        uhci_update_irq(VAR_0);

        trace_usb_uhci_packet_complete_stall(VAR_2->queue->token, VAR_2->VAR_1);

        return TD_RESULT_NEXT_QH;



    case USB_RET_BABBLE:

        VAR_1->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL;

        VAR_1->ctrl &= ~TD_CTRL_ACTIVE;

        VAR_0->status |= UHCI_STS_USBERR;

        if (VAR_1->ctrl & TD_CTRL_IOC) {

            *VAR_3 |= 0x01;

        }

        uhci_update_irq(VAR_0);

        

        trace_usb_uhci_packet_complete_babble(VAR_2->queue->token, VAR_2->VAR_1);

        return TD_RESULT_STOP_FRAME;



    case USB_RET_NAK:

        VAR_1->ctrl |= TD_CTRL_NAK;

        if (pid == USB_TOKEN_SETUP)

            break;

        return TD_RESULT_NEXT_QH;



    case USB_RET_IOERROR:

    case USB_RET_NODEV:

    default:

	break;

    }



    



    VAR_1->ctrl |= TD_CTRL_TIMEOUT;

    VAR_6 = (VAR_1->ctrl >> TD_CTRL_ERROR_SHIFT) & 3;

    if (VAR_6 != 0) {

        VAR_6--;

        if (VAR_6 == 0) {

            VAR_1->ctrl &= ~TD_CTRL_ACTIVE;

            VAR_0->status |= UHCI_STS_USBERR;

            if (VAR_1->ctrl & TD_CTRL_IOC)

                *VAR_3 |= 0x01;

            uhci_update_irq(VAR_0);

            trace_usb_uhci_packet_complete_error(VAR_2->queue->token,

                                                 VAR_2->VAR_1);

        }

    }

    VAR_1->ctrl = (VAR_1->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |

        (VAR_6 << TD_CTRL_ERROR_SHIFT);

    return TD_RESULT_NEXT_QH;

}

static int FUNC_0(UHCIState *VAR_0, UHCI_TD *VAR_1, UHCIAsync *VAR_2, uint32_t *VAR_3)
{ int VAR_4 = 0, VAR_5, VAR_6, VAR_7; uint8_t pid; VAR_5 = ((VAR_1->token >> 21) + 1) & 0x7ff; pid = VAR_1->token & 0xff; VAR_7 = VAR_2->packet.result; if (VAR_1->ctrl & TD_CTRL_IOS)
VAR_1->ctrl &= ~TD_CTRL_ACTIVE; if (VAR_7 < 0)
goto out; VAR_4 = VAR_2->packet.result; VAR_1->ctrl = (VAR_1->ctrl & ~0x7ff) | ((VAR_4 - 1) & 0x7ff); VAR_1->ctrl &= ~(TD_CTRL_ACTIVE | TD_CTRL_NAK); if (VAR_1->ctrl & TD_CTRL_IOC)
*VAR_3 |= 0x01; if (pid == USB_TOKEN_IN) { if (VAR_4 > VAR_5) { VAR_7 = USB_RET_BABBLE; goto out; } if ((VAR_1->ctrl & TD_CTRL_SPD) && VAR_4 < VAR_5) { *VAR_3 |= 0x02; trace_usb_uhci_packet_complete_shortxfer(VAR_2->queue->token,
VAR_2->VAR_1); return TD_RESULT_NEXT_QH; } } trace_usb_uhci_packet_complete_success(VAR_2->queue->token, VAR_2->VAR_1); return TD_RESULT_COMPLETE; out:
while (!QTAILQ_EMPTY(&VAR_2->queue->asyncs)) { UHCIAsync *as = QTAILQ_FIRST(&VAR_2->queue->asyncs); uhci_async_unlink(as); uhci_async_cancel(as); } switch(VAR_7) { case USB_RET_STALL:
VAR_1->ctrl |= TD_CTRL_STALL; VAR_1->ctrl &= ~TD_CTRL_ACTIVE; VAR_0->status |= UHCI_STS_USBERR; if (VAR_1->ctrl & TD_CTRL_IOC) { *VAR_3 |= 0x01; } uhci_update_irq(VAR_0); trace_usb_uhci_packet_complete_stall(VAR_2->queue->token, VAR_2->VAR_1); return TD_RESULT_NEXT_QH; case USB_RET_BABBLE:
VAR_1->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; VAR_1->ctrl &= ~TD_CTRL_ACTIVE; VAR_0->status |= UHCI_STS_USBERR; if (VAR_1->ctrl & TD_CTRL_IOC) { *VAR_3 |= 0x01; } uhci_update_irq(VAR_0); trace_usb_uhci_packet_complete_babble(VAR_2->queue->token, VAR_2->VAR_1); return TD_RESULT_STOP_FRAME; case USB_RET_NAK:
VAR_1->ctrl |= TD_CTRL_NAK; if (pid == USB_TOKEN_SETUP)
break; return TD_RESULT_NEXT_QH; case USB_RET_IOERROR:
case USB_RET_NODEV:
default:
break; } VAR_1->ctrl |= TD_CTRL_TIMEOUT; VAR_6 = (VAR_1->ctrl >> TD_CTRL_ERROR_SHIFT) & 3; if (VAR_6 != 0) { VAR_6--; if (VAR_6 == 0) { VAR_1->ctrl &= ~TD_CTRL_ACTIVE; VAR_0->status |= UHCI_STS_USBERR; if (VAR_1->ctrl & TD_CTRL_IOC)
*VAR_3 |= 0x01; uhci_update_irq(VAR_0); trace_usb_uhci_packet_complete_error(VAR_2->queue->token,
VAR_2->VAR_1); } } VAR_1->ctrl = (VAR_1->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) |
(VAR_6 << TD_CTRL_ERROR_SHIFT); return TD_RESULT_NEXT_QH; }